@unsetsoft/ryunixjs 1.0.3-nightly.7 → 1.0.3-nightly.9

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
@@ -9,13 +9,12 @@
9
9
  nextUnitOfWork: undefined,
10
10
  currentRoot: undefined,
11
11
  wipRoot: undefined,
12
- deletions: [],
13
- workInProgressFiber: undefined,
14
- hookIndex: 0,
15
- errorBoundary: null, // New property to hold error boundary references
12
+ deletions: undefined,
13
+ wipFiber: undefined,
14
+ hookIndex: undefined,
16
15
  };
17
16
 
18
- const capitalLetterRegex = /[A-Z]/g;
17
+ const reg = /[A-Z]/g;
19
18
 
20
19
  const RYUNIX_TYPES = Object.freeze({
21
20
  TEXT_ELEMENT: Symbol('text.element'),
@@ -23,7 +22,6 @@
23
22
  RYUNIX_MEMO: Symbol('ryunix.memo'),
24
23
  RYUNIX_URL_QUERY: Symbol('ryunix.urlQuery'),
25
24
  RYUNIX_REF: Symbol('ryunix.ref'),
26
- RYUNIX_ERROR_BOUNDARY: Symbol('ryunix.errorBoundary'), // New Error Boundary Type
27
25
  });
28
26
 
29
27
  const STRINGS = Object.freeze({
@@ -41,24 +39,21 @@
41
39
  });
42
40
 
43
41
  const EFFECT_TAGS = Object.freeze({
44
- PLACEMENT: Symbol('placement'),
45
- UPDATE: Symbol('update'),
46
- DELETION: Symbol('deletion'),
42
+ PLACEMENT: Symbol(),
43
+ UPDATE: Symbol(),
44
+ DELETION: Symbol(),
47
45
  });
48
46
 
49
47
  const Fragment = (props) => {
50
48
  return props.children
51
49
  };
52
50
 
