@unsetsoft/ryunixjs 0.1.14-beta.0 → 0.2.0-beta.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/lib/dom.js +409 -0
- package/lib/main.js +13 -0
- package/package.json +2 -2
- package/lib/component.js +0 -25
- package/lib/dom-utils.js +0 -25
- package/lib/element.js +0 -37
- package/lib/hooks.js +0 -5
- package/lib/reconciler.js +0 -612
- package/lib/ryunix.js +0 -13
package/lib/dom.js
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The function creates a new element with the given type, props, and children.
|
|
3
|
+
* @param type - The type of the element to be created, such as "div", "span", "h1", etc.
|
|
4
|
+
* @param props - The `props` parameter is an object that contains the properties or attributes of the
|
|
5
|
+
* element being created. These properties can include things like `className`, `id`, `style`, and any
|
|
6
|
+
* other custom attributes that the user wants to add to the element. The `props` object is spread
|
|
7
|
+
* using the spread
|
|
8
|
+
* @param children - The `children` parameter is a rest parameter that allows the function to accept
|
|
9
|
+
* any number of arguments after the `props` parameter. These arguments will be treated as children
|
|
10
|
+
* elements of the created element. The `map` function is used to iterate over each child and create a
|
|
11
|
+
* new element if it is not
|
|
12
|
+
* @returns A JavaScript object with a `type` property and a `props` property. The `type` property is
|
|
13
|
+
* set to the `type` argument passed into the function, and the `props` property is an object that
|
|
14
|
+
* includes any additional properties passed in the `props` argument, as well as a `children` property
|
|
15
|
+
* that is an array of any child elements passed in the `...children` argument
|
|
16
|
+
*/
|
|
17
|
+
function createElement(type, props, ...children) {
|
|
18
|
+
return {
|
|
19
|
+
type,
|
|
20
|
+
props: {
|
|
21
|
+
...props,
|
|
22
|
+
children: children.map((child) =>
|
|
23
|
+
typeof child === "object" ? child : createTextElement(child)
|
|
24
|
+
),
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The function creates a text element with a given text value.
|
|
31
|
+
* @param text - The text content that will be used to create a new text element.
|
|
32
|
+
* @returns A JavaScript object with a `type` property set to `"TEXT_ELEMENT"` and a `props` property
|
|
33
|
+
* that contains a `nodeValue` property set to the `text` parameter and an empty `children` array.
|
|
34
|
+
*/
|
|
35
|
+
function createTextElement(text) {
|
|
36
|
+
return {
|
|
37
|
+
type: "TEXT_ELEMENT",
|
|
38
|
+
props: {
|
|
39
|
+
nodeValue: text,
|
|
40
|
+
children: [],
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The function creates a new DOM element based on the given fiber object and updates its properties.
|
|
47
|
+
* @param fiber - The fiber parameter is an object that represents a node in the fiber tree. It
|
|
48
|
+
* contains information about the element type, props, and children of the node.
|
|
49
|
+
* @returns The `createDom` function returns a newly created DOM element based on the `fiber` object
|
|
50
|
+
* passed as an argument. If the `fiber` object represents a text element, a text node is created using
|
|
51
|
+
* `document.createTextNode("")`. Otherwise, a new element is created using
|
|
52
|
+
* `document.createElement(fiber.type)`. The function then calls the `updateDom` function to update the
|
|
53
|
+
* properties of the newly created
|
|
54
|
+
*/
|
|
55
|
+
function createDom(fiber) {
|
|
56
|
+
const dom =
|
|
57
|
+
fiber.type == "TEXT_ELEMENT"
|
|
58
|
+
? document.createTextNode("")
|
|
59
|
+
: document.createElement(fiber.type);
|
|
60
|
+
|
|
61
|
+
updateDom(dom, {}, fiber.props);
|
|
62
|
+
|
|
63
|
+
return dom;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const isEvent = (key) => key.startsWith("on");
|
|
67
|
+
const isProperty = (key) => key !== "children" && !isEvent(key);
|
|
68
|
+
const isNew = (prev, next) => (key) => prev[key] !== next[key];
|
|
69
|
+
const isGone = (prev, next) => (key) => !(key in next);
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The function updates the DOM by removing old event listeners and properties, and adding new ones
|
|
73
|
+
* based on the previous and next props.
|
|
74
|
+
* @param dom - The DOM element that needs to be updated with new props.
|
|
75
|
+
* @param prevProps - An object representing the previous props (properties) of a DOM element.
|
|
76
|
+
* @param nextProps - An object containing the new props that need to be updated in the DOM.
|
|
77
|
+
*/
|
|
78
|
+
function updateDom(dom, prevProps, nextProps) {
|
|
79
|
+
Object.keys(prevProps)
|
|
80
|
+
.filter(isEvent)
|
|
81
|
+
.filter((key) => !(key in nextProps) || isNew(prevProps, nextProps)(key))
|
|
82
|
+
.forEach((name) => {
|
|
83
|
+
const eventType = name.toLowerCase().substring(2);
|
|
84
|
+
dom.removeEventListener(eventType, prevProps[name]);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
Object.keys(prevProps)
|
|
88
|
+
.filter(isProperty)
|
|
89
|
+
.filter(isGone(prevProps, nextProps))
|
|
90
|
+
.forEach((name) => {
|
|
91
|
+
dom[name] = "";
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
Object.keys(nextProps)
|
|
95
|
+
.filter(isProperty)
|
|
96
|
+
.filter(isNew(prevProps, nextProps))
|
|
97
|
+
.forEach((name) => {
|
|
98
|
+
dom[name] = nextProps[name];
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
Object.keys(nextProps)
|
|
102
|
+
.filter(isEvent)
|
|
103
|
+
.filter(isNew(prevProps, nextProps))
|
|
104
|
+
.forEach((name) => {
|
|
105
|
+
const eventType = name.toLowerCase().substring(2);
|
|
106
|
+
dom.addEventListener(eventType, nextProps[name]);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The function commits changes made to the virtual DOM to the actual DOM.
|
|
112
|
+
*/
|
|
113
|
+
function commitRoot() {
|
|
114
|
+
deletions.forEach(commitWork);
|
|
115
|
+
commitWork(wipRoot.child);
|
|
116
|
+
currentRoot = wipRoot;
|
|
117
|
+
wipRoot = null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* The function commits changes made to the DOM based on the effect tag of the fiber.
|
|
122
|
+
* @param fiber - A fiber is a unit of work in React's reconciliation process. It represents a
|
|
123
|
+
* component and its state at a particular point in time. The `commitWork` function takes a fiber as a
|
|
124
|
+
* parameter to commit the changes made during the reconciliation process to the actual DOM.
|
|
125
|
+
* @returns The function does not return anything, it performs side effects by manipulating the DOM.
|
|
126
|
+
*/
|
|
127
|
+
function commitWork(fiber) {
|
|
128
|
+
if (!fiber) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let domParentFiber = fiber.parent;
|
|
133
|
+
while (!domParentFiber.dom) {
|
|
134
|
+
domParentFiber = domParentFiber.parent;
|
|
135
|
+
}
|
|
136
|
+
const domParent = domParentFiber.dom;
|
|
137
|
+
|
|
138
|
+
if (fiber.effectTag === "PLACEMENT" && fiber.dom != null) {
|
|
139
|
+
domParent.appendChild(fiber.dom);
|
|
140
|
+
} else if (fiber.effectTag === "UPDATE" && fiber.dom != null) {
|
|
141
|
+
updateDom(fiber.dom, fiber.alternate.props, fiber.props);
|
|
142
|
+
} else if (fiber.effectTag === "DELETION") {
|
|
143
|
+
commitDeletion(fiber, domParent);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
commitWork(fiber.child);
|
|
147
|
+
commitWork(fiber.sibling);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* The function removes a fiber's corresponding DOM node from its parent node or recursively removes
|
|
152
|
+
* its child's DOM node until it finds a node to remove.
|
|
153
|
+
* @param fiber - a fiber node in a fiber tree, which represents a component or an element in the React
|
|
154
|
+
* application.
|
|
155
|
+
* @param domParent - The parent DOM element from which the fiber's DOM element needs to be removed.
|
|
156
|
+
*/
|
|
157
|
+
function commitDeletion(fiber, domParent) {
|
|
158
|
+
if (fiber.dom) {
|
|
159
|
+
domParent.removeChild(fiber.dom);
|
|
160
|
+
} else {
|
|
161
|
+
commitDeletion(fiber.child, domParent);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
let containerRoot = null;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* The function creates a root container for a web application.
|
|
169
|
+
* @param root - The parameter `root` is likely referring to an HTML element that will serve as the
|
|
170
|
+
* root or container for a web application or component. The `createRoot` function takes this element
|
|
171
|
+
* as an argument and assigns it to a variable called `containerRoot`. This variable can then be used
|
|
172
|
+
* to manipulate the contents
|
|
173
|
+
*/
|
|
174
|
+
function createRoot(root) {
|
|
175
|
+
containerRoot = root;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* The function renders an element into a container using a work-in-progress root.
|
|
180
|
+
* @param element - The element parameter is the component or element that needs to be rendered in the
|
|
181
|
+
* container. It could be a React component or a DOM element.
|
|
182
|
+
* @param container - The container parameter is the DOM element where the rendered element will be
|
|
183
|
+
* appended to. this parameter is optional if you use createRoot().
|
|
184
|
+
*/
|
|
185
|
+
function render(element, container) {
|
|
186
|
+
wipRoot = {
|
|
187
|
+
dom: containerRoot || container,
|
|
188
|
+
props: {
|
|
189
|
+
children: [element],
|
|
190
|
+
},
|
|
191
|
+
alternate: currentRoot,
|
|
192
|
+
};
|
|
193
|
+
deletions = [];
|
|
194
|
+
nextUnitOfWork = wipRoot;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
let nextUnitOfWork = null;
|
|
198
|
+
let currentRoot = null;
|
|
199
|
+
let wipRoot = null;
|
|
200
|
+
let deletions = null;
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* This function uses requestIdleCallback to perform work on a fiber tree until it is complete or the
|
|
204
|
+
* browser needs to yield to other tasks.
|
|
205
|
+
* @param deadline - The `deadline` parameter is an object that represents the amount of time the
|
|
206
|
+
* browser has to perform work before it needs to handle other tasks. It has a `timeRemaining()` method
|
|
207
|
+
* that returns the amount of time remaining before the deadline is reached. The `shouldYield` variable
|
|
208
|
+
* is used to determine
|
|
209
|
+
*/
|
|
210
|
+
function workLoop(deadline) {
|
|
211
|
+
let shouldYield = false;
|
|
212
|
+
while (nextUnitOfWork && !shouldYield) {
|
|
213
|
+
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
|
|
214
|
+
shouldYield = deadline.timeRemaining() < 1;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (!nextUnitOfWork && wipRoot) {
|
|
218
|
+
commitRoot();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
requestIdleCallback(workLoop);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
requestIdleCallback(workLoop);
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* The function performs a unit of work by updating either a function component or a host component and
|
|
228
|
+
* returns the next fiber to be processed.
|
|
229
|
+
* @param fiber - A fiber is a unit of work in React that represents a component and its state. It
|
|
230
|
+
* contains information about the component's type, props, and children, as well as pointers to its
|
|
231
|
+
* parent, child, and sibling fibers. The `performUnitOfWork` function takes a fiber as a parameter and
|
|
232
|
+
* performs work
|
|
233
|
+
* @returns The function `performUnitOfWork` returns the next fiber to be processed. If the current
|
|
234
|
+
* fiber has a child, it returns the child. Otherwise, it looks for the next sibling of the current
|
|
235
|
+
* fiber. If there are no more siblings, it goes up the tree to the parent and looks for the next
|
|
236
|
+
* sibling of the parent. The function returns `null` if there are no more fibers to process.
|
|
237
|
+
*/
|
|
238
|
+
function performUnitOfWork(fiber) {
|
|
239
|
+
const isFunctionComponent = fiber.type instanceof Function;
|
|
240
|
+
if (isFunctionComponent) {
|
|
241
|
+
updateFunctionComponent(fiber);
|
|
242
|
+
} else {
|
|
243
|
+
updateHostComponent(fiber);
|
|
244
|
+
}
|
|
245
|
+
if (fiber.child) {
|
|
246
|
+
return fiber.child;
|
|
247
|
+
}
|
|
248
|
+
let nextFiber = fiber;
|
|
249
|
+
while (nextFiber) {
|
|
250
|
+
if (nextFiber.sibling) {
|
|
251
|
+
return nextFiber.sibling;
|
|
252
|
+
}
|
|
253
|
+
nextFiber = nextFiber.parent;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
let wipFiber = null;
|
|
258
|
+
let hookIndex = null;
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* This function updates a function component by setting up a work-in-progress fiber, resetting the
|
|
262
|
+
* hook index, creating an empty hooks array, rendering the component, and reconciling its children.
|
|
263
|
+
* @param fiber - The fiber parameter is an object that represents a node in the fiber tree. It
|
|
264
|
+
* contains information about the component, its props, state, and children. In this function, it is
|
|
265
|
+
* used to update the state of the component and its children.
|
|
266
|
+
*/
|
|
267
|
+
function updateFunctionComponent(fiber) {
|
|
268
|
+
wipFiber = fiber;
|
|
269
|
+
hookIndex = 0;
|
|
270
|
+
wipFiber.hooks = [];
|
|
271
|
+
const children = [fiber.type(fiber.props)];
|
|
272
|
+
reconcileChildren(fiber, children);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* This function updates a host component's DOM element and reconciles its children.
|
|
277
|
+
* @param fiber - A fiber is a unit of work in React that represents a component and its state. It
|
|
278
|
+
* contains information about the component's type, props, and children, as well as pointers to other
|
|
279
|
+
* fibers in the tree.
|
|
280
|
+
*/
|
|
281
|
+
function updateHostComponent(fiber) {
|
|
282
|
+
if (!fiber.dom) {
|
|
283
|
+
fiber.dom = createDom(fiber);
|
|
284
|
+
}
|
|
285
|
+
reconcileChildren(fiber, fiber.props.children);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* This function reconciles the children of a fiber node with a new set of elements, creating new
|
|
290
|
+
* fibers for new elements, updating existing fibers for elements with the same type, and marking old
|
|
291
|
+
* fibers for deletion if they are not present in the new set of elements.
|
|
292
|
+
* @param wipFiber - A work-in-progress fiber object representing a component or element in the virtual
|
|
293
|
+
* DOM tree.
|
|
294
|
+
* @param elements - an array of elements representing the new children to be rendered in the current
|
|
295
|
+
* fiber's subtree
|
|
296
|
+
*/
|
|
297
|
+
function reconcileChildren(wipFiber, elements) {
|
|
298
|
+
let index = 0;
|
|
299
|
+
let oldFiber = wipFiber.alternate && wipFiber.alternate.child;
|
|
300
|
+
let prevSibling = null;
|
|
301
|
+
|
|
302
|
+
while (index < elements.length || oldFiber != null) {
|
|
303
|
+
const element = elements[index];
|
|
304
|
+
let newFiber = null;
|
|
305
|
+
|
|
306
|
+
const sameType = oldFiber && element && element.type == oldFiber.type;
|
|
307
|
+
|
|
308
|
+
if (sameType) {
|
|
309
|
+
newFiber = {
|
|
310
|
+
type: oldFiber.type,
|
|
311
|
+
props: element.props,
|
|
312
|
+
dom: oldFiber.dom,
|
|
313
|
+
parent: wipFiber,
|
|
314
|
+
alternate: oldFiber,
|
|
315
|
+
effectTag: "UPDATE",
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
if (element && !sameType) {
|
|
319
|
+
newFiber = {
|
|
320
|
+
type: element.type,
|
|
321
|
+
props: element.props,
|
|
322
|
+
dom: null,
|
|
323
|
+
parent: wipFiber,
|
|
324
|
+
alternate: null,
|
|
325
|
+
effectTag: "PLACEMENT",
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
if (oldFiber && !sameType) {
|
|
329
|
+
oldFiber.effectTag = "DELETION";
|
|
330
|
+
deletions.push(oldFiber);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (oldFiber) {
|
|
334
|
+
oldFiber = oldFiber.sibling;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (index === 0) {
|
|
338
|
+
wipFiber.child = newFiber;
|
|
339
|
+
} else if (element) {
|
|
340
|
+
prevSibling.sibling = newFiber;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
prevSibling = newFiber;
|
|
344
|
+
index++;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Hooks
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* The function creates a state hook for a React-like framework.
|
|
352
|
+
* @param initial - The initial value of the state for the hook.
|
|
353
|
+
* @returns The `useStore` function returns an array with two elements: the current state value and a
|
|
354
|
+
* `setState` function that can be used to update the state.
|
|
355
|
+
*/
|
|
356
|
+
function useStore(initial) {
|
|
357
|
+
const oldHook =
|
|
358
|
+
wipFiber.alternate &&
|
|
359
|
+
wipFiber.alternate.hooks &&
|
|
360
|
+
wipFiber.alternate.hooks[hookIndex];
|
|
361
|
+
const hook = {
|
|
362
|
+
state: oldHook ? oldHook.state : initial,
|
|
363
|
+
queue: [],
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
const actions = oldHook ? oldHook.queue : [];
|
|
367
|
+
actions.forEach((action) => {
|
|
368
|
+
console.log(action);
|
|
369
|
+
hook.state = action(hook.state);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* The function `setState` updates the state of a component in React by adding an action to a queue
|
|
374
|
+
* and setting up a new work-in-progress root.
|
|
375
|
+
* @param action - The `action` parameter is an object that represents a state update to be performed
|
|
376
|
+
* on a component. It contains information about the type of update to be performed and any new data
|
|
377
|
+
* that needs to be applied to the component's state.
|
|
378
|
+
*/
|
|
379
|
+
const setState = (action) => {
|
|
380
|
+
hook.queue.push(action);
|
|
381
|
+
wipRoot = {
|
|
382
|
+
dom: currentRoot.dom,
|
|
383
|
+
props: currentRoot.props,
|
|
384
|
+
alternate: currentRoot,
|
|
385
|
+
};
|
|
386
|
+
nextUnitOfWork = wipRoot;
|
|
387
|
+
deletions = [];
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
wipFiber.hooks.push(hook);
|
|
391
|
+
hookIndex++;
|
|
392
|
+
return [hook.state, setState];
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function Fragment() {
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// export
|
|
400
|
+
|
|
401
|
+
export {
|
|
402
|
+
// Main functions
|
|
403
|
+
createElement,
|
|
404
|
+
render,
|
|
405
|
+
createRoot,
|
|
406
|
+
// Hooks
|
|
407
|
+
useStore,
|
|
408
|
+
Fragment,
|
|
409
|
+
};
|
package/lib/main.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unsetsoft/ryunixjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-beta.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "./dist/Ryunix.js",
|
|
6
6
|
"private": false,
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"homepage": "https://github.com/UnSetSoft/Ryunixjs#readme",
|
|
11
11
|
"scripts": {
|
|
12
|
-
"build": "rollup ./lib/
|
|
12
|
+
"build": "rollup ./lib/main.js --file ./dist/Ryunix.js --format umd --name Ryunix",
|
|
13
13
|
"postinstall": "yarn build"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
package/lib/component.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { scheduleUpdate } from "./reconciler";
|
|
2
|
-
|
|
3
|
-
export class Component {
|
|
4
|
-
constructor(props) {
|
|
5
|
-
this.props = props;
|
|
6
|
-
this.state = this.state || {};
|
|
7
|
-
}
|
|
8
|
-
setState(partialState) {
|
|
9
|
-
// this.state = Object.assign({}, this.state, partialState);
|
|
10
|
-
// scheduleUpdate(this.__internalInstance, partialState);
|
|
11
|
-
throw Error(
|
|
12
|
-
"This function is not implemented yet, has a lot of bugs. You can check https://github.com/UnSetSoft/Ryunixjs/issues/10 for more information."
|
|
13
|
-
);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export class Fragment {
|
|
18
|
-
constructor(props) {
|
|
19
|
-
this.props = props;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
render() {
|
|
23
|
-
return this.props.children;
|
|
24
|
-
}
|
|
25
|
-
}
|
package/lib/dom-utils.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This function updates the properties and event listeners of a DOM element based on the previous and
|
|
3
|
-
* next props passed as arguments.
|
|
4
|
-
* @param dom - The DOM element that needs to be updated with new properties.
|
|
5
|
-
* @param prevProps - An object representing the previous properties of a DOM element.
|
|
6
|
-
* @param nextProps - An object containing the new props that need to be updated on the DOM element.
|
|
7
|
-
*/
|
|
8
|
-
export function updateDomProperties(dom, prevProps, nextProps) {
|
|
9
|
-
const isEvent = name => name.startsWith("on");
|
|
10
|
-
const isAttribute = name => !isEvent(name) && name != "children";
|
|
11
|
-
Object.keys(prevProps).filter(isEvent).forEach(name => {
|
|
12
|
-
const eventType = name.toLowerCase().substring(2);
|
|
13
|
-
dom.removeEventListener(eventType, prevProps[name]);
|
|
14
|
-
});
|
|
15
|
-
Object.keys(prevProps).filter(isAttribute).forEach(name => {
|
|
16
|
-
dom[name] = null;
|
|
17
|
-
});
|
|
18
|
-
Object.keys(nextProps).filter(isAttribute).forEach(name => {
|
|
19
|
-
dom[name] = nextProps[name];
|
|
20
|
-
});
|
|
21
|
-
Object.keys(nextProps).filter(isEvent).forEach(name => {
|
|
22
|
-
const eventType = name.toLowerCase().substring(2);
|
|
23
|
-
dom.addEventListener(eventType, nextProps[name]);
|
|
24
|
-
});
|
|
25
|
-
}
|
package/lib/element.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
const TEXT_ELEMENT = "TEXT";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* This function creates a new element with the given type, configuration object, and children.
|
|
5
|
-
* @param type - The type of the element being created (e.g. "div", "span", "h1", etc.).
|
|
6
|
-
* @param configObject - The `configObject` parameter is an object that contains the properties and
|
|
7
|
-
* values for the element's attributes. These attributes can include things like `className`, `id`,
|
|
8
|
-
* `style`, and any other custom attributes that the user wants to add to the element.
|
|
9
|
-
* @param args - The `args` parameter is a rest parameter that allows the function to accept any number
|
|
10
|
-
* of additional arguments after the `configObject` parameter. These additional arguments are used as
|
|
11
|
-
* children elements for the created element.
|
|
12
|
-
* @returns An object with two properties: "type" and "props".
|
|
13
|
-
*/
|
|
14
|
-
export function createElement(type, configObject, ...args) {
|
|
15
|
-
const props = Object.assign({}, configObject);
|
|
16
|
-
const hasChildren = args.length > 0;
|
|
17
|
-
const nodeChildren = hasChildren ? [...args] : [];
|
|
18
|
-
props.children = nodeChildren.filter(Boolean).map(c => c instanceof Object ? c : createTextElement(c));
|
|
19
|
-
return {
|
|
20
|
-
type,
|
|
21
|
-
props
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* The function creates a text element with a given node value and an empty array of children.
|
|
27
|
-
* @param nodeValue - The value of the text node that will be created.
|
|
28
|
-
* @returns The function `createTextElement` is returning an element object with a `nodeValue` property
|
|
29
|
-
* and an empty `children` array. This element object represents a text node in the virtual DOM.
|
|
30
|
-
*/
|
|
31
|
-
function createTextElement(nodeValue) {
|
|
32
|
-
return createElement(TEXT_ELEMENT, {
|
|
33
|
-
nodeValue,
|
|
34
|
-
children: []
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
export { TEXT_ELEMENT };
|
package/lib/hooks.js
DELETED
package/lib/reconciler.js
DELETED
|
@@ -1,612 +0,0 @@
|
|
|
1
|
-
import { updateDomProperties } from "./dom-utils";
|
|
2
|
-
import { TEXT_ELEMENT } from "./element";
|
|
3
|
-
|
|
4
|
-
let rootInstance = null;
|
|
5
|
-
const ENOUGH_TIME = 1;
|
|
6
|
-
let workQueue = [];
|
|
7
|
-
let nextUnitOfWork = null;
|
|
8
|
-
const CLASS_COMPONENT = "class";
|
|
9
|
-
const HOST_ROOT = "root";
|
|
10
|
-
const HOST_COMPONENT = "host";
|
|
11
|
-
const PLACEMENT = "PLACEMENT"; // this is for a child that needs to be added
|
|
12
|
-
const DELETION = "DELETION"; //for a child that needs to be deleted.
|
|
13
|
-
const UPDATE = "UPDATE"; // for a child that needs to be updated. refresh the props
|
|
14
|
-
let pendingCommit = null;
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* The function adds a task to a work queue and requests idle callback to perform the work.
|
|
18
|
-
* @param task - The task parameter is a function that represents the work that needs to be done. It
|
|
19
|
-
* will be added to the workQueue array, which is a queue of tasks waiting to be executed. The
|
|
20
|
-
* requestIdleCallback function will be used to schedule the execution of the performWork function,
|
|
21
|
-
* which will process the tasks
|
|
22
|
-
*/
|
|
23
|
-
function schedule(task) {
|
|
24
|
-
workQueue.push(task);
|
|
25
|
-
requestIdleCallback(performWork);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* This function performs work in a loop using requestIdleCallback and commits any pending changes.
|
|
30
|
-
* @param deadline - The `deadline` parameter is a time value representing the deadline by which the
|
|
31
|
-
* `performWork` function should finish its work. It is used to ensure that the function does not
|
|
32
|
-
* exceed a certain amount of time and cause the browser to become unresponsive. The function will stop
|
|
33
|
-
* working on the current task when
|
|
34
|
-
*/
|
|
35
|
-
function performWork(deadline) {
|
|
36
|
-
if (!nextUnitOfWork) {
|
|
37
|
-
initialUnitOfWork();
|
|
38
|
-
}
|
|
39
|
-
loopThroughWork(deadline);
|
|
40
|
-
if (nextUnitOfWork || workQueue.length > 0) {
|
|
41
|
-
requestIdleCallback(performWork);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (pendingCommit) {
|
|
45
|
-
commitAllWork(pendingCommit);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* The function commits all the effects of a fiber and updates the root container fiber.
|
|
51
|
-
* @param fiber - The fiber parameter is an object that represents a node in the fiber tree. It
|
|
52
|
-
* contains information about the component, its state, props, and children. The fiber also has a
|
|
53
|
-
* reference to its parent, child, and sibling fibers.
|
|
54
|
-
*/
|
|
55
|
-
function commitAllWork(fiber) {
|
|
56
|
-
fiber.effects.forEach((f) => {
|
|
57
|
-
commitWork(f);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
fiber.stateNode._rootContainerFiber = fiber;
|
|
61
|
-
nextUnitOfWork = null;
|
|
62
|
-
pendingCommit = null;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* The function commits changes to the DOM based on the effect tag of the fiber.
|
|
67
|
-
* @param fiber - A fiber is a lightweight unit of work that represents a component and its state
|
|
68
|
-
* during the reconciliation process in React's virtual DOM. It contains information about the
|
|
69
|
-
* component's type, props, state, and children, as well as pointers to its parent, child, and sibling
|
|
70
|
-
* fibers.
|
|
71
|
-
* @returns If the fiber tag is HOST_ROOT, nothing is being returned.
|
|
72
|
-
*/
|
|
73
|
-
function commitWork(fiber) {
|
|
74
|
-
if (fiber.tag == HOST_ROOT) {
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
let domParentFiber = fiber.parent;
|
|
78
|
-
while (domParentFiber.tag == CLASS_COMPONENT) {
|
|
79
|
-
domParentFiber = domParentFiber.parent;
|
|
80
|
-
}
|
|
81
|
-
const domParent = domParentFiber.stateNode;
|
|
82
|
-
if (fiber.effectTag == PLACEMENT && fiber.tag == HOST_COMPONENT) {
|
|
83
|
-
domParent.appendChild(fiber.stateNode);
|
|
84
|
-
} else if (fiber.effectTag == UPDATE) {
|
|
85
|
-
updateDomProperties(fiber.stateNode, fiber.alternate.props, fiber.props);
|
|
86
|
-
} else if (fiber.effectTag == DELETION) {
|
|
87
|
-
commitDeletion(fiber, domParent);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* The function removes a fiber and its corresponding DOM node from the parent DOM node.
|
|
93
|
-
* @param fiber - The fiber is a data structure used by React to represent a component and its state
|
|
94
|
-
* during the rendering process. It contains information about the component's type, props, children,
|
|
95
|
-
* and other metadata.
|
|
96
|
-
* @param domParent - The DOM element that is the parent of the component being deleted.
|
|
97
|
-
* @returns The function does not explicitly return anything, but it will exit the function and return
|
|
98
|
-
* control to the calling function when the condition `if (node == fiber)` is met.
|
|
99
|
-
*/
|
|
100
|
-
function commitDeletion(fiber, domParent) {
|
|
101
|
-
let node = fiber;
|
|
102
|
-
while (true) {
|
|
103
|
-
if (node.tag == CLASS_COMPONENT) {
|
|
104
|
-
node = node.child;
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
107
|
-
domParent.removeChild(node.stateNode);
|
|
108
|
-
while (node != fiber && !node.sibling) {
|
|
109
|
-
node = node.parent;
|
|
110
|
-
}
|
|
111
|
-
if (node == fiber) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
node = node.sibling;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* The function begins the work of updating a fiber either for a class component or a host component.
|
|
120
|
-
* @param wipFiber - wipFiber is a fiber object that represents the work-in-progress (WIP) component
|
|
121
|
-
* being worked on by the reconciler in a React application. It contains information about the
|
|
122
|
-
* component's type, props, state, and children, as well as pointers to its parent, sibling, and child
|
|
123
|
-
* fibers
|
|
124
|
-
*/
|
|
125
|
-
function beginWork(wipFiber) {
|
|
126
|
-
if (wipFiber.tag == CLASS_COMPONENT) {
|
|
127
|
-
updateClassFiber(wipFiber);
|
|
128
|
-
} else {
|
|
129
|
-
updateHostFiber(wipFiber);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* This function updates the host fiber by creating a new DOM element and reconciling its children.
|
|
135
|
-
* @param wipFiber - wipFiber is a work-in-progress fiber object that represents a component or element
|
|
136
|
-
* in the virtual DOM tree. It contains information about the component's type, props, state, and
|
|
137
|
-
* children. The function `updateHostFiber` uses this wipFiber object to update the corresponding DOM
|
|
138
|
-
* element
|
|
139
|
-
*/
|
|
140
|
-
function updateHostFiber(wipFiber) {
|
|
141
|
-
if (!wipFiber.stateNode) {
|
|
142
|
-
wipFiber.stateNode = createDomElement(wipFiber);
|
|
143
|
-
}
|
|
144
|
-
const newChildElements = wipFiber.props.children;
|
|
145
|
-
reconcileChildrenArray(wipFiber, newChildElements);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* This function updates the state and props of a fiber node and reconciles its child elements.
|
|
150
|
-
* @param wipFiber - wipFiber is a work-in-progress fiber that represents a component in the fiber
|
|
151
|
-
* tree. It contains information about the component's type, props, state, and children. The function
|
|
152
|
-
* `updateClassFiber` updates the state and props of the component represented by the wipFiber.
|
|
153
|
-
* @returns Nothing is being returned explicitly in this function. It either updates the instance and
|
|
154
|
-
* child fibers or clones the child fibers and returns nothing.
|
|
155
|
-
*/
|
|
156
|
-
function updateClassFiber(wipFiber) {
|
|
157
|
-
let instance = wipFiber.stateNode;
|
|
158
|
-
if (instance == null) {
|
|
159
|
-
instance = wipFiber.stateNode = createInstance(wipFiber);
|
|
160
|
-
} else if (wipFiber.props == instance.props && !wipFiber.partialState) {
|
|
161
|
-
cloneChildFibers(wipFiber);
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
instance.props = wipFiber.props;
|
|
166
|
-
instance.state = Object.assign({}, instance.state, wipFiber.partialState);
|
|
167
|
-
wipFiber.partialState = null;
|
|
168
|
-
|
|
169
|
-
const newChildElements = wipFiber.stateNode.render();
|
|
170
|
-
reconcileChildrenArray(wipFiber, newChildElements);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* The function creates an instance of a component using the given fiber.
|
|
175
|
-
* @param fiber - The "fiber" parameter is an object that represents a node in the fiber tree. It
|
|
176
|
-
* contains information about the component type, props, children, and other metadata needed for
|
|
177
|
-
* rendering and updating the component.
|
|
178
|
-
* @returns The function `createInstance` returns an instance of the component class specified in the
|
|
179
|
-
* `fiber` argument, with the props passed to it. The instance also has a reference to the `fiber`
|
|
180
|
-
* object.
|
|
181
|
-
*/
|
|
182
|
-
function createInstance(fiber) {
|
|
183
|
-
const instance = new fiber.type(fiber.props);
|
|
184
|
-
instance.__fiber = fiber;
|
|
185
|
-
return instance;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* This function creates a new DOM element based on the given fiber object.
|
|
190
|
-
* @param fiber - The "fiber" parameter is an object that represents a node in the virtual DOM tree. It
|
|
191
|
-
* contains information about the element's type, props, and children.
|
|
192
|
-
* @returns The function `createDomElement` returns a DOM element created using the
|
|
193
|
-
* `document.createElement` method. If the `fiber` object represents a text element, then a text node
|
|
194
|
-
* is created using `document.createTextNode` method. The properties of the element are updated using
|
|
195
|
-
* the `updateDomProperties` function.
|
|
196
|
-
*/
|
|
197
|
-
function createDomElement(fiber) {
|
|
198
|
-
const isTextElement = fiber.type === TEXT_ELEMENT;
|
|
199
|
-
const dom = isTextElement
|
|
200
|
-
? document.createTextNode("")
|
|
201
|
-
: document.createElement(fiber.type);
|
|
202
|
-
updateDomProperties(dom, [], fiber.props);
|
|
203
|
-
return dom;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* This function performs work on a fiber and its children, completing each unit of work before moving
|
|
208
|
-
* on to the next.
|
|
209
|
-
* @param wipFiber - wipFiber stands for "work-in-progress fiber". In React, a fiber is a lightweight
|
|
210
|
-
* representation of a component or element in the component tree. The wipFiber parameter represents
|
|
211
|
-
* the current fiber that is being worked on by the reconciler during the rendering process. The
|
|
212
|
-
* performUnitOfWork function performs
|
|
213
|
-
* @returns the next unit of work to be performed, which is either the first child of the current fiber
|
|
214
|
-
* (if it has one), or the next sibling of the current fiber (if it has one), or the parent of the
|
|
215
|
-
* current fiber (if it has no more siblings).
|
|
216
|
-
*/
|
|
217
|
-
function performUnitOfWork(wipFiber) {
|
|
218
|
-
beginWork(wipFiber);
|
|
219
|
-
if (wipFiber.child) {
|
|
220
|
-
return wipFiber.child;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
let uow = wipFiber;
|
|
224
|
-
while (uow) {
|
|
225
|
-
completeWork(uow);
|
|
226
|
-
|
|
227
|
-
if (uow.sibling) {
|
|
228
|
-
return uow.sibling;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
uow = uow.parent;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* The function initializes a unit of work by dequeuing an update from a work queue and setting the
|
|
237
|
-
* next unit of work based on the update's properties.
|
|
238
|
-
* @returns The function does not have a return statement, so it returns undefined.
|
|
239
|
-
*/
|
|
240
|
-
function initialUnitOfWork() {
|
|
241
|
-
const update = workQueue.shift();
|
|
242
|
-
|
|
243
|
-
if (!update) {
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (update.partialState) {
|
|
248
|
-
update.instance.__fiber.partialState = update.partialState;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const root =
|
|
252
|
-
update.from === HOST_ROOT
|
|
253
|
-
? update.dom._rootContainerFiber
|
|
254
|
-
: getRootNode(update.instance.__fiber);
|
|
255
|
-
|
|
256
|
-
nextUnitOfWork = {
|
|
257
|
-
tag: HOST_ROOT,
|
|
258
|
-
stateNode: update.dom || root.stateNode,
|
|
259
|
-
props: update.newProps || root.props,
|
|
260
|
-
alternate: root,
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* The function returns the root node of a given fiber by traversing up the parent chain.
|
|
266
|
-
* @param fiber - The "fiber" parameter is likely referring to a data structure used in React.js to
|
|
267
|
-
* represent a component and its state. It is used in the function to traverse the component tree and
|
|
268
|
-
* find the root node of the tree.
|
|
269
|
-
* @returns The function `getRootNode` returns the root node of a given fiber by traversing up the
|
|
270
|
-
* fiber tree until it reaches the topmost parent node.
|
|
271
|
-
*/
|
|
272
|
-
function getRootNode(fiber) {
|
|
273
|
-
let node = fiber;
|
|
274
|
-
while (node.parent) {
|
|
275
|
-
node = node.parent;
|
|
276
|
-
}
|
|
277
|
-
return node;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* This function loops through work while there is still time remaining before the deadline.
|
|
282
|
-
* @param deadline - The `deadline` parameter is an object that represents a deadline by which the
|
|
283
|
-
* current task should be completed. It has a `timeRemaining()` method that returns the amount of time
|
|
284
|
-
* left until the deadline, in milliseconds. The `loopThroughWork()` function uses this `deadline`
|
|
285
|
-
* object to check if there
|
|
286
|
-
*/
|
|
287
|
-
function loopThroughWork(deadline) {
|
|
288
|
-
while (nextUnitOfWork && deadline.timeRemaining() > ENOUGH_TIME) {
|
|
289
|
-
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* The function creates an array of children elements, either from an array or a single element.
|
|
295
|
-
* @param children - The parameter `children` is expected to be a value that represents the children of
|
|
296
|
-
* a parent element in a web page. It can be an array of child elements or a single child element. If
|
|
297
|
-
* `children` is not provided or is falsy, an empty array is returned.
|
|
298
|
-
* @returns The function `createArrayOfChildren` is returning an array. If the `children` parameter is
|
|
299
|
-
* falsy (e.g. `null`, `undefined`, `false`, `0`, `NaN`, or an empty string), it returns an empty
|
|
300
|
-
* array. If `children` is already an array, it returns that array. Otherwise, it returns an array with
|
|
301
|
-
* `children` as its only element.
|
|
302
|
-
*/
|
|
303
|
-
function createArrayOfChildren(children) {
|
|
304
|
-
return !children ? [] : Array.isArray(children) ? children : [children];
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* This function reconciles the children of a fiber node with a new array of child elements.
|
|
309
|
-
* @param wipFiber - The work-in-progress fiber, which represents the current state of the component
|
|
310
|
-
* being rendered or updated.
|
|
311
|
-
* @param newChildElements - an array of new child elements to be reconciled with the existing children
|
|
312
|
-
* of the current fiber (wipFiber).
|
|
313
|
-
*/
|
|
314
|
-
function reconcileChildrenArray(wipFiber, newChildElements) {
|
|
315
|
-
const elements = createArrayOfChildren(newChildElements);
|
|
316
|
-
|
|
317
|
-
let index = 0;
|
|
318
|
-
|
|
319
|
-
let oldFiber = wipFiber.alternate ? wipFiber.alternate.child : null;
|
|
320
|
-
let newFiber = null;
|
|
321
|
-
while (index < elements.length || oldFiber != null) {
|
|
322
|
-
const prevFiber = newFiber;
|
|
323
|
-
|
|
324
|
-
const element = index < elements.length && elements[index];
|
|
325
|
-
|
|
326
|
-
const sameType = oldFiber && element && element.type == oldFiber.type;
|
|
327
|
-
|
|
328
|
-
if (sameType) {
|
|
329
|
-
newFiber = {
|
|
330
|
-
type: oldFiber.type,
|
|
331
|
-
tag: oldFiber.tag,
|
|
332
|
-
stateNode: oldFiber.stateNode,
|
|
333
|
-
props: element.props,
|
|
334
|
-
parent: wipFiber,
|
|
335
|
-
alternate: oldFiber,
|
|
336
|
-
partialState: oldFiber.partialState,
|
|
337
|
-
effectTag: UPDATE,
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
if (element && !sameType) {
|
|
342
|
-
newFiber = {
|
|
343
|
-
type: element.type,
|
|
344
|
-
tag:
|
|
345
|
-
typeof element.type === "string" ? HOST_COMPONENT : CLASS_COMPONENT,
|
|
346
|
-
props: element.props,
|
|
347
|
-
parent: wipFiber,
|
|
348
|
-
effectTag: PLACEMENT,
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
if (oldFiber && !sameType) {
|
|
353
|
-
oldFiber.effectTag = DELETION;
|
|
354
|
-
wipFiber.effects = wipFiber.effects || [];
|
|
355
|
-
|
|
356
|
-
wipFiber.effects.push(oldFiber);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
if (oldFiber) {
|
|
360
|
-
oldFiber = oldFiber.sibling;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if (index == 0) {
|
|
364
|
-
wipFiber.child = newFiber;
|
|
365
|
-
} else if (prevFiber && element) {
|
|
366
|
-
prevFiber.sibling = newFiber;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
index++;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* The function clones child fibers from a parent fiber.
|
|
375
|
-
* @param parentFiber - The parent fiber is an object that represents a component or element in the
|
|
376
|
-
* React tree. It contains information about the component or element, such as its type, props, and
|
|
377
|
-
* children. The function `cloneChildFibers` is used to clone the child fibers of the parent fiber.
|
|
378
|
-
* @returns If the `oldFiber` does not have a child, then nothing is returned. Otherwise, a new set of
|
|
379
|
-
* child fibers is created based on the `oldFiber` and attached to the `parentFiber`. No value is
|
|
380
|
-
* explicitly returned from the function.
|
|
381
|
-
*/
|
|
382
|
-
function cloneChildFibers(parentFiber) {
|
|
383
|
-
const oldFiber = parentFiber.alternate;
|
|
384
|
-
|
|
385
|
-
if (!oldFiber.child) {
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
let oldChild = oldFiber.child;
|
|
390
|
-
|
|
391
|
-
let prevChild = null;
|
|
392
|
-
|
|
393
|
-
while (oldChild) {
|
|
394
|
-
const newChild = {
|
|
395
|
-
type: oldChild.type,
|
|
396
|
-
tag: oldChild.tag,
|
|
397
|
-
stateNode: oldChild.stateNode,
|
|
398
|
-
props: oldChild.props,
|
|
399
|
-
partialState: oldChild.partialState,
|
|
400
|
-
alternate: oldChild,
|
|
401
|
-
parent: parentFiber,
|
|
402
|
-
};
|
|
403
|
-
if (prevChild) {
|
|
404
|
-
prevChild.sibling = newChild;
|
|
405
|
-
} else {
|
|
406
|
-
parentFiber.child = newChild;
|
|
407
|
-
}
|
|
408
|
-
prevChild = newChild;
|
|
409
|
-
oldChild = oldChild.sibling;
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
* The function completes work on a fiber and adds its effects to its parent's effects list or sets it
|
|
415
|
-
* as the pending commit.
|
|
416
|
-
* @param fiber - a fiber object representing a component or element in the React tree
|
|
417
|
-
*/
|
|
418
|
-
function completeWork(fiber) {
|
|
419
|
-
if (fiber.tag == CLASS_COMPONENT) {
|
|
420
|
-
fiber.stateNode.__fiber = fiber;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
if (fiber.parent) {
|
|
424
|
-
const childEffects = fiber.effects || [];
|
|
425
|
-
|
|
426
|
-
const thisEffect = fiber.effectTag != null ? [fiber] : [];
|
|
427
|
-
const parentEffects = fiber.parent.effects || [];
|
|
428
|
-
|
|
429
|
-
fiber.parent.effects = parentEffects.concat(childEffects, thisEffect);
|
|
430
|
-
} else {
|
|
431
|
-
pendingCommit = fiber;
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
/**
|
|
436
|
-
* This function schedules an update for a class component with the given instance and partial state.
|
|
437
|
-
* @param instance - The instance parameter refers to an instance of a class component in React. It is
|
|
438
|
-
* used to identify which component needs to be updated with the new state.
|
|
439
|
-
* @param partialState - partialState is an object that contains the updated state values for a
|
|
440
|
-
* component. When a component's state changes, the partialState object is passed to the scheduleUpdate
|
|
441
|
-
* function to schedule a re-render of the component with the updated state values.
|
|
442
|
-
*/
|
|
443
|
-
export function scheduleUpdate(instance, partialState) {
|
|
444
|
-
schedule({
|
|
445
|
-
from: CLASS_COMPONENT,
|
|
446
|
-
instance: instance,
|
|
447
|
-
partialState: partialState,
|
|
448
|
-
});
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
let rootElement;
|
|
452
|
-
|
|
453
|
-
export const createRoot = (parentDom) => {
|
|
454
|
-
rootElement = parentDom;
|
|
455
|
-
};
|
|
456
|
-
|
|
457
|
-
/**
|
|
458
|
-
* The `render` function takes in elements and a parent DOM node, and schedules a reconciliation
|
|
459
|
-
* process to update the DOM with the new elements.
|
|
460
|
-
* @param elements - an array of elements to be rendered in the parent DOM.
|
|
461
|
-
* @param parentDom - parentDom is a reference to the DOM element where the rendered elements will be
|
|
462
|
-
* appended as children. It is the container element for the rendered components.
|
|
463
|
-
*/
|
|
464
|
-
|
|
465
|
-
export function rootClient(elements) {
|
|
466
|
-
workQueue.push({
|
|
467
|
-
from: "root",
|
|
468
|
-
dom: rootElement,
|
|
469
|
-
newProps: { children: elements },
|
|
470
|
-
});
|
|
471
|
-
requestIdleCallback(performWork);
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
export function render(elements, parentDom) {
|
|
475
|
-
workQueue.push({
|
|
476
|
-
from: HOST_ROOT,
|
|
477
|
-
dom: parentDom,
|
|
478
|
-
newProps: { children: elements },
|
|
479
|
-
});
|
|
480
|
-
requestIdleCallback(performWork);
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* The function reconciles the differences between the previous and current instances of a component
|
|
485
|
-
* and updates the DOM accordingly.
|
|
486
|
-
* @param parentDom - The DOM element that serves as the parent container for the rendered component
|
|
487
|
-
* tree.
|
|
488
|
-
* @param instance - An object representing the current state of the component instance being
|
|
489
|
-
* reconciled. It contains information about the component's rendered DOM node, its element type, and
|
|
490
|
-
* its child instances. If this is the first time the component is being rendered, this parameter will
|
|
491
|
-
* be null.
|
|
492
|
-
* @param element - The element parameter represents the new element that needs to be rendered or
|
|
493
|
-
* updated in the DOM. It contains information about the type of element (e.g. div, span, custom
|
|
494
|
-
* component), its props (e.g. className, onClick), and its children (if any).
|
|
495
|
-
* @returns an instance object that represents the updated state of the component after reconciling the
|
|
496
|
-
* changes made to the virtual DOM.
|
|
497
|
-
*/
|
|
498
|
-
export function reconcile(parentDom, instance, element) {
|
|
499
|
-
if (instance === null) {
|
|
500
|
-
const newInstance = instantiate(element);
|
|
501
|
-
parentDom.appendChild(newInstance.dom);
|
|
502
|
-
return newInstance;
|
|
503
|
-
} else if (element == null) {
|
|
504
|
-
parentDom.removeChild(instance.dom);
|
|
505
|
-
return null;
|
|
506
|
-
} else if (instance.element.type !== element.type) {
|
|
507
|
-
const newInstance = instantiate(element);
|
|
508
|
-
parentDom.replaceChild(newInstance.dom, instance.dom);
|
|
509
|
-
return newInstance;
|
|
510
|
-
} else if (typeof element.type === "string") {
|
|
511
|
-
instance.childInstances = reconcileChildren(instance, element);
|
|
512
|
-
instance.element = element;
|
|
513
|
-
return instance;
|
|
514
|
-
} else {
|
|
515
|
-
instance.publicInstance.props = element.props;
|
|
516
|
-
const childElement = instance.publicInstance.render();
|
|
517
|
-
const oldChildInstance = instance.childInstance;
|
|
518
|
-
const childInstance = reconcile(parentDom, oldChildInstance, childElement);
|
|
519
|
-
instance.dom = childInstance.dom;
|
|
520
|
-
instance.childInstance = childInstance;
|
|
521
|
-
instance.element = element;
|
|
522
|
-
return instance;
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
/**
|
|
527
|
-
* The function creates an instance of a DOM element or a custom component element and returns it.
|
|
528
|
-
* @param element - The element to be instantiated, which can be a DOM element or a custom component.
|
|
529
|
-
* It contains information about the type of the element (string for DOM elements, function for custom
|
|
530
|
-
* components) and its props (attributes and children).
|
|
531
|
-
* @returns The function `instantiate` returns an instance object that contains a reference to the
|
|
532
|
-
* corresponding DOM node, the element that was passed in, and an array of child instances. The exact
|
|
533
|
-
* properties of the instance object depend on whether the element is a DOM element or a custom
|
|
534
|
-
* component.
|
|
535
|
-
*/ function instantiate(element) {
|
|
536
|
-
const { type, props } = element;
|
|
537
|
-
const isDomElement = typeof type === "string";
|
|
538
|
-
if (isDomElement) {
|
|
539
|
-
const isTextElement = type === TEXT_ELEMENT;
|
|
540
|
-
const dom = isTextElement
|
|
541
|
-
? document.createTextNode("")
|
|
542
|
-
: document.createElement(type);
|
|
543
|
-
updateDomProperties(dom, [], props);
|
|
544
|
-
const childElements = props.children || [];
|
|
545
|
-
const childInstances = childElements.map(instantiate);
|
|
546
|
-
const childDoms = childInstances.map((childInstance) => childInstance.dom);
|
|
547
|
-
childDoms.forEach((childDom) => dom.appendChild(childDom));
|
|
548
|
-
const instance = {
|
|
549
|
-
dom,
|
|
550
|
-
element,
|
|
551
|
-
childInstances,
|
|
552
|
-
};
|
|
553
|
-
return instance;
|
|
554
|
-
} else {
|
|
555
|
-
const instance = {};
|
|
556
|
-
const publicInstance = createPublicInstance(element, instance);
|
|
557
|
-
const childElement = publicInstance.render();
|
|
558
|
-
const childInstance = instantiate(childElement);
|
|
559
|
-
const dom = childInstance.dom;
|
|
560
|
-
Object.assign(instance, {
|
|
561
|
-
dom,
|
|
562
|
-
element,
|
|
563
|
-
childInstance,
|
|
564
|
-
publicInstance,
|
|
565
|
-
});
|
|
566
|
-
return instance;
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
/**
|
|
570
|
-
* The function creates a public instance of a given element with its corresponding props and internal
|
|
571
|
-
* instance.
|
|
572
|
-
* @param element - An object that represents a React element, typically created using JSX syntax or
|
|
573
|
-
* React.createElement() function.
|
|
574
|
-
* @param internalInstance - The internalInstance parameter is an object that represents the internal
|
|
575
|
-
* instance of a component. It may contain information such as the component's state, context, and
|
|
576
|
-
* lifecycle methods. This parameter is used to associate the public instance of a component with its
|
|
577
|
-
* internal instance.
|
|
578
|
-
* @returns a newly created public instance of a given element type with its props.
|
|
579
|
-
*/
|
|
580
|
-
function createPublicInstance(element, internalInstance) {
|
|
581
|
-
const { type, props } = element;
|
|
582
|
-
const publicInstance = new type(props);
|
|
583
|
-
publicInstance.__internalInstance = internalInstance;
|
|
584
|
-
return publicInstance;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
/**
|
|
588
|
-
* This function reconciles the child instances of a component with its new child elements.
|
|
589
|
-
* @param instance - an object representing the current instance of a component
|
|
590
|
-
* @param element - The element is a React element that represents the new version of the component
|
|
591
|
-
* being rendered. It contains information about the component's props and children.
|
|
592
|
-
* @returns an array of new child instances that have been reconciled with the given parent instance
|
|
593
|
-
* and child elements. The filter method is used to remove any falsy values from the array, such as
|
|
594
|
-
* null or undefined.
|
|
595
|
-
*/
|
|
596
|
-
function reconcileChildren(instance, element) {
|
|
597
|
-
const { dom, childInstances } = instance;
|
|
598
|
-
const nextChildElements = element.props.children || [];
|
|
599
|
-
|
|
600
|
-
const newChildInstances = [];
|
|
601
|
-
|
|
602
|
-
const count = Math.max(childInstances.length, nextChildElements.length);
|
|
603
|
-
|
|
604
|
-
for (let i = 0; i < count; i++) {
|
|
605
|
-
const childInstance = childInstances[i];
|
|
606
|
-
const childElement = nextChildElements[i];
|
|
607
|
-
const newChildInstance = reconcile(dom, childInstance, childElement);
|
|
608
|
-
newChildInstances.push(newChildInstance);
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
return newChildInstances.filter(Boolean);
|
|
612
|
-
}
|
package/lib/ryunix.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { render, rootClient, createRoot } from "./reconciler";
|
|
2
|
-
import { createElement } from "./element";
|
|
3
|
-
import { Component, Fragment } from "./component";
|
|
4
|
-
import { useLoaded } from "./hooks";
|
|
5
|
-
export { createElement, render, Component, useLoaded, Fragment };
|
|
6
|
-
export default {
|
|
7
|
-
render,
|
|
8
|
-
createElement,
|
|
9
|
-
Component,
|
|
10
|
-
Fragment,
|
|
11
|
-
rootClient,
|
|
12
|
-
createRoot,
|
|
13
|
-
};
|