kiru 0.54.3 → 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.
Files changed (335) hide show
  1. package/dist/{appContext.d.ts → appHandle.d.ts} +4 -4
  2. package/dist/appHandle.d.ts.map +1 -0
  3. package/dist/{appContext.js → appHandle.js} +12 -9
  4. package/dist/appHandle.js.map +1 -0
  5. package/dist/components/derive.d.ts +10 -8
  6. package/dist/components/derive.d.ts.map +1 -1
  7. package/dist/components/derive.js +50 -47
  8. package/dist/components/derive.js.map +1 -1
  9. package/dist/components/index.d.ts +0 -1
  10. package/dist/components/index.d.ts.map +1 -1
  11. package/dist/components/index.js +0 -1
  12. package/dist/components/index.js.map +1 -1
  13. package/dist/components/lazy.d.ts.map +1 -1
  14. package/dist/components/lazy.js +5 -4
  15. package/dist/components/lazy.js.map +1 -1
  16. package/dist/components/portal.d.ts.map +1 -1
  17. package/dist/components/portal.js +2 -3
  18. package/dist/components/portal.js.map +1 -1
  19. package/dist/components/transition.d.ts +3 -2
  20. package/dist/components/transition.d.ts.map +1 -1
  21. package/dist/components/transition.js +29 -26
  22. package/dist/components/transition.js.map +1 -1
  23. package/dist/constants.d.ts +1 -5
  24. package/dist/constants.d.ts.map +1 -1
  25. package/dist/constants.js +1 -5
  26. package/dist/constants.js.map +1 -1
  27. package/dist/context.d.ts +1 -1
  28. package/dist/context.d.ts.map +1 -1
  29. package/dist/context.js +25 -19
  30. package/dist/context.js.map +1 -1
  31. package/dist/devtools.d.ts +7 -0
  32. package/dist/devtools.d.ts.map +1 -0
  33. package/dist/devtools.js +15 -0
  34. package/dist/devtools.js.map +1 -0
  35. package/dist/dom.d.ts.map +1 -1
  36. package/dist/dom.js +25 -58
  37. package/dist/dom.js.map +1 -1
  38. package/dist/globalContext.d.ts +15 -16
  39. package/dist/globalContext.d.ts.map +1 -1
  40. package/dist/globalContext.js +36 -46
  41. package/dist/globalContext.js.map +1 -1
  42. package/dist/globals.d.ts +1 -4
  43. package/dist/globals.d.ts.map +1 -1
  44. package/dist/globals.js +1 -4
  45. package/dist/globals.js.map +1 -1
  46. package/dist/headlessRender.d.ts +6 -0
  47. package/dist/headlessRender.d.ts.map +1 -0
  48. package/dist/{recursiveRender.js → headlessRender.js} +17 -16
  49. package/dist/headlessRender.js.map +1 -0
  50. package/dist/hmr.d.ts +5 -7
  51. package/dist/hmr.d.ts.map +1 -1
  52. package/dist/hmr.js +27 -32
  53. package/dist/hmr.js.map +1 -1
  54. package/dist/hooks/index.d.ts +3 -14
  55. package/dist/hooks/index.d.ts.map +1 -1
  56. package/dist/hooks/index.js +3 -14
  57. package/dist/hooks/index.js.map +1 -1
  58. package/dist/hooks/onBeforeMount.d.ts +9 -0
  59. package/dist/hooks/onBeforeMount.d.ts.map +1 -0
  60. package/dist/hooks/onBeforeMount.js +12 -0
  61. package/dist/hooks/onBeforeMount.js.map +1 -0
  62. package/dist/hooks/onCleanup.d.ts +8 -0
  63. package/dist/hooks/onCleanup.d.ts.map +1 -0
  64. package/dist/hooks/onCleanup.js +15 -0
  65. package/dist/hooks/onCleanup.js.map +1 -0
  66. package/dist/hooks/onMount.d.ts +9 -0
  67. package/dist/hooks/onMount.d.ts.map +1 -0
  68. package/dist/hooks/onMount.js +12 -0
  69. package/dist/hooks/onMount.js.map +1 -0
  70. package/dist/hooks/utils.d.ts +2 -62
  71. package/dist/hooks/utils.d.ts.map +1 -1
  72. package/dist/hooks/utils.js +22 -144
  73. package/dist/hooks/utils.js.map +1 -1
  74. package/dist/index.d.ts +8 -4
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +8 -6
  77. package/dist/index.js.map +1 -1
  78. package/dist/profiling.d.ts +15 -14
  79. package/dist/profiling.d.ts.map +1 -1
  80. package/dist/profiling.js +9 -4
  81. package/dist/profiling.js.map +1 -1
  82. package/dist/reconciler.d.ts.map +1 -1
  83. package/dist/reconciler.js +12 -25
  84. package/dist/reconciler.js.map +1 -1
  85. package/dist/ref.d.ts +4 -0
  86. package/dist/ref.d.ts.map +1 -0
  87. package/dist/ref.js +4 -0
  88. package/dist/ref.js.map +1 -0
  89. package/dist/renderToString.js +1 -1
  90. package/dist/renderToString.js.map +1 -1
  91. package/dist/router/context.d.ts.map +1 -1
  92. package/dist/router/context.js +1 -2
  93. package/dist/router/context.js.map +1 -1
  94. package/dist/router/fileRouter.d.ts +1 -1
  95. package/dist/router/fileRouter.d.ts.map +1 -1
  96. package/dist/router/fileRouter.js +17 -11
  97. package/dist/router/fileRouter.js.map +1 -1
  98. package/dist/router/fileRouterController.d.ts.map +1 -1
  99. package/dist/router/fileRouterController.js +68 -55
  100. package/dist/router/fileRouterController.js.map +1 -1
  101. package/dist/router/link.d.ts.map +1 -1
  102. package/dist/router/link.js +19 -23
  103. package/dist/router/link.js.map +1 -1
  104. package/dist/router/server/index.d.ts.map +1 -1
  105. package/dist/router/server/index.js +14 -11
  106. package/dist/router/server/index.js.map +1 -1
  107. package/dist/router/types.d.ts +11 -6
  108. package/dist/router/types.d.ts.map +1 -1
  109. package/dist/scheduler.d.ts +1 -0
  110. package/dist/scheduler.d.ts.map +1 -1
  111. package/dist/scheduler.js +65 -52
  112. package/dist/scheduler.js.map +1 -1
  113. package/dist/signals/base.d.ts +0 -1
  114. package/dist/signals/base.d.ts.map +1 -1
  115. package/dist/signals/base.js +13 -36
  116. package/dist/signals/base.js.map +1 -1
  117. package/dist/signals/computed.d.ts +0 -2
  118. package/dist/signals/computed.d.ts.map +1 -1
  119. package/dist/signals/computed.js +1 -40
  120. package/dist/signals/computed.js.map +1 -1
  121. package/dist/signals/effect.d.ts +15 -14
  122. package/dist/signals/effect.d.ts.map +1 -1
  123. package/dist/signals/effect.js +65 -37
  124. package/dist/signals/effect.js.map +1 -1
  125. package/dist/signals/globals.d.ts +0 -5
  126. package/dist/signals/globals.d.ts.map +1 -1
  127. package/dist/signals/globals.js +0 -6
  128. package/dist/signals/globals.js.map +1 -1
  129. package/dist/signals/index.d.ts +4 -4
  130. package/dist/signals/index.d.ts.map +1 -1
  131. package/dist/signals/index.js +4 -4
  132. package/dist/signals/index.js.map +1 -1
  133. package/dist/signals/{for.d.ts → jsx.d.ts} +8 -1
  134. package/dist/signals/jsx.d.ts.map +1 -0
  135. package/dist/signals/{for.js → jsx.js} +4 -1
  136. package/dist/signals/jsx.js.map +1 -0
  137. package/dist/signals/tracking.d.ts +23 -0
  138. package/dist/signals/tracking.d.ts.map +1 -0
  139. package/dist/signals/tracking.js +51 -0
  140. package/dist/signals/tracking.js.map +1 -0
  141. package/dist/signals/types.d.ts +1 -1
  142. package/dist/signals/types.d.ts.map +1 -1
  143. package/dist/signals/utils.d.ts +2 -1
  144. package/dist/signals/utils.d.ts.map +1 -1
  145. package/dist/signals/utils.js +9 -2
  146. package/dist/signals/utils.js.map +1 -1
  147. package/dist/ssr/client.d.ts +3 -3
  148. package/dist/ssr/client.d.ts.map +1 -1
  149. package/dist/ssr/client.js.map +1 -1
  150. package/dist/ssr/server.js +1 -1
  151. package/dist/ssr/server.js.map +1 -1
  152. package/dist/statefulPromise.d.ts +22 -0
  153. package/dist/statefulPromise.d.ts.map +1 -0
  154. package/dist/statefulPromise.js +94 -0
  155. package/dist/statefulPromise.js.map +1 -0
  156. package/dist/types.d.ts +36 -50
  157. package/dist/types.d.ts.map +1 -1
  158. package/dist/types.dom.d.ts +4 -7
  159. package/dist/types.dom.d.ts.map +1 -1
  160. package/dist/types.utils.d.ts +3 -4
  161. package/dist/types.utils.d.ts.map +1 -1
  162. package/dist/utils/vdom.d.ts +8 -6
  163. package/dist/utils/vdom.d.ts.map +1 -1
  164. package/dist/utils/vdom.js +32 -9
  165. package/dist/utils/vdom.js.map +1 -1
  166. package/dist/viewTransitions.d.ts +7 -0
  167. package/dist/viewTransitions.d.ts.map +1 -0
  168. package/dist/viewTransitions.js +71 -0
  169. package/dist/viewTransitions.js.map +1 -0
  170. package/package.json +1 -1
  171. package/src/{appContext.ts → appHandle.ts} +21 -16
  172. package/src/components/derive.ts +74 -69
  173. package/src/components/index.ts +0 -1
  174. package/src/components/lazy.ts +5 -4
  175. package/src/components/portal.ts +2 -3
  176. package/src/components/transition.ts +33 -35
  177. package/src/constants.ts +0 -8
  178. package/src/context.ts +30 -23
  179. package/src/devtools.ts +16 -0
  180. package/src/dom.ts +29 -63
  181. package/src/globalContext.ts +57 -74
  182. package/src/globals.ts +1 -5
  183. package/src/{recursiveRender.ts → headlessRender.ts} +18 -18
  184. package/src/hmr.ts +29 -38
  185. package/src/hooks/index.ts +3 -14
  186. package/src/hooks/onBeforeMount.ts +12 -0
  187. package/src/hooks/onCleanup.ts +15 -0
  188. package/src/hooks/onMount.ts +12 -0
  189. package/src/hooks/utils.ts +28 -238
  190. package/src/index.ts +14 -6
  191. package/src/profiling.ts +22 -20
  192. package/src/reconciler.ts +18 -30
  193. package/src/ref.ts +6 -0
  194. package/src/renderToString.ts +1 -1
  195. package/src/router/context.ts +1 -2
  196. package/src/router/fileRouter.ts +23 -13
  197. package/src/router/fileRouterController.ts +72 -64
  198. package/src/router/link.ts +11 -25
  199. package/src/router/server/index.ts +24 -13
  200. package/src/router/types.ts +15 -8
  201. package/src/scheduler.ts +74 -71
  202. package/src/signals/base.ts +12 -41
  203. package/src/signals/computed.ts +1 -62
  204. package/src/signals/effect.ts +95 -48
  205. package/src/signals/globals.ts +0 -7
  206. package/src/signals/index.ts +4 -4
  207. package/src/signals/{for.ts → jsx.ts} +10 -0
  208. package/src/signals/tracking.ts +69 -0
  209. package/src/signals/types.ts +1 -1
  210. package/src/signals/utils.ts +9 -1
  211. package/src/ssr/client.ts +4 -4
  212. package/src/ssr/server.ts +2 -2
  213. package/src/statefulPromise.ts +136 -0
  214. package/src/types.dom.ts +4 -8
  215. package/src/types.ts +45 -58
  216. package/src/types.utils.ts +3 -4
  217. package/src/utils/vdom.ts +44 -15
  218. package/src/viewTransitions.ts +88 -0
  219. package/dist/appContext.d.ts.map +0 -1
  220. package/dist/appContext.js.map +0 -1
  221. package/dist/components/memo.d.ts +0 -10
  222. package/dist/components/memo.d.ts.map +0 -1
  223. package/dist/components/memo.js +0 -23
  224. package/dist/components/memo.js.map +0 -1
  225. package/dist/form/index.d.ts +0 -4
  226. package/dist/form/index.d.ts.map +0 -1
  227. package/dist/form/index.js +0 -518
  228. package/dist/form/index.js.map +0 -1
  229. package/dist/form/types.d.ts +0 -122
  230. package/dist/form/types.d.ts.map +0 -1
  231. package/dist/form/types.js +0 -2
  232. package/dist/form/types.js.map +0 -1
  233. package/dist/form/utils.d.ts +0 -3
  234. package/dist/form/utils.d.ts.map +0 -1
  235. package/dist/form/utils.js +0 -16
  236. package/dist/form/utils.js.map +0 -1
  237. package/dist/hooks/useAsync.d.ts +0 -18
  238. package/dist/hooks/useAsync.d.ts.map +0 -1
  239. package/dist/hooks/useAsync.js +0 -96
  240. package/dist/hooks/useAsync.js.map +0 -1
  241. package/dist/hooks/useCallback.d.ts +0 -7
  242. package/dist/hooks/useCallback.d.ts.map +0 -1
  243. package/dist/hooks/useCallback.js +0 -30
  244. package/dist/hooks/useCallback.js.map +0 -1
  245. package/dist/hooks/useContext.d.ts +0 -7
  246. package/dist/hooks/useContext.d.ts.map +0 -1
  247. package/dist/hooks/useContext.js +0 -59
  248. package/dist/hooks/useContext.js.map +0 -1
  249. package/dist/hooks/useEffect.d.ts +0 -8
  250. package/dist/hooks/useEffect.d.ts.map +0 -1
  251. package/dist/hooks/useEffect.js +0 -34
  252. package/dist/hooks/useEffect.js.map +0 -1
  253. package/dist/hooks/useEffectEvent.d.ts +0 -8
  254. package/dist/hooks/useEffectEvent.d.ts.map +0 -1
  255. package/dist/hooks/useEffectEvent.js +0 -23
  256. package/dist/hooks/useEffectEvent.js.map +0 -1
  257. package/dist/hooks/useId.d.ts +0 -8
  258. package/dist/hooks/useId.d.ts.map +0 -1
  259. package/dist/hooks/useId.js +0 -35
  260. package/dist/hooks/useId.js.map +0 -1
  261. package/dist/hooks/useLayoutEffect.d.ts +0 -8
  262. package/dist/hooks/useLayoutEffect.d.ts.map +0 -1
  263. package/dist/hooks/useLayoutEffect.js +0 -34
  264. package/dist/hooks/useLayoutEffect.js.map +0 -1
  265. package/dist/hooks/useMemo.d.ts +0 -8
  266. package/dist/hooks/useMemo.d.ts.map +0 -1
  267. package/dist/hooks/useMemo.js +0 -31
  268. package/dist/hooks/useMemo.js.map +0 -1
  269. package/dist/hooks/usePromise.d.ts +0 -8
  270. package/dist/hooks/usePromise.d.ts.map +0 -1
  271. package/dist/hooks/usePromise.js +0 -90
  272. package/dist/hooks/usePromise.js.map +0 -1
  273. package/dist/hooks/useReducer.d.ts +0 -7
  274. package/dist/hooks/useReducer.d.ts.map +0 -1
  275. package/dist/hooks/useReducer.js +0 -44
  276. package/dist/hooks/useReducer.js.map +0 -1
  277. package/dist/hooks/useRef.d.ts +0 -10
  278. package/dist/hooks/useRef.d.ts.map +0 -1
  279. package/dist/hooks/useRef.js +0 -29
  280. package/dist/hooks/useRef.js.map +0 -1
  281. package/dist/hooks/useState.d.ts +0 -7
  282. package/dist/hooks/useState.d.ts.map +0 -1
  283. package/dist/hooks/useState.js +0 -54
  284. package/dist/hooks/useState.js.map +0 -1
  285. package/dist/hooks/useSyncExternalStore.d.ts +0 -8
  286. package/dist/hooks/useSyncExternalStore.d.ts.map +0 -1
  287. package/dist/hooks/useSyncExternalStore.js +0 -50
  288. package/dist/hooks/useSyncExternalStore.js.map +0 -1
  289. package/dist/hooks/useViewTransition.d.ts +0 -10
  290. package/dist/hooks/useViewTransition.d.ts.map +0 -1
  291. package/dist/hooks/useViewTransition.js +0 -27
  292. package/dist/hooks/useViewTransition.js.map +0 -1
  293. package/dist/recursiveRender.d.ts +0 -7
  294. package/dist/recursiveRender.d.ts.map +0 -1
  295. package/dist/recursiveRender.js.map +0 -1
  296. package/dist/signals/for.d.ts.map +0 -1
  297. package/dist/signals/for.js.map +0 -1
  298. package/dist/signals/watch.d.ts +0 -21
  299. package/dist/signals/watch.d.ts.map +0 -1
  300. package/dist/signals/watch.js +0 -86
  301. package/dist/signals/watch.js.map +0 -1
  302. package/dist/store.d.ts +0 -28
  303. package/dist/store.d.ts.map +0 -1
  304. package/dist/store.js +0 -166
  305. package/dist/store.js.map +0 -1
  306. package/dist/swr.d.ts +0 -63
  307. package/dist/swr.d.ts.map +0 -1
  308. package/dist/swr.js +0 -236
  309. package/dist/swr.js.map +0 -1
  310. package/dist/utils/promise.d.ts +0 -16
  311. package/dist/utils/promise.d.ts.map +0 -1
  312. package/dist/utils/promise.js +0 -14
  313. package/dist/utils/promise.js.map +0 -1
  314. package/src/components/memo.ts +0 -39
  315. package/src/form/index.ts +0 -676
  316. package/src/form/types.ts +0 -262
  317. package/src/form/utils.ts +0 -19
  318. package/src/hooks/useAsync.ts +0 -121
  319. package/src/hooks/useCallback.ts +0 -32
  320. package/src/hooks/useContext.ts +0 -79
  321. package/src/hooks/useEffect.ts +0 -40
  322. package/src/hooks/useEffectEvent.ts +0 -24
  323. package/src/hooks/useId.ts +0 -42
  324. package/src/hooks/useLayoutEffect.ts +0 -43
  325. package/src/hooks/useMemo.ts +0 -34
  326. package/src/hooks/usePromise.ts +0 -126
  327. package/src/hooks/useReducer.ts +0 -50
  328. package/src/hooks/useRef.ts +0 -41
  329. package/src/hooks/useState.ts +0 -62
  330. package/src/hooks/useSyncExternalStore.ts +0 -59
  331. package/src/hooks/useViewTransition.ts +0 -25
  332. package/src/signals/watch.ts +0 -139
  333. package/src/store.ts +0 -245
  334. package/src/swr.ts +0 -351
  335. package/src/utils/promise.ts +0 -26
