@unsetsoft/ryunixjs 1.0.3-nightly.8 → 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
+ };
187
+
188
+ /**
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.
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
+ };
124
300
 
125
301
  /**
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.
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.
129
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,37 +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
- console.log('Creating DOM for fiber:', fiber);
169
-
170
- // Ensure that the fiber type is a valid HTML element or a text element
171
381
  const dom =
172
- fiber.type === RYUNIX_TYPES.TEXT_ELEMENT
173
- ? document.createTextNode(fiber.props.nodeValue || '')
382
+ fiber.type == RYUNIX_TYPES.TEXT_ELEMENT
383
+ ? document.createTextNode('')
174
384
  : document.createElement(fiber.type);
175
385
 
176
- // Update the newly created DOM element with initial props
177
386
  updateDom(dom, {}, fiber.props);
178
387
 
179
388
  return dom
180
389
  };
181
390
 
182
391
  /**
183
- * Updates a DOM element by removing old properties and event listeners,
184
- * and applying new properties and event listeners from the nextProps.
185
- *
186
- * @param dom - The DOM element that needs to be updated.
187
- * @param prevProps - The previous properties of the DOM element.
188
- * @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.
189
397
  */
190
398
  const updateDom = (dom, prevProps, nextProps) => {
191
- // Remove old or changed event listeners
192
399
  Object.keys(prevProps)
193
400
  .filter(isEvent)
194
401
  .filter((key) => isGone(nextProps)(key) || isNew(prevProps, nextProps)(key))
@@ -197,7 +404,6 @@
197
404
  dom.removeEventListener(eventType, prevProps[name]);
198
405
  });
199
406
 
200
- // Remove old properties
201
407
  Object.keys(prevProps)
202
408
  .filter(isProperty)
203
409
  .filter(isGone(nextProps))
@@ -205,21 +411,35 @@
205
411
  dom[name] = '';
206
412
  });
207
413
 
208
- // Set new or changed properties
209
414
  Object.keys(nextProps)
210
415
  .filter(isProperty)
211
416
  .filter(isNew(prevProps, nextProps))
212
417
  .forEach((name) => {
213
- if (name === STRINGS.style || name === OLD_STRINGS.style) {
214
- DomStyle(dom, nextProps[STRINGS.style] || nextProps[OLD_STRINGS.style]);
215
- } else if (name === STRINGS.className || name === OLD_STRINGS.className) {
216
- 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+/));
217
438
  } else {
218
439
  dom[name] = nextProps[name];
219
440
  }
220
441
  });
221
442
 
222
- // Add new event listeners
223
443
  Object.keys(nextProps)
224
444
  .filter(isEvent)
225
445
  .filter(isNew(prevProps, nextProps))
@@ -229,47 +449,16 @@
229
449
  });
230
450
  };
231
451
 
232
- /**
233
- * Updates the DOM element's style by applying the provided styles.
234
- *
235
- * @param dom - The DOM element that needs to be styled.
236
- * @param style - An object containing the styles to be applied.
237
- */
238
452
  const DomStyle = (dom, style) => {
239
453
  dom.style = Object.keys(style).reduce((acc, styleName) => {
240
- const key = styleName.replace(
241
- capitalLetterRegex,
242
- (v) => `-${v.toLowerCase()}`,
243
- );
454
+ const key = styleName.replace(reg, function (v) {
455
+ return '-' + v.toLowerCase()
456
+ });
244
457
  acc += `${key}: ${style[styleName]};`;
245
458
  return acc
246
459
  }, '');
247
460
  };
248
461
 
