@unsetsoft/ryunixjs 1.1.17 → 1.1.19-canary.10

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
@@ -111,6 +111,11 @@
111
111
  const isProperty = (key) => key !== STRINGS.children && !isEvent(key);
112
112
  const isNew = (prev, next) => (key) => prev[key] !== next[key];
113
113
  const isGone = (next) => (key) => !(key in next);
114
+ const hasDepsChanged = (prevDeps, nextDeps) =>
115
+ !prevDeps ||
116
+ !nextDeps ||
117
+ prevDeps.length !== nextDeps.length ||
118
+ prevDeps.some((dep, index) => dep !== nextDeps[index]);
114
119
 
115
120
  /**
116
121
  * The function cancels all effect hooks in a given fiber.
@@ -120,10 +125,11 @@
120
125
  * "cancelEffects" is likely intended
121
126
  */
122
127
  const cancelEffects = (fiber) => {
123
- if (fiber.hooks) {
128
+ if (fiber.hooks && fiber.hooks.length > 0) {
124
129
  fiber.hooks
125
- .filter((hook) => hook.tag === RYUNIX_TYPES.RYUNIX_EFFECT && hook.cancel)
130
+ .filter((hook) => hook.type === RYUNIX_TYPES.RYUNIX_EFFECT && hook.cancel)
126
131
  .forEach((effectHook) => {
132
+ console.log('[cancelEffects]: ', effectHook);
127
133
  effectHook.cancel();
128
134
  });
129
135
  }
@@ -137,12 +143,21 @@
137
143
  * contains information about a component and its children, as
138
144
  */
139
145
  const runEffects = (fiber) => {
140
- if (fiber.hooks) {
141
- fiber.hooks
142
- .filter((hook) => hook.tag === RYUNIX_TYPES.RYUNIX_EFFECT && hook.effect)
143
- .forEach((effectHook) => {
144
- effectHook.cancel = effectHook.effect();
145
- });
146
+ if (!fiber.hooks || fiber.hooks.length === 0) return
147
+
148
+ for (let i = 0; i < fiber.hooks.length; i++) {
149
+ const hook = fiber.hooks[i];
150
+ if (
151
+ hook.type === RYUNIX_TYPES.RYUNIX_EFFECT &&
152
+ typeof hook.effect === STRINGS.function
153
+ ) {
154
+ if (typeof hook.cancel === STRINGS.function) {
155
+ hook.cancel();
156
+ }
157
+
158
+ const cleanup = hook.effect();
159
+ hook.cancel = typeof cleanup === STRINGS.function ? cleanup : undefined;
160
+ }
146
161
  }
147
162
  };
148
163
 
@@ -207,16 +222,22 @@
207
222
  }
208
223
 
209
224
  prevProps['ryunix-class'] &&
210
- dom.classList.remove(...prevProps['ryunix-class'].split(/\s+/));
211
- dom.classList.add(...nextProps['ryunix-class'].split(/\s+/));
225
+ dom.classList.remove(
226
+ ...(prevProps['ryunix-class'].split(/\s+/).filter(Boolean) || []),
227
+ );
228
+ dom.classList.add(
229
+ ...nextProps['ryunix-class'].split(/\s+/).filter(Boolean),
230
+ );
212
231
  } else if (name === OLD_STRINGS.className) {
213
232
  if (nextProps.className === '') {
214
233
  throw new Error('className cannot be empty.')
215
234
  }
216
235
 
217
236
  prevProps.className &&
218
- dom.classList.remove(...prevProps.className.split(/\s+/));
219
- dom.classList.add(...nextProps.className.split(/\s+/));
237
+ dom.classList.remove(
238
+ ...(prevProps.className.split(/\s+/).filter(Boolean) || []),
239
+ );
240
+ dom.classList.add(...nextProps.className.split(/\s+/).filter(Boolean));
220
241
  } else {
221
242
  dom[name] = nextProps[name];
222
243
  }
@@ -275,7 +296,9 @@
275
296
  }
276
297
  runEffects(fiber);
277
298
  } else if (fiber.effectTag === EFFECT_TAGS.UPDATE) {
278
- cancelEffects(fiber);
299
+ if (fiber.alternate) {
300
+ cancelEffects(fiber.alternate);
301
+ }
279
302
  if (fiber.dom != null) {
280
303
  updateDom(fiber.dom, fiber.alternate.props, fiber.props);
281
304
  }
@@ -595,6 +618,22 @@
595
618
  return useReducer(reducer, initialState, init)
596
619
  };
597
620
 
621
+ /**
622
+ * The `useReducer` function in JavaScript is used to manage state updates based on actions dispatched
623
+ * to a reducer function.
624
+ * @param reducer - The `reducer` parameter in the `useReducer` function is a function that takes the
625
+ * current state and an action as arguments, and returns the new state based on the action. It is used
626
+ * to update the state in response to different actions dispatched by the `dispatch` function.
627
+ * @param initialState - The `initialState` parameter in the `useReducer` function represents the
628
+ * initial state of the reducer. It is the state that will be used when the reducer is first
629
+ * initialized or reset. This initial state can be any value or object that the reducer will operate on
630
+ * and update based on the dispatched actions
631
+ * @param init - The `init` parameter in the `useReducer` function is an optional function that can be
632
+ * used to initialize the state. If provided, it will be called with the `initialState` as its argument
633
+ * and the return value will be used as the initial state value. If `init` is not
634
+ * @returns The `useReducer` function is returning an array with two elements: the current state and a
635
+ * dispatch function.
636
+ */
598
637
  const useReducer = (reducer, initialState, init) => {
599
638
  const oldHook =
600
639
  vars.wipFiber.alternate &&
@@ -602,6 +641,8 @@
602
641
  vars.wipFiber.alternate.hooks[vars.hookIndex];
603
642
 
604
643
  const hook = {
644
+ hookID: vars.hookIndex,
645
+ type: RYUNIX_TYPES.RYUNIX_STORE,
605
646
  state: oldHook ? oldHook.state : init ? init(initialState) : initialState,
606
647
  queue: oldHook && Array.isArray(oldHook.queue) ? oldHook.queue.slice() : [],
607
648
  };
@@ -613,7 +654,9 @@
613
654
  }