53
- /**
54
- * The function takes a set of child elements and flattens them into an array to ensure all children are handled properly.
55
- * @param children - The child elements, which can be of different types (array, object, primitive).
56
- * @param out - The array where the final children will be stored.
57
- * @returns An array with all the child elements.
58
- */
59
- const childArray = (children, out = []) => {
60
- if (children == undefined || typeof children === STRINGS.boolean) ; else if (Array.isArray(children)) {
61
- children.forEach((child) => childArray(child, out)); // Use forEach instead of some
51
+ const childArray = (children, out) => {
52
+ out = out || [];
53
+ if (children == undefined || typeof children == STRINGS.boolean) ; else if (Array.isArray(children)) {
54
+ children.some((child) => {
55
+ childArray(child, out);
56
+ });
62
57
  } else {
63
58
  out.push(children);
64
59
  }
@@ -66,12 +61,22 @@
66
61
  };
67
62
 
68
63
  /**
69
- * The function creates a new element with a given type, properties, and children.
70
- * @param type - The type of element to create (div, span, etc.).
71
- * @param props - The properties of the element.
72
- * @param children - The child elements of the new element.
73
- * @returns An object representing the created element.
64
+ * The function creates a new element with the given type, props, and children.
65
+ * @param type - The type of the element to be created, such as "div", "span", "h1", etc.
66
+ * @param props - The `props` parameter is an object that contains the properties or attributes of the
67
+ * element being created. These properties can include things like `className`, `id`, `style`, and any
68
+ * other custom attributes that the user wants to add to the element. The `props` object is spread
69
+ * using the spread
70
+ * @param children - The `children` parameter is a rest parameter that allows the function to accept
71
+ * any number of arguments after the `props` parameter. These arguments will be treated as children
72
+ * elements of the created element. The `map` function is used to iterate over each child and create a
73
+ * new element if it is not
74
+ * @returns A JavaScript object with a `type` property and a `props` property. The `type` property is
75
+ * set to the `type` argument passed into the function, and the `props` property is an object that
76
+ * includes any additional properties passed in the `props` argument, as well as a `children` property
77
+ * that is an array of any child elements passed in the `...children` argument
74
78
  */
79
+
75
80
  const createElement = (type, props, ...children) => {
76
81
  children = childArray(children, []);
77
82
  return {
@@ -86,52 +91,254 @@
86
91
  };
87
92
 
88
93
  /**
89
- * The function creates a text element from a given text value.
90
- * @param text - The text content to create the element.
91
- * @returns An object representing a text element.
94
+ * The function creates a text element with a given text value.
95
+ * @param text - The text content that will be used to create a new text element.
96
+ * @returns A JavaScript object with a `type` property set to `"TEXT_ELEMENT"` and a `props` property
97
+ * that contains a `nodeValue` property set to the `text` parameter and an empty `children` array.
92
98
  */
99
+
93
100
  const createTextElement = (text) => {
94
101
  return {
95
102
  type: RYUNIX_TYPES.TEXT_ELEMENT,
96
103
  props: {
97
104
  nodeValue: text,
98
- children: [], // Text elements don't have children.
105
+ children: [],
99
106
  },
100
107
  }
101
108
  };
102
109
 
103
110
  /**
104
- * Checks if a key is an event handler (i.e., starts with 'on').
105
- * @param key - The key to check.
106
- * @returns A boolean indicating if the key is an event.
111
+ * The function renders an element into a container using a work-in-progress root.
112
+ * @param element - The element parameter is the component or element that needs to be rendered in the
113
+ * container. It could be a Ryunix component or a DOM element.
114
+ * @param container - The container parameter is the DOM element where the rendered element will be
115
+ * appended to. this parameter is optional if you use createRoot().
107
116
  */
108
- const isEvent = (key) => key.startsWith('on');
117
+ const render = (element, container) => {
118
+ vars.wipRoot = {
119
+ dom: vars.containerRoot || container,
120
+ props: {
121
+ children: [element],
122
+ },
123
+ alternate: vars.currentRoot,
124
+ };
125
+ vars.deletions = [];
126
+ vars.nextUnitOfWork = vars.wipRoot;
127
+ };
109
128
 
110
129
  /**
111
- * Checks if a key is a property (not 'children' and not an event).
112
- * @param key - The key to check.
113
- * @returns A boolean indicating if the key is a property.
130
+ * @description The function creates a reference to a DOM element with the specified ID. This will be used to initialize the app.
131
+ * @example Ryunix.init("root") -> <div id="root" />
132
+ * @param root - The parameter "root" is the id of the HTML element that will serve as the container
133
+ * for the root element.
114
134
  */
115
- const isProperty = (key) => key !== STRINGS.children && !isEvent(key);
135
+ const init = (root) => {
136
+ const rootElement = root || '__ryunix';
137
+ vars.containerRoot = document.getElementById(rootElement);
138
+ return undefined
139
+ };
116
140
 
117
141
  /**
118
- * Checks if a property has changed between the previous and next props.
119
- * @param prev - The previous props object.
120
- * @param next - The next props object.
121
- * @returns A function that takes a key and returns true if the property has changed.
142
+ * @description The function creates a state.
143
+ * @param initial - The initial value of the state for the hook.
144
+ * @returns The `useStore` function returns an array with two elements: the current state value and a
145
+ * `setState` function that can be used to update the state.
122
146
  */
123
- const isNew = (prev, next) => (key) => prev[key] !== next[key];
147
+ const useStore = (initial) => {
148
+ const oldHook =
149
+ vars.wipFiber.alternate &&
150
+ vars.wipFiber.alternate.hooks &&
151
+ vars.wipFiber.alternate.hooks[vars.hookIndex];
152
+ const hook = {
153
+ state: oldHook ? oldHook.state : initial,
154
+ queue: [],
155
+ };
156
+
157
+ const actions = oldHook ? oldHook.queue : [];
158
+ actions.forEach((action) => {
159
+ hook.state =
160
+ typeof action === STRINGS.function ? action(hook.state) : action;
161
+ });
162
+
163
+ /**
164
+ * The function `setState` updates the state of a component in Ryunix by adding an action to a queue
165
+ * and setting up a new work-in-progress root.
166
+ * @param action - The `action` parameter is an object that represents a state update to be performed
167
+ * on a component. It contains information about the type of update to be performed and any new data
168
+ * that needs to be applied to the component's state.
169
+ */
170
+ const setState = (action) => {
171
+ hook.queue.push(action);
172
+ vars.wipRoot = {
173
+ dom: vars.currentRoot.dom,
174
+ props: vars.currentRoot.props,
175
+ alternate: vars.currentRoot,
176
+ };
177
+ vars.nextUnitOfWork = vars.wipRoot;
178
+ vars.deletions = [];
179
+ };
180
+
181
+ if (vars.wipFiber && vars.wipFiber.hooks) {
182
+ vars.wipFiber.hooks.push(hook);
183
+ vars.hookIndex++;
184
+ }
185
+ return [hook.state, setState]
186
+ };
124
187
 
125
188
  /**
126
- * Checks if a property is no longer present in the next props.
127
- * @param next - The next props object.
128
- * @returns A function that takes a key and returns true if the property is not present in the next props.
189
+ * This is a function that creates a hook for managing side effects in Ryunix components.
190
+ * @param effect - The effect function that will be executed after the component has rendered or when
191
+ * the dependencies have changed. It can perform side effects such as fetching data, updating the DOM,
192
+ * or subscribing to events.
193
+ * @param deps - An array of dependencies that the effect depends on. If any of the dependencies change
194
+ * between renders, the effect will be re-run. If the array is empty, the effect will only run once on
195
+ * mount and never again.
129
196
  */
197
+
198
+ const useEffect = (callback, deps) => {
199
+ const oldHook =
200
+ vars.wipFiber.alternate &&
201
+ vars.wipFiber.alternate.hooks &&
202
+ vars.wipFiber.alternate.hooks[vars.hookIndex];
203
+
204
+ const hook = {
205
+ type: RYUNIX_TYPES.RYUNIX_EFFECT,
206
+ deps,
207
+ };
208
+
209
+ if (!oldHook) {
210
+ // invoke callback if this is the first time
211
+ callback();
212
+ } else {
213
+ if (!lodash.isEqual(oldHook.deps, hook.deps)) {
214
+ callback();
215
+ }
216
+ }
217
+
218
+ if (vars.wipFiber.hooks) {
219
+ vars.wipFiber.hooks.push(hook);
220
+ vars.hookIndex++;
221
+ }
222
+ };
223
+
224
+ const useRef = (initial) => {
225
+ const oldHook =
226
+ vars.wipFiber.alternate &&
227
+ vars.wipFiber.alternate.hooks &&
228
+ vars.wipFiber.alternate.hooks[vars.hookIndex];
229
+
230
+ const hook = {
231
+ type: RYUNIX_TYPES.RYUNIX_REF,
232
+ value: oldHook ? oldHook.value : { current: initial },
233
+ };
234
+
235
+ if (vars.wipFiber.hooks) {
236
+ vars.wipFiber.hooks.push(hook);
237
+ vars.hookIndex++;
238
+ }
239
+
240
+ return hook.value
241
+ };
242
+
243
+ const useMemo = (comp, deps) => {
244
+ const oldHook =
245
+ vars.wipFiber.alternate &&
246
+ vars.wipFiber.alternate.hooks &&
247
+ vars.wipFiber.alternate.hooks[vars.hookIndex];
248
+
249
+ const hook = {
250
+ type: RYUNIX_TYPES.RYUNIX_MEMO,
251
+ value: null,
252
+ deps,
253
+ };
254
+
255
+ if (oldHook) {
256
+ if (lodash.isEqual(oldHook.deps, hook.deps)) {
257
+ hook.value = oldHook.value;
258
+ } else {
259
+ hook.value = comp();
260
+ }
261
+ } else {
262
+ hook.value = comp();
263
+ }
264
+
265
+ if (vars.wipFiber.hooks) {
266
+ vars.wipFiber.hooks.push(hook);
267
+ vars.hookIndex++;
268
+ }
269
+
270
+ return hook.value
271
+ };
272
+ const useCallback = (callback, deps) => {
273
+ return useMemo(() => callback, deps)
274
+ };
275
+
276
+ const useRouter = (routes) => {
277
+ const [location, setLocation] = useStore(window.location.pathname);
278
+
279
+ const navigate = (path) => {
280
+ window.history.pushState({}, '', path);
281
+ setLocation(path);
282
+ };
283
+
284
+ useEffect(() => {
285
+ const onPopState = () => {
286
+ setLocation(window.location.pathname);
287
+ };
288
+
289
+ window.addEventListener('popstate', onPopState);
290
+ return () => {
291
+ window.removeEventListener('popstate', onPopState);
292
+ }
293
+ }, []);
294
+
295
+ const currentRoute = routes.find((route) => route.path === location);
296
+ const Children = () => (currentRoute ? currentRoute.component : null);
297
+
298
+ return { Children, navigate }
299
+ };
300
+
301
+ /**
302
+ * The `useQuery` function is a custom hook in JavaScript that retrieves query parameters from the URL
303
+ * and stores them in a hook for easy access.
304
+ * @returns The `useQuery` function returns the `query` property of the `hook` object.
305
+ */
306
+ const useQuery = () => {
307
+ const oldHook =
308
+ vars.wipFiber.alternate &&
309
+ vars.wipFiber.alternate.hooks &&
310
+ vars.wipFiber.alternate.hooks[vars.hookIndex];
311
+
312
+ const hasOld = oldHook ? oldHook : undefined;
313
+
314
+ const urlSearchParams = new URLSearchParams(window.location.search);
315
+ const params = Object.fromEntries(urlSearchParams.entries());
316
+ const Query = hasOld ? hasOld : params;
317
+
318
+ const hook = {
319
+ type: RYUNIX_TYPES.RYUNIX_URL_QUERY,
320
+ query: Query,
321
+ };
322
+
323
+ if (vars.wipFiber.hooks) {
324
+ vars.wipFiber.hooks.push(hook);
325
+ vars.hookIndex++;
326
+ }
327
+
328
+ return hook.query
329
+ };
330
+
331
+ const isEvent = (key) => key.startsWith('on');
332
+ const isProperty = (key) => key !== STRINGS.children && !isEvent(key);
333
+ const isNew = (prev, next) => (key) => prev[key] !== next[key];
130
334
  const isGone = (next) => (key) => !(key in next);
131
335
 
132
336
  /**
133
- * Cancels all effect hooks in a given fiber.
134
- * @param fiber - The fiber object containing hooks.
337
+ * The function cancels all effect hooks in a given fiber.
338
+ * @param fiber - The "fiber" parameter is likely referring to a data structure used in React.js to
339
+ * represent a component and its state. It contains information about the component's props, state, and
340
+ * children, as well as metadata used by React to manage updates and rendering. The function
341
+ * "cancelEffects" is likely intended
135
342
  */
136
343
  const cancelEffects = (fiber) => {
137
344
  if (fiber.hooks) {
@@ -144,8 +351,11 @@
144
351
  };
145
352
 
146
353
  /**
147
- * Runs all effect hooks in a given fiber.
148
- * @param fiber - The fiber object containing hooks.
354
+ * The function runs all effect hooks in a given fiber.
355
+ * @param fiber - The "fiber" parameter is likely referring to a data structure used in the
356
+ * implementation of a fiber-based reconciliation algorithm, such as the one used in React. A fiber
357
+ * represents a unit of work that needs to be performed by the reconciliation algorithm, and it
358
+ * contains information about a component and its children, as
149
359
  */
150
360
  const runEffects = (fiber) => {
151
361
  if (fiber.hooks) {
@@ -158,38 +368,34 @@
158
368
  };
159
369
 
160
370
  /**
161
- * Creates a new DOM element based on the given fiber object and updates its properties.
162
- *
163
- * @param fiber - The fiber object represents a node in the fiber tree and contains
164
- * information about the element type, props, and children.
165
- * @returns A newly created DOM element based on the fiber object.
371
+ * The function creates a new DOM element based on the given fiber object and updates its properties.
372
+ * @param fiber - The fiber parameter is an object that represents a node in the fiber tree. It
373
+ * contains information about the element type, props, and children of the node.
374
+ * @returns The `createDom` function returns a newly created DOM element based on the `fiber` object
375
+ * passed as an argument. If the `fiber` object represents a text element, a text node is created using
376
+ * `document.createTextNode("")`. Otherwise, a new element is created using
377
+ * `document.createElement(fiber.type)`. The function then calls the `updateDom` function to update the
378
+ * properties of the newly created
166
379
  */
167
380
  const createDom = (fiber) => {
168
- // Log to verify fiber type before creating DOM
169
- console.log('Creating DOM for fiber:', fiber);
170
-
171
- // Check if the fiber is a text element or a regular element
172
381
  const dom =
173
- fiber.type === RYUNIX_TYPES.TEXT_ELEMENT
174
- ? document.createTextNode(fiber.props.nodeValue || '')
382
+ fiber.type == RYUNIX_TYPES.TEXT_ELEMENT
383
+ ? document.createTextNode('')
175
384
  : document.createElement(fiber.type);
176
385
 
177
- // Update the newly created DOM element with its initial props
178
386
  updateDom(dom, {}, fiber.props);
179
387
 
180
388
  return dom
181
389
  };
182
390
 
183
391
  /**
184
- * Updates a DOM element by removing old properties and event listeners,
185
- * and applying new properties and event listeners from the nextProps.
186
- *
187
- * @param dom - The DOM element that needs to be updated.
188
- * @param prevProps - The previous properties of the DOM element.
189
- * @param nextProps - The new properties that should be applied to the DOM element.
392
+ * The function updates the DOM by removing old event listeners and properties, and adding new ones
393
+ * based on the previous and next props.
394
+ * @param dom - The DOM element that needs to be updated with new props.
395
+ * @param prevProps - An object representing the previous props (properties) of a DOM element.
396
+ * @param nextProps - An object containing the new props that need to be updated in the DOM.
190
397
  */
191
398
  const updateDom = (dom, prevProps, nextProps) => {
192
- // Remove old or changed event listeners
193
399
  Object.keys(prevProps)
194
400
  .filter(isEvent)
195
401
  .filter((key) => isGone(nextProps)(key) || isNew(prevProps, nextProps)(key))
@@ -198,7 +404,6 @@
198
404
  dom.removeEventListener(eventType, prevProps[name]);
199
405
  });
200
406
 
201
- // Remove old properties
202
407
  Object.keys(prevProps)
203
408
  .filter(isProperty)
204
409
  .filter(isGone(nextProps))
@@ -206,21 +411,35 @@
206
411
  dom[name] = '';
207
412
  });
208
413
 
209
- // Set new or changed properties
210
414
  Object.keys(nextProps)
211
415
  .filter(isProperty)
212
416
  .filter(isNew(prevProps, nextProps))
213
417
  .forEach((name) => {
214
- if (name === STRINGS.style || name === OLD_STRINGS.style) {
215
- DomStyle(dom, nextProps[STRINGS.style] || nextProps[OLD_STRINGS.style]);
216
- } else if (name === STRINGS.className || name === OLD_STRINGS.className) {
217
- handleClassName(dom, prevProps, nextProps, name);
418
+ if (name === STRINGS.style) {
419
+ DomStyle(dom, nextProps['ryunix-style']);
420
+ } else if (name === OLD_STRINGS.style) {
421
+ DomStyle(dom, nextProps.style);
422
+ } else if (name === STRINGS.className) {
423
+ if (nextProps['ryunix-class'] === '') {
424
+ throw new Error('data-class cannot be empty.')
425
+ }
426
+
427
+ prevProps['ryunix-class'] &&
428
+ dom.classList.remove(...prevProps['ryunix-class'].split(/\s+/));
429
+ dom.classList.add(...nextProps['ryunix-class'].split(/\s+/));
430
+ } else if (name === OLD_STRINGS.className) {
431
+ if (nextProps.className === '') {
432
+ throw new Error('className cannot be empty.')
433
+ }
434
+
435
+ prevProps.className &&
436
+ dom.classList.remove(...prevProps.className.split(/\s+/));
437
+ dom.classList.add(...nextProps.className.split(/\s+/));
218
438
  } else {
219
439
  dom[name] = nextProps[name];
220
440
  }
221
441
  });
222
442
 
223
- // Add new event listeners
224
443
  Object.keys(nextProps)
225
444
  .filter(isEvent)
226
445
  .filter(isNew(prevProps, nextProps))
@@ -230,47 +449,16 @@
230
449
  });
231
450
  };
