@unsetsoft/ryunixjs 1.0.2 → 1.0.3-nightly.3
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 +308 -377
- package/package.json +2 -2
- package/src/lib/commits.js +73 -29
- package/src/lib/components.js +16 -21
- package/src/lib/createElement.js +25 -28
- package/src/lib/dom.js +61 -38
- package/src/lib/effects.js +35 -10
- package/src/lib/hooks.js +36 -157
- package/src/lib/index.js +2 -19
- package/src/lib/reconciler.js +3 -3
- package/src/lib/render.js +22 -16
- package/src/lib/workers.js +16 -28
- package/src/main.js +0 -2
- package/src/utils/index.js +17 -8
- package/dist/cj/Ryunix.js +0 -702
package/src/lib/hooks.js
CHANGED
|
@@ -1,35 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { vars } from '../utils/index'
|
|
2
2
|
import { isEqual } from 'lodash'
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
* @param initial - The initial value of the state for the hook.
|
|
7
|
-
* @returns The `useStore` function returns an array with two elements: the current state value and a
|
|
8
|
-
* `setState` function that can be used to update the state.
|
|
5
|
+
* useStore is similar to useState in React, managing local state within a functional component.
|
|
9
6
|
*/
|
|
10
7
|
const useStore = (initial) => {
|
|
11
|
-
const oldHook =
|
|
12
|
-
|
|
13
|
-
vars.wipFiber.alternate.hooks &&
|
|
14
|
-
vars.wipFiber.alternate.hooks[vars.hookIndex]
|
|
15
|
-
const hook = {
|
|
16
|
-
state: oldHook ? oldHook.state : initial,
|
|
17
|
-
queue: [],
|
|
18
|
-
}
|
|
8
|
+
const oldHook = vars.workInProgressFiber.alternate?.hooks?.[vars.hookIndex]
|
|
9
|
+
const hook = { state: oldHook ? oldHook.state : initial, queue: [] }
|
|
19
10
|
|
|
20
11
|
const actions = oldHook ? oldHook.queue : []
|
|
21
12
|
actions.forEach((action) => {
|
|
22
|
-
hook.state =
|
|
23
|
-
typeof action === STRINGS.function ? action(hook.state) : action
|
|
13
|
+
hook.state = typeof action === 'function' ? action(hook.state) : action
|
|
24
14
|
})
|
|
25
15
|
|
|
26
|
-
/**
|
|
27
|
-
* The function `setState` updates the state of a component in Ryunix by adding an action to a queue
|
|
28
|
-
* and setting up a new work-in-progress root.
|
|
29
|
-
* @param action - The `action` parameter is an object that represents a state update to be performed
|
|
30
|
-
* on a component. It contains information about the type of update to be performed and any new data
|
|
31
|
-
* that needs to be applied to the component's state.
|
|
32
|
-
*/
|
|
33
16
|
const setState = (action) => {
|
|
34
17
|
hook.queue.push(action)
|
|
35
18
|
vars.wipRoot = {
|
|
@@ -41,162 +24,58 @@ const useStore = (initial) => {
|
|
|
41
24
|
vars.deletions = []
|
|
42
25
|
}
|
|
43
26
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
vars.hookIndex++
|
|
47
|
-
}
|
|
27
|
+
vars.workInProgressFiber.hooks.push(hook)
|
|
28
|
+
vars.hookIndex++
|
|
48
29
|
return [hook.state, setState]
|
|
49
30
|
}
|
|
50
31
|
|
|
51
32
|
/**
|
|
52
|
-
*
|
|
53
|
-
* @param effect - The effect function that will be executed after the component has rendered or when
|
|
54
|
-
* the dependencies have changed. It can perform side effects such as fetching data, updating the DOM,
|
|
55
|
-
* or subscribing to events.
|
|
56
|
-
* @param deps - An array of dependencies that the effect depends on. If any of the dependencies change
|
|
57
|
-
* between renders, the effect will be re-run. If the array is empty, the effect will only run once on
|
|
58
|
-
* mount and never again.
|
|
33
|
+
* useEffect runs side effects after rendering based on dependencies.
|
|
59
34
|
*/
|
|
60
|
-
|
|
61
35
|
const useEffect = (callback, deps) => {
|
|
62
|
-
const oldHook =
|
|
63
|
-
|
|
64
|
-
vars.wipFiber.alternate.hooks &&
|
|
65
|
-
vars.wipFiber.alternate.hooks[vars.hookIndex]
|
|
66
|
-
|
|
67
|
-
const hook = {
|
|
68
|
-
type: RYUNIX_TYPES.RYUNIX_EFFECT,
|
|
69
|
-
deps,
|
|
70
|
-
}
|
|
36
|
+
const oldHook = vars.workInProgressFiber.alternate?.hooks?.[vars.hookIndex]
|
|
37
|
+
const hook = { type: 'effect', deps }
|
|
71
38
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
callback()
|
|
75
|
-
|
|
76
|
-
if (!isEqual(oldHook.deps, hook.deps)) {
|
|
77
|
-
callback()
|
|
78
|
-
}
|
|
39
|
+
const hasChanged = !oldHook || !isEqual(oldHook.deps, deps)
|
|
40
|
+
if (hasChanged) {
|
|
41
|
+
const cleanup = callback()
|
|
42
|
+
hook.cleanup = cleanup
|
|
79
43
|
}
|
|
80
44
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
vars.hookIndex++
|
|
84
|
-
}
|
|
45
|
+
vars.workInProgressFiber.hooks.push(hook)
|
|
46
|
+
vars.hookIndex++
|
|
85
47
|
}
|
|
86
48
|
|
|
87
49
|
/**
|
|
88
|
-
*
|
|
89
|
-
* and stores them in a hook for easy access.
|
|
90
|
-
* @returns The `useQuery` function returns the `query` property of the `hook` object.
|
|
50
|
+
* useRef creates a mutable ref object to store values across renders.
|
|
91
51
|
*/
|
|
92
|
-
const
|
|
93
|
-
const oldHook =
|
|
94
|
-
|
|
95
|
-
vars.wipFiber.alternate.hooks &&
|
|
96
|
-
vars.wipFiber.alternate.hooks[vars.hookIndex]
|
|
97
|
-
|
|
98
|
-
const hasOld = oldHook ? oldHook : undefined
|
|
99
|
-
|
|
100
|
-
const urlSearchParams = new URLSearchParams(window.location.search)
|
|
101
|
-
const params = Object.fromEntries(urlSearchParams.entries())
|
|
102
|
-
const Query = hasOld ? hasOld : params
|
|
103
|
-
|
|
104
|
-
const hook = {
|
|
105
|
-
type: RYUNIX_TYPES.RYUNIX_URL_QUERY,
|
|
106
|
-
query: Query,
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (vars.wipFiber.hooks) {
|
|
110
|
-
vars.wipFiber.hooks.push(hook)
|
|
111
|
-
vars.hookIndex++
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return hook.query
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const useRef = (initial) => {
|
|
118
|
-
const oldHook =
|
|
119
|
-
vars.wipFiber.alternate &&
|
|
120
|
-
vars.wipFiber.alternate.hooks &&
|
|
121
|
-
vars.wipFiber.alternate.hooks[vars.hookIndex]
|
|
122
|
-
|
|
123
|
-
const hook = {
|
|
124
|
-
type: RYUNIX_TYPES.RYUNIX_REF,
|
|
125
|
-
value: oldHook ? oldHook.value : { current: initial },
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (vars.wipFiber.hooks) {
|
|
129
|
-
vars.wipFiber.hooks.push(hook)
|
|
130
|
-
vars.hookIndex++
|
|
131
|
-
}
|
|
52
|
+
const useRef = (initialValue) => {
|
|
53
|
+
const oldHook = vars.workInProgressFiber.alternate?.hooks?.[vars.hookIndex]
|
|
54
|
+
const hook = { value: oldHook ? oldHook.value : { current: initialValue } }
|
|
132
55
|
|
|
56
|
+
vars.workInProgressFiber.hooks.push(hook)
|
|
57
|
+
vars.hookIndex++
|
|
133
58
|
return hook.value
|
|
134
59
|
}
|
|
135
60
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
61
|
+
/**
|
|
62
|
+
* useMemo memoizes a value to avoid recomputations.
|
|
63
|
+
*/
|
|
64
|
+
const useMemo = (computeFn, deps) => {
|
|
65
|
+
const oldHook = vars.workInProgressFiber.alternate?.hooks?.[vars.hookIndex]
|
|
142
66
|
const hook = {
|
|
143
|
-
type: RYUNIX_TYPES.RYUNIX_MEMO,
|
|
144
|
-
value: null,
|
|
145
67
|
deps,
|
|
68
|
+
value: oldHook && isEqual(deps, oldHook.deps) ? oldHook.value : computeFn(),
|
|
146
69
|
}
|
|
147
70
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
hook.value = oldHook.value
|
|
151
|
-
} else {
|
|
152
|
-
hook.value = comp()
|
|
153
|
-
}
|
|
154
|
-
} else {
|
|
155
|
-
hook.value = comp()
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (vars.wipFiber.hooks) {
|
|
159
|
-
vars.wipFiber.hooks.push(hook)
|
|
160
|
-
vars.hookIndex++
|
|
161
|
-
}
|
|
162
|
-
|
|
71
|
+
vars.workInProgressFiber.hooks.push(hook)
|
|
72
|
+
vars.hookIndex++
|
|
163
73
|
return hook.value
|
|
164
74
|
}
|
|
165
|
-
const useCallback = (callback, deps) => {
|
|
166
|
-
return useMemo(() => callback, deps)
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const useRouter = (routes) => {
|
|
170
|
-
const [location, setLocation] = useStore(window.location.pathname)
|
|
171
75
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
useEffect(() => {
|
|
178
|
-
const onPopState = () => {
|
|
179
|
-
setLocation(window.location.pathname)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
window.addEventListener('popstate', onPopState)
|
|
183
|
-
return () => {
|
|
184
|
-
window.removeEventListener('popstate', onPopState)
|
|
185
|
-
}
|
|
186
|
-
}, [])
|
|
187
|
-
|
|
188
|
-
const currentRoute = routes.find((route) => route.path === location)
|
|
189
|
-
const Children = () => (currentRoute ? currentRoute.component : null)
|
|
190
|
-
|
|
191
|
-
return { Children, navigate }
|
|
192
|
-
}
|
|
76
|
+
/**
|
|
77
|
+
* useCallback memoizes a callback function to avoid unnecessary recreations.
|
|
78
|
+
*/
|
|
79
|
+
const useCallback = (callback, deps) => useMemo(() => callback, deps)
|
|
193
80
|
|
|
194
|
-
export {
|
|
195
|
-
useStore,
|
|
196
|
-
useEffect,
|
|
197
|
-
useQuery,
|
|
198
|
-
useRef,
|
|
199
|
-
useMemo,
|
|
200
|
-
useCallback,
|
|
201
|
-
useRouter,
|
|
202
|
-
}
|
|
81
|
+
export { useStore, useEffect, useRef, useMemo, useCallback }
|
package/src/lib/index.js
CHANGED
|
@@ -1,30 +1,13 @@
|
|
|
1
1
|
import { createElement, cloneElement, Fragment } from './createElement'
|
|
2
2
|
import { render, init } from './render'
|
|
3
|
-
import {
|
|
4
|
-
useStore,
|
|
5
|
-
useEffect,
|
|
6
|
-
useQuery,
|
|
7
|
-
useRef,
|
|
8
|
-
useMemo,
|
|
9
|
-
useCallback,
|
|
10
|
-
useRouter,
|
|
11
|
-
} from './hooks'
|
|
3
|
+
import { useStore, useEffect, useRef, useMemo, useCallback } from './hooks'
|
|
12
4
|
import * as Dom from './dom'
|
|
13
5
|
import * as Workers from './workers'
|
|
14
6
|
import * as Reconciler from './reconciler'
|
|
15
7
|
import * as Components from './components'
|
|
16
8
|
import * as Commits from './commits'
|
|
17
9
|
|
|
18
|
-
export {
|
|
19
|
-
useStore,
|
|
20
|
-
useEffect,
|
|
21
|
-
useQuery,
|
|
22
|
-
useRef,
|
|
23
|
-
useMemo,
|
|
24
|
-
useCallback,
|
|
25
|
-
useRouter,
|
|
26
|
-
Fragment,
|
|
27
|
-
}
|
|
10
|
+
export { useStore, useEffect, useRef, useMemo, useCallback, Fragment }
|
|
28
11
|
|
|
29
12
|
export default {
|
|
30
13
|
createElement,
|
package/src/lib/reconciler.js
CHANGED
|
@@ -22,9 +22,9 @@ const reconcileChildren = (wipFiber, elements) => {
|
|
|
22
22
|
|
|
23
23
|
if (sameType) {
|
|
24
24
|
newFiber = {
|
|
25
|
-
type: oldFiber
|
|
25
|
+
type: oldFiber.type,
|
|
26
26
|
props: element.props,
|
|
27
|
-
dom: oldFiber
|
|
27
|
+
dom: oldFiber.dom,
|
|
28
28
|
parent: wipFiber,
|
|
29
29
|
alternate: oldFiber,
|
|
30
30
|
effectTag: EFFECT_TAGS.UPDATE,
|
|
@@ -40,7 +40,7 @@ const reconcileChildren = (wipFiber, elements) => {
|
|
|
40
40
|
effectTag: EFFECT_TAGS.PLACEMENT,
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
-
if (
|
|
43
|
+
if (!element && oldFiber) {
|
|
44
44
|
oldFiber.effectTag = EFFECT_TAGS.DELETION
|
|
45
45
|
vars.deletions.push(oldFiber)
|
|
46
46
|
}
|
package/src/lib/render.js
CHANGED
|
@@ -1,33 +1,39 @@
|
|
|
1
1
|
import { vars } from '../utils/index'
|
|
2
|
+
import { commitRoot } from './commits'
|
|
3
|
+
import { performUnitOfWork, workLoop } from './workers'
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
|
-
*
|
|
5
|
-
* @param element - The element parameter is the component or element that needs to be rendered in the
|
|
6
|
-
* container. It could be a Ryunix component or a DOM element.
|
|
7
|
-
* @param container - The container parameter is the DOM element where the rendered element will be
|
|
8
|
-
* appended to. this parameter is optional if you use createRoot().
|
|
6
|
+
* Renders an element into the specified container or the default root element.
|
|
9
7
|
*/
|
|
10
8
|
const render = (element, container) => {
|
|
9
|
+
if (!element || !container) {
|
|
10
|
+
console.error('Invalid element or container provided.')
|
|
11
|
+
return
|
|
12
|
+
}
|
|
13
|
+
|
|
11
14
|
vars.wipRoot = {
|
|
12
|
-
dom:
|
|
13
|
-
props: {
|
|
14
|
-
children: [element],
|
|
15
|
-
},
|
|
15
|
+
dom: container,
|
|
16
|
+
props: { children: [element] },
|
|
16
17
|
alternate: vars.currentRoot,
|
|
17
18
|
}
|
|
19
|
+
|
|
18
20
|
vars.deletions = []
|
|
19
21
|
vars.nextUnitOfWork = vars.wipRoot
|
|
22
|
+
requestIdleCallback(workLoop)
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
/**
|
|
23
|
-
*
|
|
24
|
-
* @example Ryunix.init("root") -> <div id="root" />
|
|
25
|
-
* @param root - The parameter "root" is the id of the HTML element that will serve as the container
|
|
26
|
-
* for the root element.
|
|
26
|
+
* Initializes the app with a root container.
|
|
27
27
|
*/
|
|
28
|
-
const init = (
|
|
29
|
-
const rootElement =
|
|
30
|
-
|
|
28
|
+
const init = (rootId = '__ryunix') => {
|
|
29
|
+
const rootElement = document.getElementById(rootId)
|
|
30
|
+
if (!rootElement) {
|
|
31
|
+
console.error(`Root element with ID '${rootId}' not found.`)
|
|
32
|
+
return null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
vars.containerRoot = rootElement
|
|
36
|
+
console.log(`Ryunix initialized with root ID: ${rootId}`)
|
|
31
37
|
return this
|
|
32
38
|
}
|
|
33
39
|
|
package/src/lib/workers.js
CHANGED
|
@@ -3,15 +3,13 @@ import { updateFunctionComponent, updateHostComponent } from './components'
|
|
|
3
3
|
import { vars } from '../utils/index'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* browser needs to yield
|
|
8
|
-
* @param deadline -
|
|
9
|
-
* browser has to perform work before it needs to handle other tasks. It has a `timeRemaining()` method
|
|
10
|
-
* that returns the amount of time remaining before the deadline is reached. The `shouldYield` variable
|
|
11
|
-
* is used to determine
|
|
6
|
+
* Main work loop that processes the fiber tree using requestIdleCallback.
|
|
7
|
+
* It continues processing until all units of work are completed or the browser needs to yield.
|
|
8
|
+
* @param {IdleDeadline} deadline - Represents the time remaining for the browser to execute tasks before yielding.
|
|
12
9
|
*/
|
|
13
10
|
const workLoop = (deadline) => {
|
|
14
11
|
let shouldYield = false
|
|
12
|
+
|
|
15
13
|
while (vars.nextUnitOfWork && !shouldYield) {
|
|
16
14
|
vars.nextUnitOfWork = performUnitOfWork(vars.nextUnitOfWork)
|
|
17
15
|
shouldYield = deadline.timeRemaining() < 1
|
|
@@ -24,38 +22,28 @@ const workLoop = (deadline) => {
|
|
|
24
22
|
requestIdleCallback(workLoop)
|
|
25
23
|
}
|
|
26
24
|
|
|
25
|
+
// Start the work loop for the first time
|
|
27
26
|
requestIdleCallback(workLoop)
|
|
28
27
|
|
|
29
28
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* @param fiber -
|
|
33
|
-
*
|
|
34
|
-
* parent, child, and sibling fibers. The `performUnitOfWork` function takes a fiber as a parameter and
|
|
35
|
-
* performs work
|
|
36
|
-
* @returns The function `performUnitOfWork` returns the next fiber to be processed. If the current
|
|
37
|
-
* fiber has a child, it returns the child. Otherwise, it looks for the next sibling of the current
|
|
38
|
-
* fiber. If there are no more siblings, it goes up the tree to the parent and looks for the next
|
|
39
|
-
* sibling of the parent. The function returns `undefined` if there are no more fibers to process.
|
|
29
|
+
* Processes a unit of work in the fiber tree.
|
|
30
|
+
* Decides whether to update a function component or a host component (DOM element).
|
|
31
|
+
* @param {Object} fiber - The current fiber representing a component and its state in the virtual DOM tree.
|
|
32
|
+
* @returns {null} The next fiber to process, or undefined if there are no more.
|
|
40
33
|
*/
|
|
41
34
|
const performUnitOfWork = (fiber) => {
|
|
42
35
|
const isFunctionComponent = fiber.type instanceof Function
|
|
43
|
-
|
|
44
|
-
updateFunctionComponent(fiber)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (fiber.child) {
|
|
49
|
-
return fiber.child
|
|
50
|
-
}
|
|
36
|
+
isFunctionComponent
|
|
37
|
+
? updateFunctionComponent(fiber)
|
|
38
|
+
: updateHostComponent(fiber)
|
|
39
|
+
|
|
40
|
+
if (fiber.child) return fiber.child
|
|
51
41
|
let nextFiber = fiber
|
|
52
42
|
while (nextFiber) {
|
|
53
|
-
if (nextFiber.sibling)
|
|
54
|
-
return nextFiber.sibling
|
|
55
|
-
}
|
|
43
|
+
if (nextFiber.sibling) return nextFiber.sibling
|
|
56
44
|
nextFiber = nextFiber.parent
|
|
57
45
|
}
|
|
58
|
-
return
|
|
46
|
+
return null
|
|
59
47
|
}
|
|
60
48
|
|
|
61
49
|
export { performUnitOfWork, workLoop }
|
package/src/main.js
CHANGED
package/src/utils/index.js
CHANGED
|
@@ -3,12 +3,13 @@ const vars = {
|
|
|
3
3
|
nextUnitOfWork: undefined,
|
|
4
4
|
currentRoot: undefined,
|
|
5
5
|
wipRoot: undefined,
|
|
6
|
-
deletions:
|
|
7
|
-
|
|
8
|
-
hookIndex:
|
|
6
|
+
deletions: [],
|
|
7
|
+
workInProgressFiber: undefined,
|
|
8
|
+
hookIndex: 0,
|
|
9
|
+
errorBoundary: null, // New property to hold error boundary references
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
const
|
|
12
|
+
const capitalLetterRegex = /[A-Z]/g
|
|
12
13
|
|
|
13
14
|
const RYUNIX_TYPES = Object.freeze({
|
|
14
15
|
TEXT_ELEMENT: Symbol('text.element'),
|
|
@@ -16,6 +17,7 @@ const RYUNIX_TYPES = Object.freeze({
|
|
|
16
17
|
RYUNIX_MEMO: Symbol('ryunix.memo'),
|
|
17
18
|
RYUNIX_URL_QUERY: Symbol('ryunix.urlQuery'),
|
|
18
19
|
RYUNIX_REF: Symbol('ryunix.ref'),
|
|
20
|
+
RYUNIX_ERROR_BOUNDARY: Symbol('ryunix.errorBoundary'), // New Error Boundary Type
|
|
19
21
|
})
|
|
20
22
|
|
|
21
23
|
const STRINGS = Object.freeze({
|
|
@@ -33,9 +35,16 @@ const OLD_STRINGS = Object.freeze({
|
|
|
33
35
|
})
|
|
34
36
|
|
|
35
37
|
const EFFECT_TAGS = Object.freeze({
|
|
36
|
-
PLACEMENT: Symbol(),
|
|
37
|
-
UPDATE: Symbol(),
|
|
38
|
-
DELETION: Symbol(),
|
|
38
|
+
PLACEMENT: Symbol('placement'),
|
|
39
|
+
UPDATE: Symbol('update'),
|
|
40
|
+
DELETION: Symbol('deletion'),
|
|
39
41
|
})
|
|
40
42
|
|
|
41
|
-
export {
|
|
43
|
+
export {
|
|
44
|
+
vars,
|
|
45
|
+
capitalLetterRegex,
|
|
46
|
+
RYUNIX_TYPES,
|
|
47
|
+
EFFECT_TAGS,
|
|
48
|
+
STRINGS,
|
|
49
|
+
OLD_STRINGS,
|
|
50
|
+
}
|