249
- /**
250
- * Handles updating the className or ryunix-class properties, ensuring
251
- * that the old class names are removed and the new ones are applied.
252
- *
253
- * @param dom - The DOM element to be updated.
254
- * @param prevProps - The previous properties, including className.
255
- * @param nextProps - The new properties, including className.
256
- * @param name - The name of the class property (className or ryunix-class).
257
- */
258
- const handleClassName = (dom, prevProps, nextProps, name) => {
259
- const classProp = name === STRINGS.className ? 'ryunix-class' : 'className';
260
-
261
- if (nextProps[classProp] === '') {
262
- throw new Error(`${classProp} cannot be empty.`)
263
- }
264
-
265
- // Remove old class names if they exist
266
- prevProps[classProp] &&
267
- dom.classList.remove(...prevProps[classProp].split(/\s+/));
268
-
269
- // Add new class names
270
- dom.classList.add(...nextProps[classProp].split(/\s+/));
271
- };
272
-
273
462
  var Dom = /*#__PURE__*/Object.freeze({
274
463
  __proto__: null,
275
464
  DomStyle: DomStyle,
@@ -281,10 +470,8 @@
281
470
  * The function commits changes made to the virtual DOM to the actual DOM.
282
471
  */
283
472
  const commitRoot = () => {
284
- console.log('Committing root...');
285
473
  vars.deletions.forEach(commitWork);
286
474
  if (vars.wipRoot && vars.wipRoot.child) {
287
- console.log('Committing child...');
288
475
  commitWork(vars.wipRoot.child);
289
476
  vars.currentRoot = vars.wipRoot;
290
477
  }
@@ -292,107 +479,57 @@
292
479
  };
293
480
 
294
481
  /**
295
- * Helper function to find the DOM parent of a given fiber.
296
- * It walks up the fiber tree until it finds a parent with a DOM node.
297
- * @param {Object} fiber - The fiber node whose DOM parent needs to be found.
298
- * @returns {HTMLElement} The DOM node of the fiber's parent.
299
- */
300
- const findDomParent = (fiber) => {
301
- let domParentFiber = fiber.parent;
302
- // Walk up the tree until a DOM node is found or the root is reached
303
- while (domParentFiber && !domParentFiber.dom) {
304
- domParentFiber = domParentFiber.parent;
305
- }
306
- return domParentFiber ? domParentFiber.dom : null
307
- };
308
-
309
- /**
310
- * Safely removes a child DOM node from its parent, with error handling.
311
- * @param {HTMLElement} domParent - The parent DOM node.
312
- * @param {HTMLElement} childDom - The child DOM node to be removed.
313
- */
314
- const safeRemoveChild = (domParent, childDom) => {
315
- try {
316
- domParent.removeChild(childDom);
317
- } catch (error) {
318
- console.error('Error removing DOM child:', error);
319
- }
320
- };
321
-
322
- /**
323
- * The function handles the deletion of a fiber's corresponding DOM node.
324
- * It removes the fiber's DOM element or recursively removes its child.
325
- * @param {Object} fiber - The fiber node to be deleted.
326
- * @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.
327
487
  */
328
- const commitDeletion = (fiber, domParent) => {
329
- if (fiber && fiber.dom) {
330
- safeRemoveChild(domParent, fiber.dom);
331
- } else if (fiber && fiber.child) {
332
- commitDeletion(fiber.child, domParent);
488
+ const commitWork = (fiber) => {
489
+ if (!fiber) {
490
+ return
333
491
  }
334
- };
335
492
 
336
- /**
337
- * Cleans up the effects associated with a fiber node, specifically for
338
- * UPDATE and DELETION effect tags.
339
- * @param {Object} fiber - The fiber node whose effects need to be cleaned up.
340
- */
341
- const cleanupEffects = (fiber) => {
342
- if (
343
- fiber.effectTag === EFFECT_TAGS.UPDATE ||
344
- fiber.effectTag === EFFECT_TAGS.DELETION
345
- ) {
346
- cancelEffects(fiber);
493
+ let domParentFiber = fiber.parent;
494
+ while (!domParentFiber.dom) {
495
+ domParentFiber = domParentFiber.parent;
347
496
  }
348
- };
497
+ const domParent = domParentFiber.dom;
349
498
 
350
- /**
351
- * An object that maps effect tags to their corresponding handling functions.
352
- * Each function takes a fiber node and a DOM parent, and applies the necessary changes to the DOM.
353
- */
354
- const effectHandlers = {
355
- [EFFECT_TAGS.PLACEMENT]: (fiber, domParent) => {
499
+ if (fiber.effectTag === EFFECT_TAGS.PLACEMENT) {
356
500
  if (fiber.dom != undefined) {
357
501
  domParent.appendChild(fiber.dom);
358
- console.log('Appending child DOM node:', fiber.dom);
359
- } else {
360
- console.error('Failed to append DOM. Fiber has no DOM:', fiber);
361
502
  }
362
503
  runEffects(fiber);
363
- },
364
- [EFFECT_TAGS.UPDATE]: (fiber, domParent) => {
365
- cleanupEffects(fiber); // Cleanup effects before updating
504
+ } else if (fiber.effectTag === EFFECT_TAGS.UPDATE) {
505
+ cancelEffects(fiber);
366
506
  if (fiber.dom != undefined) {
367
507
  updateDom(fiber.dom, fiber.alternate.props, fiber.props);
368
508
  }
369
509
  runEffects(fiber);
370
- },
371
- [EFFECT_TAGS.DELETION]: (fiber, domParent) => {
372
- cleanupEffects(fiber);
510
+ } else if (fiber.effectTag === EFFECT_TAGS.DELETION) {
511
+ cancelEffects(fiber);
373
512
  commitDeletion(fiber, domParent);
374
- },
513
+ return
514
+ }
515
+
516
+ commitWork(fiber.child);
517
+ commitWork(fiber.sibling);
375
518
  };
376
519
 
377
520
  /**
378
- * The function commits changes made to the DOM based on the effect tag of the fiber.
379
- * It handles PLACEMENT, UPDATE, and DELETION of DOM nodes, and processes child and sibling fibers.
380
- * @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.
381
526
  */
382
- const commitWork = (fiber) => {
383
- if (!fiber) return
384
-
385
- const domParent = findDomParent(fiber);
386
- if (!domParent) return // If no parent DOM found, skip
387
-
388
- const effectHandler = effectHandlers[fiber.effectTag];
389
- if (effectHandler) {
390
- 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);
391
532
  }
392
-
393
- // Process child and sibling fibers recursively
394
- commitWork(fiber.child);
395
- commitWork(fiber.sibling);
396
533
  };
397
534
 
398
535
  var Commits = /*#__PURE__*/Object.freeze({
@@ -402,6 +539,20 @@
402
539
  commitWork: commitWork
403
540
  });
404
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
+
405
556
  /**
406
557
  * This function reconciles the children of a fiber node with a new set of elements, creating new
407
558
  * fibers for new elements, updating existing fibers for elements with the same type, and marking old
@@ -419,20 +570,20 @@
419
570
  while (index < elements.length || oldFiber != undefined) {
420
571
  const element = elements[index];
421
572
  let newFiber;
422
-
423
573
  const sameType = oldFiber && element && element.type == oldFiber.type;
424
574
 
425
575
  if (sameType) {
426
576
  newFiber = {
427
- type: oldFiber.type,
577
+ type: oldFiber ? oldFiber.type : undefined,
428
578
  props: element.props,
429
- dom: oldFiber.dom,
579
+ dom: oldFiber ? oldFiber.dom : undefined,
430
580
  parent: wipFiber,
431
581
  alternate: oldFiber,
432
- effectTag: EFFECT_TAGS.UPDATE,
582
+ effectTag: isPropsChanged(oldFiber.props, element.props)
583
+ ? EFFECT_TAGS.UPDATE
584
+ : null,
433
585
  };
434
- }
435
- if (element && !sameType) {
586
+ } else if (element) {
436
587
  newFiber = {
437
588
  type: element.type,
438
589
  props: element.props,
@@ -441,8 +592,7 @@
441
592
  alternate: undefined,
442
593
  effectTag: EFFECT_TAGS.PLACEMENT,
443
594
  };
444
- }
445
- if (!element && oldFiber) {
595
+ } else if (oldFiber) {
446
596
  oldFiber.effectTag = EFFECT_TAGS.DELETION;
447
597
  vars.deletions.push(oldFiber);
448
598
  }
@@ -468,34 +618,38 @@
468
618
  });
469
619
 
470
620
  /**
471
- * Updates a function component by setting up a work-in-progress fiber,
472
- * resetting the hook index, initializing an empty hooks array, rendering the component,
473
- * and reconciling its children.
474
- *
475
- * @param fiber - The fiber node representing the function component being updated. It contains
476
- * 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.
477
626
  */
478
627
  const updateFunctionComponent = (fiber) => {
479
- // Set the current work-in-progress fiber
480
- vars.workInProgressFiber = fiber;
628
+ vars.wipFiber = fiber;
481
629
  vars.hookIndex = 0;
482
- vars.workInProgressFiber.hooks = [];
483
-
630
+ vars.wipFiber.hooks = [];
484
631
  const children = fiber.type(fiber.props);
485
- 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);
486
641
  };
642
+
487
643
  /**
488
- * Updates a host component's DOM element and reconciles its children.
489
- * This function handles standard DOM elements like div, span, etc.
490
- *
491
- * @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.
492
648
  */
493
649
  const updateHostComponent = (fiber) => {
494
650
  if (!fiber.dom) {
495
651
  fiber.dom = createDom(fiber);
496
- console.log('DOM node created for host component:', fiber.dom);
497
652
  }
498
-
499
653
  reconcileChildren(fiber, fiber.props.children);
500
654
  };
501
655
 
@@ -506,13 +660,15 @@
506
660
  });
507
661
 
508
662
  /**
509
- * Main work loop that processes the fiber tree using requestIdleCallback.
510
- * It continues processing until all units of work are completed or the browser needs to yield.
511
- * @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
512
669
  */
513
670
  const workLoop = (deadline) => {
514
671
  let shouldYield = false;
515
-
516
672
  while (vars.nextUnitOfWork && !shouldYield) {
517
673
  vars.nextUnitOfWork = performUnitOfWork(vars.nextUnitOfWork);
518
674
  shouldYield = deadline.timeRemaining() < 1;
@@ -522,35 +678,43 @@
522
678
  commitRoot();
523
679
  }
524
680
 
525
- requestIdleCallback(workLoop);
681
+ if (vars.nextUnitOfWork) {
682
+ requestIdleCallback(workLoop, { timeout: 100 });
683
+ }
526
684
  };
527
685
 
528
- // Start the work loop for the first time
529
686
  requestIdleCallback(workLoop);
530
687
 
531
688
  /**
532
- * Processes a unit of work in the fiber tree.
533
- * Decides whether to update a function component or a host component (DOM element).
534
- * @param {Object} fiber - The current fiber representing a component and its state in the virtual DOM tree.
535
- * @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.
536
699
  */
537
700
  const performUnitOfWork = (fiber) => {
538
- console.log('Performing unit of work for fiber:', fiber);
539
-
540
701
  const isFunctionComponent = fiber.type instanceof Function;
541
702
  if (isFunctionComponent) {
542
703
  updateFunctionComponent(fiber);
543
704
  } else {
544
705
  updateHostComponent(fiber);
545
706
  }
546
-
547
- if (fiber.child) return fiber.child
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 });