@unsetsoft/ryunixjs 1.0.0-alpha.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/Ryunix.js CHANGED
@@ -1,186 +1,736 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Ryunix = {}));
5
- })(this, (function (exports) { 'use strict';
6
-
7
- /**
8
- * This function updates the properties and event listeners of a DOM element based on the previous and
9
- * next props passed as arguments.
10
- * @param dom - The DOM element that needs to be updated with new properties.
11
- * @param prevProps - An object representing the previous properties of a DOM element.
12
- * @param nextProps - An object containing the new props that need to be updated on the DOM element.
13
- */
14
- function updateDomProperties(dom, prevProps, nextProps) {
15
- const isEvent = name => name.startsWith("on");
16
- const isAttribute = name => !isEvent(name) && name != "children";
17
- Object.keys(prevProps).filter(isEvent).forEach(name => {
18
- const eventType = name.toLowerCase().substring(2);
19
- dom.removeEventListener(eventType, prevProps[name]);
20
- });
21
- Object.keys(prevProps).filter(isAttribute).forEach(name => {
22
- dom[name] = null;
23
- });
24
- Object.keys(nextProps).filter(isAttribute).forEach(name => {
25
- dom[name] = nextProps[name];
26
- });
27
- Object.keys(nextProps).filter(isEvent).forEach(name => {
28
- const eventType = name.toLowerCase().substring(2);
29
- dom.addEventListener(eventType, nextProps[name]);
30
- });
31
- }
32
-
33
- const TEXT_ELEMENT = "TEXT";
34
-
35
- /**
36
- * This function creates a new element with the given type, configuration object, and children.
37
- * @param type - The type of the element being created (e.g. "div", "span", "h1", etc.).
38
- * @param configObject - The `configObject` parameter is an object that contains the properties and
39
- * values for the element's attributes. These attributes can include things like `className`, `id`,
40
- * `style`, and any other custom attributes that the user wants to add to the element.
41
- * @param args - The `args` parameter is a rest parameter that allows the function to accept any number
42
- * of additional arguments after the `configObject` parameter. These additional arguments are used as
43
- * children elements for the created element.
44
- * @returns An object with two properties: "type" and "props".
45
- */
46
- function createElement(type, configObject, ...args) {
47
- const props = Object.assign({}, configObject);
48
- const hasChildren = args.length > 0;
49
- const nodeChildren = hasChildren ? [...args] : [];
50
- props.children = nodeChildren.filter(Boolean).map(c => c instanceof Object ? c : createTextElement(c));
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('lodash')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'lodash'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Ryunix = {}, global.lodash));
5
+ })(this, (function (exports, lodash) { 'use strict';
6
+
7
+ const vars = {
8
+ containerRoot: undefined,
9
+ nextUnitOfWork: undefined,
10
+ currentRoot: undefined,
11
+ wipRoot: undefined,
12
+ deletions: undefined,
13
+ wipFiber: undefined,
14
+ hookIndex: undefined,
15
+ };
16
+
17
+ const reg = /[A-Z]/g;
18
+
19
+ const RYUNIX_TYPES = Object.freeze({
20
+ TEXT_ELEMENT: Symbol('text.element'),
21
+ RYUNIX_EFFECT: Symbol('ryunix.effect'),
22
+ RYUNIX_MEMO: Symbol('ryunix.memo'),
23
+ RYUNIX_URL_QUERY: Symbol('ryunix.urlQuery'),
24
+ RYUNIX_REF: Symbol('ryunix.ref'),
25
+ });
26
+
27
+ const STRINGS = Object.freeze({
28
+ object: 'object',
29
+ function: 'function',
30
+ style: 'ryunix-style',
31
+ className: 'ryunix-class',
32
+ children: 'children',
33
+ boolean: 'boolean',
34
+ });
35
+
36
+ const OLD_STRINGS = Object.freeze({
37
+ style: 'style',
38
+ className: 'className',
39
+ });
40
+
41
+ const EFFECT_TAGS = Object.freeze({
42
+ PLACEMENT: Symbol(),
43
+ UPDATE: Symbol(),
44
+ DELETION: Symbol(),
45
+ });
46
+
47
+ const Fragment = (props) => {
48
+ return props.children
49
+ };
50
+
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
+ });
57
+ } else {
58
+ out.push(children);
59
+ }
60
+ return out
61
+ };
62
+
63
+ /**
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
78
+ */
79
+
80
+ const createElement = (type, props, ...children) => {
81
+ children = childArray(children, []);
51
82
  return {
52
83
  type,
53
- props
84
+ props: {
85
+ ...props,
86
+ children: children.map((child) =>
87
+ typeof child === STRINGS.object ? child : createTextElement(child),
88
+ ),
89
+ },
90
+ }
91
+ };
92
+
93
+ /**
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.
98
+ */
99
+
100
+ const createTextElement = (text) => {
101
+ return {
102
+ type: RYUNIX_TYPES.TEXT_ELEMENT,
103
+ props: {
104
+ nodeValue: text,
105
+ children: [],
106
+ },
107
+ }
108
+ };
109
+
110
+ /**
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().
116
+ */
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
+ };
128
+
129
+ /**
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.
134
+ */
135
+ const init = (root) => {
136
+ const rootElement = root || '__ryunix';
137
+ vars.containerRoot = document.getElementById(rootElement);
138
+ return undefined
139
+ };
140
+
141
+ /**
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.
146
+ */
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: [],
54
155
  };