614
655
 
615
656
  const dispatch = (action) => {
616
- hook.queue.push(action);
657
+ hook.queue.push(
658
+ typeof action === STRINGS.function ? action : (prev) => action,
659
+ );
617
660
 
618
661
  vars.wipRoot = {
619
662
  dom: vars.currentRoot.dom,
@@ -651,30 +694,18 @@
651
694
  vars.wipFiber.alternate.hooks &&
652
695
  vars.wipFiber.alternate.hooks[vars.hookIndex];
653
696
 
697
+ const hasChanged = hasDepsChanged(oldHook?.deps, deps);
698
+
654
699
  const hook = {
700
+ hookID: vars.hookIndex,
655
701
  type: RYUNIX_TYPES.RYUNIX_EFFECT,
656
702
  deps,
657
- cleanup: oldHook?.cleanup,
703
+ cancel: oldHook?.cancel,
704
+ effect: hasChanged ? callback : null,
658
705
  };
659
706
 
660
- const hasChanged = !oldHook || !lodash.isEqual(oldHook.deps, deps);
661
-
662
- if (hasChanged) {
663
- vars.effects.push(() => {
664
- // Llama al cleanup anterior si existe
665
- if (typeof hook.cleanup === 'function') {
666
- hook.cleanup();
667
- }
668
-
669
- // Ejecuta el nuevo efecto y guarda el nuevo cleanup
670
- const result = callback();
671
- if (typeof result === 'function') {
672
- hook.cleanup = result;
673
- }
674
- });
675
- }
676
-
677
707
  vars.wipFiber.hooks[vars.hookIndex] = hook;
708
+ console.log('[useEffect]: ', vars.wipFiber.hooks[vars.hookIndex]);
678
709
  vars.hookIndex++;
679
710
  };
680
711
 
@@ -759,24 +790,11 @@
759
790
  return useMemo(() => callback, deps)
760
791
  };
761
792
 