package/src/scheduler.ts CHANGED
@@ -1,18 +1,9 @@
1
- import type {
2
- ContextProviderNode,
3
- DomVNode,
4
- ErrorBoundaryNode,
5
- FunctionVNode,
6
- } from "./types.utils"
1
+ import type { DomVNode, ErrorBoundaryNode, FunctionVNode } from "./types.utils"
7
2
  import {
8
- $CONTEXT_PROVIDER,
9
3
  $ERROR_BOUNDARY,
10
- $MEMO,
11
4
  CONSECUTIVE_DIRTY_LIMIT,
12
5
  FLAG_DELETION,
13
6
  FLAG_DIRTY,
14
- FLAG_MEMO,
15
- FLAG_NOOP,
16
7
  } from "./constants.js"
17
8
  import {
18
9
  commitDeletion,
@@ -24,7 +15,7 @@ import {
24
15
  } from "./dom.js"
25
16
  import { __DEV__ } from "./env.js"
26
17
  import { KiruError } from "./error.js"
27
- import { hookIndex, node, renderMode } from "./globals.js"
18
+ import { node, renderMode } from "./globals.js"
28
19
  import { hydrationStack } from "./hydration.js"
29
20
  import { reconcileChildren } from "./reconciler.js"
30
21
  import {
@@ -32,17 +23,17 @@ import {
32
23
  latest,
33
24
  traverseApply,
34
25
  isExoticType,
35
- getVNodeAppContext,
26
+ getVNodeApp,
36
27
  findParentErrorBoundary,
37
28
  call,
29
+ propsChanged,
38
30
  } from "./utils/index.js"
39
- import type { AppContext } from "./appContext"
40
- import type { MemoFn } from "./components/memo"
31
+ import type { AppHandle } from "./appHandle"
41
32
  import { isHmrUpdate } from "./hmr.js"
42
33
 
43
34
  type VNode = Kiru.VNode
44
35
 
45
- let appCtx: AppContext | null
36
+ let app: AppHandle | null
46
37
  let treesInProgress: VNode[] = []
47
38
  let isRunningOrQueued = false
48
39
  let nextIdleEffects: (() => void)[] = []
@@ -51,8 +42,8 @@ let isImmediateEffectsMode = false
51
42
  let immediateEffectDirtiedRender = false
52
43
  let isRenderDirtied = false
53
44
  let consecutiveDirtyCount = 0
54
- let preEffects: Array<Function> = []
55
- let postEffects: Array<Function> = []
45
+ let preEffects: Kiru.LifecycleHookCallback[] = []
46
+ let postEffects: Kiru.LifecycleHookCallback[] = []
56
47
  let animationFrameHandle = -1
57
48
 
58
49
  /**
@@ -94,6 +85,14 @@ export function requestUpdate(vNode: VNode): void {
94
85
  queueUpdate(vNode)
95
86
  }
96
87
 
88
+ export function useRequestUpdate(): () => void {
89
+ const n = node.current
90
+ if (!n) {
91
+ throw new Error("useRequestUpdate must be called inside a Kiru component")
92
+ }
93
+ return () => requestUpdate(n)
94
+ }
95
+
97
96
  function queueBeginWork(): void {
98
97
  if (isRunningOrQueued) return
99
98
  isRunningOrQueued = true
@@ -116,7 +115,7 @@ function queueUpdate(vNode: VNode): void {
116
115
  // If this node is currently being rendered, just mark it dirty
117
116
  if (node.current === vNode) {
118
117
  if (__DEV__) {
119
- window.__kiru.profilingContext?.emit("updateDirtied", appCtx!)
118
+ window.__kiru.profilingContext?.emit("updateDirtied", app!)
120
119
  }
121
120
  isRenderDirtied = true
122
121
  return
@@ -146,10 +145,10 @@ function doWork(): void {
146
145
  if (__DEV__) {
147
146
  const n = deletions[0] ?? treesInProgress[0]
148
147
  if (n) {
149
- appCtx = getVNodeAppContext(n)!
150
- window.__kiru.profilingContext?.beginTick(appCtx)
148
+ app = getVNodeApp(n)!
149
+ window.__kiru.profilingContext?.beginTick(app)
151
150
  } else {
152
- appCtx = null
151
+ app = null
153
152
  }
154
153
  }
155
154
 
@@ -190,8 +189,8 @@ function doWork(): void {
190
189
  immediateEffectDirtiedRender = false
191
190
  consecutiveDirtyCount++
192
191
  if (__DEV__) {
193
- window.__kiru.profilingContext?.endTick(appCtx!)
194
- window.__kiru.profilingContext?.emit("updateDirtied", appCtx!)
192
+ window.__kiru.profilingContext?.endTick(app!)
193
+ window.__kiru.profilingContext?.emit("updateDirtied", app!)
195
194
  }
196
195
  return flushSync()
197
196
  }
@@ -200,9 +199,9 @@ function doWork(): void {
200
199
  onWorkFinished()
201
200
  queueMicrotask(() => flushEffects(postEffects))
202
201
  if (__DEV__) {
203
- window.__kiru.emit("update", appCtx!)
204
- window.__kiru.profilingContext?.emit("update", appCtx!)
205
- window.__kiru.profilingContext?.endTick(appCtx!)
202
+ window.__kiru.emit("update", app!)
203
+ window.__kiru.profilingContext?.emit("update", app!)
204
+ window.__kiru.profilingContext?.endTick(app!)
206
205
  }
207
206
  }
208
207
 
@@ -221,13 +220,12 @@ function performUnitOfWork(vNode: VNode): VNode | null {
221
220
  let nextNode: VNode | null = vNode
222
221
  while (nextNode) {
223
222
  // queue effects upon ascent
224
- if (nextNode.immediateEffects) {
225
- preEffects.push(...nextNode.immediateEffects)
226
- nextNode.immediateEffects = undefined
227
- }
228
- if (nextNode.effects) {
229
- postEffects.push(...nextNode.effects)
230
- nextNode.effects = undefined
223
+ const { hooks } = nextNode
224
+ if (hooks) {
225
+ preEffects.push(...hooks.pre)
226
+ postEffects.push(...hooks.post)
227
+ hooks.pre.length = 0
228
+ hooks.post.length = 0
231
229
  }
232
230
 
233
231
  if (nextNode === currentWorkRoot) return null
@@ -246,8 +244,13 @@ function performUnitOfWork(vNode: VNode): VNode | null {
246
244
 
247
245
  function updateVNode(vNode: VNode): VNode | null {
248
246
  const { type, props, prev, flags } = vNode
247
+
249
248
  if (__DEV__ && isHmrUpdate()) {
250
- } else if ((flags & FLAG_DIRTY) === 0 && props === prev?.props) {
249
+ } else if (
250
+ prev &&
251
+ (flags & FLAG_DIRTY) === 0 &&
252
+ (prev.props === props || !propsChanged(prev.props, props))
253
+ ) {
251
254
  return null
252
255
  }
253
256
  try {
@@ -262,7 +265,7 @@ function updateVNode(vNode: VNode): VNode | null {
262
265
  if (__DEV__) {
263
266
  window.__kiru.emit(
264
267
  "error",
265
- appCtx!,
268
+ app!,
266
269
  error instanceof Error ? error : new Error(String(error))
267
270
  )
268
271
  }
@@ -302,16 +305,7 @@ function updateExoticComponent(vNode: VNode): VNode | null {
302
305
  const { props, type } = vNode
303
306
  let children = props.children
304
307
 
305
- if (type === $CONTEXT_PROVIDER) {
306
- const {
307
- props: { dependents, value },
308
- prev,
309
- } = vNode as ContextProviderNode<unknown>
310
-
311
- if (dependents.size && prev && prev.props.value !== value) {
312
- dependents.forEach(queueUpdate)
313
- }
314
- } else if (type === $ERROR_BOUNDARY) {
308
+ if (type === $ERROR_BOUNDARY) {
315
309
  const n = vNode as ErrorBoundaryNode
316
310
  const { error } = n
317
311
  if (error) {
@@ -328,18 +322,8 @@ function updateExoticComponent(vNode: VNode): VNode | null {
328
322
  }
329
323
 
330
324
  function updateFunctionComponent(vNode: FunctionVNode): VNode | null {
331
- const { type, props, subs, prev, flags } = vNode
332
- if (flags & FLAG_MEMO) {
333
- if (
334
- prev &&
335
- (type as MemoFn)[$MEMO](prev.props, props) &&
336
- !(__DEV__ && isHmrUpdate())
337
- ) {
338
- vNode.flags |= FLAG_NOOP
339
- return null
340
- }
341
- vNode.flags &= ~FLAG_NOOP
342
- }
325
+ const { type, props, subs } = vNode
326
+
343
327
  try {
344
328
  node.current = vNode
345
329
  let newChild
@@ -347,7 +331,6 @@ function updateFunctionComponent(vNode: FunctionVNode): VNode | null {
347
331
  do {
348
332
  vNode.flags &= ~FLAG_DIRTY
349
333
  isRenderDirtied = false
350
- hookIndex.current = 0
351
334
 
352
335
  /**
353
336
  * remove previous signal subscriptions (if any) every render.
@@ -364,18 +347,29 @@ function updateFunctionComponent(vNode: FunctionVNode): VNode | null {
364
347
  }
365
348
 
366
349
  if (__DEV__) {
367
- newChild = latest(type)(props)
368
-
369
- if (isHmrUpdate() && vNode.hooks && vNode.hookSig) {
370
- const len = vNode.hooks.length
371
- if (hookIndex.current < len) {
372
- // clean up any hooks that were removed
373
- for (let i = hookIndex.current; i < len; i++) {
374
- const hook = vNode.hooks[i]
375
- hook.cleanup?.()
376
- }
377
- vNode.hooks.length = hookIndex.current
378
- vNode.hookSig.length = hookIndex.current
350
+ if (isHmrUpdate()) {
351
+ const { hooks } = vNode
352
+ if (vNode.cleanups) {
353
+ Object.values(vNode.cleanups).forEach(call)
354
+ delete vNode.cleanups
355
+ }
356
+ if (hooks) {
357
+ const { preCleanups, postCleanups } = hooks
358
+ preCleanups.forEach(call)
359
+ postCleanups.forEach(call)
360
+ preCleanups.length = postCleanups.length = 0
361
+ }
362
+ delete vNode.render
363
+ }
364
+
365
+ if (vNode.render) {
366
+ newChild = vNode.render(props)
367
+ } else {
368
+ newChild = latest(type)(props)
369
+ if (typeof newChild === "function") {
370
+ vNode.subs?.forEach(call)
371
+ vNode.render = newChild as (props: any) => unknown
372
+ newChild = vNode.render(props)
379
373
  }
380
374
  }
381
375
 
@@ -389,7 +383,16 @@ function updateFunctionComponent(vNode: FunctionVNode): VNode | null {
389
383
  }
390
384
  continue
391
385
  }
392
- newChild = type(props)
386
+
387
+ if (vNode.render) {
388
+ newChild = vNode.render(props)
389
+ } else {
390
+ newChild = type(props)
391
+ if (typeof newChild === "function") {
392
+ vNode.render = newChild as (props: any) => unknown
393
+ newChild = vNode.render(props)
394
+ }
395
+ }
393
396
  } while (isRenderDirtied)
394
397
 
395
398
  return (vNode.child = reconcileChildren(vNode, newChild))
@@ -3,13 +3,14 @@ import {
3
3
  safeStringify,
4
4
  sideEffectsEnabled,
5
5
  generateRandomID,
6
+ registerVNodeCleanup,
6
7
  } from "../utils/index.js"
7
8
  import { $HMR_ACCEPT, $SIGNAL } from "../constants.js"
8
9
  import { __DEV__ } from "../env.js"
9
10
  import { node } from "../globals.js"
10
- import { useHook } from "../hooks/utils.js"
11
11
  import { requestUpdate } from "../scheduler.js"
12
- import { tracking, signalSubsMap } from "./globals.js"
12
+ import { signalSubsMap } from "./globals.js"
13
+ import { tracking } from "./tracking.js"
13
14
  import type { SignalSubscriber, ReadonlySignal } from "./types.js"
14
15
  import type { HMRAccept } from "../hmr.js"
15
16
 
@@ -38,6 +39,7 @@ export class Signal<T> {
38
39
  return this as Signal<any>
39
40
  },
40
41
  inject: (prev) => {
42
+ if ("window" in globalThis) window.__kiru.devtools?.untrack(prev)
41
43
  signalSubsMap.get(this.$id)?.clear?.()
42
44
  signalSubsMap.delete(this.$id)
43
45
  this.$id = prev.$id
@@ -56,6 +58,11 @@ export class Signal<T> {
56
58
  } else {
57
59
  this.$subs = new Set()
58
60
  }
61
+
62
+ const n = node.current
63
+ if (n) {
64
+ registerVNodeCleanup(n, this.$id, Signal.dispose.bind(null, this))
65
+ }
59
66
  }
60
67
 
61
68
  get value() {
@@ -175,6 +182,8 @@ export class Signal<T> {
175
182
  }
176
183
 
177
184
  static entangle<T>(signal: Signal<T>) {
185
+ if (tracking.enabled === false) return
186
+
178
187
  const vNode = node.current
179
188
  const trackedSignalObservations = tracking.current()
180
189
  if (trackedSignalObservations) {
@@ -192,6 +201,7 @@ export class Signal<T> {
192
201
  signal.$isDisposed = true
193
202
  if (__DEV__) {
194
203
  signalSubsMap.delete(signal.$id)
204
+ if ("window" in globalThis) window.__kiru.devtools?.untrack(signal)
195
205
  return
196
206
  }
197
207
  signal.$subs!.clear()
@@ -201,42 +211,3 @@ export class Signal<T> {
201
211
  export const signal = <T>(initial: T, displayName?: string) => {
202
212
  return new Signal(initial, displayName)
203
213
  }
204
-
205
- export const useSignal = <T>(initial: T, displayName?: string) => {
206
- return useHook(
207
- "useSignal",
208
- { signal: null! as Signal<T> },
209
- ({ hook, isInit, isHMR }) => {
210
- if (__DEV__) {
211
- if (isInit) {
212
- hook.dev = {
213
- devtools: {
214
- get: () => ({
215
- displayName: hook.signal.displayName,
216
- value: hook.signal.peek(),
217
- }),
218
- set: ({ value }) => {
219
- hook.signal.value = value
220
- },
221
- },
222
- initialArgs: [initial, displayName],
223
- }
224
- }
225
- if (isHMR) {
226
- const [v, name] = hook.dev!.initialArgs
227
- if (v !== initial || name !== displayName) {
228
- hook.cleanup?.()
229
- isInit = true
230
- hook.dev!.initialArgs = [initial, displayName]
231
- }
232
- }
233
- }
234
-
235
- if (isInit) {
236
- hook.cleanup = () => Signal.dispose(hook.signal)
237
- hook.signal = new Signal(initial, displayName)
238
- }
239
- return hook.signal
240
- }
241
- )
242
- }
@@ -1,9 +1,8 @@
1
1
  import { __DEV__ } from "../env.js"
2
2
  import { $HMR_ACCEPT } from "../constants.js"
3
- import { depsRequireChange, useHook } from "../hooks/utils.js"
4
3
  import { call, latest } from "../utils/index.js"
5
4
  import { effectQueue, signalSubsMap } from "./globals.js"
6
- import { executeWithTracking } from "./effect.js"
5
+ import { executeWithTracking } from "./tracking.js"
7
6
  import { Signal } from "./base.js"
8
7
  import type { HMRAccept } from "../hmr.js"
9
8
 
@@ -131,63 +130,3 @@ export function computed<T>(
131
130
  ): ComputedSignal<T> {
132
131
  return new ComputedSignal(getter, displayName)
133
132
  }
134
-
135
- export function useComputed<T>(
136
- getter: (prev?: T) => T,
137
- displayName?: string
138
- ): ComputedSignal<T>
139
-
140
- export function useComputed<T>(
141
- getter: (prev?: T) => T,
142
- deps?: unknown[],
143
- displayName?: string
144
- ): ComputedSignal<T>
145
-
146
- export function useComputed<T>(
147
- getter: (prev?: T) => T,
148
- depsOrDisplayName?: string | unknown[],
149
- displayName?: string
150
- ) {
151
- return useHook(
152
- "useComputedSignal",
153
- {
154
- signal: null! as ComputedSignal<T>,
155
- deps: void 0 as unknown[] | undefined,
156
- },
157
- ({ hook, isInit, isHMR }) => {
158
- if (__DEV__) {
159
- hook.dev = {
160
- devtools: {
161
- get: () => ({
162
- displayName: hook.signal.displayName,
163
- value: hook.signal.peek(),
164
- }),
165
- },
166
- }
167
- if (isHMR) {
168
- // useComputed is always considered side-effecty, so we need to re-run
169
- hook.cleanup?.()
170
- isInit = true
171
- }
172
- }
173
- if (isInit) {
174
- if (typeof depsOrDisplayName === "string") {
175
- displayName = depsOrDisplayName
176
- depsOrDisplayName = void 0
177
- }
178
- hook.deps = depsOrDisplayName
179
- hook.cleanup = () => ComputedSignal.dispose(hook.signal)
180
- hook.signal = computed(getter, displayName)
181
- } else if (
182
- hook.deps &&
183
- typeof depsOrDisplayName !== "string" &&
184
- depsRequireChange(hook.deps, depsOrDisplayName)
185
- ) {
186
- hook.deps = depsOrDisplayName
187
- ComputedSignal.updateGetter(hook.signal, getter)
188
- }
189
-
190
- return hook.signal
191
- }
192
- )
193
- }
@@ -1,61 +1,108 @@
1
- import { node } from "../globals.js"
2
- import { sideEffectsEnabled } from "../utils/index.js"
3
- import { tracking, effectQueue } from "./globals.js"
4
- import { tick } from "./utils.js"
1
+ import { __DEV__ } from "../env.js"
2
+ import { effectQueue } from "./globals.js"
3
+ import { executeWithTracking } from "./tracking.js"
4
+ import {
5
+ latest,
6
+ generateRandomID,
7
+ call,
8
+ registerVNodeCleanup,
9
+ } from "../utils/index.js"
5
10
  import type { Signal } from "./base.js"
6
11
  import type { SignalValues } from "./types.js"
12
+ import { node } from "../globals.js"
7
13
 
8
- type TrackedExecutionContext<T, Deps extends readonly Signal<unknown>[]> = {
9
- id: string
10
- subs: Map<string, Function>
11
- fn: (...values: SignalValues<Deps>) => T
12
- deps?: Deps
13
- onDepChanged: () => void
14
- }
15
-
16
- /**
17
- * Executes an effect function with dependency tracking enabled, and manages
18
- * the effect's subscriptions.
19
- * @param ctx - The execution context
20
- * @returns The result of the effect function
21
- */
22
- export function executeWithTracking<T, Deps extends readonly Signal<unknown>[]>(
23
- ctx: TrackedExecutionContext<T, Deps>
24
- ): T {
25
- const { id, subs, fn, deps = [], onDepChanged } = ctx
26
- let observations: Map<string, Signal<unknown>> | undefined
27
-
28
- effectQueue.delete(id)
29
- const isServer = !!node.current && !sideEffectsEnabled()
30
-
31
- if (!isServer) {
32
- observations = new Map<string, Signal<unknown>>()
33
- tracking.stack.push(observations)
34
- }
14
+ type EffectCallbackReturn = (() => void) | void
35
15
 
36
- const result = fn(...(deps.map((s) => s.value) as SignalValues<Deps>))
16
+ export class Effect<const Deps extends readonly Signal<unknown>[] = []> {
17
+ protected id: string
18
+ protected callback: (...values: SignalValues<Deps>) => EffectCallbackReturn
19
+ protected deps?: Deps
20
+ protected unsubs: Map<string, Function>
21
+ protected cleanup: (() => void) | null
22
+ protected isRunning?: boolean
37
23
 
38
- if (!isServer) {
39
- for (const [id, unsub] of subs) {
40
- if (observations!.has(id)) continue
41
- unsub()
42
- subs.delete(id)
24
+ constructor(
25
+ callback: (...values: SignalValues<Deps>) => EffectCallbackReturn,
26
+ deps?: Deps
27
+ ) {
28
+ this.id = generateRandomID()
29
+ this.callback = callback
30
+ this.deps = deps
31
+ this.unsubs = new Map()
32
+ this.isRunning = false
33
+ this.cleanup = null
34
+ if (__DEV__ && "window" in globalThis) {
35
+ window.__kiru.HMRContext!.moduleEffects.push(this)
36
+ }
37
+ const n = node.current
38
+ if (n) {
39
+ registerVNodeCleanup(n, this.id, this.stop.bind(this))
43
40
  }
41
+ this.start()
42
+ }
44
43
 
45
- const effect = () => {
46
- if (!effectQueue.size) {
47
- queueMicrotask(tick)
48
- }
49
- effectQueue.set(id, onDepChanged)
44
+ start() {
45
+ if (this.isRunning) {
46
+ return
50
47
  }
51
48
 
52
- for (const [id, sig] of observations!) {
53
- if (subs.has(id)) continue
54
- const unsub = sig.subscribe(effect)
55
- subs.set(id, unsub)
49
+ this.isRunning = true
50
+
51
+ // postpone execution during HMR
52
+ if (
53
+ __DEV__ &&
54
+ "window" in globalThis &&
55
+ window.__kiru.HMRContext?.isReplacement()
56
+ ) {
57
+ return queueMicrotask(() => {
58
+ if (this.isRunning) {
59
+ Effect.run(this as Effect)
60
+ }
61
+ })
56
62
  }
57
- tracking.stack.pop()
63
+ Effect.run(this as Effect)
58
64
  }
59
65
 
60
- return result
66
+ stop() {
67
+ effectQueue.delete(this.id)
68
+ this.unsubs.forEach(call)
69
+ this.unsubs.clear()
70
+ this.cleanup?.()
71
+ this.cleanup = null
72
+ this.isRunning = false
73
+ }
74
+
75
+ private static run(watchEffect: Effect) {
76
+ const effect = latest(watchEffect)
77
+ const { id, callback: getter, unsubs: subs, deps } = effect
78
+
79
+ effect.cleanup =
80
+ executeWithTracking({
81
+ id,
82
+ subs,
83
+ fn: getter,
84
+ deps,
85
+ onDepChanged: () => {
86
+ effect.cleanup?.()
87
+ Effect.run(effect)
88
+ },
89
+ }) ?? null
90
+ }
91
+ }
92
+
93
+ export function effect(callback: () => EffectCallbackReturn): Effect
94
+ export function effect<const Deps extends readonly Signal<unknown>[]>(
95
+ dependencies: Deps,
96
+ callback: (...values: SignalValues<Deps>) => EffectCallbackReturn
97
+ ): Effect<Deps>
98
+ export function effect<const Deps extends readonly Signal<unknown>[]>(
99
+ depsOrGetter: Deps | (() => EffectCallbackReturn),
100
+ callback?: (...values: SignalValues<Deps>) => EffectCallbackReturn
101
+ ): Effect<Deps> | Effect {
102
+ if (typeof depsOrGetter === "function") {
103
+ return new Effect<[]>(depsOrGetter)
104
+ }
105
+ const dependencies = depsOrGetter
106
+ const effectGetter = callback!
107
+ return new Effect(effectGetter, dependencies)
61
108
  }
@@ -1,11 +1,4 @@
1
- import type { Signal } from "./base.js"
2
1
  import type { SignalSubscriber } from "./types.js"
3
2
 
4
- export const tracking = {
5
- stack: new Array<Map<string, Signal<unknown>>>(),
6
- current: function (): Map<string, Signal<unknown>> | undefined {
7
- return this.stack[this.stack.length - 1]
8
- },
9
- }
10
3
  export const effectQueue = new Map<string, Function>()
11
4
  export const signalSubsMap: Map<string, Set<SignalSubscriber<any>>> = new Map()
@@ -4,9 +4,9 @@
4
4
  * 2. global computed will lose its vNode subscription on HMR
5
5
  * */
6
6
 
7
- export { Signal, signal, useSignal } from "./base.js"
8
- export { ComputedSignal, computed, useComputed } from "./computed.js"
9
- export { WatchEffect, watch, useWatch } from "./watch.js"
7
+ export { Signal, signal } from "./base.js"
8
+ export { ComputedSignal, computed } from "./computed.js"
9
+ export { Effect, effect } from "./effect.js"
10
10
  export { unwrap, tick } from "./utils.js"
11
- export * from "./for.js"
11
+ export * from "./jsx.js"
12
12
  export * from "./types.js"
@@ -1,3 +1,4 @@
1
+ import { Signalable } from "../types.js"
1
2
  import type { Signal } from "./base.js"
2
3
  import { unwrap } from "./utils.js"
3
4
 
@@ -28,3 +29,12 @@ export function For<T extends Signal<any[]> | unknown[]>({
28
29
  if (items.length === 0) return fallback
29
30
  return items.map(children)
30
31
  }
32
+
33
+ export interface ShowProps {
34
+ children: JSX.Element
35
+ when: Signalable<unknown>
36
+ fallback?: JSX.Element
37
+ }
38
+ export function Show({ children, when, fallback }: ShowProps): JSX.Element {
39
+ return !!unwrap(when, true) ? children : fallback
40
+ }