@unsetsoft/ryunixjs 0.2.29-nightly.0 → 0.2.29

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
@@ -14,6 +14,8 @@
14
14
  hookIndex: null,
15
15
  };
16
16
 
17
+ const reg = /[A-Z]/g;
18
+
17
19
  const RYUNIX_TYPES = Object.freeze({
18
20
  TEXT_ELEMENT: Symbol("text.element"),
19
21
  RYUNIX_EFFECT: Symbol("ryunix.effect"),
@@ -28,6 +30,12 @@
28
30
  children: "children",
29
31
  });
30
32
 
33
+ const EFFECT_TAGS = Object.freeze({
34
+ PLACEMENT: Symbol(),
35
+ UPDATE: Symbol(),
36
+ DELETION: Symbol(),
37
+ });
38
+
31
39
  /**
32
40
  * The function creates a new element with the given type, props, and children.
33
41
  * @param type - The type of the element to be created, such as "div", "span", "h1", etc.
@@ -115,12 +123,50 @@
115
123
  vars.containerRoot = document.getElementById(root);
116
124
  };
117
125
 
126
+ const isEvent = (key) => key.startsWith("on");
127
+ const isProperty = (key) => key !== STRINGS.children && !isEvent(key);
128
+ const isNew = (prev, next) => (key) => prev[key] !== next[key];
129
+ const isGone = (next) => (key) => !(key in next);
118
130
  const hasDepsChanged = (prevDeps, nextDeps) =>
119
131
  !prevDeps ||
120
132
  !nextDeps ||
121
133
  prevDeps.length !== nextDeps.length ||
122
134
  prevDeps.some((dep, index) => dep !== nextDeps[index]);
123
135
 
136
+ /**
137
+ * The function cancels all effect hooks in a given fiber.
138
+ * @param fiber - The "fiber" parameter is likely referring to a data structure used in React.js to
139
+ * represent a component and its state. It contains information about the component's props, state, and
140
+ * children, as well as metadata used by React to manage updates and rendering. The function
141
+ * "cancelEffects" is likely intended
142
+ */
143
+ const cancelEffects = (fiber) => {
144
+ if (fiber.hooks) {
145
+ fiber.hooks
146
+ .filter((hook) => hook.tag === RYUNIX_TYPES.RYUNIX_EFFECT && hook.cancel)
147
+ .forEach((effectHook) => {
148
+ effectHook.cancel();
149
+ });
150
+ }
151
+ };
152
+
153
+ /**
154
+ * The function runs all effect hooks in a given fiber.
155
+ * @param fiber - The "fiber" parameter is likely referring to a data structure used in the
156
+ * implementation of a fiber-based reconciliation algorithm, such as the one used in React. A fiber
157
+ * represents a unit of work that needs to be performed by the reconciliation algorithm, and it
158
+ * contains information about a component and its children, as
159
+ */
160
+ const runEffects = (fiber) => {
161
+ if (fiber.hooks) {
162
+ fiber.hooks
163
+ .filter((hook) => hook.tag === RYUNIX_TYPES.RYUNIX_EFFECT && hook.effect)
164
+ .forEach((effectHook) => {
165
+ effectHook.cancel = effectHook.effect();
166
+ });
167
+ }
168
+ };
169
+
124
170
  /**
125
171
  * The function `useContext` is used to read and subscribe to context from your component.
126
172
  * @param ref - The `ref` parameter is a reference to a context object.
@@ -239,12 +285,335 @@
239
285
  return context;
240
286
  };
241
287
 
288
+ /**
289
+ * The function creates a new DOM element based on the given fiber object and updates its properties.
290
+ * @param fiber - The fiber parameter is an object that represents a node in the fiber tree. It
291
+ * contains information about the element type, props, and children of the node.
292
+ * @returns The `createDom` function returns a newly created DOM element based on the `fiber` object
293
+ * passed as an argument. If the `fiber` object represents a text element, a text node is created using
294
+ * `document.createTextNode("")`. Otherwise, a new element is created using
295
+ * `document.createElement(fiber.type)`. The function then calls the `updateDom` function to update the
296
+ * properties of the newly created
297
+ */
298
+ const createDom = (fiber) => {
299
+ const dom =
300
+ fiber.type == RYUNIX_TYPES.TEXT_ELEMENT
301
+ ? document.createTextNode("")
302
+ : document.createElement(fiber.type);
303
+
304
+ updateDom(dom, {}, fiber.props);
305
+
306
+ return dom;
307
+ };
308
+
309
+ /**
310
+ * The function updates the DOM by removing old event listeners and properties, and adding new ones
311
+ * based on the previous and next props.
312
+ * @param dom - The DOM element that needs to be updated with new props.
313
+ * @param prevProps - An object representing the previous props (properties) of a DOM element.
314
+ * @param nextProps - An object containing the new props that need to be updated in the DOM.
315
+ */
316
+ const updateDom = (dom, prevProps, nextProps) => {
317
+ Object.keys(prevProps)
318
+ .filter(isEvent)
319
+ .filter((key) => isGone(nextProps)(key) || isNew(prevProps, nextProps)(key))
320
+ .forEach((name) => {
321
+ const eventType = name.toLowerCase().substring(2);
322
+ dom.removeEventListener(eventType, prevProps[name]);
323
+ });
324
+
325
+ Object.keys(prevProps)
326
+ .filter(isProperty)
327
+ .filter(isGone(nextProps))
328
+ .forEach((name) => {
329
+ dom[name] = "";
330
+ });
331
+
332
+ Object.keys(nextProps)
333
+ .filter(isProperty)
334
+ .filter(isNew(prevProps, nextProps))
335
+ .forEach((name) => {
336
+ if (name === STRINGS.style) {
337
+ DomStyle(dom, nextProps.style);
338
+ } else if (name === STRINGS.className) {
339
+ if (nextProps.className === "") {
340
+ throw new Error("className cannot be empty.");
341
+ }
342
+ prevProps.className &&
343
+ dom.classList.remove(...prevProps.className.split(/\s+/));
344
+ dom.classList.add(...nextProps.className.split(/\s+/));
345
+ } else {
346
+ dom[name] = nextProps[name];
347
+ }
348
+ });
349
+
350
+ Object.keys(nextProps)
351
+ .filter(isEvent)
352
+ .filter(isNew(prevProps, nextProps))
353
+ .forEach((name) => {
354
+ const eventType = name.toLowerCase().substring(2);
355
+ dom.addEventListener(eventType, nextProps[name]);
356
+ });
357
+ };
358
+
359
+ const DomStyle = (dom, style) => {
360
+ dom.style = Object.keys(style).reduce((acc, styleName) => {
361
+ const key = styleName.replace(reg, function (v) {
362
+ return "-" + v.toLowerCase();
363
+ });
364
+ acc += `${key}: ${style[styleName]};`;
365
+ return acc;
366
+ }, "");
367
+ };
368
+
369
+ var Dom = /*#__PURE__*/Object.freeze({
370
+ __proto__: null,
371
+ DomStyle: DomStyle,
372
+ createDom: createDom,
373
+ updateDom: updateDom
374
+ });
375
+
376
+ /**
377
+ * The function commits changes made to the virtual DOM to the actual DOM.
378
+ */
379
+ const commitRoot = () => {
380
+ vars.deletions.forEach(commitWork);
381
+ commitWork(vars.wipRoot.child);
382
+ vars.currentRoot = vars.wipRoot;
383
+ vars.wipRoot = null;
384
+ };
385
+
386
+ /**
387
+ * The function commits changes made to the DOM based on the effect tag of the fiber.
388
+ * @param fiber - A fiber is a unit of work in Ryunix's reconciliation process. It represents a
389
+ * component and its state at a particular point in time. The `commitWork` function takes a fiber as a
390
+ * parameter to commit the changes made during the reconciliation process to the actual DOM.
391
+ * @returns The function does not return anything, it performs side effects by manipulating the DOM.
392
+ */
393
+ const commitWork = (fiber) => {
394
+ if (!fiber) {
395
+ return;
396
+ }
397
+
398
+ let domParentFiber = fiber.parent;
399
+ while (!domParentFiber.dom) {
400
+ domParentFiber = domParentFiber.parent;
401
+ }
402
+ const domParent = domParentFiber.dom;
403
+
404
+ if (fiber.effectTag === EFFECT_TAGS.PLACEMENT) {
405
+ if (fiber.dom != null) {
406
+ domParent.appendChild(fiber.dom);
407
+ }
408
+ runEffects(fiber);
409
+ } else if (fiber.effectTag === EFFECT_TAGS.UPDATE) {
410
+ cancelEffects(fiber);
411
+ if (fiber.dom != null) {
412
+ updateDom(fiber.dom, fiber.alternate.props, fiber.props);
413
+ }
414
+ runEffects(fiber);
415
+ } else if (fiber.effectTag === EFFECT_TAGS.DELETION) {
416
+ cancelEffects(fiber);
417
+ commitDeletion(fiber, domParent);
418
+ return;
419
+ }
420
+
421
+ commitWork(fiber.child);
422
+ commitWork(fiber.sibling);
423
+ };
424
+
425
+ /**
426
+ * The function removes a fiber's corresponding DOM node from its parent node or recursively removes
427
+ * its child's DOM node until it finds a node to remove.
428
+ * @param fiber - a fiber node in a fiber tree, which represents a component or an element in the Ryunix
429
+ * application.
430
+ * @param domParent - The parent DOM element from which the fiber's DOM element needs to be removed.
431
+ */
432
+ const commitDeletion = (fiber, domParent) => {
433
+ if (fiber.dom) {
434
+ domParent.removeChild(fiber.dom);
435
+ } else {
436
+ commitDeletion(fiber.child, domParent);
437
+ }
438
+ };
439
+
440
+ var Commits = /*#__PURE__*/Object.freeze({
441
+ __proto__: null,
442
+ commitDeletion: commitDeletion,
443
+ commitRoot: commitRoot,
444
+ commitWork: commitWork
445
+ });
446
+
447
+ /**
448
+ * This function reconciles the children of a fiber node with a new set of elements, creating new
449
+ * fibers for new elements, updating existing fibers for elements with the same type, and marking old
450
+ * fibers for deletion if they are not present in the new set of elements.
451
+ * @param wipFiber - A work-in-progress fiber object representing a component or element in the virtual
452
+ * DOM tree.
453
+ * @param elements - an array of elements representing the new children to be rendered in the current
454
+ * fiber's subtree
455
+ */
456
+ const reconcileChildren = (wipFiber, elements) => {
457
+ let index = 0;
458
+ let oldFiber = wipFiber.alternate && wipFiber.alternate.child;
459
+ let prevSibling;
460
+
461
+ while (index < elements.length || oldFiber != null) {
462
+ const element = elements[index];
463
+ let newFiber;
464
+
465
+ const sameType = oldFiber && element && element.type == oldFiber.type;
466
+
467
+ if (sameType) {
468
+ newFiber = {
469
+ type: oldFiber.type,
470
+ props: element.props,
471
+ dom: oldFiber.dom,
472
+ parent: wipFiber,
473
+ alternate: oldFiber,
474
+ effectTag: EFFECT_TAGS.UPDATE,
475
+ };
476
+ }
477
+ if (element && !sameType) {
478
+ newFiber = {
479
+ type: element.type,
480
+ props: element.props,
481
+ dom: null,
482
+ parent: wipFiber,
483
+ alternate: null,
484
+ effectTag: EFFECT_TAGS.PLACEMENT,
485
+ };
486
+ }
487
+ if (oldFiber && !sameType) {
488
+ oldFiber.effectTag = EFFECT_TAGS.DELETION;
489
+ vars.deletions.push(oldFiber);
490
+ }
491
+
492
+ if (oldFiber) {
493
+ oldFiber = oldFiber.sibling;
494
+ }
495
+
496
+ if (index === 0) {
497
+ wipFiber.child = newFiber;
498
+ } else if (element) {
499
+ prevSibling.sibling = newFiber;
500
+ }
501
+
502
+ prevSibling = newFiber;
503
+ index++;
504
+ }
505
+ };
506
+
507
+ var Reconciler = /*#__PURE__*/Object.freeze({
508
+ __proto__: null,
509
+ reconcileChildren: reconcileChildren
510
+ });
511
+
512
+ /**
513
+ * This function updates a function component by setting up a work-in-progress fiber, resetting the
514
+ * hook index, creating an empty hooks array, rendering the component, and reconciling its children.
515
+ * @param fiber - The fiber parameter is an object that represents a node in the fiber tree. It
516
+ * contains information about the component, its props, state, and children. In this function, it is
517
+ * used to update the state of the component and its children.
518
+ */
519
+ const updateFunctionComponent = (fiber) => {
520
+ vars.wipFiber = fiber;
521
+ vars.hookIndex = 0;
522
+ vars.wipFiber.hooks = [];
523
+ const children = [fiber.type(fiber.props)];
524
+ reconcileChildren(fiber, children);
525
+ };
526
+
527
+ /**
528
+ * This function updates a host component's DOM element and reconciles its children.
529
+ * @param fiber - A fiber is a unit of work in Ryunix that represents a component and its state. It
530
+ * contains information about the component's type, props, and children, as well as pointers to other
531
+ * fibers in the tree.
532
+ */
533
+ const updateHostComponent = (fiber) => {
534
+ if (!fiber.dom) {
535
+ fiber.dom = createDom(fiber);
536
+ }
537
+ reconcileChildren(fiber, fiber.props.children.flat());
538
+ };
539
+
540
+ var Components = /*#__PURE__*/Object.freeze({
541
+ __proto__: null,
542
+ updateFunctionComponent: updateFunctionComponent,
543
+ updateHostComponent: updateHostComponent
544
+ });
545
+
546
+ /**
547
+ * This function uses requestIdleCallback to perform work on a fiber tree until it is complete or the
548
+ * browser needs to yield to other tasks.
549
+ * @param deadline - The `deadline` parameter is an object that represents the amount of time the
550
+ * browser has to perform work before it needs to handle other tasks. It has a `timeRemaining()` method
551
+ * that returns the amount of time remaining before the deadline is reached. The `shouldYield` variable
552
+ * is used to determine
553
+ */
554
+ const workLoop = (deadline) => {
555
+ let shouldYield = false;
556
+ while (vars.nextUnitOfWork && !shouldYield) {
557
+ vars.nextUnitOfWork = performUnitOfWork(vars.nextUnitOfWork);
558
+ shouldYield = deadline.timeRemaining() < 1;
559
+ }
560
+
561
+ if (!vars.nextUnitOfWork && vars.wipRoot) {
562
+ commitRoot();
563
+ }
564
+
565
+ requestIdleCallback(workLoop);
566
+ };
567
+
568
+ requestIdleCallback(workLoop);
569
+
570
+ /**
571
+ * The function performs a unit of work by updating either a function component or a host component and
572
+ * returns the next fiber to be processed.
573
+ * @param fiber - A fiber is a unit of work in Ryunix that represents a component and its state. It
574
+ * contains information about the component's type, props, and children, as well as pointers to its
575
+ * parent, child, and sibling fibers. The `performUnitOfWork` function takes a fiber as a parameter and
576
+ * performs work
577
+ * @returns The function `performUnitOfWork` returns the next fiber to be processed. If the current
578
+ * fiber has a child, it returns the child. Otherwise, it looks for the next sibling of the current
579
+ * fiber. If there are no more siblings, it goes up the tree to the parent and looks for the next
580
+ * sibling of the parent. The function returns `null` if there are no more fibers to process.
581
+ */
582
+ const performUnitOfWork = (fiber) => {
583
+ const isFunctionComponent = fiber.type instanceof Function;
584
+ if (isFunctionComponent) {
585
+ updateFunctionComponent(fiber);
586
+ } else {
587
+ updateHostComponent(fiber);
588
+ }
589
+ if (fiber.child) {
590
+ return fiber.child;
591
+ }
592
+ let nextFiber = fiber;
593
+ while (nextFiber) {
594
+ if (nextFiber.sibling) {
595
+ return nextFiber.sibling;
596
+ }
597
+ nextFiber = nextFiber.parent;
598
+ }
599
+ };
600
+
601
+ var Workers = /*#__PURE__*/Object.freeze({
602
+ __proto__: null,
603
+ performUnitOfWork: performUnitOfWork,
604
+ workLoop: workLoop
605
+ });
606
+
242
607
  var Ryunix = {
243
608
  createElement,
244
609
  render,
245
-
246
610
  init,
247
611
  Fragments,
612
+ Dom,
613
+ Workers,
614
+ Reconciler,
615
+ Components,
616
+ Commits,
248
617
  };
249
618
 
250
619
  window.Ryunix = Ryunix;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unsetsoft/ryunixjs",
3
- "version": "0.2.29-nightly.0",
3
+ "version": "0.2.29",
4
4
  "license": "MIT",
5
5
  "main": "./dist/Ryunix.js",
6
6
  "private": false,
package/src/lib/index.js CHANGED
@@ -2,13 +2,22 @@ import { createElement, Fragments } from "./createElement";
2
2
  import { render, init } from "./render";
3
3
  import { useContext, useStore, useEffect } from "./hooks";
4
4
  import { createContext } from "./createContext";
5
+ import * as Dom from "./dom";
6
+ import * as Workers from "./workers";
7
+ import * as Reconciler from "./reconciler";
8
+ import * as Components from "./components";
9
+ import * as Commits from "./commits";
5
10
 
6
11
  export { useStore, useEffect, createContext, useContext, Fragments };
7
12
 
8
13
  export default {
9
14
  createElement,
10
15
  render,
11
-
12
16
  init,
13
17
  Fragments,
18
+ Dom,
19
+ Workers,
20
+ Reconciler,
21
+ Components,
22
+ Commits,
14
23
  };