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/dom.ts CHANGED
@@ -3,9 +3,11 @@ import {
3
3
  commitSnapshot,
4
4
  propFilters,
5
5
  propToHtmlAttr,
6
- getVNodeAppContext,
6
+ getVNodeApp,
7
7
  setRef,
8
8
  isValidTextChild,
9
+ registerVNodeCleanup,
10
+ call,
9
11
  } from "./utils/index.js"
10
12
  import {
11
13
  booleanAttributes,
@@ -13,7 +15,6 @@ import {
13
15
  FLAG_UPDATE,
14
16
  FLAG_STATIC_DOM,
15
17
  svgTags,
16
- FLAG_NOOP,
17
18
  EVENT_PREFIX_REGEX,
18
19
  } from "./constants.js"
19
20
  import { Signal } from "./signals/base.js"
@@ -30,7 +31,7 @@ import type {
30
31
  SomeDom,
31
32
  SomeElement,
32
33
  } from "./types.utils"
33
- import type { AppContext } from "./appContext.js"
34
+ import type { AppHandle } from "./appHandle.js"
34
35
 
35
36
  export {
36
37
  commitWork,
@@ -49,6 +50,8 @@ type HostNode = {
49
50
 
50
51
  let persistingFocus = false
51
52
  let didBlurActiveElement = false
53
+ const postHookCleanups: (() => void)[] = []
54
+
52
55
  const placementBlurHandler = (event: Event) => {
53
56
  event.preventDefault()
54
57
  event.stopPropagation()
@@ -73,6 +76,10 @@ function onAfterFlushDomChanges() {
73
76
  didBlurActiveElement = false
74
77
  }
75
78
  persistingFocus = false
79
+ queueMicrotask(() => {
80
+ postHookCleanups.forEach(call)
81
+ postHookCleanups.length = 0
82
+ })
76
83
  }
77
84
 
78
85
  function createDom(vNode: DomVNode): SomeDom {
@@ -243,15 +250,15 @@ function setSignalProp(
243
250
  prevValue: unknown
244
251
  ) {
245
252
  const [modifier, attr] = key.split(":")
246
- const cleanups = (vNode.cleanups ??= {})
247
253
  if (modifier !== "bind") {
248
- cleanups[key] = signal.subscribe((value, prev) => {
254
+ const unsub = signal.subscribe((value, prev) => {
249
255
  if (value === prev) return
250
256
  setProp(dom, key, value, prev)
251
257
  if (__DEV__) {
252
258
  emitSignalAttrUpdate(vNode)
253
259
  }
254
260
  })
261
+ registerVNodeCleanup(vNode, key, unsub)
255
262
  } else {
256
263
  const evtName = bindAttrToEventMap[attr]
257
264
  if (!evtName) {
@@ -262,7 +269,8 @@ function setSignalProp(
262
269
  }
263
270
  return
264
271
  }
265
- cleanups[key] = bindElementProp(vNode, dom, attr, evtName, signal)
272
+ const cleanup = bindElementProp(vNode, dom, attr, evtName, signal)
273
+ registerVNodeCleanup(vNode, key, cleanup)
266
274
  }
267
275
 
268
276
  const value = signal.peek()
@@ -355,23 +363,21 @@ function createInputValueReader(
355
363
  }
356
364
 
357
365
  function emitSignalAttrUpdate(vNode: VNode) {
358
- window.__kiru.profilingContext?.emit(
359
- "signalAttrUpdate",
360
- getVNodeAppContext(vNode)!
361
- )
366
+ window.__kiru.profilingContext?.emit("signalAttrUpdate", getVNodeApp(vNode)!)
362
367
  }
363
368
 
364
369
  function subTextNode(vNode: VNode, textNode: Text, signal: Signal<string>) {
365
- ;(vNode.cleanups ??= {}).nodeValue = signal.subscribe((value, prev) => {
370
+ const cleanup = signal.subscribe((value, prev) => {
366
371
  if (value === prev) return
367
372
  textNode.nodeValue = value
368
373
  if (__DEV__) {
369
374
  window.__kiru.profilingContext?.emit(
370
375
  "signalTextUpdate",
371
- getVNodeAppContext(vNode)!
376
+ getVNodeApp(vNode)!
372
377
  )
373
378
  }
374
379
  })
380
+ registerVNodeCleanup(vNode, "nodeValue", cleanup)
375
381
  }
376
382
 
377
383
  /**
@@ -684,15 +690,6 @@ function commitWork_impl(
684
690
  ) {
685
691
  let child: VNode | null = vNode.child
686
692
  while (child) {
687
- if (child.flags & FLAG_NOOP) {
688
- if (child.flags & FLAG_PLACEMENT) {
689
- placeAndCommitNoopChildren(child, currentHostNode)
690
- }
691
- commitSnapshot(child)
692
- child = child.sibling
693
- continue
694
- }
695
-
696
693
  if (child.dom) {
697
694
  commitWork_impl(child, { node: child as ElementVNode }, false)
698
695
  if (!(child.flags & FLAG_STATIC_DOM)) {
@@ -733,25 +730,31 @@ function commitDeletion(vNode: VNode) {
733
730
  if (vNode === vNode.parent?.child) {
734
731
  vNode.parent.child = vNode.sibling
735
732
  }
736
- let ctx: AppContext
733
+ let app: AppHandle
737
734
  if (__DEV__) {
738
- ctx = getVNodeAppContext(vNode)!
735
+ app = getVNodeApp(vNode)!
739
736
  }
740
737
  traverseApply(vNode, (node) => {
741
738
  const {
742
- hooks,
743
739
  subs,
744
740
  cleanups,
745
741
  dom,
746
742
  props: { ref },
743
+ hooks,
747
744
  } = node
748
745
 
749
746
  subs?.forEach((unsub) => unsub())
750
747
  if (cleanups) Object.values(cleanups).forEach((c) => c())
751
- while (hooks?.length) hooks.pop()!.cleanup?.()
748
+ if (hooks) {
749
+ const { preCleanups, postCleanups } = hooks
750
+
751
+ preCleanups.forEach(call)
752
+ postHookCleanups.push(...postCleanups)
753
+ preCleanups.length = postCleanups.length = 0
754
+ }
752
755
 
753
756
  if (__DEV__) {
754
- window.__kiru.profilingContext?.emit("removeNode", ctx)
757
+ window.__kiru.profilingContext?.emit("removeNode", app)
755
758
  if (dom instanceof Element) {
756
759
  delete dom.__kiruNode
757
760
  }
@@ -770,40 +773,3 @@ function commitDeletion(vNode: VNode) {
770
773
 
771
774
  vNode.parent = null
772
775
  }
773
-
774
- function placeAndCommitNoopChildren(
775
- parent: VNode,
776
- currentHostNode: HostNode
777
- ): void {
778
- if (!parent.child) return
779
-
780
- const domChildren: SomeDom[] = []
781
- collectDomNodes(parent.child, domChildren)
782
- if (domChildren.length === 0) return
783
-
784
- const { node, lastChild } = currentHostNode
785
- if (lastChild) {
786
- lastChild.after(...domChildren)
787
- } else {
788
- const nextSiblingDom = getNextSiblingDom(parent, node)
789
- const parentDom = node.dom
790
- if (nextSiblingDom) {
791
- nextSiblingDom.before(...domChildren)
792
- } else {
793
- parentDom.append(...domChildren)
794
- }
795
- }
796
- currentHostNode.lastChild = domChildren[domChildren.length - 1]
797
- }
798
-
799
- function collectDomNodes(firstChild: VNode, children: SomeDom[]): void {
800
- let child: VNode | null = firstChild
801
- while (child) {
802
- if (child.dom) {
803
- children.push(child.dom)
804
- } else if (child.child) {
805
- collectDomNodes(child.child, children)
806
- }
807
- child = child.sibling
808
- }
809
- }
@@ -3,57 +3,11 @@ import { createHMRContext } from "./hmr.js"
3
3
  import { createProfilingContext } from "./profiling.js"
4
4
  import { fileRouterInstance } from "./router/globals.js"
5
5
  import type { FileRouterController } from "./router/fileRouterController"
6
- import type { AppContext } from "./appContext"
7
- import type { Store } from "./store"
8
- import type { SWRCache } from "./swr"
6
+ import type { AppHandle } from "./appHandle"
9
7
  import type { requestUpdate } from "./index.js"
10
8
 
11
9
  export { createKiruGlobalContext, type GlobalKiruEvent, type KiruGlobalContext }
12
10
 
13
- interface ReactiveMap<V> {
14
- add(key: string, value: V): void
15
- delete(key: string): void
16
- subscribe(cb: (value: Record<string, V>) => void): () => void
17
- readonly size: number
18
- }
19
-
20
- function createReactiveMap<V>(): ReactiveMap<V> {
21
- const map = new Map<string, V>()
22
- const listeners = new Set<(value: Record<string, V>) => void>()
23
-
24
- function add(key: string, value: V): void {
25
- if (map.has(key)) return
26
- map.set(key, value)
27
- notify()
28
- }
29
-
30
- function deleteKey(key: string): void {
31
- if (!map.has(key)) return
32
- map.delete(key)
33
- notify()
34
- }
35
-
36
- function notify(): void {
37
- const val = Object.fromEntries(map)
38
- listeners.forEach((cb) => cb(val))
39
- }
40
-
41
- function subscribe(cb: (value: Record<string, V>) => void): () => void {
42
- listeners.add(cb)
43
- cb(Object.fromEntries(map))
44
- return () => listeners.delete(cb)
45
- }
46
-
47
- return {
48
- add,
49
- delete: deleteKey,
50
- subscribe,
51
- get size() {
52
- return map.size
53
- },
54
- }
55
- }
56
-
57
11
  type Evt =
58
12
  | {
59
13
  name: "mount"
@@ -78,48 +32,53 @@ interface SchedulerInterface {
78
32
  requestUpdate: (vNode: Kiru.VNode) => void
79
33
  }
80
34
 
35
+ export type DebuggerEntry = {
36
+ label: string
37
+ signal: Kiru.Signal<unknown>
38
+ }
39
+
81
40
  interface KiruGlobalContext {
82
- readonly apps: AppContext[]
83
- emit<T extends Evt>(event: T["name"], ctx: AppContext, data?: T["data"]): void
41
+ readonly apps: AppHandle[]
42
+ emit<T extends Evt>(event: T["name"], app: AppHandle, data?: T["data"]): void
84
43
  on<T extends Evt>(
85
44
  event: T["name"],
86
- callback: (ctx: AppContext, data: T["data"]) => void
45
+ callback: (app: AppHandle, data: T["data"]) => void
87
46
  ): void
88
47
  off<T extends Evt>(
89
48
  event: T["name"],
90
- callback: (ctx: AppContext, data?: T["data"]) => void
49
+ callback: (app: AppHandle, data?: T["data"]) => void
91
50
  ): void
92
- stores?: ReactiveMap<Store<any, any>>
51
+ devtools?: {
52
+ track: (signal: Kiru.Signal<unknown>, label?: string) => void
53
+ untrack: (signal: Kiru.Signal<unknown>) => void
54
+ subscribe: (callback: (entries: Set<DebuggerEntry>) => void) => () => void
55
+ }
93
56
  HMRContext?: ReturnType<typeof createHMRContext>
94
57
  profilingContext?: ReturnType<typeof createProfilingContext>
95
- SWRGlobalCache?: SWRCache
96
58
  fileRouterInstance?: {
97
59
  current: FileRouterController | null
98
60
  }
99
- getSchedulerInterface?: (app: AppContext) => SchedulerInterface | null
61
+ getSchedulerInterface?: (app: AppHandle) => SchedulerInterface | null
100
62
  }
101
63
 
102
64
  function createKiruGlobalContext(): KiruGlobalContext {
103
- const contexts = new Set<AppContext>()
104
- const contextToSchedulerInterface = new WeakMap<
105
- AppContext,
106
- SchedulerInterface
107
- >()
65
+ const apps = new Set<AppHandle>()
66
+ const appToSchedulerInterface = new WeakMap<AppHandle, SchedulerInterface>()
108
67
  const listeners = new Map<
109
68
  GlobalKiruEvent,
110
- Set<(ctx: AppContext, data?: Evt["data"]) => void>
69
+ Set<(app: AppHandle, data?: Evt["data"]) => void>
111
70
  >()
112
71
  function emit<T extends Evt>(
113
72
  event: T["name"],
114
- ctx: AppContext,
73
+ app: AppHandle,
115
74
  data?: T["data"]
116
75
  ): void {
117
- listeners.get(event)?.forEach((cb) => cb(ctx, data))
76
+ listeners.get(event)?.forEach((cb) => cb(app, data))
118
77
  }
119
78
 
120
79
  function on<T extends Evt>(
121
80
  event: T["name"],
122
- callback: (ctx: AppContext, data: T["data"]) => void
81
+ callback: (app: AppHandle, data: T["data"]) => void
123
82
  ): void {
124
83
  if (!listeners.has(event)) {
125
84
  listeners.set(event, new Set())
@@ -129,14 +88,14 @@ function createKiruGlobalContext(): KiruGlobalContext {
129
88
 
130
89
  function off<T extends Evt>(
131
90
  event: T["name"],
132
- callback: (ctx: AppContext, data?: T["data"]) => void
91
+ callback: (ctx: AppHandle, data?: T["data"]) => void
133
92
  ): void {
134
93
  listeners.get(event)?.delete(callback)
135
94
  }
136
95
 
137
96
  const globalContext: KiruGlobalContext = {
138
97
  get apps() {
139
- return Array.from(contexts)
98
+ return Array.from(apps)
140
99
  },
141
100
  emit,
142
101
  on,
@@ -144,24 +103,48 @@ function createKiruGlobalContext(): KiruGlobalContext {
144
103
  }
145
104
 
146
105
  // Initialize event listeners
147
- on("mount", (ctx, requestUpdate) => {
148
- contexts.add(ctx)
106
+ on("mount", (app, requestUpdate) => {
107
+ apps.add(app)
149
108
  if (requestUpdate && typeof requestUpdate === "function") {
150
- contextToSchedulerInterface.set(ctx, { requestUpdate })
109
+ appToSchedulerInterface.set(app, { requestUpdate })
151
110
  }
152
111
  })
153
- on("unmount", (ctx) => {
154
- contexts.delete(ctx)
155
- contextToSchedulerInterface.delete(ctx)
112
+ on("unmount", (app) => {
113
+ apps.delete(app)
114
+ appToSchedulerInterface.delete(app)
156
115
  })
157
-
158
116
  if (__DEV__) {
159
117
  globalContext.HMRContext = createHMRContext()
160
118
  globalContext.profilingContext = createProfilingContext()
161
- globalContext.stores = createReactiveMap()
162
119
  globalContext.fileRouterInstance = fileRouterInstance
163
120
  globalContext.getSchedulerInterface = (app) => {
164
- return contextToSchedulerInterface.get(app) ?? null
121
+ return appToSchedulerInterface.get(app) ?? null
122
+ }
123
+
124
+ const debuggerEntries = new Set<DebuggerEntry>()
125
+ const subscribers = new Set<(debuggerEntries: Set<DebuggerEntry>) => void>()
126
+
127
+ globalContext.devtools = {
128
+ track: (signal, label) => {
129
+ debuggerEntries.add({
130
+ label: label ?? signal.displayName ?? "Unnamed Signal",
131
+ signal,
132
+ })
133
+ subscribers.forEach((cb) => cb(debuggerEntries))
134
+ },
135
+ untrack: (signal) => {
136
+ debuggerEntries.forEach((entry) => {
137
+ if (entry.signal === signal) {
138
+ debuggerEntries.delete(entry)
139
+ }
140
+ })
141
+ subscribers.forEach((cb) => cb(debuggerEntries))
142
+ },
143
+ subscribe: (cb) => {
144
+ subscribers.add(cb)
145
+ cb(debuggerEntries)
146
+ return () => subscribers.delete(cb)
147
+ },
165
148
  }
166
149
  }
167
150
 
package/src/globals.ts CHANGED
@@ -1,13 +1,9 @@
1
- export { node, hookIndex, renderMode, hydrationMode }
1
+ export { node, renderMode, hydrationMode }
2
2
 
3
3
  const node = {
4
4
  current: null as Kiru.VNode | null,
5
5
  }
6
6
 
7
- const hookIndex = {
8
- current: 0,
9
- }
10
-
11
7
  const renderMode = {
12
8
  current: ("window" in globalThis ? "dom" : "string") as Kiru.RenderMode,
13
9
  }
@@ -1,4 +1,4 @@
1
- import { node, hookIndex } from "./globals.js"
1
+ import { node } from "./globals.js"
2
2
  import {
3
3
  isVNode,
4
4
  encodeHtmlEntities,
@@ -8,7 +8,7 @@ import {
8
8
  isPrimitiveChild,
9
9
  isValidTextChild,
10
10
  } from "./utils/index.js"
11
- import { isStreamDataThrowValue } from "./utils/promise.js"
11
+ import { isStreamDataThrowValue } from "./statefulPromise.js"
12
12
  import { Signal } from "./signals/base.js"
13
13
  import { $ERROR_BOUNDARY, voidElements, $STREAM_DATA } from "./constants.js"
14
14
  import { __DEV__ } from "./env.js"
@@ -16,12 +16,10 @@ import type { ErrorBoundaryNode } from "./types.utils"
16
16
 
17
17
  export interface HeadlessRenderContext {
18
18
  write(chunk: string): void
19
- onStreamData?: (data: Kiru.StatefulPromise<unknown>[]) => void
19
+ onStreamData?: (data: Kiru.StatefulPromiseBase<unknown>[]) => void
20
20
  }
21
21
 
22
- export { render as headlessRender }
23
-
24
- function render(
22
+ export function headlessRender(
25
23
  ctx: HeadlessRenderContext,
26
24
  el: unknown,
27
25
  parent: Kiru.VNode | null,
@@ -37,7 +35,7 @@ function render(
37
35
  return ctx.write(el.toString())
38
36
  }
39
37
  if (el instanceof Array) {
40
- return el.forEach((c, i) => render(ctx, c, parent, i))
38
+ return el.forEach((c, i) => headlessRender(ctx, c, parent, i))
41
39
  }
42
40
  if (Signal.isSignal(el)) {
43
41
  const value = el.peek()
@@ -68,7 +66,7 @@ function render(
68
66
  if (isExoticType(type)) {
69
67
  if (type === $ERROR_BOUNDARY) {
70
68
  let boundaryBuffer = ""
71
- const streamPromises = new Set<Kiru.StatefulPromise<unknown>>()
69
+ const streamPromises = new Set<Kiru.StatefulPromiseBase<unknown>>()
72
70
  const boundaryCtx: HeadlessRenderContext = {
73
71
  write(chunk) {
74
72
  boundaryBuffer += chunk
@@ -78,7 +76,7 @@ function render(
78
76
  },
79
77
  }
80
78
  try {
81
- render(boundaryCtx, children, el, idx)
79
+ headlessRender(boundaryCtx, children, el, idx)
82
80
  // flush successful render
83
81
  ctx.write(boundaryBuffer)
84
82
  ctx.onStreamData?.([...streamPromises])
@@ -91,27 +89,29 @@ function render(
91
89
  onError?.(e)
92
90
  const fallbackContent =
93
91
  typeof fallback === "function" ? fallback(e) : fallback
94
- render(ctx, fallbackContent, el, 0)
92
+ headlessRender(ctx, fallbackContent, el, 0)
95
93
  }
96
94
  return
97
95
  }
98
96
 
99
- render(ctx, children, el, idx)
97
+ headlessRender(ctx, children, el, idx)
100
98
  return
101
99
  }
102
100
 
103
- if (typeof type !== "string") {
101
+ if (typeof type === "function") {
104
102
  try {
105
- hookIndex.current = 0
106
103
  node.current = el
107
- const res = type(props)
108
- render(ctx, res, el, idx)
104
+ let children = type(props)
105
+ if (typeof children === "function") {
106
+ children = children(props)
107
+ }
108
+ headlessRender(ctx, children, el, idx)
109
109
  return
110
110
  } catch (error) {
111
111
  if (isStreamDataThrowValue(error)) {
112
112
  const { fallback, data } = error[$STREAM_DATA]
113
113
  ctx.onStreamData?.(data)
114
- return render(ctx, fallback, el, 0)
114
+ return headlessRender(ctx, fallback, el, 0)
115
115
  }
116
116
  throw error
117
117
  } finally {
@@ -134,9 +134,9 @@ function render(
134
134
  )
135
135
  )
136
136
  } else if (Array.isArray(children)) {
137
- children.forEach((c, i) => render(ctx, c, el, i))
137
+ children.forEach((c, i) => headlessRender(ctx, c, el, i))
138
138
  } else {
139
- render(ctx, children, el, 0)
139
+ headlessRender(ctx, children, el, 0)
140
140
  }
141
141
  ctx.write(`</${type}>`)
142
142
  }
package/src/hmr.ts CHANGED
@@ -2,9 +2,7 @@ import { $HMR_ACCEPT, $DEV_FILE_LINK } from "./constants.js"
2
2
  import { traverseApply } from "./utils/index.js"
3
3
  import { flushSync, requestUpdate } from "./scheduler.js"
4
4
  import { Signal } from "./signals/base.js"
5
- import type { WatchEffect } from "./signals/watch.js"
6
- import type { Store } from "./store.js"
7
- import type { AppContext } from "./appContext.js"
5
+ import type { Effect } from "./signals/effect.js"
8
6
 
9
7
  export type HMRAccept<T = {}> = {
10
8
  provide: () => T
@@ -15,7 +13,7 @@ export type HMRAccept<T = {}> = {
15
13
  export type GenericHMRAcceptor<T = {}> = {
16
14
  [$HMR_ACCEPT]: HMRAccept<T>
17
15
  }
18
- type HotVar = Kiru.FC | Store<any, any> | Signal<any> | Kiru.Context<any>
16
+ type HotVar = Kiru.FC | Signal<any> | Kiru.ContextBase<any>
19
17
 
20
18
  type HotVarDesc = {
21
19
  type: string
@@ -43,7 +41,7 @@ export function isGenericHmrAcceptor(
43
41
 
44
42
  type ModuleMemory = {
45
43
  hotVars: Map<string, HotVarDesc>
46
- unnamedWatchers: Array<WatchEffect>
44
+ unnamedEffects: Array<Effect>
47
45
  }
48
46
 
49
47
  type HotVarRegistrationEntry = {
@@ -59,7 +57,7 @@ export function createHMRContext() {
59
57
  let currentModuleMemory: ModuleMemory | null = null
60
58
  let isModuleReplacementExecution = false
61
59
  const isReplacement = () => isModuleReplacementExecution
62
- let isWaitingForNextWatchCall = false
60
+ let isWaitingForNextEffect = false
63
61
 
64
62
  const onHmrCallbacks: Array<() => void> = []
65
63
  const onHmr = (callback: () => void) => {
@@ -72,14 +70,15 @@ export function createHMRContext() {
72
70
  if (!mod) {
73
71
  mod = {
74
72
  hotVars: new Map(),
75
- unnamedWatchers: [],
73
+ unnamedEffects: [],
76
74
  }
77
75
  moduleMap.set(filePath, mod)
78
76
  } else {
79
77
  while (onHmrCallbacks.length) onHmrCallbacks.shift()!()
80
- for (const prevWatcher of mod.unnamedWatchers.splice(0)) {
81
- prevWatcher.stop()
78
+ for (const effect of mod.unnamedEffects) {
79
+ effect.stop()
82
80
  }
81
+ mod.unnamedEffects.length = 0
83
82
  }
84
83
 
85
84
  currentModuleMemory = mod!
@@ -92,26 +91,20 @@ export function createHMRContext() {
92
91
  if (currentModuleMemory === null)
93
92
  throw new Error("[kiru]: HMR could not register: No active module")
94
93
 
95
- let dirtiedApps: Set<AppContext> = new Set()
94
+ let dirtyNodes = new Set<Kiru.VNode>()
96
95
  for (const [name, newEntry] of Object.entries(hotVarRegistrationEntries)) {
97
96
  const oldEntry = currentModuleMemory.hotVars.get(name)
98
97
 
99
98
  // @ts-ignore - this is how we tell devtools what file the hotvar is from
100
99
  newEntry.value[$DEV_FILE_LINK] = newEntry.link
101
100
 
102
- if (typeof newEntry.value === "function") {
103
- if (oldEntry?.value) {
104
- /**
105
- * this is how, when the previous function has been stored somewhere else (eg. in a Map, or by Vike),
106
- * we can trace it to its latest version
107
- */
108
- // @ts-ignore
109
- oldEntry.value.__next = newEntry.value
110
- }
111
- }
112
-
113
- if (newEntry.type === "createStore") {
114
- window.__kiru.stores!.add(name, newEntry.value as Store<any, any>)
101
+ if (oldEntry?.value) {
102
+ /**
103
+ * this is how, when the previous value has been stored somewhere else (eg. in a Map, or by Vike),
104
+ * we can trace it to its current version by using latest(value)
105
+ */
106
+ // @ts-ignore
107
+ oldEntry.value.__next = newEntry.value
115
108
  }
116
109
 
117
110
  currentModuleMemory.hotVars.set(name, newEntry)
@@ -127,20 +120,20 @@ export function createHMRContext() {
127
120
  continue
128
121
  }
129
122
  if (oldEntry.type === "component" && newEntry.type === "component") {
130
- window.__kiru.apps.forEach((ctx) => {
131
- traverseApply(ctx.rootNode, (vNode) => {
123
+ window.__kiru.apps.forEach((app) => {
124
+ traverseApply(app.rootNode, (vNode) => {
132
125
  if (vNode.type === oldEntry.value) {
133
126
  vNode.type = newEntry.value as any
134
- dirtiedApps.add(ctx)
127
+ dirtyNodes.add(vNode)
135
128
  }
136
129
  })
137
130
  })
138
131
  }
139
132
  }
140
133
 
141
- if (dirtiedApps.size) {
134
+ if (dirtyNodes.size) {
142
135
  _isHmrUpdate = true
143
- dirtiedApps.forEach((ctx) => requestUpdate(ctx.rootNode))
136
+ dirtyNodes.forEach((n) => requestUpdate(n))
144
137
  flushSync()
145
138
  _isHmrUpdate = false
146
139
  }
@@ -150,16 +143,14 @@ export function createHMRContext() {
150
143
  currentModuleFilePath = null
151
144
  }
152
145
 
153
- const signals = {
154
- registerNextWatch() {
155
- isWaitingForNextWatchCall = true
156
- },
157
- isWaitingForNextWatchCall() {
158
- return isWaitingForNextWatchCall
146
+ const moduleEffects = {
147
+ registerNext() {
148
+ isWaitingForNextEffect = true
159
149
  },
160
- pushWatch(watch: WatchEffect) {
161
- currentModuleMemory!.unnamedWatchers.push(watch)
162
- isWaitingForNextWatchCall = false
150
+ push(effect: Effect<any>) {
151
+ if (!isWaitingForNextEffect) return
152
+ currentModuleMemory!.unnamedEffects.push(effect)
153
+ isWaitingForNextEffect = false
163
154
  },
164
155
  }
165
156
 
@@ -167,7 +158,7 @@ export function createHMRContext() {
167
158
  register,
168
159
  prepare,
169
160
  isReplacement,
170
- signals,
161
+ moduleEffects,
171
162
  onHmr,
172
163
  getCurrentFilePath() {
173
164
  return currentModuleFilePath
@@ -1,15 +1,4 @@
1
- export * from "./useAsync.js"
2
- export * from "./useCallback.js"
3
- export * from "./useContext.js"
4
- export * from "./useEffect.js"
5
- export * from "./useEffectEvent.js"
6
- export * from "./useId.js"
7
- export * from "./useLayoutEffect.js"
8
- export * from "./useMemo.js"
9
- export * from "./usePromise.js"
10
- export * from "./useReducer.js"
11
- export * from "./useRef.js"
12
- export * from "./useState.js"
13
- export * from "./useSyncExternalStore.js"
14
- export * from "./useViewTransition.js"
1
+ export * from "./onCleanup.js"
2
+ export * from "./onMount.js"
3
+ export * from "./onBeforeMount.js"
15
4
  export * from "./utils.js"