@unsetsoft/ryunixjs 1.1.5-nightly.77 → 1.1.5-nightly.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/Ryunix.js CHANGED
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("lodash")):"function"==typeof define&&define.amd?define(["exports","lodash"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Ryunix={},e.lodash)}(this,(function(e,t){"use strict";let o={containerRoot:{},nextUnitOfWork:{},currentRoot:{},wipRoot:{},deletions:[],wipFiber:{},hookIndex:0};const n=/[A-Z]/g,r=Object.freeze({TEXT_ELEMENT:Symbol("text.element"),Ryunix_ELEMENT:Symbol("ryunix.element"),RYUNIX_EFFECT:Symbol("ryunix.effect"),RYUNIX_MEMO:Symbol("ryunix.memo"),RYUNIX_URL_QUERY:Symbol("ryunix.urlQuery"),RYUNIX_REF:Symbol("ryunix.ref"),RYUNIX_STORE:Symbol("ryunix.store"),RYUNIX_REDUCE:Symbol("ryunix.reduce")}),i=Object.freeze({object:"object",function:"function",style:"ryunix-style",className:"ryunix-class",children:"children",boolean:"boolean",string:"string"}),s=Object.freeze({style:"style",className:"className"}),l=Object.freeze({PLACEMENT:Symbol("ryunix.reconciler.status.placement").toString(),UPDATE:Symbol("ryunix.reconciler.status.update").toString(),DELETION:Symbol("ryunix.reconciler.status.deletion").toString()}),a=({_id:e=p("fiber"),type:t,props:o,parent:n,alternate:r,effectTag:i,dom:s,child:l,sibling:a,hooks:c=[],key:u})=>({_id:e,type:t,props:o,parent:n,dom:s,alternate:r,child:l,sibling:a,effectTag:i,hooks:c,key:u}),c=e=>e.map((e=>JSON.stringify(e))).join("-"),u=(e,t)=>`${e.key}-${t.toString()}-${Math.random().toString(36).substring(2,9)}`,p=e=>`${e}-${Math.random().toString(36).substring(2,9)}`,d=e=>e.children,f=(e,t)=>(t=t||[],null==e||typeof e==i.boolean||(Array.isArray(e)?e.some((e=>{f(e,t)})):t.push(e)),t),h=(e,t,...o)=>{o=f(o,[]);const n=t&&t.key?t.key:`${r.Ryunix_ELEMENT.toString()}-${Math.random().toString(36).substring(2,9)}`;return{type:e,props:{...t,key:n,children:o.map((e=>typeof e===i.object&&null!==e?e:m(String(e))))}}},m=e=>{const t=`${r.TEXT_ELEMENT.toString()}-${Math.random().toString(36).substring(2,9)}`;return{type:r.TEXT_ELEMENT,props:{key:t,nodeValue:e,children:[]}}},y=e=>e.startsWith("on"),b=e=>e!==i.children&&!y(e),E=(e,t)=>o=>e[o]!==t[o],k=e=>t=>!(t in e),w=e=>{e.hooks&&e.hooks.filter((e=>e.tag===r.RYUNIX_EFFECT&&e.cancel)).forEach((e=>{e.cancel()}))},R=e=>{e.hooks&&e.hooks.filter((e=>e.tag===r.RYUNIX_EFFECT&&e.effect)).forEach((e=>{e.cancel=e.effect()}))},g=e=>{const t=e.type==r.TEXT_ELEMENT?document.createTextNode(""):document.createElement(e.type);return F(t,{},e.props),t},F=(e,t,o)=>{Object.keys(t).filter(y).filter((e=>k(o)(e)||E(t,o)(e))).forEach((o=>{const n=o.toLowerCase().substring(2);e.removeEventListener(n,t[o])})),Object.keys(t).filter(b).filter(k(o)).forEach((t=>{e[t]=""})),Object.keys(o).filter(b).filter(E(t,o)).forEach((n=>{if(n===i.style)_(e,o["ryunix-style"]);else if(n===s.style)_(e,o.style);else if(n===i.className){if(""===o["ryunix-class"])throw new Error("data-class cannot be empty.");t["ryunix-class"]&&e.classList.remove(...t["ryunix-class"].split(/\s+/)),e.classList.add(...o["ryunix-class"].split(/\s+/))}else if(n===s.className){if(""===o.className)throw new Error("className cannot be empty.");t.className&&e.classList.remove(...t.className.split(/\s+/)),e.classList.add(...o.className.split(/\s+/))}else e[n]=o[n]})),Object.keys(o).filter(y).filter(E(t,o)).forEach((t=>{const n=t.toLowerCase().substring(2);e.addEventListener(n,o[t])}))},_=(e,t)=>{e.style=Object.keys(t).reduce(((e,o)=>e+=`${o.replace(n,(function(e){return"-"+e.toLowerCase()}))}: ${t[o]};`),"")};var N=Object.freeze({__proto__:null,DomStyle:_,createDom:g,updateDom:F});const T=()=>{o.deletions.forEach((e=>{x(e)})),o.wipRoot&&o.wipRoot.child&&(x(o.wipRoot.child),o.currentRoot=o.wipRoot),o.wipRoot=void 0},x=e=>{if(!e)return;let t=e.parent;for(;!t.dom;)t=t.parent;const o=t.dom;if(e.effectTag===l.PLACEMENT)null!=e.dom&&o.appendChild(e.dom),R(e);else if(e.effectTag===l.UPDATE)e.alternate&&e.alternate.props!==e.props&&(w(e),null!=e.dom&&F(e.dom,e.alternate.props,e.props),R(e));else if(e.effectTag===l.DELETION)return U(e,o),void w(e);e.child&&x(e.child),e.sibling&&x(e.sibling)},U=(e,t)=>{e.dom?t.removeChild(e.dom):U(e.child,t)};var v=Object.freeze({__proto__:null,commitDeletion:U,commitRoot:T,commitWork:x});const O=(e,t)=>{let n=0,r=e.alternate&&e.alternate.child,i=null;const s=new Map;for(;r;){const e=r.props.key||r.type;s.set(e,r),r=r.sibling}for(;n<t.length;){const o=t[n],c=o.props.key||o.type;let u;r=s.get(c);r&&o&&o.type===r.type?(u=a({_id:r.id,type:r.type,props:o.props,dom:r.dom,parent:e,alternate:r,effectTag:l.UPDATE,child:r.child,sibling:r.sibling,hooks:r.hooks,key:c}),s.delete(c)):o&&(u=a({type:o.type,props:o.props,dom:void 0,parent:e,alternate:null,effectTag:l.PLACEMENT,child:null,sibling:null,hooks:[],key:c})),0===n?e.child=u:i&&(i.sibling=u),i=u,n++}s.forEach((e=>{e.effectTag=l.DELETION,o.deletions.push(e)}))};var S=Object.freeze({__proto__:null,reconcileChildren:O});const C=e=>{o.wipFiber=e,o.hookIndex=0,o.wipFiber.hooks=[];const t=e.type(e.props);O(e,Array.isArray(t)?t:[t])},L=e=>{e.dom||(e.dom=g(e)),O(e,e.props.children)};var I=Object.freeze({__proto__:null,updateFunctionComponent:C,updateHostComponent:L});const M=e=>{let t=!1;for(;o.nextUnitOfWork&&!t;)o.nextUnitOfWork=j(o.nextUnitOfWork),t=e.timeRemaining()<1;!o.nextUnitOfWork&&o.wipRoot&&T(),o.wipRoot&&requestIdleCallback(M)};function j(e){if(e.type instanceof Function?C(e):L(e),e.child)return e.child;let t=e;for(;t;){if(t.sibling)return t.sibling;t=t.parent}}const X=(e,t)=>{o.wipRoot={dom:t,props:{children:[e]},alternate:o.currentRoot},o.deletions=[],o.nextUnitOfWork=o.wipRoot,requestIdleCallback(M)},Y=(e,t,n)=>{const i=u(o.wipFiber,r.RYUNIX_REDUCE),s=o.wipFiber.alternate?.hooks?.[i],l=q((()=>n?n(t):t),[]),a={state:s?s.state:l,queue:s?s.queue:[],reducer:e};console.log(`--------------[${i}]------------------`),console.log("[useReducer] initial state ",t),console.log("[useReducer] hook.state: ",a.state),console.log("[useReducer] hook.reducer: ",a.reducer),console.log("[useReducer] hook.queue: ",a.queue),console.log("[useReducer] hook: ",a),console.log("---------------------------------------------");const c=A((e=>{a.queue.push(e),o.wipRoot={dom:o.currentRoot.dom,props:o.currentRoot.props,alternate:o.currentRoot},o.nextUnitOfWork=o.wipRoot,o.deletions=[],requestIdleCallback(M)}),[]);return a.queue.forEach((e=>{a.state=a.reducer(a.state,e)})),a.queue=[],o.wipFiber.hooks=o.wipFiber.hooks||[],o.wipFiber.hooks[i]=a,$((()=>{console.log("El estado se ha actualizado: ",a.state)}),[a.state]),[a.state,c]},D=e=>Y(((e,t)=>typeof t===i.function?t(e):t),e),$=(e,n)=>{const s=u(o.wipFiber,r.RYUNIX_EFFECT),l=o.wipFiber.alternate&&o.wipFiber.alternate.hooks&&o.wipFiber.alternate.hooks[s],a={type:r.RYUNIX_EFFECT,deps:n,cleanup:null};l&&t.isEqual(l.deps,a.deps)||(typeof l?.cleanup===i.function&&l.cleanup(),a.cleanup=e()),o.wipFiber.hooks=o.wipFiber.hooks||[],o.wipFiber.hooks[s]=a},q=(e,t)=>{const n=u(o.wipFiber,r.RYUNIX_MEMO),i=o.wipFiber.alternate&&o.wipFiber.alternate.hooks&&o.wipFiber.alternate.hooks[n],s={type:r.RYUNIX_MEMO,value:null,deps:t,hash:c(t)};return i&&i.hash===s.hash?s.value=i.value:s.value=e(),o.wipFiber.hooks=o.wipFiber.hooks||[],o.wipFiber.hooks[n]=s,s.value},A=(e,t)=>q((()=>e),t),W=()=>{const e=new URLSearchParams(window.location.search),t={};for(let[o,n]of e.entries())t[o]=n;return t};var z={createElement:h,render:X,init:(e,t="__ryunix")=>{o.containerRoot=document.getElementById(t),X(e,o.containerRoot)},Fragment:d,Dom:N,Workers:Object.freeze({__proto__:null,performUnitOfWork:j,workLoop:M}),Reconciler:S,Components:I,Commits:v,RYUNIX_VARS:o};window.Ryunix=z,e.Fragment=d,e.default=z,e.useCallback=A,e.useEffect=$,e.useMemo=q,e.useQuery=W,e.useReducer=Y,e.useRef=e=>{const t=u(o.wipFiber,r.RYUNIX_REF),n=o.wipFiber.alternate&&o.wipFiber.alternate.hooks&&o.wipFiber.alternate.hooks[t],i={type:r.RYUNIX_REF,value:n?n.value:{current:e}};return o.wipFiber.hooks=o.wipFiber.hooks||[],o.wipFiber.hooks[t]=i,i.value},e.useRouter=e=>{const[t,o]=D(window.location.pathname),n=(e,t)=>{const o=t.split("?")[0],r=e.find((e=>e.NotFound)),i=r?{route:{component:r.NotFound},params:{}}:{route:{component:null},params:{}};for(const r of e){if(r.subRoutes){const e=n(r.subRoutes,t);if(e)return e}if("*"===r.path)return i;if(!r.path||"string"!=typeof r.path){console.warn("Invalid route detected:",r),console.info("if you are using { NotFound: NotFound } please add { path: '*', NotFound: NotFound }");continue}const e=[],s=new RegExp(`^${r.path.replace(/:\w+/g,(t=>(e.push(t.substring(1)),"([^/]+)")))}$`),l=o.match(s);if(l){return{route:r,params:e.reduce(((e,t,o)=>(e[t]=l[o+1],e)),{})}}}return i},r=e=>{window.history.pushState({},"",e),s(e)},s=e=>{const t=e.split("?")[0];o(t)};$((()=>{const e=()=>s(window.location.pathname);return window.addEventListener("popstate",e),()=>window.removeEventListener("popstate",e)}),[]);const l=n(e,t)||{};return{Children:()=>{const e=W(),{route:t}=l;return t&&t.component&&typeof t.component===i.function?t.component({params:l.params||{},query:e}):(console.error("Component not found for current path or the component is not a valid function:",l),null)},NavLink:({to:e,...t})=>h("a",{href:e,onClick:t=>{t.preventDefault(),r(e)},...t},t.children),navigate:r}},e.useStore=D,Object.defineProperty(e,"__esModule",{value:!0})}));
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("lodash")):"function"==typeof define&&define.amd?define(["exports","lodash"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Ryunix={},e.lodash)}(this,(function(e,t){"use strict";let o={containerRoot:{},nextUnitOfWork:{},currentRoot:{},wipRoot:{},deletions:[],wipFiber:{},hookIndex:0};const n=/[A-Z]/g,r=Object.freeze({TEXT_ELEMENT:Symbol("text.element"),Ryunix_ELEMENT:Symbol("ryunix.element"),RYUNIX_EFFECT:Symbol("ryunix.effect"),RYUNIX_MEMO:Symbol("ryunix.memo"),RYUNIX_URL_QUERY:Symbol("ryunix.urlQuery"),RYUNIX_REF:Symbol("ryunix.ref"),RYUNIX_STORE:Symbol("ryunix.store"),RYUNIX_REDUCE:Symbol("ryunix.reduce")}),s=Object.freeze({object:"object",function:"function",style:"ryunix-style",className:"ryunix-class",children:"children",boolean:"boolean",string:"string"}),i=Object.freeze({style:"style",className:"className"}),l=Object.freeze({PLACEMENT:Symbol("ryunix.reconciler.status.placement").toString(),UPDATE:Symbol("ryunix.reconciler.status.update").toString(),DELETION:Symbol("ryunix.reconciler.status.deletion").toString()}),a=({_id:e=u("fiber"),type:t,props:o,parent:n,alternate:r,effectTag:s,dom:i,child:l,sibling:a,hooks:c=[],key:p})=>({_id:e,type:t,props:o,parent:n,dom:i,alternate:r,child:l,sibling:a,effectTag:s,hooks:c,key:p}),c=(e,t)=>`${e.key}-${t.toString()}-${Math.random().toString(36).substring(2,9)}`,u=e=>`${e}-${Math.random().toString(36).substring(2,9)}`,p=e=>e.children,d=(e,t)=>(t=t||[],null==e||typeof e==s.boolean||(Array.isArray(e)?e.some((e=>{d(e,t)})):t.push(e)),t),f=(e,t,...o)=>{o=d(o,[]);const n=t&&t.key?t.key:`${r.Ryunix_ELEMENT.toString()}-${Math.random().toString(36).substring(2,9)}`;return{type:e,props:{...t,key:n,children:o.map((e=>typeof e===s.object&&null!==e?e:h(String(e))))}}},h=e=>{const t=`${r.TEXT_ELEMENT.toString()}-${Math.random().toString(36).substring(2,9)}`;return{type:r.TEXT_ELEMENT,props:{key:t,nodeValue:e,children:[]}}},m=(e,t)=>{o.wipRoot={dom:o.containerRoot||t,props:{children:[e]},alternate:o.currentRoot},o.deletions=[],o.nextUnitOfWork=o.wipRoot},y=e=>e.startsWith("on"),b=e=>e!==s.children&&!y(e),E=(e,t)=>o=>e[o]!==t[o],k=e=>t=>!(t in e),R=e=>{e.hooks&&e.hooks.filter((e=>e.tag===r.RYUNIX_EFFECT&&e.cancel)).forEach((e=>{e.cancel()}))},w=e=>{e.hooks&&e.hooks.filter((e=>e.tag===r.RYUNIX_EFFECT&&e.effect)).forEach((e=>{e.cancel=e.effect()}))},g=e=>{const t=e.type==r.TEXT_ELEMENT?document.createTextNode(""):document.createElement(e.type);return _(t,{},e.props),t},_=(e,t,o)=>{Object.keys(t).filter(y).filter((e=>k(o)(e)||E(t,o)(e))).forEach((o=>{const n=o.toLowerCase().substring(2);e.removeEventListener(n,t[o])})),Object.keys(t).filter(b).filter(k(o)).forEach((t=>{e[t]=""})),Object.keys(o).filter(b).filter(E(t,o)).forEach((n=>{if(n===s.style)F(e,o["ryunix-style"]);else if(n===i.style)F(e,o.style);else if(n===s.className){if(""===o["ryunix-class"])throw new Error("data-class cannot be empty.");t["ryunix-class"]&&e.classList.remove(...t["ryunix-class"].split(/\s+/)),e.classList.add(...o["ryunix-class"].split(/\s+/))}else if(n===i.className){if(""===o.className)throw new Error("className cannot be empty.");t.className&&e.classList.remove(...t.className.split(/\s+/)),e.classList.add(...o.className.split(/\s+/))}else e[n]=o[n]})),Object.keys(o).filter(y).filter(E(t,o)).forEach((t=>{const n=t.toLowerCase().substring(2);e.addEventListener(n,o[t])}))},F=(e,t)=>{e.style=Object.keys(t).reduce(((e,o)=>e+=`${o.replace(n,(function(e){return"-"+e.toLowerCase()}))}: ${t[o]};`),"")};var N=Object.freeze({__proto__:null,DomStyle:F,createDom:g,updateDom:_});const x=()=>{o.deletions.forEach(T),o.wipRoot&&o.wipRoot.child&&(T(o.wipRoot.child),o.currentRoot=o.wipRoot),o.wipRoot=void 0},T=e=>{if(!e)return;let t=e.parent;for(;!t.dom;)t=t.parent;const o=t.dom;if(e.effectTag===l.PLACEMENT&&(null!=e.dom&&o.appendChild(e.dom),w(e)),e.effectTag===l.UPDATE&&(R(e),null!=e.dom&&_(e.dom,e.alternate.props,e.props),w(e)),e.effectTag===l.DELETION)return U(e,o),void R(e);T(e.child),T(e.sibling)},U=(e,t)=>{e.dom?t.removeChild(e.dom):U(e.child,t)};var O=Object.freeze({__proto__:null,commitDeletion:U,commitRoot:x,commitWork:T});const v=(e,t)=>{let n=0,r=e.alternate&&e.alternate.child,s=null;const i=new Map;for(;r;){const e=r.props.key||r.type;i.set(e,r),r=r.sibling}for(;n<t.length;){const r=t[n],c=r.props.key||r.type,u=i.get(c);let p;u&&r&&r.type===u.type?(p=a({_id:u.id,type:u.type,props:r.props,dom:u.dom,parent:e,alternate:u,effectTag:l.UPDATE,child:u.child,sibling:u.sibling,hooks:u.hooks,key:c}),i.delete(c)):r&&(p=a({type:r.type,props:r.props,dom:void 0,parent:e,alternate:null,effectTag:l.PLACEMENT,child:null,sibling:null,hooks:[],key:c})),i.forEach((e=>{e.effectTag=l.DELETION,o.deletions.push(e)})),0===n?e.child=p:s&&(s.sibling=p),s=p,n++}};var I=Object.freeze({__proto__:null,reconcileChildren:v});const S=e=>{o.wipFiber=e,o.hookIndex=0,o.wipFiber.hooks=[];const t=e.type(e.props);v(e,Array.isArray(t)?t:[t])},C=e=>{e.dom||(e.dom=g(e)),v(e,e.props.children)};var L=Object.freeze({__proto__:null,updateFunctionComponent:S,updateHostComponent:C});const M=e=>{let t=!1;for(;o.nextUnitOfWork&&!t;)o.nextUnitOfWork=X(o.nextUnitOfWork),t=e.timeRemaining()<1;!o.nextUnitOfWork&&o.wipRoot&&x(),requestIdleCallback(M)};requestIdleCallback(M);const X=e=>{if(e.type instanceof Function?S(e):C(e),e.child)return e.child;let t=e;for(;t;){if(t.sibling)return t.sibling;t=t.parent}};const j=(e,t=!1)=>{if(t)return((e,t,n)=>{const s=c(o.wipFiber,r.RYUNIX_REDUCE),i=o.wipFiber.alternate?.hooks?.[s],l=Y((()=>n?n(t):t),[]),a={state:i?i.state:l,queue:i?i.queue:[],reducer:e};console.log(`--------------[${s}]------------------`),console.log("[useReducer] initial state ",t),console.log("[useReducer] hook.state: ",a.state),console.log("[useReducer] hook.reducer: ",a.reducer),console.log("[useReducer] hook.queue: ",a.queue),console.log("[useReducer] hook: ",a),console.log("---------------------------------------------");const u=D((e=>{a.queue.push(e),o.wipRoot={dom:o.currentRoot.dom,props:o.currentRoot.props,alternate:o.currentRoot},o.nextUnitOfWork=o.wipRoot,o.deletions=[],requestIdleCallback(M)}),[]);return a.queue.forEach((e=>{a.state=a.reducer(a.state,e)})),a.queue=[],o.wipFiber.hooks=o.wipFiber.hooks||[],o.wipFiber.hooks[s]=a,q((()=>{console.log("El estado se ha actualizado: ",a.state)}),[a.state]),[a.state,u]})(((e,t)=>typeof t===s.function?t(e):t),e);const n=c(o.wipFiber,r.RYUNIX_STORE),i=o.wipFiber.alternate?.hooks?.[n],l={state:i?i.state:e,queue:i?[...i.queue]:[]};l.queue.forEach((e=>{l.state=typeof e===s.function?e(l.state):e})),l.queue=[];return o.wipFiber&&o.wipFiber.hooks&&(o.wipFiber.hooks.push(l),o.hookIndex++),[l.state,e=>{l.queue.push(e),o.wipRoot={dom:o.currentRoot.dom,props:o.currentRoot.props,alternate:o.currentRoot},o.nextUnitOfWork=o.wipRoot,o.deletions=[]}]},q=(e,n)=>{const s=c(o.wipFiber,r.RYUNIX_EFFECT),i=o.wipFiber.alternate?.hooks?.[s],l={type:r.RYUNIX_EFFECT,deps:n};i&&t.isEqual(i.deps,l.deps)||e(),o.wipFiber.hooks&&(o.wipFiber.hooks.push(l),o.hookIndex++)},Y=(e,n)=>{const s=c(o.wipFiber,r.RYUNIX_MEMO),i=o.wipFiber.alternate?.hooks?.[s],l={type:r.RYUNIX_MEMO,value:null,deps:n};return i&&t.isEqual(i.deps,l.deps)?l.value=i.value:l.value=e(),o.wipFiber.hooks&&(o.wipFiber.hooks.push(l),o.hookIndex++),l.value},D=(e,t)=>Y((()=>e),t),$=()=>{const e=new URLSearchParams(window.location.search),t={};for(let[o,n]of e.entries())t[o]=n;return t};var W={createElement:f,render:m,init:(e,t="__ryunix")=>{o.containerRoot=document.getElementById(t),m(e,o.containerRoot)},Fragment:p,Dom:N,Workers:Object.freeze({__proto__:null,performUnitOfWork:X,workLoop:M}),Reconciler:I,Components:L,Commits:O};window.Ryunix=W,e.Fragment=p,e.default=W,e.useCallback=D,e.useEffect=q,e.useMemo=Y,e.useQuery=$,e.useRef=e=>{const t=c(o.wipFiber,r.RYUNIX_REF),n=o.wipFiber.alternate?.hooks?.[t],s={type:r.RYUNIX_REF,value:n?n.value:{current:e}};return o.wipFiber.hooks&&(o.wipFiber.hooks.push(s),o.hookIndex++),s.value},e.useRouter=e=>{const[t,o]=j(window.location.pathname),n=(e,t)=>{const o=t.split("?")[0],r=e.find((e=>e.NotFound)),s=r?{route:{component:r.NotFound},params:{}}:{route:{component:null},params:{}};for(const r of e){if(r.subRoutes){const e=n(r.subRoutes,t);if(e)return e}if("*"===r.path)return s;if(!r.path||"string"!=typeof r.path){console.warn("Invalid route detected:",r),console.info("if you are using { NotFound: NotFound } please add { path: '*', NotFound: NotFound }");continue}const e=[],i=new RegExp(`^${r.path.replace(/:\w+/g,(t=>(e.push(t.substring(1)),"([^/]+)")))}$`),l=o.match(i);if(l){return{route:r,params:e.reduce(((e,t,o)=>(e[t]=l[o+1],e)),{})}}}return s},r=e=>{window.history.pushState({},"",e),i(e)},i=e=>{const t=e.split("?")[0];o(t)};q((()=>{const e=()=>i(window.location.pathname);return window.addEventListener("popstate",e),()=>window.removeEventListener("popstate",e)}),[]);const l=n(e,t)||{};return{Children:()=>{const e=$(),{route:t}=l;return t&&t.component&&typeof t.component===s.function?t.component({params:l.params||{},query:e}):(console.error("Component not found for current path or the component is not a valid function:",l),null)},NavLink:({to:e,...t})=>f("a",{href:e,onClick:t=>{t.preventDefault(),r(e)},...t},t.children),navigate:r}},e.useStore=j,Object.defineProperty(e,"__esModule",{value:!0})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unsetsoft/ryunixjs",
3
- "version": "1.1.5-nightly.77",
3
+ "version": "1.1.5-nightly.78",
4
4
  "license": "MIT",
5
5
  "main": "./dist/Ryunix.js",
6
6
  "types": "./dist/Ryunix.d.ts",
@@ -11,16 +11,16 @@
11
11
  "homepage": "https://github.com/UnSetSoft/Ryunixjs#readme",
12
12
  "scripts": {
13
13
  "build:js": "rollup ./src/main.js --file ./dist/Ryunix.js --format umd --name Ryunix --plugin @rollup/plugin-terser",
14
- "build": "rollup ./src/main.js --file ./dist/Ryunix.um.js --format umd --name Ryunix",
15
14
  "prepublishOnly": "npm run build:js",
15
+ "postinstall": "npm run build:js",
16
16
  "nightly:release": "npm publish --tag nightly",
17
17
  "release": "npm publish",
18
18
  "lint": "eslint . --ext .ts --fix --max-warnings=0 --config .eslintrc.js --no-eslintrc"
19
19
  },
20
20
  "dependencies": {
21
- "@rollup/plugin-terser": "0.4.4",
21
+ "@rollup/plugin-terser": "^0.4.4",
22
22
  "eslint": "8.56.0",
23
- "lodash": "4.17.20",
23
+ "lodash": "^4.17.20",
24
24
  "rollup": "4.9.2"
25
25
  },
26
26
  "engines": {
package/dist/Ryunix.um.js DELETED
@@ -1,1016 +0,0 @@
1
- ;(function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined'
3
- ? factory(exports, require('lodash'))
4
- : typeof define === 'function' && define.amd
5
- ? define(['exports', 'lodash'], factory)
6
- : ((global =
7
- typeof globalThis !== 'undefined' ? globalThis : global || self),
8
- factory((global.Ryunix = {}), global.lodash))
9
- })(this, function (exports, lodash) {
10
- 'use strict'
11
-
12
- let vars = {
13
- containerRoot: null,
14
- nextUnitOfWork: null,
15
- currentRoot: null,
16
- wipRoot: null,
17
- deletions: null,
18
- wipFiber: null,
19
- hookIndex: null,
20
- }
21
-
22
- const reg = /[A-Z]/g
23
-
24
- const RYUNIX_TYPES = Object.freeze({
25
- TEXT_ELEMENT: Symbol('text.element'),
26
- Ryunix_ELEMENT: Symbol('ryunix.element'),
27
- RYUNIX_EFFECT: Symbol('ryunix.effect'),
28
- RYUNIX_MEMO: Symbol('ryunix.memo'),
29
- RYUNIX_URL_QUERY: Symbol('ryunix.urlQuery'),
30
- RYUNIX_REF: Symbol('ryunix.ref'),
31
- RYUNIX_STORE: Symbol('ryunix.store'),
32
- RYUNIX_REDUCE: Symbol('ryunix.reduce'),
33
- })
34
-
35
- const STRINGS = Object.freeze({
36
- object: 'object',
37
- function: 'function',
38
- style: 'ryunix-style',
39
- className: 'ryunix-class',
40
- children: 'children',
41
- boolean: 'boolean',
42
- string: 'string',
43
- })
44
-
45
- const OLD_STRINGS = Object.freeze({
46
- style: 'style',
47
- className: 'className',
48
- })
49
-
50
- const EFFECT_TAGS = Object.freeze({
51
- PLACEMENT: Symbol(),
52
- UPDATE: Symbol(),
53
- DELETION: Symbol(),
54
- })
55
-
56
- const generateHash = (deps) => {
57
- return deps.map((dep) => JSON.stringify(dep)).join('-')
58
- }
59
-
60
- const generateHookHash = (fiber, descriptor) => {
61
- return `${fiber.key}-${descriptor.toString()}-${Math.random().toString(36).substring(2, 9)}` // Or any other unique combination
62
- }
63
-
64
- const Fragment = (props) => {
65
- return props.children
66
- }
67
-
68
- const childArray = (children, out) => {
69
- out = out || []
70
- if (children == undefined || typeof children == STRINGS.boolean);
71
- else if (Array.isArray(children)) {
72
- children.some((child) => {
73
- childArray(child, out)
74
- })
75
- } else {
76
- out.push(children)
77
- }
78
- return out
79
- }
80
-
81
- /**
82
- * The function creates a new element with the given type, props, and children.
83
- * @param type - The type of the element to be created, such as "div", "span", "h1", etc.
84
- * @param props - The `props` parameter is an object that contains the properties or attributes of the
85
- * element being created. These properties can include things like `className`, `id`, `style`, and any
86
- * other custom attributes that the user wants to add to the element. The `props` object is spread
87
- * using the spread
88
- * @param children - The `children` parameter is a rest parameter that allows the function to accept
89
- * any number of arguments after the `props` parameter. These arguments will be treated as children
90
- * elements of the created element. The `map` function is used to iterate over each child and create a
91
- * new element if it is not
92
- * @returns A JavaScript object with a `type` property and a `props` property. The `type` property is
93
- * set to the `type` argument passed into the function, and the `props` property is an object that
94
- * includes any additional properties passed in the `props` argument, as well as a `children` property
95
- * that is an array of any child elements passed in the `...children` argument
96
- */
97
-
98
- const createElement = (type, props, ...children) => {
99
- children = childArray(children, [])
100
- const key =
101
- props && props.key
102
- ? props.key
103
- : `${RYUNIX_TYPES.Ryunix_ELEMENT.toString()}-${Math.random().toString(36).substring(2, 9)}`
104
-
105
- return {
106
- type,
107
- props: {
108
- ...props,
109
- key,
110
- children: children.map((child) =>
111
- typeof child === STRINGS.object && child !== null
112
- ? child
113
- : createTextElement(String(child)),
114
- ),
115
- },
116
- }
117
- }
118
-
119
- /**
120
- * The function creates a text element with a given text value.
121
- * @param text - The text content that will be used to create a new text element.
122
- * @returns A JavaScript object with a `type` property set to `"TEXT_ELEMENT"` and a `props` property
123
- * that contains a `nodeValue` property set to the `text` parameter and an empty `children` array.
124
- */
125
-
126
- const createTextElement = (text) => {
127
- const key = `${RYUNIX_TYPES.TEXT_ELEMENT.toString()}-${Math.random().toString(36).substring(2, 9)}`
128
- return {
129
- type: RYUNIX_TYPES.TEXT_ELEMENT,
130
- props: {
131
- key,
132
- nodeValue: text,
133
- children: [],
134
- },
135
- }
136
- }
137
-
138
- const isEvent = (key) => key.startsWith('on')
139
- const isProperty = (key) => key !== STRINGS.children && !isEvent(key)
140
- const isNew = (prev, next) => (key) => prev[key] !== next[key]
141
- const isGone = (next) => (key) => !(key in next)
142
-
143
- /**
144
- * The function cancels all effect hooks in a given fiber.
145
- * @param fiber - The "fiber" parameter is likely referring to a data structure used in React.js to
146
- * represent a component and its state. It contains information about the component's props, state, and
147
- * children, as well as metadata used by React to manage updates and rendering. The function
148
- * "cancelEffects" is likely intended
149
- */
150
- const cancelEffects = (fiber) => {
151
- if (fiber.hooks) {
152
- fiber.hooks
153
- .filter(
154
- (hook) => hook.tag === RYUNIX_TYPES.RYUNIX_EFFECT && hook.cancel,
155
- )
156
- .forEach((effectHook) => {
157
- effectHook.cancel()
158
- })
159
- }
160
- }
161
-
162
- /**
163
- * The function runs all effect hooks in a given fiber.
164
- * @param fiber - The "fiber" parameter is likely referring to a data structure used in the
165
- * implementation of a fiber-based reconciliation algorithm, such as the one used in React. A fiber
166
- * represents a unit of work that needs to be performed by the reconciliation algorithm, and it
167
- * contains information about a component and its children, as
168
- */
169
- const runEffects = (fiber) => {
170
- if (fiber.hooks) {
171
- fiber.hooks
172
- .filter(
173
- (hook) => hook.tag === RYUNIX_TYPES.RYUNIX_EFFECT && hook.effect,
174
- )
175
- .forEach((effectHook) => {
176
- effectHook.cancel = effectHook.effect()
177
- })
178
- }
179
- }
180
-
181
- /**
182
- * The function creates a new DOM element based on the given fiber object and updates its properties.
183
- * @param fiber - The fiber parameter is an object that represents a node in the fiber tree. It
184
- * contains information about the element type, props, and children of the node.
185
- * @returns The `createDom` function returns a newly created DOM element based on the `fiber` object
186
- * passed as an argument. If the `fiber` object represents a text element, a text node is created using
187
- * `document.createTextNode("")`. Otherwise, a new element is created using
188
- * `document.createElement(fiber.type)`. The function then calls the `updateDom` function to update the
189
- * properties of the newly created
190
- */
191
- const createDom = (fiber) => {
192
- const dom =
193
- fiber.type == RYUNIX_TYPES.TEXT_ELEMENT
194
- ? document.createTextNode('')
195
- : document.createElement(fiber.type)
196
-
197
- updateDom(dom, {}, fiber.props)
198
-
199
- return dom
200
- }
201
-
202
- /**
203
- * The function updates the DOM by removing old event listeners and properties, and adding new ones
204
- * based on the previous and next props.
205
- * @param dom - The DOM element that needs to be updated with new props.
206
- * @param prevProps - An object representing the previous props (properties) of a DOM element.
207
- * @param nextProps - An object containing the new props that need to be updated in the DOM.
208
- */
209
- const updateDom = (dom, prevProps, nextProps) => {
210
- Object.keys(prevProps)
211
- .filter(isEvent)
212
- .filter(
213
- (key) => isGone(nextProps)(key) || isNew(prevProps, nextProps)(key),
214
- )
215
- .forEach((name) => {
216
- const eventType = name.toLowerCase().substring(2)
217
- dom.removeEventListener(eventType, prevProps[name])
218
- })
219
-
220
- Object.keys(prevProps)
221
- .filter(isProperty)
222
- .filter(isGone(nextProps))
223
- .forEach((name) => {
224
- dom[name] = ''
225
- })
226
-
227
- Object.keys(nextProps)
228
- .filter(isProperty)
229
- .filter(isNew(prevProps, nextProps))
230
- .forEach((name) => {
231
- if (name === STRINGS.style) {
232
- DomStyle(dom, nextProps['ryunix-style'])
233
- } else if (name === OLD_STRINGS.style) {
234
- DomStyle(dom, nextProps.style)
235
- } else if (name === STRINGS.className) {
236
- if (nextProps['ryunix-class'] === '') {
237
- throw new Error('data-class cannot be empty.')
238
- }
239
-
240
- prevProps['ryunix-class'] &&
241
- dom.classList.remove(...prevProps['ryunix-class'].split(/\s+/))
242
- dom.classList.add(...nextProps['ryunix-class'].split(/\s+/))
243
- } else if (name === OLD_STRINGS.className) {
244
- if (nextProps.className === '') {
245
- throw new Error('className cannot be empty.')
246
- }
247
-
248
- prevProps.className &&
249
- dom.classList.remove(...prevProps.className.split(/\s+/))
250
- dom.classList.add(...nextProps.className.split(/\s+/))
251
- } else {
252
- dom[name] = nextProps[name]
253
- }
254
- })
255
-
256
- Object.keys(nextProps)
257
- .filter(isEvent)
258
- .filter(isNew(prevProps, nextProps))
259
- .forEach((name) => {
260
- const eventType = name.toLowerCase().substring(2)
261
- dom.addEventListener(eventType, nextProps[name])
262
- })
263
- }
264
-
265
- const DomStyle = (dom, style) => {
266
- dom.style = Object.keys(style).reduce((acc, styleName) => {
267
- const key = styleName.replace(reg, function (v) {
268
- return '-' + v.toLowerCase()
269
- })
270
- acc += `${key}: ${style[styleName]};`
271
- return acc
272
- }, '')
273
- }
274
-
275
- var Dom = /*#__PURE__*/ Object.freeze({
276
- __proto__: null,
277
- DomStyle: DomStyle,
278
- createDom: createDom,
279
- updateDom: updateDom,
280
- })
281
-
282
- /**
283
- * The function commits changes made to the virtual DOM to the actual DOM.
284
- */
285
- const commitRoot = () => {
286
- // Eliminar nodos marcados para eliminación
287
- vars.deletions.forEach((fiber) => {
288
- console.log(`Eliminando nodo con key: ${fiber.props.key}`)
289
- commitWork(fiber)
290
- })
291
-
292
- // Si existe un hijo en la raíz de trabajo, aplicar el commit en el árbol de hijos
293
- if (vars.wipRoot && vars.wipRoot.child) {
294
- console.log('Iniciando commit de la raíz...')
295
- commitWork(vars.wipRoot.child)
296
- vars.currentRoot = vars.wipRoot
297
- }
298
-
299
- // Limpiar la raíz de trabajo
300
- vars.wipRoot = undefined
301
- }
302
-
303
- /**
304
- * The function commits changes made to the DOM based on the effect tag of the fiber.
305
- * @param fiber - A fiber is a unit of work in Ryunix's reconciliation process. It represents a
306
- * component and its state at a particular point in time. The `commitWork` function takes a fiber as a
307
- * parameter to commit the changes made during the reconciliation process to the actual DOM.
308
- * @returns The function does not return anything, it performs side effects by manipulating the DOM.
309
- */
310
- const commitWork = (fiber) => {
311
- if (!fiber) return
312
-
313
- let domParentFiber = fiber.parent
314
- while (!domParentFiber.dom) {
315
- domParentFiber = domParentFiber.parent
316
- }
317
- const domParent = domParentFiber.dom
318
-
319
- if (fiber.effectTag === EFFECT_TAGS.PLACEMENT) {
320
- if (fiber.dom != null) {
321
- domParent.appendChild(fiber.dom)
322
- }
323
- runEffects(fiber)
324
- } else if (fiber.effectTag === EFFECT_TAGS.UPDATE) {
325
- if (fiber.alternate && fiber.alternate.props !== fiber.props) {
326
- cancelEffects(fiber)
327
- if (fiber.dom != null) {
328
- updateDom(fiber.dom, fiber.alternate.props, fiber.props)
329
- }
330
- runEffects(fiber)
331
- }
332
- } else if (fiber.effectTag === EFFECT_TAGS.DELETION) {
333
- commitDeletion(fiber, domParent)
334
- cancelEffects(fiber)
335
- return
336
- }
337
-
338
- if (fiber.child) {
339
- commitWork(fiber.child)
340
- }
341
- if (fiber.sibling) commitWork(fiber.sibling)
342
- }
343
-
344
- /**
345
- * The function removes a fiber's corresponding DOM node from its parent node or recursively removes
346
- * its child's DOM node until it finds a node to remove.
347
- * @param fiber - a fiber node in a fiber tree, which represents a component or an element in the Ryunix
348
- * application.
349
- * @param domParent - The parent DOM element from which the fiber's DOM element needs to be removed.
350
- */
351
- const commitDeletion = (fiber, domParent) => {
352
- if (fiber.dom) {
353
- domParent.removeChild(fiber.dom)
354
- } else {
355
- commitDeletion(fiber.child, domParent)
356
- }
357
- }
358
-
359
- var Commits = /*#__PURE__*/ Object.freeze({
360
- __proto__: null,
361
- commitDeletion: commitDeletion,
362
- commitRoot: commitRoot,
363
- commitWork: commitWork,
364
- })
365
-
366
- /**
367
- * This function reconciles the children of a fiber node with a new set of elements, creating new
368
- * fibers for new elements, updating existing fibers for elements with the same type, and marking old
369
- * fibers for deletion if they are not present in the new set of elements.
370
- * @param wipFiber - A work-in-progress fiber object representing a component or element in the virtual
371
- * DOM tree.
372
- * @param elements - an array of elements representing the new children to be rendered in the current
373
- * fiber's subtree
374
- */
375
- const reconcileChildren = (wipFiber, elements) => {
376
- let index = 0
377
- let oldFiber = wipFiber.alternate && wipFiber.alternate.child
378
- let prevSibling = null
379
-
380
- const oldFibersMap = new Map()
381
- while (oldFiber) {
382
- const oldKey = oldFiber.props.key || oldFiber.type
383
- oldFibersMap.set(oldKey, oldFiber)
384
- oldFiber = oldFiber.sibling
385
- }
386
-
387
- while (index < elements.length) {
388
- const element = elements[index]
389
- const key = element.props.key || element.type
390
- oldFiber = oldFibersMap.get(key)
391
-
392
- let newFiber
393
- const sameType = oldFiber && element && element.type === oldFiber.type
394
-
395
- if (sameType) {
396
- newFiber = {
397
- type: oldFiber.type,
398
- props: element.props,
399
- dom: oldFiber.dom,
400
- parent: wipFiber,
401
- alternate: oldFiber,
402
- effectTag: EFFECT_TAGS.UPDATE,
403
- }
404
-
405
- oldFibersMap.delete(key)
406
- } else if (element) {
407
- newFiber = {
408
- type: element.type,
409
- props: element.props,
410
- dom: undefined,
411
- parent: wipFiber,
412
- alternate: undefined,
413
- effectTag: EFFECT_TAGS.PLACEMENT,
414
- }
415
- }
416
-
417
- if (index === 0) {
418
- wipFiber.child = newFiber
419
- } else if (prevSibling) {
420
- prevSibling.sibling = newFiber
421
- }
422
-
423
- prevSibling = newFiber
424
- index++
425
- }
426
-
427
- oldFibersMap.forEach((oldFiber) => {
428
- oldFiber.effectTag = EFFECT_TAGS.DELETION
429
- vars.deletions.push(oldFiber)
430
- })
431
- }
432
-
433
- var Reconciler = /*#__PURE__*/ Object.freeze({
434
- __proto__: null,
435
- reconcileChildren: reconcileChildren,
436
- })
437
-
438
- /**
439
- * This function updates a function component by setting up a work-in-progress fiber, resetting the
440
- * hook index, creating an empty hooks array, rendering the component, and reconciling its children.
441
- * @param fiber - The fiber parameter is an object that represents a node in the fiber tree. It
442
- * contains information about the component, its props, state, and children. In this function, it is
443
- * used to update the state of the component and its children.
444
- */
445
- const updateFunctionComponent = (fiber) => {
446
- vars.wipFiber = fiber
447
- vars.hookIndex = 0
448
- vars.wipFiber.hooks = []
449
-
450
- const children = fiber.type(fiber.props)
451
-
452
- reconcileChildren(fiber, Array.isArray(children) ? children : [children])
453
- }
454
-
455
- /**
456
- * This function updates a host component's DOM element and reconciles its children.
457
- * @param fiber - A fiber is a unit of work in Ryunix that represents a component and its state. It
458
- * contains information about the component's type, props, and children, as well as pointers to other
459
- * fibers in the tree.
460
- */
461
- const updateHostComponent = (fiber) => {
462
- if (!fiber.dom) {
463
- fiber.dom = createDom(fiber)
464
- }
465
- reconcileChildren(fiber, fiber.props.children)
466
- }
467
-
468
- var Components = /*#__PURE__*/ Object.freeze({
469
- __proto__: null,
470
- updateFunctionComponent: updateFunctionComponent,
471
- updateHostComponent: updateHostComponent,
472
- })
473
-
474
- /**
475
- * This function uses requestIdleCallback to perform work on a fiber tree until it is complete or the
476
- * browser needs to yield to other tasks.
477
- * @param deadline - The `deadline` parameter is an object that represents the amount of time the
478
- * browser has to perform work before it needs to handle other tasks. It has a `timeRemaining()` method
479
- * that returns the amount of time remaining before the deadline is reached. The `shouldYield` variable
480
- * is used to determine
481
- */
482
- const workLoop = (deadline) => {
483
- let shouldYield = false
484
- while (vars.nextUnitOfWork && !shouldYield) {
485
- console.log('Procesando unidad de trabajo:', vars.nextUnitOfWork)
486
- vars.nextUnitOfWork = performUnitOfWork(vars.nextUnitOfWork)
487
- shouldYield = deadline.timeRemaining() < 1
488
- }
489
-
490
- if (!vars.nextUnitOfWork && vars.wipRoot) {
491
- console.log('Iniciando commit de la raíz...')
492
- commitRoot()
493
- }
494
-
495
- if (vars.wipRoot) {
496
- requestIdleCallback(workLoop)
497
- }
498
- }
499
-
500
- /**
501
- * The function performs a unit of work by updating either a function component or a host component and
502
- * returns the next fiber to be processed.
503
- * @param fiber - A fiber is a unit of work in Ryunix that represents a component and its state. It
504
- * contains information about the component's type, props, and children, as well as pointers to its
505
- * parent, child, and sibling fibers. The `performUnitOfWork` function takes a fiber as a parameter and
506
- * performs work
507
- * @returns The function `performUnitOfWork` returns the next fiber to be processed. If the current
508
- * fiber has a child, it returns the child. Otherwise, it looks for the next sibling of the current
509
- * fiber. If there are no more siblings, it goes up the tree to the parent and looks for the next
510
- * sibling of the parent. The function returns `undefined` if there are no more fibers to process.
511
- */
512
- const performUnitOfWork = (fiber) => {
513
- const isFunctionComponent = fiber.type instanceof Function
514
-
515
- if (isFunctionComponent) {
516
- updateFunctionComponent(fiber)
517
- } else {
518
- updateHostComponent(fiber)
519
- }
520
-
521
- if (fiber.child) {
522
- return fiber.child
523
- }
524
-
525
- let nextFiber = fiber
526
- while (nextFiber) {
527
- if (nextFiber.sibling) {
528
- return nextFiber.sibling
529
- }
530
- nextFiber = nextFiber.parent
531
- }
532
-
533
- return null
534
- }
535
-
536
- var Workers = /*#__PURE__*/ Object.freeze({
537
- __proto__: null,
538
- performUnitOfWork: performUnitOfWork,
539
- workLoop: workLoop,
540
- })
541
-
542
- /**
543
- * Renders an element into a container using a work-in-progress (WIP) root.
544
- * @function render
545
- * @param {Object|HTMLElement} element - The element to be rendered in the container. It can be a Ryunix component (custom element) or a standard DOM element.
546
- * @param {HTMLElement} container - The container where the element will be rendered. This parameter is optional if `createRoot()` is used beforehand to set up the container.
547
- * @description The function assigns the `container` to a work-in-progress root and sets up properties for reconciliation, including children and the reference to the current root.
548
- * It also clears any scheduled deletions and establishes the next unit of work for incremental rendering.
549
- */
550
- const render = (element, container) => {
551
- vars.wipRoot = {
552
- dom: container,
553
- props: {
554
- children: [element],
555
- },
556
- alternate: vars.currentRoot,
557
- }
558
-
559
- vars.deletions = []
560
- vars.nextUnitOfWork = vars.wipRoot
561
-
562
- requestIdleCallback(workLoop)
563
- }
564
-
565
- /**
566
- * Initializes the application by creating a reference to a DOM element with the specified ID and rendering the main component.
567
- * @function init
568
- * @param {Object} MainElement - The main component to render, typically the root component of the application.
569
- * @param {string} [root='__ryunix'] - The ID of the HTML element that serves as the container for the root element. Defaults to `'__ryunix'` if not provided.
570
- * @example
571
- * Ryunix.init(App, "__ryunix"); // Initializes and renders the App component into the <div id="__ryunix"></div> element.
572
- * @description This function retrieves the container element by its ID and invokes the `render` function to render the main component into it.
573
- */
574
- const init = (MainElement, root = '__ryunix') => {
575
- vars.containerRoot = document.getElementById(root)
576
-
577
- render(MainElement, vars.containerRoot)
578
- }
579
-
580
- /**
581
- * `useReducer` hook for managing complex state with reducer logic.
582
- *
583
- * @param {function} reducer - A reducer function that takes the current state and an action, and returns the new state.
584
- * @param {*} initialState - The initial state value or an initial function that returns the initial state.
585
- * @param {function} [init] - An optional initializer function to transform initial state.
586
- * @returns {Array} - An array containing:
587
- * - `state` (any): The current state value.
588
- * - `dispatch` (function): A function to dispatch actions to update the state.
589
- *
590
- * @example
591
- * // Using useReducer in a component to manage a counter
592
- * const reducer = (state, action) => {
593
- * switch (action.type) {
594
- * case "INCREMENT":
595
- * return state + 1;
596
- * case "DECREMENT":
597
- * return state - 1;
598
- * default:
599
- * return state;
600
- * }
601
- * };
602
- *
603
- * const App = () => {
604
- * const [state, dispatch] = useReducer(reducer, 0);
605
- * return (
606
- * <>
607
- * <button onClick={() => dispatch({ type: "INCREMENT" })}>Increment</button>
608
- * <div>Count: {state}</div>
609
- * </>
610
- * );
611
- * };
612
- */
613
- const useReducer = (reducer, initialState, init) => {
614
- const hookHash = generateHookHash(vars.wipFiber, RYUNIX_TYPES.RYUNIX_REDUCE)
615
- const oldHook = vars.wipFiber.alternate?.hooks?.[hookHash]
616
-
617
- // Initialize state with init function if provided, otherwise use initialState
618
- const initial = init ? init(initialState) : initialState
619
-
620
- // Create the hook with previous state or initial state and an empty action queue
621
- const hook = {
622
- state: oldHook ? oldHook.state : initial,
623
- queue: [],
624
- reducer,
625
- }
626
-
627
- // Apply queued actions with the reducer function
628
- if (oldHook) {
629
- oldHook.queue.forEach((action) => {
630
- hook.state = hook.reducer(hook.state, action)
631
- })
632
- }
633
-
634
- // Define the dispatch function to process actions
635
- const dispatch = (action) => {
636
- hook.queue.push(action)
637
- vars.wipRoot = {
638
- dom: vars.currentRoot.dom,
639
- props: vars.currentRoot.props,
640
- alternate: vars.currentRoot,
641
- }
642
- vars.nextUnitOfWork = vars.wipRoot
643
- vars.deletions = []
644
-
645
- requestIdleCallback(workLoop)
646
- }
647
-
648
- vars.wipFiber.hooks = vars.wipFiber.hooks || []
649
- vars.wipFiber.hooks[hookHash] = hook
650
- return [hook.state, dispatch]
651
- }
652
-
653
- /**
654
- * `useStore` is a state management hook to handle component state updates efficiently.
655
- *
656
- * @param {*} initial - The initial state value for the component.
657
- *
658
- * @returns {Array} - An array containing:
659
- * - `state` (any): The current state value.
660
- * - `setState` (function): A function to update the state.
661
- *
662
- * @example
663
- * // Using useStore in a component to manage a counter
664
- * const App = () => {
665
- * const [count, setCount] = useStore(0);
666
- * return (
667
- * <>
668
- * <button onClick={() => setCount(count + 1)}>Count: {count}</button>
669
- * </>
670
- * );
671
- * };
672
- */
673
-
674
- /**
675
- * @description The function creates a state.
676
- * @param initial - The initial value of the state for the hook.
677
- * @returns The `useStore` function returns an array with two elements: the current state value and a
678
- * `setState` function that can be used to update the state.
679
- */
680
- const useStore = (initial) => {
681
- // Wrap `useReducer` with a simple reducer for updating state directly
682
- return useReducer((state, action) => {
683
- return typeof action === STRINGS.function ? action(state) : action
684
- }, initial)
685
- }
686
-
687
- /**
688
- * `useEffect` is a hook to handle side effects in components with optimized dependency tracking.
689
-
690
- *
691
- * @param {function} callback - A function to execute after the component has rendered or when dependencies have changed.
692
- * - If the callback returns a function, it will be used as a cleanup function to execute when the effect needs to be cleaned up.
693
- * @param {Array} deps - An array of dependencies that determine when the callback should be executed. If any dependency changes, the effect will re-run.
694
- *
695
- * @example
696
- * // Using useEffect to set up an interval and clean it up automatically
697
- * const App = () => {
698
- * useEffect(() => {
699
- * const interval = setInterval(() => {
700
- * console.log("Running effect");
701
- * }, 1000);
702
- * return () => clearInterval(interval); // Cleanup automatically when unmounted
703
- * }, []);
704
- * return (
705
- * <>
706
- * <div>Effect Example</div>
707
- * </>
708
- * );
709
- * };
710
- */
711
-
712
- const useEffect = (callback, deps) => {
713
- const hookHash = generateHookHash(vars.wipFiber, RYUNIX_TYPES.RYUNIX_EFFECT)
714
-
715
- const oldHook =
716
- vars.wipFiber.alternate &&
717
- vars.wipFiber.alternate.hooks &&
718
- vars.wipFiber.alternate.hooks[hookHash]
719
-
720
- const hook = {
721
- type: RYUNIX_TYPES.RYUNIX_EFFECT,
722
- deps,
723
- cleanup: null,
724
- }
725
-
726
- if (!oldHook || !lodash.isEqual(oldHook.deps, hook.deps)) {
727
- if (typeof oldHook?.cleanup === STRINGS.function) {
728
- oldHook.cleanup()
729
- }
730
-
731
- hook.cleanup = callback()
732
- }
733
- vars.wipFiber.hooks = vars.wipFiber.hooks || []
734
- vars.wipFiber.hooks[hookHash] = hook
735
- }
736
-
737
- const useRef = (initial) => {
738
- const hookHash = generateHookHash(vars.wipFiber, RYUNIX_TYPES.RYUNIX_REF)
739
-
740
- const oldHook =
741
- vars.wipFiber.alternate &&
742
- vars.wipFiber.alternate.hooks &&
743
- vars.wipFiber.alternate.hooks[hookHash]
744
-
745
- const hook = {
746
- type: RYUNIX_TYPES.RYUNIX_REF,
747
- value: oldHook ? oldHook.value : { current: initial },
748
- }
749
-
750
- vars.wipFiber.hooks = vars.wipFiber.hooks || []
751
- vars.wipFiber.hooks[hookHash] = hook
752
- return hook.value
753
- }
754
-
755
- /**
756
- * `useMemo` is a custom hook to memoize a value based on its dependencies, with optimized dependency tracking.
757
- *
758
- * This hook returns a memoized value that is only recomputed when its dependencies change.
759
- * Dependency changes are detected using an efficient hash comparison, which reduces unnecessary recomputations.
760
- *
761
- * @param {function} compute - A function that computes the value to be memoized.
762
- * @param {Array} deps - An array of dependencies that determine when the memoized value should be recomputed.
763
- *
764
- * @returns {*} - The memoized value.
765
- *
766
- * @example
767
- * // Using useMemo to memoize a calculated value based on dependencies
768
- * const App = () => {
769
- * const memoizedValue = useMemo(() => {
770
- * return computeHeavyOperation();
771
- * }, [dependency1, dependency2]);
772
- *
773
- * return (
774
- * <>
775
- * <div>Memoized Value: {memoizedValue}</div>
776
- * </>
777
- * );
778
- * };
779
- */
780
- const useMemo = (compute, deps) => {
781
- const hookHash = generateHookHash(vars.wipFiber, RYUNIX_TYPES.RYUNIX_MEMO)
782
-
783
- const oldHook =
784
- vars.wipFiber.alternate &&
785
- vars.wipFiber.alternate.hooks &&
786
- vars.wipFiber.alternate.hooks[hookHash]
787
-
788
- const hook = {
789
- type: RYUNIX_TYPES.RYUNIX_MEMO,
790
- value: null,
791
- deps,
792
- hash: generateHash(deps),
793
- }
794
-
795
- if (!oldHook || oldHook.hash !== hook.hash) {
796
- hook.value = compute()
797
- } else {
798
- hook.value = oldHook.value
799
- }
800
-
801
- vars.wipFiber.hooks = vars.wipFiber.hooks || []
802
- vars.wipFiber.hooks[hookHash] = hook
803
-
804
- return hook.value
805
- }
806
-
807
- const useCallback = (callback, deps) => {
808
- return useMemo(() => callback, deps)
809
- }
810
-
811
- /**
812
- * The `useQuery` function parses the query parameters from the URL and returns them as an object.
813
- * @returns An object containing key-value pairs of the query parameters from the URLSearchParams in
814
- * the current window's URL is being returned.
815
- */
816
- const useQuery = () => {
817
- const searchParams = new URLSearchParams(window.location.search)
818
- const query = {}
819
- for (let [key, value] of searchParams.entries()) {
820
- query[key] = value
821
- }
822
- return query
823
- }
824
-
825
- /**
826
- * `useRouter` is a routing function to manage navigation, nested routes, and route pre-loading.
827
- *
828
- * This function handles client-side routing, URL updates, and component rendering based on defined routes. It supports:
829
- * - Dynamic routes (e.g., "/user/:id").
830
- * - Optional nested routes with an `subRoutes` property in route objects.
831
- * - Default pre-loading of all routes except the current active route.
832
- *
833
- * @param {Array} routes - An array of route objects, each containing:
834
- * - `path` (string): The URL path to match (supports dynamic segments like "/user/:id").
835
- * - `component` (function): The component to render when the route matches.
836
- * - `subRoutes` (optional array): An optional array of nested route objects, defining sub-routes for this route.
837
- * - `NotFound` (optional function): Component to render for unmatched routes (default 404 behavior).
838
- *
839
- * @returns {Object} - An object with:
840
- * - `Children` (function): Returns the component that matches the current route, passing route parameters and query parameters as props.
841
- * - `NavLink` (component): A link component to navigate within the application without refreshing the page.
842
- * - `navigate` (function): Allows programmatically navigating to a specific path.
843
- *
844
- * @example
845
- * // Define nested routes
846
- * const routes = [
847
- * {
848
- * path: "/",
849
- * component: HomePage,
850
- * subRoutes: [
851
- * {
852
- * path: "/settings",
853
- * component: SettingsPage,
854
- * },
855
- * ],
856
- * },
857
- * {
858
- * path: "/user/:id",
859
- * component: UserProfile,
860
- * },
861
- * {
862
- * path: "*",
863
- * NotFound: NotFoundPage,
864
- * },
865
- * ];
866
- *
867
- * // Use the routing function
868
- * const { Children, NavLink } = useRouter(routes);
869
- *
870
- * // Render the matched component
871
- * const App = () => (
872
- * <>
873
- * <NavLink to="/">Home</NavLink>
874
- * <NavLink to="/settings">Settings</NavLink>
875
- * <NavLink to="/user/123">User Profile</NavLink>
876
- * <Children />
877
- * </>
878
- * );
879
- */
880
- const useRouter = (routes) => {
881
- const [location, setLocation] = useStore(window.location.pathname)
882
-
883
- const findRoute = (routes, path) => {
884
- const pathname = path.split('?')[0]
885
-
886
- const notFoundRoute = routes.find((route) => route.NotFound)
887
- const notFound = notFoundRoute
888
- ? { route: { component: notFoundRoute.NotFound }, params: {} }
889
- : { route: { component: null }, params: {} }
890
-
891
- for (const route of routes) {
892
- if (route.subRoutes) {
893
- const childRoute = findRoute(route.subRoutes, path)
894
- if (childRoute) return childRoute
895
- }
896
-
897
- if (route.path === '*') {
898
- return notFound
899
- }
900
-
901
- if (!route.path || typeof route.path !== 'string') {
902
- console.warn('Invalid route detected:', route)
903
- console.info(
904
- "if you are using { NotFound: NotFound } please add { path: '*', NotFound: NotFound }",
905
- )
906
- continue
907
- }
908
-
909
- const keys = []
910
- const pattern = new RegExp(
911
- `^${route.path.replace(/:\w+/g, (match) => {
912
- keys.push(match.substring(1))
913
- return '([^/]+)'
914
- })}$`,
915
- )
916
-
917
- const match = pathname.match(pattern)
918
- if (match) {
919
- const params = keys.reduce((acc, key, index) => {
920
- acc[key] = match[index + 1]
921
- return acc
922
- }, {})
923
-
924
- return { route, params }
925
- }
926
- }
927
-
928
- return notFound
929
- }
930
-
931
- const navigate = (path) => {
932
- window.history.pushState({}, '', path)
933
- updateRoute(path)
934
- }
935
-
936
- const updateRoute = (path) => {
937
- const cleanedPath = path.split('?')[0]
938
- setLocation(cleanedPath)
939
- }
940
-
941
- useEffect(() => {
942
- const onPopState = () => updateRoute(window.location.pathname)
943
- window.addEventListener('popstate', onPopState)
944
-
945
- return () => window.removeEventListener('popstate', onPopState)
946
- }, [])
947
-
948
- const currentRouteData = findRoute(routes, location) || {}
949
-
950
- const Children = () => {
951
- const query = useQuery()
952
- const { route } = currentRouteData
953
-
954
- if (
955
- !route ||
956
- !route.component ||
957
- typeof route.component !== STRINGS.function
958
- ) {
959
- console.error(
960
- 'Component not found for current path or the component is not a valid function:',
961
- currentRouteData,
962
- )
963
- return null
964
- }
965
-
966
- return route.component({
967
- params: currentRouteData.params || {},
968
- query,
969
- })
970
- }
971
-
972
- const NavLink = ({ to, ...props }) => {
973
- const handleClick = (e) => {
974
- e.preventDefault()
975
- navigate(to)
976
- }
977
- return createElement(
978
- 'a',
979
- { href: to, onClick: handleClick, ...props },
980
- props.children,
981
- )
982
- }
983
-
984
- return { Children, NavLink, navigate }
985
- }
986
-
987
- const RYUNIX_VARS = vars
988
-
989
- var Ryunix = {
990
- createElement,
991
- render,
992
- init,
993
- Fragment,
994
- Dom,
995
- Workers,
996
- Reconciler,
997
- Components,
998
- Commits,
999
- RYUNIX_VARS,
1000
- }
1001
-
1002
- window.Ryunix = Ryunix
1003
-
1004
- exports.Fragment = Fragment
1005
- exports.default = Ryunix
1006
- exports.useCallback = useCallback
1007
- exports.useEffect = useEffect
1008
- exports.useMemo = useMemo
1009
- exports.useQuery = useQuery
1010
- exports.useReducer = useReducer
1011
- exports.useRef = useRef
1012
- exports.useRouter = useRouter
1013
- exports.useStore = useStore
1014
-
1015
- Object.defineProperty(exports, '__esModule', { value: true })
1016
- })