55
- }
56
-
57
- /**
58
- * The function creates a text element with a given node value and an empty array of children.
59
- * @param nodeValue - The value of the text node that will be created.
60
- * @returns The function `createTextElement` is returning an element object with a `nodeValue` property
61
- * and an empty `children` array. This element object represents a text node in the virtual DOM.
62
- */
63
- function createTextElement(nodeValue) {
64
- return createElement(TEXT_ELEMENT, {
65
- nodeValue,
66
- children: []
156
+
157
+ const actions = oldHook ? oldHook.queue : [];
158
+ actions.forEach((action) => {
159
+ hook.state =
160
+ typeof action === STRINGS.function ? action(hook.state) : action;
67
161
  });
68
- }
69
-
70
- let rootInstance = null;
71
- function render(element, parentDom) {
72
- const prevInstance = rootInstance;
73
- const nextInstance = reconcile(parentDom, prevInstance, element);
74
- rootInstance = nextInstance;
75
- }
76
- function reconcile(parentDom, instance, element) {
77
- if (instance === null) {
78
- const newInstance = instantiate(element);
79
- parentDom.appendChild(newInstance.dom);
80
- return newInstance;
81
- } else if (element == null) {
82
- parentDom.removeChild(instance.dom);
83
- return null;
84
- } else if (instance.element.type !== element.type) {
85
- const newInstance = instantiate(element);
86
- parentDom.replaceChild(newInstance.dom, instance.dom);
87
- return newInstance;
88
- } else if (typeof element.type === "string") {
89
- instance.childInstances = reconcileChildren(instance, element);
90
- instance.element = element;
91
- return instance;
92
- } else {
93
- instance.publicInstance.props = element.props;
94
- const childElement = instance.publicInstance.render();
95
- const oldChildInstance = instance.childInstance;
96
- const childInstance = reconcile(parentDom, oldChildInstance, childElement);
97
- instance.dom = childInstance.dom;
98
- instance.childInstance = childInstance;
99
- instance.element = element;
100
- return instance;
101
- }
102
- }
103
- function instantiate(element) {
104
- const { type, props } = element;
105
- const isDomElement = typeof type === "string";
106
- if (isDomElement) {
107
- const isTextElement = type === TEXT_ELEMENT;
108
- const dom = isTextElement
109
- ? document.createTextNode("")
110
- : document.createElement(type);
111
- updateDomProperties(dom, [], props);
112
- const childElements = props.children || [];
113
- const childInstances = childElements.map(instantiate);
114
- const childDoms = childInstances.map((childInstance) => childInstance.dom);
115
- childDoms.forEach((childDom) => dom.appendChild(childDom));
116
- const instance = {
117
- dom,
118
- element,
119
- childInstances,
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,
120
176
  };
121
- return instance;
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();
122
212
  } else {
123
- const instance = {};
124
- const publicInstance = createPublicInstance(element, instance);
125
- const childElement = publicInstance.render();
126
- const childInstance = instantiate(childElement);
127
- const dom = childInstance.dom;
128
- Object.assign(instance, {
129
- dom,
130
- element,
131
- childInstance,
132
- publicInstance,
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
+ /**
225
+ * The `useQuery` function is a custom hook in JavaScript that retrieves query parameters from the URL
226
+ * and stores them in a hook for easy access.
227
+ * @returns The `useQuery` function returns the `query` property of the `hook` object.
228
+ */
229
+ const useQuery = () => {
230
+ const oldHook =
231
+ vars.wipFiber.alternate &&
232
+ vars.wipFiber.alternate.hooks &&
233
+ vars.wipFiber.alternate.hooks[vars.hookIndex];
234
+
235
+ const hasOld = oldHook ? oldHook : undefined;
236
+
237
+ const urlSearchParams = new URLSearchParams(window.location.search);
238
+ const params = Object.fromEntries(urlSearchParams.entries());
239
+ const Query = hasOld ? hasOld : params;
240
+
241
+ const hook = {
242
+ type: RYUNIX_TYPES.RYUNIX_URL_QUERY,
243
+ query: Query,
244
+ };
245
+
246
+ if (vars.wipFiber.hooks) {
247
+ vars.wipFiber.hooks.push(hook);
248
+ vars.hookIndex++;
249
+ }
250
+
251
+ return hook.query
252
+ };
253
+
254
+ const useRef = (initial) => {
255
+ const oldHook =
256
+ vars.wipFiber.alternate &&
257
+ vars.wipFiber.alternate.hooks &&
258
+ vars.wipFiber.alternate.hooks[vars.hookIndex];
259
+
260
+ const hook = {
261
+ type: RYUNIX_TYPES.RYUNIX_REF,
262
+ value: oldHook ? oldHook.value : { current: initial },
263
+ };
264
+
265
+ if (vars.wipFiber.hooks) {
266
+ vars.wipFiber.hooks.push(hook);
267
+ vars.hookIndex++;
268
+ }
269
+
270
+ return hook.value
271
+ };
272
+
273
+ const useMemo = (comp, deps) => {
274
+ const oldHook =
275
+ vars.wipFiber.alternate &&
276
+ vars.wipFiber.alternate.hooks &&
277
+ vars.wipFiber.alternate.hooks[vars.hookIndex];
278
+
279
+ const hook = {
280
+ type: RYUNIX_TYPES.RYUNIX_MEMO,
281
+ value: null,
282
+ deps,
283
+ };
284
+
285
+ if (oldHook) {
286
+ if (lodash.isEqual(oldHook.deps, hook.deps)) {
287
+ hook.value = oldHook.value;
288
+ } else {
289
+ hook.value = comp();
290
+ }
291
+ } else {
292
+ hook.value = comp();
293
+ }
294
+
295
+ if (vars.wipFiber.hooks) {
296
+ vars.wipFiber.hooks.push(hook);
297
+ vars.hookIndex++;
298
+ }
299
+
300
+ return hook.value
301
+ };
302
+ const useCallback = (callback, deps) => {
303
+ return useMemo(() => callback, deps)
304
+ };
305
+
306
+ const useRouter = (routes) => {
307
+ const [location, setLocation] = useStore(window.location.pathname);
308
+
309
+ const navigate = (path) => {
310
+ window.history.pushState({}, '', path);
311
+ setLocation(path);
312
+ };
313
+
314
+ useEffect(() => {
315
+ const onPopState = () => {
316
+ setLocation(window.location.pathname);
317
+ };
318
+
319
+ window.addEventListener('popstate', onPopState);
320
+ return () => {
321
+ window.removeEventListener('popstate', onPopState);
322
+ }
323
+ }, []);
324
+
325
+ const currentRoute = routes.find((route) => route.path === location);
326
+ const Children = () => (currentRoute ? currentRoute.component : null);
327
+
328
+ return { Children, navigate }
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];
334
+ const isGone = (next) => (key) => !(key in next);
335
+
336
+ /**
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
342
+ */
343
+ const cancelEffects = (fiber) => {
344
+ if (fiber.hooks) {
345
+ fiber.hooks
346
+ .filter((hook) => hook.tag === RYUNIX_TYPES.RYUNIX_EFFECT && hook.cancel)
347
+ .forEach((effectHook) => {
348
+ effectHook.cancel();
349
+ });
350
+ }
351
+ };
352
+
353
+ /**
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
359
+ */
360
+ const runEffects = (fiber) => {
361
+ if (fiber.hooks) {
362
+ fiber.hooks
363
+ .filter((hook) => hook.tag === RYUNIX_TYPES.RYUNIX_EFFECT && hook.effect)
364
+ .forEach((effectHook) => {
365
+ effectHook.cancel = effectHook.effect();
366
+ });
367
+ }
368
+ };
369
+
370
+ /**
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
379
+ */
380
+ const createDom = (fiber) => {
381
+ const dom =
382
+ fiber.type == RYUNIX_TYPES.TEXT_ELEMENT
383
+ ? document.createTextNode('')
384
+ : document.createElement(fiber.type);
385
+
386
+ updateDom(dom, {}, fiber.props);
387
+
388
+ return dom
389
+ };
390
+
391
+ /**
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.
397
+ */
398
+ const updateDom = (dom, prevProps, nextProps) => {
399
+ Object.keys(prevProps)
400
+ .filter(isEvent)
401
+ .filter((key) => isGone(nextProps)(key) || isNew(prevProps, nextProps)(key))
402
+ .forEach((name) => {
403
+ const eventType = name.toLowerCase().substring(2);
404
+ dom.removeEventListener(eventType, prevProps[name]);
133
405
  });
134
- return instance;
135
- }
136
- }
137
- function createPublicInstance(element, internalInstance) {
138
- const { type, props } = element;
139
- const publicInstance = new type(props);
140
- publicInstance.__internalInstance = internalInstance;
141
- return publicInstance;
142
- }
143
- function reconcileChildren(instance, element) {
144
- const dom = instance.dom;
145
- const childInstances = instance.childInstances;
146
- const nextChildElements = element.props.children || [];
147
- const newChildInstances = [];
148
- const count = Math.max(childInstances.length, nextChildElements.length);
149
- for (let i = 0; i < count; i++) {
150
- const childInstance = childInstances[i];
151
- const childElement = nextChildElements[i];
152
- const newChildInstance = reconcile(dom, childInstance, childElement);
153
- newChildInstances.push(newChildInstance);
154
- }
155
- return newChildInstances.filter((instance) => instance != null);
156
- }
157
-
158
- class Component {
159
- constructor(props) {
160
- this.props = props;
161
- this.state = this.state || {};
162
- }
163
- setState(partialState) {
164
- this.state = Object.assign({}, this.state, partialState);
165
- updateInstance(this.__internalInstance);
166
- }
167
- }
168
- function updateInstance(internalInstance) {
169
- const parentDom = internalInstance.dom.parentNode;
170
- const element = internalInstance.element;
171
- reconcile(parentDom, internalInstance, element);
172
- }
173
-
174
- var ryunix = {
175
- render,
406
+
407
+ Object.keys(prevProps)
408
+ .filter(isProperty)
409
+ .filter(isGone(nextProps))
410
+ .forEach((name) => {
411
+ dom[name] = '';
412
+ });
413
+
414
+ Object.keys(nextProps)
415
+ .filter(isProperty)
416
+ .filter(isNew(prevProps, nextProps))
417
+ .forEach((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+/));
438
+ } else {
439
+ dom[name] = nextProps[name];
440
+ }
441
+ });
442
+
443
+ Object.keys(nextProps)
444
+ .filter(isEvent)
445
+ .filter(isNew(prevProps, nextProps))
446
+ .forEach((name) => {
447
+ const eventType = name.toLowerCase().substring(2);
448
+ dom.addEventListener(eventType, nextProps[name]);
449
+ });
450
+ };
451
+
452
+ const DomStyle = (dom, style) => {
453
+ dom.style = Object.keys(style).reduce((acc, styleName) => {
454
+ const key = styleName.replace(reg, function (v) {
455
+ return '-' + v.toLowerCase()
456
+ });
457
+ acc += `${key}: ${style[styleName]};`;
458
+ return acc
459
+ }, '');
460
+ };
461
+
462
+ var Dom = /*#__PURE__*/Object.freeze({
463
+ __proto__: null,
464
+ DomStyle: DomStyle,
465
+ createDom: createDom,
466
+ updateDom: updateDom
467
+ });
468
+
469
+ /**
470
+ * The function commits changes made to the virtual DOM to the actual DOM.
471
+ */
472
+ const commitRoot = () => {
473
+ vars.deletions.forEach(commitWork);
474
+ if (vars.wipRoot && vars.wipRoot.child) {
475
+ commitWork(vars.wipRoot.child);
476
+ vars.currentRoot = vars.wipRoot;
477
+ }
478
+ vars.wipRoot = undefined;
479
+ };
480
+
481
+ /**
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.
487
+ */
488
+ const commitWork = (fiber) => {
489
+ if (!fiber) {
490
+ return
491
+ }
492
+
493
+ let domParentFiber = fiber.parent;
494
+ while (!domParentFiber.dom) {
495
+ domParentFiber = domParentFiber.parent;
496
+ }
497
+ const domParent = domParentFiber.dom;
498
+
499
+ if (fiber.effectTag === EFFECT_TAGS.PLACEMENT) {
500
+ if (fiber.dom != undefined) {
501
+ domParent.appendChild(fiber.dom);
502
+ }
503
+ runEffects(fiber);
504
+ } else if (fiber.effectTag === EFFECT_TAGS.UPDATE) {
505
+ cancelEffects(fiber);
506
+ if (fiber.dom != undefined) {
507
+ updateDom(fiber.dom, fiber.alternate.props, fiber.props);
508
+ }
509
+ runEffects(fiber);
510
+ } else if (fiber.effectTag === EFFECT_TAGS.DELETION) {
511
+ cancelEffects(fiber);
512
+ commitDeletion(fiber, domParent);
513
+ return
514
+ }
515
+
516
+ commitWork(fiber.child);
517
+ commitWork(fiber.sibling);
518
+ };
519
+
520
+ /**
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.
526
+ */
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);
532
+ }
533
+ };
534
+
535
+ var Commits = /*#__PURE__*/Object.freeze({
536
+ __proto__: null,
537
+ commitDeletion: commitDeletion,
538
+ commitRoot: commitRoot,
539
+ commitWork: commitWork
540
+ });
541
+
542
+ /**
543
+ * This function reconciles the children of a fiber node with a new set of elements, creating new
544
+ * fibers for new elements, updating existing fibers for elements with the same type, and marking old
545
+ * fibers for deletion if they are not present in the new set of elements.
546
+ * @param wipFiber - A work-in-progress fiber object representing a component or element in the virtual
547
+ * DOM tree.
548
+ * @param elements - an array of elements representing the new children to be rendered in the current
549
+ * fiber's subtree
550
+ */
551
+ const reconcileChildren = (wipFiber, elements) => {
552
+ let index = 0;
553
+ let oldFiber = wipFiber.alternate && wipFiber.alternate.child;
554
+ let prevSibling;
555
+
556
+ while (index < elements.length || oldFiber != undefined) {
557
+ const element = elements[index];
558
+ let newFiber;
559
+
560
+ const sameType = oldFiber && element && element.type == oldFiber.type;
561
+
562
+ if (sameType) {
563
+ newFiber = {
564
+ type: oldFiber ? oldFiber.type : undefined,
565
+ props: element.props,
566
+ dom: oldFiber ? oldFiber.dom : undefined,
567
+ parent: wipFiber,
568
+ alternate: oldFiber,
569
+ effectTag: EFFECT_TAGS.UPDATE,
570
+ };
571
+ }
572
+ if (element && !sameType) {
573
+ newFiber = {
574
+ type: element.type,
575
+ props: element.props,
576
+ dom: undefined,
577
+ parent: wipFiber,
578
+ alternate: undefined,
579
+ effectTag: EFFECT_TAGS.PLACEMENT,
580
+ };
581
+ }
582
+ if (oldFiber && !sameType) {
583
+ oldFiber.effectTag = EFFECT_TAGS.DELETION;
584
+ vars.deletions.push(oldFiber);
585
+ }
586
+
587
+ if (oldFiber) {
588
+ oldFiber = oldFiber.sibling;
589
+ }
590
+
591
+ if (index === 0) {
592
+ wipFiber.child = newFiber;
593
+ } else if (element && prevSibling) {
594
+ prevSibling.sibling = newFiber;
595
+ }
596
+
597
+ prevSibling = newFiber;
598
+ index++;
599
+ }
600
+ };
601
+
602
+ var Reconciler = /*#__PURE__*/Object.freeze({
603
+ __proto__: null,
604
+ reconcileChildren: reconcileChildren
605
+ });
606
+
607
+ /**
608
+ * This function updates a function component by setting up a work-in-progress fiber, resetting the
609
+ * hook index, creating an empty hooks array, rendering the component, and reconciling its children.
610
+ * @param fiber - The fiber parameter is an object that represents a node in the fiber tree. It
611
+ * contains information about the component, its props, state, and children. In this function, it is
612
+ * used to update the state of the component and its children.
613
+ */
614
+ const updateFunctionComponent = (fiber) => {
615
+ vars.wipFiber = fiber;
616
+ vars.hookIndex = 0;
617
+ vars.wipFiber.hooks = [];
618
+ const children = fiber.type(fiber.props);
619
+ let childArr = [];
620
+ if (Array.isArray(children)) {
621
+ // Fragment results returns array
622
+ childArr = [...children];
623
+ } else {
624
+ // Normal function component returns single root node
625
+ childArr = [children];
626
+ }
627
+ reconcileChildren(fiber, childArr);
628
+ };
629
+
630
+ /**
631
+ * This function updates a host component's DOM element and reconciles its children.
632
+ * @param fiber - A fiber is a unit of work in Ryunix that represents a component and its state. It
633
+ * contains information about the component's type, props, and children, as well as pointers to other
634
+ * fibers in the tree.
635
+ */
636
+ const updateHostComponent = (fiber) => {
637
+ if (!fiber.dom) {
638
+ fiber.dom = createDom(fiber);
639
+ }
640
+ reconcileChildren(fiber, fiber.props.children);
641
+ };
642
+
643
+ var Components = /*#__PURE__*/Object.freeze({
644
+ __proto__: null,
645
+ updateFunctionComponent: updateFunctionComponent,
646
+ updateHostComponent: updateHostComponent
647
+ });
648
+
649
+ /**
650
+ * This function uses requestIdleCallback to perform work on a fiber tree until it is complete or the
651
+ * browser needs to yield to other tasks.
652
+ * @param deadline - The `deadline` parameter is an object that represents the amount of time the
653
+ * browser has to perform work before it needs to handle other tasks. It has a `timeRemaining()` method
654
+ * that returns the amount of time remaining before the deadline is reached. The `shouldYield` variable
655
+ * is used to determine
656
+ */
657
+ const workLoop = (deadline) => {
658
+ let shouldYield = false;
659
+ while (vars.nextUnitOfWork && !shouldYield) {
660
+ vars.nextUnitOfWork = performUnitOfWork(vars.nextUnitOfWork);
661
+ shouldYield = deadline.timeRemaining() < 1;
662
+ }
663
+
664
+ if (!vars.nextUnitOfWork && vars.wipRoot) {
665
+ commitRoot();
666
+ }
667
+
668
+ requestIdleCallback(workLoop);
669
+ };
670
+
671
+ requestIdleCallback(workLoop);
672
+
673
+ /**
674
+ * The function performs a unit of work by updating either a function component or a host component and
675
+ * returns the next fiber to be processed.
676
+ * @param fiber - A fiber is a unit of work in Ryunix that represents a component and its state. It
677
+ * contains information about the component's type, props, and children, as well as pointers to its
678
+ * parent, child, and sibling fibers. The `performUnitOfWork` function takes a fiber as a parameter and
679
+ * performs work
680
+ * @returns The function `performUnitOfWork` returns the next fiber to be processed. If the current
681
+ * fiber has a child, it returns the child. Otherwise, it looks for the next sibling of the current
682
+ * fiber. If there are no more siblings, it goes up the tree to the parent and looks for the next
683
+ * sibling of the parent. The function returns `undefined` if there are no more fibers to process.
684
+ */
685
+ const performUnitOfWork = (fiber) => {
686
+ const isFunctionComponent = fiber.type instanceof Function;
687
+ if (isFunctionComponent) {
688
+ updateFunctionComponent(fiber);
689
+ } else {
690
+ updateHostComponent(fiber);
691
+ }
692
+ if (fiber.child) {
693
+ return fiber.child
694
+ }
695
+ let nextFiber = fiber;
696
+ while (nextFiber) {
697
+ if (nextFiber.sibling) {
698
+ return nextFiber.sibling
699
+ }
700
+ nextFiber = nextFiber.parent;
701
+ }
702
+ return undefined
703
+ };
704
+
705
+ var Workers = /*#__PURE__*/Object.freeze({
706
+ __proto__: null,
707
+ performUnitOfWork: performUnitOfWork,
708
+ workLoop: workLoop
709
+ });
710
+
711
+ var Ryunix = {
176
712
  createElement,
177
- Component,
713
+ render,
714
+ init,
715
+ Fragment,
716
+ Dom,
717
+ Workers,
718
+ Reconciler,
719
+ Components,
720
+ Commits,
178
721
  };
179
722
 
180
- exports.Component = Component;
181
- exports.createElement = createElement;
182
- exports.default = ryunix;
183
- exports.render = render;
723
+ window.Ryunix = Ryunix;
724
+
725
+ exports.Fragment = Fragment;
726
+ exports.default = Ryunix;
727
+ exports.useCallback = useCallback;
728
+ exports.useEffect = useEffect;
729
+ exports.useMemo = useMemo;
730
+ exports.useQuery = useQuery;
731
+ exports.useRef = useRef;
732
+ exports.useRouter = useRouter;
733
+ exports.useStore = useStore;
184
734
 
185
735
  Object.defineProperty(exports, '__esModule', { value: true });
186
736