232
451
 
233
- /**
234
- * Updates the DOM element's style by applying the provided styles.
235
- *
236
- * @param dom - The DOM element that needs to be styled.
237
- * @param style - An object containing the styles to be applied.
238
- */
239
452
  const DomStyle = (dom, style) => {
240
453
  dom.style = Object.keys(style).reduce((acc, styleName) => {
241
- const key = styleName.replace(
242
- capitalLetterRegex,
243
- (v) => `-${v.toLowerCase()}`,
244
- );
454
+ const key = styleName.replace(reg, function (v) {
455
+ return '-' + v.toLowerCase()
456
+ });
245
457
  acc += `${key}: ${style[styleName]};`;
246
458
  return acc
247
459
  }, '');
248
460
  };
249
461
 
250
- /**
251
- * Handles updating the className or ryunix-class properties, ensuring
252
- * that the old class names are removed and the new ones are applied.
253
- *
254
- * @param dom - The DOM element to be updated.
255
- * @param prevProps - The previous properties, including className.
256
- * @param nextProps - The new properties, including className.
257
- * @param name - The name of the class property (className or ryunix-class).
258
- */
259
- const handleClassName = (dom, prevProps, nextProps, name) => {
260
- const classProp = name === STRINGS.className ? 'ryunix-class' : 'className';
261
-
262
- if (nextProps[classProp] === '') {
263
- throw new Error(`${classProp} cannot be empty.`)
264
- }
265
-
266
- // Remove old class names if they exist
267
- prevProps[classProp] &&
268
- dom.classList.remove(...prevProps[classProp].split(/\s+/));
269
-
270
- // Add new class names
271
- dom.classList.add(...nextProps[classProp].split(/\s+/));
272
- };
273
-
274
462
  var Dom = /*#__PURE__*/Object.freeze({
275
463
  __proto__: null,
276
464
  DomStyle: DomStyle,
@@ -282,10 +470,8 @@
282
470
  * The function commits changes made to the virtual DOM to the actual DOM.
283
471
  */
284
472
  const commitRoot = () => {
285
- console.log('Committing root...');
286
473
  vars.deletions.forEach(commitWork);
287
474
  if (vars.wipRoot && vars.wipRoot.child) {
288
- console.log('Committing child...');
289
475
  commitWork(vars.wipRoot.child);
290
476
  vars.currentRoot = vars.wipRoot;
291
477
  }
@@ -293,107 +479,57 @@
293
479
  };
294
480
 
295
481
  /**
296
- * Helper function to find the DOM parent of a given fiber.
297
- * It walks up the fiber tree until it finds a parent with a DOM node.
298
- * @param {Object} fiber - The fiber node whose DOM parent needs to be found.
299
- * @returns {HTMLElement} The DOM node of the fiber's parent.
300
- */
301
- const findDomParent = (fiber) => {
302
- let domParentFiber = fiber.parent;
303
- // Walk up the tree until a DOM node is found or the root is reached
304
- while (domParentFiber && !domParentFiber.dom) {
305
- domParentFiber = domParentFiber.parent;
306
- }
307
- return domParentFiber ? domParentFiber.dom : null
308
- };
309
-
310
- /**
311
- * Safely removes a child DOM node from its parent, with error handling.
312
- * @param {HTMLElement} domParent - The parent DOM node.
313
- * @param {HTMLElement} childDom - The child DOM node to be removed.
314
- */
315
- const safeRemoveChild = (domParent, childDom) => {
316
- try {
317
- domParent.removeChild(childDom);
318
- } catch (error) {
319
- console.error('Error removing DOM child:', error);
320
- }
321
- };
322
-
323
- /**
324
- * The function handles the deletion of a fiber's corresponding DOM node.
325
- * It removes the fiber's DOM element or recursively removes its child.
326
- * @param {Object} fiber - The fiber node to be deleted.
327
- * @param {HTMLElement} domParent - The parent DOM node from which the fiber's DOM node will be removed.
482
+ * The function commits changes made to the DOM based on the effect tag of the fiber.
483
+ * @param fiber - A fiber is a unit of work in Ryunix's reconciliation process. It represents a
484
+ * component and its state at a particular point in time. The `commitWork` function takes a fiber as a
485
+ * parameter to commit the changes made during the reconciliation process to the actual DOM.
486
+ * @returns The function does not return anything, it performs side effects by manipulating the DOM.
328
487
  */
329
- const commitDeletion = (fiber, domParent) => {
330
- if (fiber && fiber.dom) {
331
- safeRemoveChild(domParent, fiber.dom);
332
- } else if (fiber && fiber.child) {
333
- commitDeletion(fiber.child, domParent);
488
+ const commitWork = (fiber) => {
489
+ if (!fiber) {
490
+ return
334
491
  }
335
- };
336
492
 
337
- /**
338
- * Cleans up the effects associated with a fiber node, specifically for
339
- * UPDATE and DELETION effect tags.
340
- * @param {Object} fiber - The fiber node whose effects need to be cleaned up.
341
- */
342
- const cleanupEffects = (fiber) => {
343
- if (
344
- fiber.effectTag === EFFECT_TAGS.UPDATE ||
345
- fiber.effectTag === EFFECT_TAGS.DELETION
346
- ) {
347
- cancelEffects(fiber);
493
+ let domParentFiber = fiber.parent;
494
+ while (!domParentFiber.dom) {
495
+ domParentFiber = domParentFiber.parent;
348
496
  }
349
- };
497
+ const domParent = domParentFiber.dom;
350
498
 
351
- /**
352
- * An object that maps effect tags to their corresponding handling functions.
353
- * Each function takes a fiber node and a DOM parent, and applies the necessary changes to the DOM.
354
- */
355
- const effectHandlers = {
356
- [EFFECT_TAGS.PLACEMENT]: (fiber, domParent) => {
499
+ if (fiber.effectTag === EFFECT_TAGS.PLACEMENT) {
357
500
  if (fiber.dom != undefined) {
358
501
  domParent.appendChild(fiber.dom);
359
- console.log('Appending child DOM node:', fiber.dom);
360
- } else {
361
- console.error('Failed to append DOM. Fiber has no DOM:', fiber);
362
502
  }
363
503
  runEffects(fiber);
364
- },
365
- [EFFECT_TAGS.UPDATE]: (fiber, domParent) => {
366
- cleanupEffects(fiber); // Cleanup effects before updating
504
+ } else if (fiber.effectTag === EFFECT_TAGS.UPDATE) {
505
+ cancelEffects(fiber);
367
506
  if (fiber.dom != undefined) {
368
507
  updateDom(fiber.dom, fiber.alternate.props, fiber.props);
369
508
  }
370
509
  runEffects(fiber);
371
- },
372
- [EFFECT_TAGS.DELETION]: (fiber, domParent) => {
373
- cleanupEffects(fiber);
510
+ } else if (fiber.effectTag === EFFECT_TAGS.DELETION) {
511
+ cancelEffects(fiber);
374
512
  commitDeletion(fiber, domParent);
375
- },
513
+ return
514
+ }
515
+
516
+ commitWork(fiber.child);
517
+ commitWork(fiber.sibling);
376
518
  };
377
519
 
378
520
  /**
379
- * The function commits changes made to the DOM based on the effect tag of the fiber.
380
- * It handles PLACEMENT, UPDATE, and DELETION of DOM nodes, and processes child and sibling fibers.
381
- * @param {Object} fiber - The fiber node whose changes need to be committed to the DOM.
521
+ * The function removes a fiber's corresponding DOM node from its parent node or recursively removes
522
+ * its child's DOM node until it finds a node to remove.
523
+ * @param fiber - a fiber node in a fiber tree, which represents a component or an element in the Ryunix
524
+ * application.
525
+ * @param domParent - The parent DOM element from which the fiber's DOM element needs to be removed.
382
526
  */
383
- const commitWork = (fiber) => {
384
- if (!fiber) return
385
-
386
- const domParent = findDomParent(fiber);
387
- if (!domParent) return // If no parent DOM found, skip
388
-
389
- const effectHandler = effectHandlers[fiber.effectTag];
390
- if (effectHandler) {
391
- effectHandler(fiber, domParent);
527
+ const commitDeletion = (fiber, domParent) => {
528
+ if (fiber && fiber.dom) {
529
+ domParent.removeChild(fiber.dom);
530
+ } else if (fiber && fiber.child) {
531
+ commitDeletion(fiber.child, domParent);
392
532
  }
393
-
394
- // Process child and sibling fibers recursively
395
- commitWork(fiber.child);
396
- commitWork(fiber.sibling);
397
533
  };
398
534
 
399
535
  var Commits = /*#__PURE__*/Object.freeze({
@@ -403,6 +539,20 @@
403
539
  commitWork: commitWork
404
540
  });
405
541
 
542
+ const isPropsChanged = (prevProps, nextProps) => {
543
+ for (let key in prevProps) {
544
+ if (prevProps[key] !== nextProps[key]) {
545
+ return true
546
+ }
547
+ }
548
+ for (let key in nextProps) {
549
+ if (!(key in prevProps)) {
550
+ return true
551
+ }
552
+ }
553
+ return false
554
+ };
555
+
406
556
  /**
407
557
  * This function reconciles the children of a fiber node with a new set of elements, creating new
408
558
  * fibers for new elements, updating existing fibers for elements with the same type, and marking old
@@ -420,20 +570,20 @@
420
570
  while (index < elements.length || oldFiber != undefined) {
421
571
  const element = elements[index];
422
572
  let newFiber;
423
-
424
573
  const sameType = oldFiber && element && element.type == oldFiber.type;
425
574
 
426
575
  if (sameType) {
427
576
  newFiber = {
428
- type: oldFiber.type,
577
+ type: oldFiber ? oldFiber.type : undefined,
429
578
  props: element.props,
430
- dom: oldFiber.dom,
579
+ dom: oldFiber ? oldFiber.dom : undefined,
431
580
  parent: wipFiber,
432
581
  alternate: oldFiber,
433
- effectTag: EFFECT_TAGS.UPDATE,
582
+ effectTag: isPropsChanged(oldFiber.props, element.props)
583
+ ? EFFECT_TAGS.UPDATE
584
+ : null,
434
585
  };
435
- }
436
- if (element && !sameType) {
586
+ } else if (element) {
437
587
  newFiber = {
438
588
  type: element.type,
439
589
  props: element.props,
@@ -442,8 +592,7 @@
442
592
  alternate: undefined,
443
593
  effectTag: EFFECT_TAGS.PLACEMENT,
444
594
  };
445
- }
446
- if (!element && oldFiber) {
595
+ } else if (oldFiber) {
447
596
  oldFiber.effectTag = EFFECT_TAGS.DELETION;
448
597
  vars.deletions.push(oldFiber);
449
598
  }
@@ -469,36 +618,38 @@
469
618
  });
470
619
 
471
620
  /**
472
- * Updates a function component by setting up a work-in-progress fiber,
473
- * resetting the hook index, initializing an empty hooks array, rendering the component,
474
- * and reconciling its children.
475
- *
476
- * @param fiber - The fiber node representing the function component being updated. It contains
477
- * properties such as the component type, props, and hooks.
621
+ * This function updates a function component by setting up a work-in-progress fiber, resetting the
622
+ * hook index, creating an empty hooks array, rendering the component, and reconciling its children.
623
+ * @param fiber - The fiber parameter is an object that represents a node in the fiber tree. It
624
+ * contains information about the component, its props, state, and children. In this function, it is
625
+ * used to update the state of the component and its children.
478
626
  */
479
627
  const updateFunctionComponent = (fiber) => {
480
- // Set the current work-in-progress fiber
481
- vars.workInProgressFiber = fiber;
628
+ vars.wipFiber = fiber;
482
629
  vars.hookIndex = 0;
483
- vars.workInProgressFiber.hooks = [];
484
-
630
+ vars.wipFiber.hooks = [];
485
631
  const children = fiber.type(fiber.props);
486
- reconcileChildren(fiber, children);
632
+ let childArr = [];
633
+ if (Array.isArray(children)) {
634
+ // Fragment results returns array
635
+ childArr = [...children];
636
+ } else {
637
+ // Normal function component returns single root node
638
+ childArr = [children];
639
+ }
640
+ reconcileChildren(fiber, childArr);
487
641
  };
642
+
488
643
  /**
489
- * Updates a host component's DOM element and reconciles its children.
490
- * This function handles standard DOM elements like div, span, etc.
491
- *
492
- * @param fiber - A fiber node representing the host component (e.g., a DOM node like div, span, etc.).
644
+ * This function updates a host component's DOM element and reconciles its children.
645
+ * @param fiber - A fiber is a unit of work in Ryunix that represents a component and its state. It
646
+ * contains information about the component's type, props, and children, as well as pointers to other
647
+ * fibers in the tree.
493
648
  */
494
649
  const updateHostComponent = (fiber) => {
495
- // If the fiber doesn't already have a DOM node, create one
496
650
  if (!fiber.dom) {
497
651
  fiber.dom = createDom(fiber);
498
- console.log('DOM node created:', fiber.dom);
499
652
  }
500
-
501
- // Reconcile the fiber's children with its new or updated props
502
653
  reconcileChildren(fiber, fiber.props.children);
503
654
  };
504
655
 
@@ -509,13 +660,15 @@
509
660
  });
510
661
 
511
662
  /**
512
- * Main work loop that processes the fiber tree using requestIdleCallback.
513
- * It continues processing until all units of work are completed or the browser needs to yield.
514
- * @param {IdleDeadline} deadline - Represents the time remaining for the browser to execute tasks before yielding.
663
+ * This function uses requestIdleCallback to perform work on a fiber tree until it is complete or the
664
+ * browser needs to yield to other tasks.
665
+ * @param deadline - The `deadline` parameter is an object that represents the amount of time the
666
+ * browser has to perform work before it needs to handle other tasks. It has a `timeRemaining()` method
667
+ * that returns the amount of time remaining before the deadline is reached. The `shouldYield` variable
668
+ * is used to determine
515
669
  */
516
670
  const workLoop = (deadline) => {
517
671
  let shouldYield = false;
518
-
519
672
  while (vars.nextUnitOfWork && !shouldYield) {
520
673
  vars.nextUnitOfWork = performUnitOfWork(vars.nextUnitOfWork);
521
674
  shouldYield = deadline.timeRemaining() < 1;
@@ -525,32 +678,43 @@
525
678
  commitRoot();
526
679
  }
527
680
 
528
- requestIdleCallback(workLoop);
681
+ if (vars.nextUnitOfWork) {
682
+ requestIdleCallback(workLoop, { timeout: 100 });
683
+ }
529
684
  };
530
685
 
531
- // Start the work loop for the first time
532
686
  requestIdleCallback(workLoop);
533
687
 
534
688
  /**
535
- * Processes a unit of work in the fiber tree.
536
- * Decides whether to update a function component or a host component (DOM element).
537
- * @param {Object} fiber - The current fiber representing a component and its state in the virtual DOM tree.
538
- * @returns {null} The next fiber to process, or undefined if there are no more.
689
+ * The function performs a unit of work by updating either a function component or a host component and
690
+ * returns the next fiber to be processed.
691
+ * @param fiber - A fiber is a unit of work in Ryunix that represents a component and its state. It
692
+ * contains information about the component's type, props, and children, as well as pointers to its
693
+ * parent, child, and sibling fibers. The `performUnitOfWork` function takes a fiber as a parameter and
694
+ * performs work
695
+ * @returns The function `performUnitOfWork` returns the next fiber to be processed. If the current
696
+ * fiber has a child, it returns the child. Otherwise, it looks for the next sibling of the current
697
+ * fiber. If there are no more siblings, it goes up the tree to the parent and looks for the next
698
+ * sibling of the parent. The function returns `undefined` if there are no more fibers to process.
539
699
  */
540
700
  const performUnitOfWork = (fiber) => {
541
- console.log('Performing unit of work for fiber:', fiber);
542
701
  const isFunctionComponent = fiber.type instanceof Function;
543
- isFunctionComponent
544
- ? updateFunctionComponent(fiber)
545
- : updateHostComponent(fiber);
546
-
547
- if (fiber.child) return fiber.child
702
+ if (isFunctionComponent) {
703
+ updateFunctionComponent(fiber);
704
+ } else {
705
+ updateHostComponent(fiber);
706
+ }
707
+ if (fiber.child) {
708
+ return fiber.child
709
+ }
548
710
  let nextFiber = fiber;
549
711
  while (nextFiber) {
550
- if (nextFiber.sibling) return nextFiber.sibling
712
+ if (nextFiber.sibling) {
713
+ return nextFiber.sibling
714
+ }
551
715
  nextFiber = nextFiber.parent;
552
716
  }
553
- return null
717
+ return undefined
554
718
  };
555
719
 
556
720
  var Workers = /*#__PURE__*/Object.freeze({
@@ -559,116 +723,6 @@
559
723
  workLoop: workLoop
560
724
  });
561
725
 
562
- /**
563
- * Renders an element into the specified container or the default root element.
564
- */
565
- const render = (element, container) => {
566
- vars.wipRoot = {
567
- dom: vars.containerRoot || container,
568
- props: { children: [element] },
569
- alternate: vars.currentRoot,
570
- };
571
-
572
- console.log('Rendering element:', element);
573
- console.log('Rendering to container:', vars.wipRoot.dom);
574
-
575
- vars.deletions = [];
576
- vars.nextUnitOfWork = vars.wipRoot;
577
- requestIdleCallback(workLoop);
578
- };
579
-
580
- /**
581
- * Initializes the app with a root container.
582
- */
583
- const init = (rootId = '__ryunix') => {
584
- const rootElement = document.getElementById(rootId);
585
- if (!rootElement) {
586
- console.error(`Root element with ID '${rootId}' not found.`);
587
- return null
588
- }
589
- console.log('Container initialized:', vars.containerRoot);
590
-
591
- vars.containerRoot = rootElement;
592
- return undefined
593
- };
594
-
595
- /**
596
- * useStore is similar to useState in React, managing local state within a functional component.
597
- */
598
- const useStore = (initial) => {
599
- const oldHook = vars.workInProgressFiber.alternate?.hooks?.[vars.hookIndex];
600
- const hook = { state: oldHook ? oldHook.state : initial, queue: [] };
601
-
602
- const actions = oldHook ? oldHook.queue : [];
603
- actions.forEach((action) => {
604
- hook.state = typeof action === 'function' ? action(hook.state) : action;
605
- });
606
-
607
- const setState = (action) => {
608
- hook.queue.push(action);
609
- vars.wipRoot = {
610
- dom: vars.currentRoot.dom,
611
- props: vars.currentRoot.props,
612
- alternate: vars.currentRoot,
613
- };
614
- vars.nextUnitOfWork = vars.wipRoot;
615
- vars.deletions = [];
616
- };
617
-
618
- vars.workInProgressFiber.hooks.push(hook);
619
- vars.hookIndex++;
620
- return [hook.state, setState]
621
- };
622
-
623
- /**
624
- * useEffect runs side effects after rendering based on dependencies.
625
- */
626
- const useEffect = (callback, deps) => {
627
- const oldHook = vars.workInProgressFiber.alternate?.hooks?.[vars.hookIndex];
628
- const hook = { type: 'effect', deps };
629
-
630
- const hasChanged = !oldHook || !lodash.isEqual(oldHook.deps, deps);
631
- if (hasChanged) {
632
- const cleanup = callback();
633
- hook.cleanup = cleanup;
634
- }
635
-
636
- vars.workInProgressFiber.hooks.push(hook);
637
- vars.hookIndex++;
638
- };
639
-
640
- /**
641
- * useRef creates a mutable ref object to store values across renders.
642
- */
643
- const useRef = (initialValue) => {
644
- const oldHook = vars.workInProgressFiber.alternate?.hooks?.[vars.hookIndex];
645
- const hook = { value: oldHook ? oldHook.value : { current: initialValue } };
646
-
647
- vars.workInProgressFiber.hooks.push(hook);
648
- vars.hookIndex++;
649
- return hook.value
650
- };
651
-
652
- /**
653
- * useMemo memoizes a value to avoid recomputations.
654
- */
655
- const useMemo = (computeFn, deps) => {
656
- const oldHook = vars.workInProgressFiber.alternate?.hooks?.[vars.hookIndex];
657
- const hook = {
658
- deps,
659
- value: oldHook && lodash.isEqual(deps, oldHook.deps) ? oldHook.value : computeFn(),
660
- };
661
-
662
- vars.workInProgressFiber.hooks.push(hook);
663
- vars.hookIndex++;
664
- return hook.value
665
- };
666
-
667
- /**
668
- * useCallback memoizes a callback function to avoid unnecessary recreations.
669
- */
670
- const useCallback = (callback, deps) => useMemo(() => callback, deps);
671
-
672
726
  var Ryunix = {
673
727
  createElement,
674
728
  render,
@@ -688,7 +742,9 @@
688
742
  exports.useCallback = useCallback;
689
743
  exports.useEffect = useEffect;
690
744
  exports.useMemo = useMemo;
745
+ exports.useQuery = useQuery;
691
746
  exports.useRef = useRef;
747
+ exports.useRouter = useRouter;
692
748
  exports.useStore = useStore;
693
749
 
694
750
  Object.defineProperty(exports, '__esModule', { value: true });