762
- /**
763
- * The `useQuery` function parses the query parameters from the URL and returns them as an object.
764
- * @returns An object containing key-value pairs of the query parameters from the URLSearchParams in
765
- * the current window's URL is being returned.
766
- */
767
- const useQuery = () => {
768
- const searchParams = new URLSearchParams(window.location.search);
769
- const query = {};
770
- for (let [key, value] of searchParams.entries()) {
771
- query[key] = value;
772
- }
773
- return query
774
- };
775
-
776
- const createContext = (defaultValue) => {
777
- const contextId = RYUNIX_TYPES.RYUNIX_CONTEXT;
778
-
779
- const Provider = ({ value, children }) => {
793
+ const createContext = (
794
+ contextId = RYUNIX_TYPES.RYUNIX_CONTEXT,
795
+ defaultValue = {},
796
+ ) => {
797
+ const Provider = ({ children }) => {
780
798
  return Fragment({
781
799
  children: children,
782
800
  })
@@ -784,10 +802,10 @@
784
802
 
785
803
  Provider._contextId = contextId;
786
804
 
787
- const useContext = () => {
805
+ const useContext = (ctxID = RYUNIX_TYPES.RYUNIX_CONTEXT) => {
788
806
  let fiber = vars.wipFiber;
789
807
  while (fiber) {
790
- if (fiber.type && fiber.type._contextId === contextId) {
808
+ if (fiber.type && fiber.type._contextId === ctxID) {
791
809
  if (fiber.props && 'value' in fiber.props) {
792
810
  return fiber.props.value
793
811
  }
@@ -804,175 +822,28 @@
804
822
  }
805
823
  };
806
824
 
807
- /**
808
- * `useRouter` is a routing function to manage navigation, nested routes, and route pre-loading.
809
- *
810
- * This function handles client-side routing, URL updates, and component rendering based on defined routes. It supports:
811
- * - Dynamic routes (e.g., "/user/:id").
812
- * - Optional nested routes with an `subRoutes` property in route objects.
813
- * - Default pre-loading of all routes except the current active route.
814
- *
815
- * @param {Array} routes - An array of route objects, each containing:
816
- * - `path` (string): The URL path to match (supports dynamic segments like "/user/:id").
817
- * - `component` (function): The component to render when the route matches.
818
- * - `subRoutes` (optional array): An optional array of nested route objects, defining sub-routes for this route.
819
- * - `NotFound` (optional function): Component to render for unmatched routes (default 404 behavior).
820
- *
821
- * @returns {Object} - An object with:
822
- * - `Children` (function): Returns the component that matches the current route, passing route parameters and query parameters as props.
823
- * - `NavLink` (component): A link component to navigate within the application without refreshing the page.
824
- * - `navigate` (function): Allows programmatically navigating to a specific path.
825
- *
826
- * @example
827
- * // Define nested routes
828
- * const routes = [
829
- * {
830
- * path: "/",
831
- * component: HomePage,
832
- * subRoutes: [
833
- * {
834
- * path: "/settings",
835
- * component: SettingsPage,
836
- * },
837
- * ],
838
- * },
839
- * {
840
- * path: "/user/:id",
841
- * component: UserProfile,
842
- * },
843
- * {
844
- * path: "*",
845
- * NotFound: NotFoundPage,
846
- * },
847
- * ];
848
- *
849
- * // Use the routing function
850
- * const { Children, NavLink } = useRouter(routes);
851
- *
852
- * // Render the matched component
853
- * const App = () => (
854
- * <>
855
- * <NavLink to="/">Home</NavLink>
856
- * <NavLink to="/settings">Settings</NavLink>
857
- * <NavLink to="/user/123">User Profile</NavLink>
858
- * <Children />
859
- * </>
860
- * );
861
- */
862
- // const useRouter = (routes) => {
863
- // const [location, setLocation] = useStore(window.location.pathname)
864
-
865
- // const findRoute = (routes, path) => {
866
- // const pathname = path.split('?')[0]
867
-
868
- // const notFoundRoute = routes.find((route) => route.NotFound)
869
- // const notFound = notFoundRoute
870
- // ? { route: { component: notFoundRoute.NotFound }, params: {} }
871
- // : { route: { component: null }, params: {} }
872
-
873
- // for (const route of routes) {
874
- // if (route.subRoutes) {
875
- // const childRoute = findRoute(route.subRoutes, path)
876
- // if (childRoute) return childRoute
877
- // }
878
-
879
- // if (route.path === '*') {
880
- // return notFound
881
- // }
882
-
883
- // if (!route.path || typeof route.path !== 'string') {
884
- // console.warn('Invalid route detected:', route)
885
- // console.info(
886
- // "if you are using { NotFound: NotFound } please add { path: '*', NotFound: NotFound }",
887
- // )
888
- // continue
889
- // }
890
-
891
- // const keys = []
892
- // const pattern = new RegExp(
893
- // `^${route.path.replace(/:\w+/g, (match) => {
894
- // keys.push(match.substring(1))
895
- // return '([^/]+)'
896
- // })}$`,
897
- // )
898
-
899
- // const match = pathname.match(pattern)
900
- // if (match) {
901
- // const params = keys.reduce((acc, key, index) => {
902
- // acc[key] = match[index + 1]
903
- // return acc
904
- // }, {})
905
-
906
- // return { route, params }
907
- // }
908
- // }
909
-
910
- // return notFound
911
- // }
912
-
913
- // const navigate = (path) => {
914
- // window.history.pushState({}, '', path)
915
-
916
- // updateRoute(path)
917
- // }
918
-
919
- // const updateRoute = (path) => {
920
- // const cleanedPath = path.split('?')[0]
921
- // setLocation(cleanedPath)
922
- // }
923
-
924
- // useEffect(() => {
925
- // const onPopState = () => updateRoute(window.location.pathname)
926
- // window.addEventListener('popstate', onPopState)
927
-
928
- // return () => window.removeEventListener('popstate', onPopState)
929
- // }, [])
930
-
931
- // const currentRouteData = findRoute(routes, location) || {}
932
-
933
- // const Children = () => {
934
- // const query = useQuery()
935
- // const { route } = currentRouteData
936
-
937
- // if (
938
- // !route ||
939
- // !route.component ||
940
- // typeof route.component !== STRINGS.function
941
- // ) {
942
- // console.error(
943
- // 'Component not found for current path or the component is not a valid function:',
944
- // currentRouteData,
945
- // )
946
- // return null
947
- // }
948
-
949
- // const WrappedComponent = () =>
950
- // createElement(route.component, {
951
- // key: location,
952
- // params: currentRouteData.params || {},
953
- // query,
954
- // })
955
-
956
- // return createElement(WrappedComponent)
957
- // }
958
-
959
- // const NavLink = ({ to, ...props }) => {
960
- // const handleClick = (e) => {
961
- // e.preventDefault()
962
- // navigate(to)
963
- // }
964
- // return createElement(
965
- // 'a',
966
- // { href: to, onClick: handleClick, ...props },
967
- // props.children,
968
- // )
969
- // }
970
-
971
- // return { Children, NavLink, navigate }
972
- // }
973
-
974
- // Crear contexto para Router
975
- const RouterContext = createContext({
825
+ const useQuery = () => {
826
+ const searchParams = new URLSearchParams(window.location.search);
827
+ const query = {};
828
+ for (let [key, value] of searchParams.entries()) {
829
+ query[key] = value;
830
+ }
831
+ return query
832
+ };
833
+
834
+ const useHash = () => {
835
+ const [hash, setHash] = useStore(window.location.hash);
836
+ useEffect(() => {
837
+ const onHashChange = () => {
838
+ setHash(window.location.hash);
839
+ };
840
+ window.addEventListener('hashchange', onHashChange);
841
+ return () => window.removeEventListener('hashchange', onHashChange)
842
+ }, []);
843
+ return hash
844
+ };
845
+
846
+ const RouterContext = createContext('ryunix.navigation', {
976
847
  location: '/',
977
848
  params: {},
978
849
  query: {},
@@ -981,7 +852,7 @@
981
852
  });
982
853
 
983
854
  const findRoute = (routes, path) => {
984
- const pathname = path.split('?')[0];
855
+ const pathname = path.split('?')[0].split('#')[0];
985
856
 
986
857
  const notFoundRoute = routes.find((route) => route.NotFound);
987
858
  const notFound = notFoundRoute
@@ -1032,17 +903,22 @@
1032
903
  const [location, setLocation] = useStore(window.location.pathname);
1033
904
 
1034
905
  useEffect(() => {
1035
- const onPopState = () => setLocation(window.location.pathname);
1036
- window.addEventListener('popstate', onPopState);
1037
- return () => window.removeEventListener('popstate', onPopState)
906
+ const update = () => setLocation(window.location.pathname);
907
+
908
+ window.addEventListener('popstate', update);
909
+ window.addEventListener('hashchange', update);
910
+ return () => {
911
+ window.removeEventListener('popstate', update);
912
+ window.removeEventListener('hashchange', update);
913
+ }
1038
914
  }, []);
1039
915
 
1040
916
  const navigate = (path) => {
1041
917
  window.history.pushState({}, '', path);
1042
- setLocation(path);
918
+ setLocation(window.location.pathname);
1043
919
  };
1044
920
 
1045
- const currentRouteData = findRoute(routes, location) || {};
921
+ const currentRouteData = findRoute(routes, window.location.pathname) || {};
1046
922
  const query = useQuery();
1047
923
 
1048
924
  const contextValue = {
@@ -1063,15 +939,28 @@
1063
939
  };
1064
940
 
1065
941
  const useRouter = () => {
1066
- return RouterContext.useContext()
942
+ return RouterContext.useContext('ryunix.navigation')
1067
943
  };
1068
944
 
1069
945
  const Children = () => {
1070
946
  const { route, params, query, location } = useRouter();
1071
-
1072
947
  if (!route || !route.component) return null
948
+ const hash = useHash();
949
+
950
+ useEffect(() => {
951
+ if (hash) {
952
+ const id = hash.slice(1);
953
+ const el = document.getElementById(id);
954
+ if (el) el.scrollIntoView({ block: 'start', behavior: 'smooth' });
955
+ }
956
+ }, [hash]);
1073
957
 
1074
- return createElement(route.component, { key: location, params, query })
958
+ return createElement(route.component, {
959
+ key: location,
960
+ params,
961
+ query,
962
+ hash,
963
+ })
1075
964
  };
1076
965
 
1077
966
  // Componente NavLink para navegación interna
@@ -1098,6 +987,7 @@
1098
987
  createContext: createContext,
1099
988
  useCallback: useCallback,
1100
989
  useEffect: useEffect,
990
+ useHash: useHash,
1101
991
  useMemo: useMemo,
1102
992
  useQuery: useQuery,
1103
993
  useRef: useRef,
@@ -1123,6 +1013,7 @@
1123
1013
  exports.default = Ryunix;
1124
1014
  exports.useCallback = useCallback;
1125
1015
  exports.useEffect = useEffect;
1016
+ exports.useHash = useHash;
1126
1017
  exports.useMemo = useMemo;
1127
1018
  exports.useQuery = useQuery;
1128
1019
  exports.useRef = useRef;
@@ -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:null,nextUnitOfWork:null,currentRoot:null,wipRoot:null,deletions:null,wipFiber:null,hookIndex:null,effects:null};const n=/[A-Z]/g,r=Object.freeze({TEXT_ELEMENT:Symbol("text.element").toString(),Ryunix_ELEMENT:Symbol("ryunix.element").toString(),RYUNIX_EFFECT:Symbol("ryunix.effect").toString(),RYUNIX_MEMO:Symbol("ryunix.memo").toString(),RYUNIX_URL_QUERY:Symbol("ryunix.urlQuery").toString(),RYUNIX_REF:Symbol("ryunix.ref").toString(),RYUNIX_STORE:Symbol("ryunix.store").toString(),RYUNIX_REDUCE:Symbol("ryunix.reduce").toString(),RYUNIX_FRAGMENT:Symbol("ryunix.fragment").toString(),RYUNIX_CONTEXT:Symbol("ryunix.context").toString()}),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(),NO_EFFECT:Symbol("ryunix.reconciler.status.no_efect").toString()}),a=(e,t,...o)=>({type:e,props:{...t,children:o.flat().map((e=>typeof e===i.object?e:c(e)))}}),c=e=>({type:r.TEXT_ELEMENT,props:{nodeValue:e,children:[]}}),u=e=>{const t=Array.isArray(e.children)?e.children:[e.children];return a(r.RYUNIX_FRAGMENT,{},...t)},p=e=>e.startsWith("on"),d=e=>e!==i.children&&!p(e),f=(e,t)=>o=>e[o]!==t[o],h=e=>t=>!(t in e),y=e=>{e.hooks&&e.hooks.filter((e=>e.tag===r.RYUNIX_EFFECT&&e.cancel)).forEach((e=>{e.cancel()}))},m=e=>{e.hooks&&e.hooks.filter((e=>e.tag===r.RYUNIX_EFFECT&&e.effect)).forEach((e=>{e.cancel=e.effect()}))},E=(e,t,o)=>{Object.keys(t).filter(p).filter((e=>h(o)(e)||f(t,o)(e))).forEach((o=>{const n=o.toLowerCase().substring(2);e.removeEventListener(n,t[o])})),Object.keys(t).filter(d).filter(h(o)).forEach((t=>{e[t]=""})),Object.keys(o).filter(d).filter(f(t,o)).forEach((n=>{if(n===i.style)b(e,o["ryunix-style"]);else if(n===s.style)b(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(p).filter(f(t,o)).forEach((t=>{const n=t.toLowerCase().substring(2);e.addEventListener(n,o[t])}))},b=(e,t)=>{e.style=Object.keys(t).reduce(((e,o)=>e+=`${o.replace(n,(function(e){return"-"+e.toLowerCase()}))}: ${t[o]};`),"")},w=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),m(e);else if(e.effectTag===l.UPDATE)y(e),null!=e.dom&&E(e.dom,e.alternate.props,e.props),m(e);else if(e.effectTag===l.DELETION)return y(e),void x(e,o);w(e.child),w(e.sibling)},x=(e,t)=>{if(e.dom)t.removeChild(e.dom);else{let o=e.child;for(;o;)x(o,t),o=o.sibling}},R=(e,t)=>{let n,r=0,i=e.alternate&&e.alternate.child;for(;r<t.length||null!=i;){const s=t[r];let a;const c=i&&s&&s.type==i.type;c&&(a={type:i.type,props:s.props,dom:i.dom,parent:e,alternate:i,effectTag:l.UPDATE}),s&&!c&&(a={type:s.type,props:s.props,dom:null,parent:e,alternate:null,effectTag:l.PLACEMENT}),i&&!c&&(i.effectTag=l.DELETION,o.deletions.push(i)),i&&(i=i.sibling),0===r?e.child=a:s&&(n.sibling=a),n=a,r++}},g=e=>{const t=Array.isArray(e.props.children)?e.props.children.flat():[e.props.children];e.type===r.RYUNIX_FRAGMENT||e.dom||(e.dom=(e=>{if(e.type===r.RYUNIX_FRAGMENT)return null;const t=e.type==r.TEXT_ELEMENT?document.createTextNode(""):document.createElement(e.type);return E(t,{},e.props),t})(e)),R(e,t)},k=({src:e,props:t})=>{const o=new URLSearchParams,n=!e.startsWith("http")||!e.startsWith("https");t.width&&o.set("width",t.width),t.height&&o.set("height",t.height),t.quality&&o.set("quality",t.quality);const r=t.extension?`@${t.extension}`:"";return n?(()=>{const{hostname:e}=window.location;return"localhost"===e||"127.0.0.1"===e})()?(console.warn("Image optimizations only work with full links and must not contain localhost."),e):`${window.location.origin}/${e}`:`https://image.unsetsoft.com/image/${e}${r}?${o.toString()}`},N=e=>{let t=!1;for(;o.nextUnitOfWork&&!t;)o.nextUnitOfWork=I(o.nextUnitOfWork),t=e.timeRemaining()<1;!o.nextUnitOfWork&&o.wipRoot&&(o.deletions.forEach(w),w(o.wipRoot.child),o.currentRoot=o.wipRoot,o.wipRoot=null),requestIdleCallback(N)};requestIdleCallback(N);const I=e=>{if(e.type instanceof Function?(e=>{o.wipFiber=e,o.hookIndex=0,o.wipFiber.hooks=[];const t=[e.type(e.props)];e.type._contextId&&void 0!==e.props.value&&(e._contextId=e.type._contextId,e._contextValue=e.props.value),R(e,t)})(e):g(e),e.child)return e.child;let t=e;for(;t;){if(t.sibling)return t.sibling;t=t.parent}},F=e=>{o.nextUnitOfWork=e,o.wipRoot=e,o.deletions=[],o.hookIndex=0,o.effects=[],requestIdleCallback(N)},T=(e,t)=>(o.wipRoot={dom:t,props:{children:[e]},alternate:o.currentRoot},o.nextUnitOfWork=o.wipRoot,o.deletions=[],F(o.wipRoot),o.wipRoot),v=(e,t)=>_(((e,t)=>"function"==typeof t?t(e):t),e,t),_=(e,t,n)=>{const r=o.wipFiber.alternate&&o.wipFiber.alternate.hooks&&o.wipFiber.alternate.hooks[o.hookIndex],i={state:r?r.state:n?n(t):t,queue:r&&Array.isArray(r.queue)?r.queue.slice():[]};r&&Array.isArray(r.queue)&&r.queue.forEach((t=>{i.state=e(i.state,t)}));return i.queue.forEach((t=>{i.state=e(i.state,t)})),o.wipFiber.hooks[o.hookIndex]=i,o.hookIndex++,[i.state,e=>{i.queue.push(e),o.wipRoot={dom:o.currentRoot.dom,props:o.currentRoot.props,alternate:o.currentRoot},o.deletions=[],o.hookIndex=0,F(o.wipRoot)}]},S=(e,n)=>{const i=o.wipFiber.alternate&&o.wipFiber.alternate.hooks&&o.wipFiber.alternate.hooks[o.hookIndex],s={type:r.RYUNIX_EFFECT,deps:n,cleanup:i?.cleanup};(!i||!t.isEqual(i.deps,n))&&o.effects.push((()=>{"function"==typeof s.cleanup&&s.cleanup();const t=e();"function"==typeof t&&(s.cleanup=t)})),o.wipFiber.hooks[o.hookIndex]=s,o.hookIndex++},U=e=>{const t=o.wipFiber.alternate&&o.wipFiber.alternate.hooks&&o.wipFiber.alternate.hooks[o.hookIndex],n={type:r.RYUNIX_REF,value:t?t.value:{current:e}};return o.wipFiber.hooks[o.hookIndex]=n,o.hookIndex++,n.value},C=(e,n)=>{const i=o.wipFiber.alternate&&o.wipFiber.alternate.hooks&&o.wipFiber.alternate.hooks[o.hookIndex],s={type:r.RYUNIX_MEMO,value:null,deps:n};return i&&t.isEqual(i.deps,s.deps)?s.value=i.value:s.value=e(),o.wipFiber.hooks[o.hookIndex]=s,o.hookIndex++,s.value},O=(e,t)=>C((()=>e),t),L=()=>{const e=new URLSearchParams(window.location.search),t={};for(let[o,n]of e.entries())t[o]=n;return t},X=e=>{const t=r.RYUNIX_CONTEXT,n=({value:e,children:t})=>u({children:t});n._contextId=t;return{Provider:n,useContext:()=>{let n=o.wipFiber;for(;n;){if(n.type&&n.type._contextId===t)return n.props&&"value"in n.props?n.props.value:void 0;n=n.parent}return e}}},q=X({location:"/",params:{},query:{},navigate:e=>{},route:null}),A=(e,t)=>{const o=t.split("?")[0],n=e.find((e=>e.NotFound)),r=n?{route:{component:n.NotFound},params:{}}:{route:{component:null},params:{}};for(const n of e){if(n.subRoutes){const e=A(n.subRoutes,t);if(e)return e}if("*"===n.path)return r;if(!n.path||"string"!=typeof n.path){console.warn("Invalid route detected:",n),console.info("if you are using { NotFound: NotFound } please add { path: '*', NotFound: NotFound }");continue}const e=[],i=new RegExp(`^${n.path.replace(/:\w+/g,(t=>(e.push(t.substring(1)),"([^/]+)")))}$`),s=o.match(i);if(s){return{route:n,params:e.reduce(((e,t,o)=>(e[t]=s[o+1],e)),{})}}}return r},M=({routes:e,children:t})=>{const[o,n]=v(window.location.pathname);S((()=>{const e=()=>n(window.location.pathname);return window.addEventListener("popstate",e),()=>window.removeEventListener("popstate",e)}),[]);const r=A(e,o)||{},i=L(),s={location:o,params:r.params||{},query:i,navigate:e=>{window.history.pushState({},"",e),n(e)},route:r.route};return a(q.Provider,{value:s},u({children:t}))},Y=()=>q.useContext(),j=()=>{const{route:e,params:t,query:o,location:n}=Y();return e&&e.component?a(e.component,{key:n,params:t,query:o}):null},P=({to:e,...t})=>{const{navigate:o}=Y();return a("a",{href:e,onClick:t=>{t.preventDefault(),o(e)},...t},t.children)};var W={createElement:a,render:T,init:(e,t="__ryunix")=>{o.containerRoot=document.getElementById(t);return T(e,o.containerRoot)},Fragment:u,Hooks:Object.freeze({__proto__:null,Children:j,NavLink:P,RouterProvider:M,createContext:X,useCallback:O,useEffect:S,useMemo:C,useQuery:L,useRef:U,useRouter:Y,useStore:v})};window.Ryunix=W,e.Children=j,e.Image=({src:e,...t})=>{const o={src:"true"===t.optimization?k({src:e,props:t}):e,...t};return a("img",o,null)},e.NavLink=P,e.RouterProvider=M,e.createContext=X,e.default=W,e.useCallback=O,e.useEffect=S,e.useMemo=C,e.useQuery=L,e.useRef=U,e.useRouter=Y,e.useStore=v,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:null,nextUnitOfWork:null,currentRoot:null,wipRoot:null,deletions:null,wipFiber:null,hookIndex:null,effects:null};const n=/[A-Z]/g,r=Object.freeze({TEXT_ELEMENT:Symbol("text.element").toString(),Ryunix_ELEMENT:Symbol("ryunix.element").toString(),RYUNIX_EFFECT:Symbol("ryunix.effect").toString(),RYUNIX_MEMO:Symbol("ryunix.memo").toString(),RYUNIX_URL_QUERY:Symbol("ryunix.urlQuery").toString(),RYUNIX_REF:Symbol("ryunix.ref").toString(),RYUNIX_STORE:Symbol("ryunix.store").toString(),RYUNIX_REDUCE:Symbol("ryunix.reduce").toString(),RYUNIX_FRAGMENT:Symbol("ryunix.fragment").toString(),RYUNIX_CONTEXT:Symbol("ryunix.context").toString()}),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(),NO_EFFECT:Symbol("ryunix.reconciler.status.no_efect").toString()}),a=(e,t,...o)=>({type:e,props:{...t,children:o.flat().map((e=>typeof e===i.object?e:c(e)))}}),c=e=>({type:r.TEXT_ELEMENT,props:{nodeValue:e,children:[]}}),u=e=>{const t=Array.isArray(e.children)?e.children:[e.children];return a(r.RYUNIX_FRAGMENT,{},...t)},p=e=>e.startsWith("on"),d=e=>e!==i.children&&!p(e),h=(e,t)=>o=>e[o]!==t[o],f=e=>t=>!(t in e),y=e=>{e.hooks&&e.hooks.length>0&&e.hooks.filter((e=>e.type===r.RYUNIX_EFFECT&&e.cancel)).forEach((e=>{console.log("[cancelEffects]: ",e),e.cancel()}))},m=e=>{if(e.hooks&&0!==e.hooks.length)for(let t=0;t<e.hooks.length;t++){const o=e.hooks[t];if(o.type===r.RYUNIX_EFFECT&&typeof o.effect===i.function){typeof o.cancel===i.function&&o.cancel();const e=o.effect();o.cancel=typeof e===i.function?e:void 0}}},w=(e,t,o)=>{Object.keys(t).filter(p).filter((e=>f(o)(e)||h(t,o)(e))).forEach((o=>{const n=o.toLowerCase().substring(2);e.removeEventListener(n,t[o])})),Object.keys(t).filter(d).filter(f(o)).forEach((t=>{e[t]=""})),Object.keys(o).filter(d).filter(h(t,o)).forEach((n=>{if(n===i.style)E(e,o["ryunix-style"]);else if(n===s.style)E(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+/).filter(Boolean)||[]),e.classList.add(...o["ryunix-class"].split(/\s+/).filter(Boolean))}else if(n===s.className){if(""===o.className)throw new Error("className cannot be empty.");t.className&&e.classList.remove(...t.className.split(/\s+/).filter(Boolean)||[]),e.classList.add(...o.className.split(/\s+/).filter(Boolean))}else e[n]=o[n]})),Object.keys(o).filter(p).filter(h(t,o)).forEach((t=>{const n=t.toLowerCase().substring(2);e.addEventListener(n,o[t])}))},E=(e,t)=>{e.style=Object.keys(t).reduce(((e,o)=>e+=`${o.replace(n,(function(e){return"-"+e.toLowerCase()}))}: ${t[o]};`),"")},b=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),m(e);else if(e.effectTag===l.UPDATE)e.alternate&&y(e.alternate),null!=e.dom&&w(e.dom,e.alternate.props,e.props),m(e);else if(e.effectTag===l.DELETION)return y(e),void x(e,o);b(e.child),b(e.sibling)},x=(e,t)=>{if(e.dom)t.removeChild(e.dom);else{let o=e.child;for(;o;)x(o,t),o=o.sibling}},g=(e,t)=>{let n,r=0,i=e.alternate&&e.alternate.child;for(;r<t.length||null!=i;){const s=t[r];let a;const c=i&&s&&s.type==i.type;c&&(a={type:i.type,props:s.props,dom:i.dom,parent:e,alternate:i,effectTag:l.UPDATE}),s&&!c&&(a={type:s.type,props:s.props,dom:null,parent:e,alternate:null,effectTag:l.PLACEMENT}),i&&!c&&(i.effectTag=l.DELETION,o.deletions.push(i)),i&&(i=i.sibling),0===r?e.child=a:s&&(n.sibling=a),n=a,r++}},k=e=>{const t=Array.isArray(e.props.children)?e.props.children.flat():[e.props.children];e.type===r.RYUNIX_FRAGMENT||e.dom||(e.dom=(e=>{if(e.type===r.RYUNIX_FRAGMENT)return null;const t=e.type==r.TEXT_ELEMENT?document.createTextNode(""):document.createElement(e.type);return w(t,{},e.props),t})(e)),g(e,t)},R=({src:e,props:t})=>{const o=new URLSearchParams,n=!e.startsWith("http")||!e.startsWith("https");t.width&&o.set("width",t.width),t.height&&o.set("height",t.height),t.quality&&o.set("quality",t.quality);const r=t.extension?`@${t.extension}`:"";return n?(()=>{const{hostname:e}=window.location;return"localhost"===e||"127.0.0.1"===e})()?(console.warn("Image optimizations only work with full links and must not contain localhost."),e):`${window.location.origin}/${e}`:`https://image.unsetsoft.com/image/${e}${r}?${o.toString()}`},I=e=>{let t=!1;for(;o.nextUnitOfWork&&!t;)o.nextUnitOfWork=N(o.nextUnitOfWork),t=e.timeRemaining()<1;!o.nextUnitOfWork&&o.wipRoot&&(o.deletions.forEach(b),b(o.wipRoot.child),o.currentRoot=o.wipRoot,o.wipRoot=null),requestIdleCallback(I)};requestIdleCallback(I);const N=e=>{if(e.type instanceof Function?(e=>{o.wipFiber=e,o.hookIndex=0,o.wipFiber.hooks=[];const t=[e.type(e.props)];e.type._contextId&&void 0!==e.props.value&&(e._contextId=e.type._contextId,e._contextValue=e.props.value),g(e,t)})(e):k(e),e.child)return e.child;let t=e;for(;t;){if(t.sibling)return t.sibling;t=t.parent}},v=e=>{o.nextUnitOfWork=e,o.wipRoot=e,o.deletions=[],o.hookIndex=0,o.effects=[],requestIdleCallback(I)},F=(e,t)=>(o.wipRoot={dom:t,props:{children:[e]},alternate:o.currentRoot},o.nextUnitOfWork=o.wipRoot,o.deletions=[],v(o.wipRoot),o.wipRoot),T=(e,t)=>_(((e,t)=>"function"==typeof t?t(e):t),e,t),_=(e,t,n)=>{const s=o.wipFiber.alternate&&o.wipFiber.alternate.hooks&&o.wipFiber.alternate.hooks[o.hookIndex],l={hookID:o.hookIndex,type:r.RYUNIX_STORE,state:s?s.state:n?n(t):t,queue:s&&Array.isArray(s.queue)?s.queue.slice():[]};s&&Array.isArray(s.queue)&&s.queue.forEach((t=>{l.state=e(l.state,t)}));return l.queue.forEach((t=>{l.state=e(l.state,t)})),o.wipFiber.hooks[o.hookIndex]=l,o.hookIndex++,[l.state,e=>{l.queue.push(typeof e===i.function?e:t=>e),o.wipRoot={dom:o.currentRoot.dom,props:o.currentRoot.props,alternate:o.currentRoot},o.deletions=[],o.hookIndex=0,v(o.wipRoot)}]},S=(e,t)=>{const n=o.wipFiber.alternate&&o.wipFiber.alternate.hooks&&o.wipFiber.alternate.hooks[o.hookIndex],i=(s=n?.deps,l=t,!s||!l||s.length!==l.length||s.some(((e,t)=>e!==l[t])));var s,l;const a={hookID:o.hookIndex,type:r.RYUNIX_EFFECT,deps:t,cancel:n?.cancel,effect:i?e:null};o.wipFiber.hooks[o.hookIndex]=a,console.log("[useEffect]: ",o.wipFiber.hooks[o.hookIndex]),o.hookIndex++},U=e=>{const t=o.wipFiber.alternate&&o.wipFiber.alternate.hooks&&o.wipFiber.alternate.hooks[o.hookIndex],n={type:r.RYUNIX_REF,value:t?t.value:{current:e}};return o.wipFiber.hooks[o.hookIndex]=n,o.hookIndex++,n.value},L=(e,n)=>{const i=o.wipFiber.alternate&&o.wipFiber.alternate.hooks&&o.wipFiber.alternate.hooks[o.hookIndex],s={type:r.RYUNIX_MEMO,value:null,deps:n};return i&&t.isEqual(i.deps,s.deps)?s.value=i.value:s.value=e(),o.wipFiber.hooks[o.hookIndex]=s,o.hookIndex++,s.value},C=(e,t)=>L((()=>e),t),O=(e=r.RYUNIX_CONTEXT,t={})=>{const n=({children:e})=>u({children:e});n._contextId=e;return{Provider:n,useContext:(e=r.RYUNIX_CONTEXT)=>{let n=o.wipFiber;for(;n;){if(n.type&&n.type._contextId===e)return n.props&&"value"in n.props?n.props.value:void 0;n=n.parent}return t}}},X=()=>{const e=new URLSearchParams(window.location.search),t={};for(let[o,n]of e.entries())t[o]=n;return t},Y=()=>{const[e,t]=T(window.location.hash);return S((()=>{const e=()=>{t(window.location.hash)};return window.addEventListener("hashchange",e),()=>window.removeEventListener("hashchange",e)}),[]),e},q=O("ryunix.navigation",{location:"/",params:{},query:{},navigate:e=>{},route:null}),A=(e,t)=>{const o=t.split("?")[0].split("#")[0],n=e.find((e=>e.NotFound)),r=n?{route:{component:n.NotFound},params:{}}:{route:{component:null},params:{}};for(const n of e){if(n.subRoutes){const e=A(n.subRoutes,t);if(e)return e}if("*"===n.path)return r;if(!n.path||"string"!=typeof n.path){console.warn("Invalid route detected:",n),console.info("if you are using { NotFound: NotFound } please add { path: '*', NotFound: NotFound }");continue}const e=[],i=new RegExp(`^${n.path.replace(/:\w+/g,(t=>(e.push(t.substring(1)),"([^/]+)")))}$`),s=o.match(i);if(s){return{route:n,params:e.reduce(((e,t,o)=>(e[t]=s[o+1],e)),{})}}}return r},M=({routes:e,children:t})=>{const[o,n]=T(window.location.pathname);S((()=>{const e=()=>n(window.location.pathname);return window.addEventListener("popstate",e),window.addEventListener("hashchange",e),()=>{window.removeEventListener("popstate",e),window.removeEventListener("hashchange",e)}}),[]);const r=A(e,window.location.pathname)||{},i=X(),s={location:o,params:r.params||{},query:i,navigate:e=>{window.history.pushState({},"",e),n(window.location.pathname)},route:r.route};return a(q.Provider,{value:s},u({children:t}))},j=()=>q.useContext("ryunix.navigation"),P=()=>{const{route:e,params:t,query:o,location:n}=j();if(!e||!e.component)return null;const r=Y();return S((()=>{if(r){const e=r.slice(1),t=document.getElementById(e);t&&t.scrollIntoView({block:"start",behavior:"smooth"})}}),[r]),a(e.component,{key:n,params:t,query:o,hash:r})},D=({to:e,...t})=>{const{navigate:o}=j();return a("a",{href:e,onClick:t=>{t.preventDefault(),o(e)},...t},t.children)};var W={createElement:a,render:F,init:(e,t="__ryunix")=>{o.containerRoot=document.getElementById(t);return F(e,o.containerRoot)},Fragment:u,Hooks:Object.freeze({__proto__:null,Children:P,NavLink:D,RouterProvider:M,createContext:O,useCallback:C,useEffect:S,useHash:Y,useMemo:L,useQuery:X,useRef:U,useRouter:j,useStore:T})};window.Ryunix=W,e.Children=P,e.Image=({src:e,...t})=>{const o={src:"true"===t.optimization?R({src:e,props:t}):e,...t};return a("img",o,null)},e.NavLink=D,e.RouterProvider=M,e.createContext=O,e.default=W,e.useCallback=C,e.useEffect=S,e.useHash=Y,e.useMemo=L,e.useQuery=X,e.useRef=U,e.useRouter=j,e.useStore=T,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.17",
3
+ "version": "1.1.19-canary.10",
4
4
  "license": "MIT",
5
5
  "main": "./dist/Ryunix.min.js",
6
6
  "types": "./dist/Ryunix.d.ts",
@@ -12,7 +12,6 @@
12
12
  "build:js": "rollup ./src/main.js --file ./dist/Ryunix.min.js --format umd --name Ryunix --plugin @rollup/plugin-terser",
13
13
  "build": "rollup ./src/main.js --file ./dist/Ryunix.js --format umd --name Ryunix",
14
14
  "prepublishOnly": "npm run build:js | npm run build",
15
- "nightly:release": "npm publish --tag nightly",
16
15
  "canary:release": "npm publish --tag canary",
17
16
  "release": "npm publish",
18
17
  "lint": "eslint . --ext .ts --fix --max-warnings=0 --config .eslintrc.js --no-eslintrc",