kiru 0.54.4 → 1.1.0

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 (381) 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} +13 -10
  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 +7 -6
  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 -30
  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 +19 -0
  34. package/dist/devtools.js.map +1 -0
  35. package/dist/dom/commit.d.ts +5 -0
  36. package/dist/dom/commit.d.ts.map +1 -0
  37. package/dist/dom/commit.js +94 -0
  38. package/dist/dom/commit.js.map +1 -0
  39. package/dist/dom/focus.d.ts +4 -0
  40. package/dist/dom/focus.d.ts.map +1 -0
  41. package/dist/dom/focus.js +32 -0
  42. package/dist/dom/focus.js.map +1 -0
  43. package/dist/dom/index.d.ts +4 -0
  44. package/dist/dom/index.d.ts.map +1 -0
  45. package/dist/dom/index.js +4 -0
  46. package/dist/dom/index.js.map +1 -0
  47. package/dist/dom/nodes.d.ts +12 -0
  48. package/dist/dom/nodes.d.ts.map +1 -0
  49. package/dist/dom/nodes.js +165 -0
  50. package/dist/dom/nodes.js.map +1 -0
  51. package/dist/dom/props.d.ts +8 -0
  52. package/dist/dom/props.d.ts.map +1 -0
  53. package/dist/dom/props.js +675 -0
  54. package/dist/dom/props.js.map +1 -0
  55. package/dist/env.d.ts +2 -0
  56. package/dist/env.d.ts.map +1 -1
  57. package/dist/env.js +2 -0
  58. package/dist/env.js.map +1 -1
  59. package/dist/globalContext.d.ts +17 -23
  60. package/dist/globalContext.d.ts.map +1 -1
  61. package/dist/globalContext.js +31 -53
  62. package/dist/globalContext.js.map +1 -1
  63. package/dist/globals.d.ts +21 -4
  64. package/dist/globals.d.ts.map +1 -1
  65. package/dist/globals.js +22 -5
  66. package/dist/globals.js.map +1 -1
  67. package/dist/headlessRender.d.ts +6 -0
  68. package/dist/headlessRender.d.ts.map +1 -0
  69. package/dist/{recursiveRender.js → headlessRender.js} +17 -16
  70. package/dist/headlessRender.js.map +1 -0
  71. package/dist/hmr.d.ts +21 -8
  72. package/dist/hmr.d.ts.map +1 -1
  73. package/dist/hmr.js +58 -37
  74. package/dist/hmr.js.map +1 -1
  75. package/dist/hooks/index.d.ts +4 -14
  76. package/dist/hooks/index.d.ts.map +1 -1
  77. package/dist/hooks/index.js +4 -14
  78. package/dist/hooks/index.js.map +1 -1
  79. package/dist/hooks/onBeforeMount.d.ts +9 -0
  80. package/dist/hooks/onBeforeMount.d.ts.map +1 -0
  81. package/dist/hooks/onBeforeMount.js +19 -0
  82. package/dist/hooks/onBeforeMount.js.map +1 -0
  83. package/dist/hooks/onCleanup.d.ts +8 -0
  84. package/dist/hooks/onCleanup.d.ts.map +1 -0
  85. package/dist/hooks/onCleanup.js +18 -0
  86. package/dist/hooks/onCleanup.js.map +1 -0
  87. package/dist/hooks/onMount.d.ts +9 -0
  88. package/dist/hooks/onMount.d.ts.map +1 -0
  89. package/dist/hooks/onMount.js +19 -0
  90. package/dist/hooks/onMount.js.map +1 -0
  91. package/dist/hooks/setup.d.ts +13 -0
  92. package/dist/hooks/setup.d.ts.map +1 -0
  93. package/dist/hooks/setup.js +54 -0
  94. package/dist/hooks/setup.js.map +1 -0
  95. package/dist/hooks/utils.d.ts +2 -63
  96. package/dist/hooks/utils.d.ts.map +1 -1
  97. package/dist/hooks/utils.js +17 -144
  98. package/dist/hooks/utils.js.map +1 -1
  99. package/dist/index.d.ts +9 -4
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/index.js +11 -8
  102. package/dist/index.js.map +1 -1
  103. package/dist/profiling.d.ts +15 -14
  104. package/dist/profiling.d.ts.map +1 -1
  105. package/dist/profiling.js +9 -4
  106. package/dist/profiling.js.map +1 -1
  107. package/dist/reconciler.d.ts.map +1 -1
  108. package/dist/reconciler.js +15 -28
  109. package/dist/reconciler.js.map +1 -1
  110. package/dist/ref.d.ts +4 -0
  111. package/dist/ref.d.ts.map +1 -0
  112. package/dist/ref.js +4 -0
  113. package/dist/ref.js.map +1 -0
  114. package/dist/renderToString.js +1 -1
  115. package/dist/renderToString.js.map +1 -1
  116. package/dist/router/context.d.ts.map +1 -1
  117. package/dist/router/context.js +1 -2
  118. package/dist/router/context.js.map +1 -1
  119. package/dist/router/fileRouter.d.ts +1 -1
  120. package/dist/router/fileRouter.d.ts.map +1 -1
  121. package/dist/router/fileRouter.js +17 -11
  122. package/dist/router/fileRouter.js.map +1 -1
  123. package/dist/router/fileRouterController.d.ts.map +1 -1
  124. package/dist/router/fileRouterController.js +68 -55
  125. package/dist/router/fileRouterController.js.map +1 -1
  126. package/dist/router/head.js +2 -2
  127. package/dist/router/head.js.map +1 -1
  128. package/dist/router/link.d.ts.map +1 -1
  129. package/dist/router/link.js +19 -23
  130. package/dist/router/link.js.map +1 -1
  131. package/dist/router/pageConfig.js +2 -2
  132. package/dist/router/pageConfig.js.map +1 -1
  133. package/dist/router/server/index.d.ts.map +1 -1
  134. package/dist/router/server/index.js +14 -11
  135. package/dist/router/server/index.js.map +1 -1
  136. package/dist/router/types.d.ts +11 -6
  137. package/dist/router/types.d.ts.map +1 -1
  138. package/dist/scheduler.d.ts +1 -0
  139. package/dist/scheduler.d.ts.map +1 -1
  140. package/dist/scheduler.js +91 -73
  141. package/dist/scheduler.js.map +1 -1
  142. package/dist/signals/base.d.ts +0 -1
  143. package/dist/signals/base.d.ts.map +1 -1
  144. package/dist/signals/base.js +14 -37
  145. package/dist/signals/base.js.map +1 -1
  146. package/dist/signals/computed.d.ts +0 -2
  147. package/dist/signals/computed.d.ts.map +1 -1
  148. package/dist/signals/computed.js +1 -40
  149. package/dist/signals/computed.js.map +1 -1
  150. package/dist/signals/effect.d.ts +15 -14
  151. package/dist/signals/effect.d.ts.map +1 -1
  152. package/dist/signals/effect.js +65 -37
  153. package/dist/signals/effect.js.map +1 -1
  154. package/dist/signals/globals.d.ts +0 -5
  155. package/dist/signals/globals.d.ts.map +1 -1
  156. package/dist/signals/globals.js +0 -6
  157. package/dist/signals/globals.js.map +1 -1
  158. package/dist/signals/index.d.ts +4 -4
  159. package/dist/signals/index.d.ts.map +1 -1
  160. package/dist/signals/index.js +4 -4
  161. package/dist/signals/index.js.map +1 -1
  162. package/dist/signals/{for.d.ts → jsx.d.ts} +8 -1
  163. package/dist/signals/jsx.d.ts.map +1 -0
  164. package/dist/signals/{for.js → jsx.js} +4 -1
  165. package/dist/signals/jsx.js.map +1 -0
  166. package/dist/signals/tracking.d.ts +24 -0
  167. package/dist/signals/tracking.d.ts.map +1 -0
  168. package/dist/signals/tracking.js +51 -0
  169. package/dist/signals/tracking.js.map +1 -0
  170. package/dist/signals/types.d.ts +1 -1
  171. package/dist/signals/types.d.ts.map +1 -1
  172. package/dist/signals/utils.d.ts +2 -1
  173. package/dist/signals/utils.d.ts.map +1 -1
  174. package/dist/signals/utils.js +9 -2
  175. package/dist/signals/utils.js.map +1 -1
  176. package/dist/ssr/client.d.ts +3 -3
  177. package/dist/ssr/client.d.ts.map +1 -1
  178. package/dist/ssr/client.js.map +1 -1
  179. package/dist/ssr/server.js +1 -1
  180. package/dist/ssr/server.js.map +1 -1
  181. package/dist/statefulPromise.d.ts +22 -0
  182. package/dist/statefulPromise.d.ts.map +1 -0
  183. package/dist/statefulPromise.js +94 -0
  184. package/dist/statefulPromise.js.map +1 -0
  185. package/dist/types.d.ts +40 -50
  186. package/dist/types.d.ts.map +1 -1
  187. package/dist/types.dom.d.ts +5 -8
  188. package/dist/types.dom.d.ts.map +1 -1
  189. package/dist/types.utils.d.ts +3 -4
  190. package/dist/types.utils.d.ts.map +1 -1
  191. package/dist/utils/format.d.ts.map +1 -1
  192. package/dist/utils/format.js +4 -1
  193. package/dist/utils/format.js.map +1 -1
  194. package/dist/utils/vdom.d.ts +8 -6
  195. package/dist/utils/vdom.d.ts.map +1 -1
  196. package/dist/utils/vdom.js +32 -9
  197. package/dist/utils/vdom.js.map +1 -1
  198. package/dist/viewTransitions.d.ts +7 -0
  199. package/dist/viewTransitions.d.ts.map +1 -0
  200. package/dist/viewTransitions.js +72 -0
  201. package/dist/viewTransitions.js.map +1 -0
  202. package/package.json +1 -1
  203. package/src/{appContext.ts → appHandle.ts} +22 -17
  204. package/src/components/derive.ts +74 -69
  205. package/src/components/index.ts +0 -1
  206. package/src/components/lazy.ts +10 -10
  207. package/src/components/portal.ts +2 -3
  208. package/src/components/transition.ts +33 -39
  209. package/src/constants.ts +0 -8
  210. package/src/context.ts +30 -23
  211. package/src/devtools.ts +18 -0
  212. package/src/dom/commit.ts +133 -0
  213. package/src/dom/focus.ts +34 -0
  214. package/src/dom/index.ts +3 -0
  215. package/src/dom/nodes.ts +204 -0
  216. package/src/dom/props.ts +818 -0
  217. package/src/env.ts +3 -0
  218. package/src/globalContext.ts +51 -85
  219. package/src/globals.ts +25 -6
  220. package/src/{recursiveRender.ts → headlessRender.ts} +18 -18
  221. package/src/hmr.ts +60 -42
  222. package/src/hooks/index.ts +4 -14
  223. package/src/hooks/onBeforeMount.ts +18 -0
  224. package/src/hooks/onCleanup.ts +21 -0
  225. package/src/hooks/onMount.ts +18 -0
  226. package/src/hooks/setup.ts +70 -0
  227. package/src/hooks/utils.ts +24 -239
  228. package/src/index.ts +17 -7
  229. package/src/profiling.ts +22 -20
  230. package/src/reconciler.ts +21 -33
  231. package/src/ref.ts +6 -0
  232. package/src/renderToString.ts +1 -1
  233. package/src/router/context.ts +1 -2
  234. package/src/router/fileRouter.ts +23 -13
  235. package/src/router/fileRouterController.ts +72 -64
  236. package/src/router/head.ts +2 -2
  237. package/src/router/link.ts +11 -25
  238. package/src/router/pageConfig.ts +2 -2
  239. package/src/router/server/index.ts +24 -13
  240. package/src/router/types.ts +15 -8
  241. package/src/scheduler.ts +116 -98
  242. package/src/signals/base.ts +13 -42
  243. package/src/signals/computed.ts +1 -62
  244. package/src/signals/effect.ts +93 -48
  245. package/src/signals/globals.ts +0 -7
  246. package/src/signals/index.ts +4 -4
  247. package/src/signals/{for.ts → jsx.ts} +10 -0
  248. package/src/signals/tracking.ts +70 -0
  249. package/src/signals/types.ts +1 -1
  250. package/src/signals/utils.ts +9 -1
  251. package/src/ssr/client.ts +4 -4
  252. package/src/ssr/server.ts +2 -2
  253. package/src/statefulPromise.ts +136 -0
  254. package/src/types.dom.ts +6 -10
  255. package/src/types.ts +51 -60
  256. package/src/types.utils.ts +3 -4
  257. package/src/utils/format.ts +3 -1
  258. package/src/utils/vdom.ts +44 -15
  259. package/src/viewTransitions.ts +89 -0
  260. package/dist/appContext.d.ts.map +0 -1
  261. package/dist/appContext.js.map +0 -1
  262. package/dist/components/memo.d.ts +0 -10
  263. package/dist/components/memo.d.ts.map +0 -1
  264. package/dist/components/memo.js +0 -23
  265. package/dist/components/memo.js.map +0 -1
  266. package/dist/dom.d.ts +0 -10
  267. package/dist/dom.d.ts.map +0 -1
  268. package/dist/dom.js +0 -634
  269. package/dist/dom.js.map +0 -1
  270. package/dist/form/index.d.ts +0 -4
  271. package/dist/form/index.d.ts.map +0 -1
  272. package/dist/form/index.js +0 -518
  273. package/dist/form/index.js.map +0 -1
  274. package/dist/form/types.d.ts +0 -122
  275. package/dist/form/types.d.ts.map +0 -1
  276. package/dist/form/types.js +0 -2
  277. package/dist/form/types.js.map +0 -1
  278. package/dist/form/utils.d.ts +0 -3
  279. package/dist/form/utils.d.ts.map +0 -1
  280. package/dist/form/utils.js +0 -16
  281. package/dist/form/utils.js.map +0 -1
  282. package/dist/hooks/useAsync.d.ts +0 -18
  283. package/dist/hooks/useAsync.d.ts.map +0 -1
  284. package/dist/hooks/useAsync.js +0 -96
  285. package/dist/hooks/useAsync.js.map +0 -1
  286. package/dist/hooks/useCallback.d.ts +0 -7
  287. package/dist/hooks/useCallback.d.ts.map +0 -1
  288. package/dist/hooks/useCallback.js +0 -30
  289. package/dist/hooks/useCallback.js.map +0 -1
  290. package/dist/hooks/useContext.d.ts +0 -7
  291. package/dist/hooks/useContext.d.ts.map +0 -1
  292. package/dist/hooks/useContext.js +0 -59
  293. package/dist/hooks/useContext.js.map +0 -1
  294. package/dist/hooks/useEffect.d.ts +0 -8
  295. package/dist/hooks/useEffect.d.ts.map +0 -1
  296. package/dist/hooks/useEffect.js +0 -34
  297. package/dist/hooks/useEffect.js.map +0 -1
  298. package/dist/hooks/useEffectEvent.d.ts +0 -8
  299. package/dist/hooks/useEffectEvent.d.ts.map +0 -1
  300. package/dist/hooks/useEffectEvent.js +0 -23
  301. package/dist/hooks/useEffectEvent.js.map +0 -1
  302. package/dist/hooks/useId.d.ts +0 -8
  303. package/dist/hooks/useId.d.ts.map +0 -1
  304. package/dist/hooks/useId.js +0 -35
  305. package/dist/hooks/useId.js.map +0 -1
  306. package/dist/hooks/useLayoutEffect.d.ts +0 -8
  307. package/dist/hooks/useLayoutEffect.d.ts.map +0 -1
  308. package/dist/hooks/useLayoutEffect.js +0 -34
  309. package/dist/hooks/useLayoutEffect.js.map +0 -1
  310. package/dist/hooks/useMemo.d.ts +0 -8
  311. package/dist/hooks/useMemo.d.ts.map +0 -1
  312. package/dist/hooks/useMemo.js +0 -31
  313. package/dist/hooks/useMemo.js.map +0 -1
  314. package/dist/hooks/usePromise.d.ts +0 -8
  315. package/dist/hooks/usePromise.d.ts.map +0 -1
  316. package/dist/hooks/usePromise.js +0 -90
  317. package/dist/hooks/usePromise.js.map +0 -1
  318. package/dist/hooks/useReducer.d.ts +0 -7
  319. package/dist/hooks/useReducer.d.ts.map +0 -1
  320. package/dist/hooks/useReducer.js +0 -44
  321. package/dist/hooks/useReducer.js.map +0 -1
  322. package/dist/hooks/useRef.d.ts +0 -10
  323. package/dist/hooks/useRef.d.ts.map +0 -1
  324. package/dist/hooks/useRef.js +0 -29
  325. package/dist/hooks/useRef.js.map +0 -1
  326. package/dist/hooks/useState.d.ts +0 -7
  327. package/dist/hooks/useState.d.ts.map +0 -1
  328. package/dist/hooks/useState.js +0 -54
  329. package/dist/hooks/useState.js.map +0 -1
  330. package/dist/hooks/useSyncExternalStore.d.ts +0 -8
  331. package/dist/hooks/useSyncExternalStore.d.ts.map +0 -1
  332. package/dist/hooks/useSyncExternalStore.js +0 -50
  333. package/dist/hooks/useSyncExternalStore.js.map +0 -1
  334. package/dist/hooks/useViewTransition.d.ts +0 -10
  335. package/dist/hooks/useViewTransition.d.ts.map +0 -1
  336. package/dist/hooks/useViewTransition.js +0 -27
  337. package/dist/hooks/useViewTransition.js.map +0 -1
  338. package/dist/recursiveRender.d.ts +0 -7
  339. package/dist/recursiveRender.d.ts.map +0 -1
  340. package/dist/recursiveRender.js.map +0 -1
  341. package/dist/signals/for.d.ts.map +0 -1
  342. package/dist/signals/for.js.map +0 -1
  343. package/dist/signals/watch.d.ts +0 -21
  344. package/dist/signals/watch.d.ts.map +0 -1
  345. package/dist/signals/watch.js +0 -86
  346. package/dist/signals/watch.js.map +0 -1
  347. package/dist/store.d.ts +0 -28
  348. package/dist/store.d.ts.map +0 -1
  349. package/dist/store.js +0 -166
  350. package/dist/store.js.map +0 -1
  351. package/dist/swr.d.ts +0 -63
  352. package/dist/swr.d.ts.map +0 -1
  353. package/dist/swr.js +0 -236
  354. package/dist/swr.js.map +0 -1
  355. package/dist/utils/promise.d.ts +0 -16
  356. package/dist/utils/promise.d.ts.map +0 -1
  357. package/dist/utils/promise.js +0 -14
  358. package/dist/utils/promise.js.map +0 -1
  359. package/src/components/memo.ts +0 -39
  360. package/src/dom.ts +0 -809
  361. package/src/form/index.ts +0 -676
  362. package/src/form/types.ts +0 -262
  363. package/src/form/utils.ts +0 -19
  364. package/src/hooks/useAsync.ts +0 -121
  365. package/src/hooks/useCallback.ts +0 -32
  366. package/src/hooks/useContext.ts +0 -79
  367. package/src/hooks/useEffect.ts +0 -40
  368. package/src/hooks/useEffectEvent.ts +0 -24
  369. package/src/hooks/useId.ts +0 -42
  370. package/src/hooks/useLayoutEffect.ts +0 -43
  371. package/src/hooks/useMemo.ts +0 -34
  372. package/src/hooks/usePromise.ts +0 -126
  373. package/src/hooks/useReducer.ts +0 -50
  374. package/src/hooks/useRef.ts +0 -40
  375. package/src/hooks/useState.ts +0 -62
  376. package/src/hooks/useSyncExternalStore.ts +0 -59
  377. package/src/hooks/useViewTransition.ts +0 -25
  378. package/src/signals/watch.ts +0 -139
  379. package/src/store.ts +0 -245
  380. package/src/swr.ts +0 -351
  381. package/src/utils/promise.ts +0 -26
package/src/env.ts CHANGED
@@ -4,3 +4,6 @@ if (NODE_ENV !== "development" && NODE_ENV !== "production") {
4
4
  }
5
5
 
6
6
  export const __DEV__ = NODE_ENV === "development"
7
+
8
+ export const isBrowser = "window" in globalThis && typeof window !== "undefined"
9
+ export const isServer = !isBrowser
@@ -1,63 +1,16 @@
1
1
  import { __DEV__ } from "./env.js"
2
- import { createHMRContext } from "./hmr.js"
2
+ 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"
9
- import type { requestUpdate } from "./index.js"
6
+ import type { AppHandle } from "./appHandle"
10
7
 
11
8
  export { createKiruGlobalContext, type GlobalKiruEvent, type KiruGlobalContext }
12
9
 
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
10
  type Evt =
58
11
  | {
59
12
  name: "mount"
60
- data?: typeof requestUpdate
13
+ data?: undefined
61
14
  }
62
15
  | {
63
16
  name: "unmount"
@@ -74,52 +27,51 @@ type Evt =
74
27
 
75
28
  type GlobalKiruEvent = Evt["name"]
76
29
 
77
- interface SchedulerInterface {
78
- requestUpdate: (vNode: Kiru.VNode) => void
30
+ export type DebuggerEntry = {
31
+ label: string
32
+ signal: Kiru.Signal<unknown>
79
33
  }
80
34
 
81
35
  interface KiruGlobalContext {
82
- readonly apps: AppContext[]
83
- emit<T extends Evt>(event: T["name"], ctx: AppContext, data?: T["data"]): void
36
+ readonly apps: AppHandle[]
37
+ emit<T extends Evt>(event: T["name"], app: AppHandle, data?: T["data"]): void
84
38
  on<T extends Evt>(
85
39
  event: T["name"],
86
- callback: (ctx: AppContext, data: T["data"]) => void
40
+ callback: (app: AppHandle, data: T["data"]) => void
87
41
  ): void
88
42
  off<T extends Evt>(
89
43
  event: T["name"],
90
- callback: (ctx: AppContext, data?: T["data"]) => void
44
+ callback: (app: AppHandle, data?: T["data"]) => void
91
45
  ): void
92
- stores?: ReactiveMap<Store<any, any>>
93
- HMRContext?: ReturnType<typeof createHMRContext>
46
+ devtools?: {
47
+ track: (signal: Kiru.Signal<unknown>, label?: string) => void
48
+ untrack: (signal: Kiru.Signal<unknown>) => void
49
+ subscribe: (callback: (entries: Set<DebuggerEntry>) => void) => () => void
50
+ }
51
+ HMRContext?: ReturnType<typeof createHmrContext>
94
52
  profilingContext?: ReturnType<typeof createProfilingContext>
95
- SWRGlobalCache?: SWRCache
96
53
  fileRouterInstance?: {
97
54
  current: FileRouterController | null
98
55
  }
99
- getSchedulerInterface?: (app: AppContext) => SchedulerInterface | null
100
56
  }
101
57
 
102
58
  function createKiruGlobalContext(): KiruGlobalContext {
103
- const contexts = new Set<AppContext>()
104
- const contextToSchedulerInterface = new WeakMap<
105
- AppContext,
106
- SchedulerInterface
107
- >()
59
+ const apps = new Set<AppHandle>()
108
60
  const listeners = new Map<
109
61
  GlobalKiruEvent,
110
- Set<(ctx: AppContext, data?: Evt["data"]) => void>
62
+ Set<(app: AppHandle, data?: Evt["data"]) => void>
111
63
  >()
112
64
  function emit<T extends Evt>(
113
65
  event: T["name"],
114
- ctx: AppContext,
66
+ app: AppHandle,
115
67
  data?: T["data"]
116
68
  ): void {
117
- listeners.get(event)?.forEach((cb) => cb(ctx, data))
69
+ listeners.get(event)?.forEach((cb) => cb(app, data))
118
70
  }
119
71
 
120
72
  function on<T extends Evt>(
121
73
  event: T["name"],
122
- callback: (ctx: AppContext, data: T["data"]) => void
74
+ callback: (app: AppHandle, data: T["data"]) => void
123
75
  ): void {
124
76
  if (!listeners.has(event)) {
125
77
  listeners.set(event, new Set())
@@ -129,14 +81,14 @@ function createKiruGlobalContext(): KiruGlobalContext {
129
81
 
130
82
  function off<T extends Evt>(
131
83
  event: T["name"],
132
- callback: (ctx: AppContext, data?: T["data"]) => void
84
+ callback: (ctx: AppHandle, data?: T["data"]) => void
133
85
  ): void {
134
86
  listeners.get(event)?.delete(callback)
135
87
  }
136
88
 
137
89
  const globalContext: KiruGlobalContext = {
138
90
  get apps() {
139
- return Array.from(contexts)
91
+ return Array.from(apps)
140
92
  },
141
93
  emit,
142
94
  on,
@@ -144,24 +96,38 @@ function createKiruGlobalContext(): KiruGlobalContext {
144
96
  }
145
97
 
146
98
  // Initialize event listeners
147
- on("mount", (ctx, requestUpdate) => {
148
- contexts.add(ctx)
149
- if (requestUpdate && typeof requestUpdate === "function") {
150
- contextToSchedulerInterface.set(ctx, { requestUpdate })
151
- }
152
- })
153
- on("unmount", (ctx) => {
154
- contexts.delete(ctx)
155
- contextToSchedulerInterface.delete(ctx)
156
- })
99
+ on("mount", (app) => apps.add(app))
100
+ on("unmount", (app) => apps.delete(app))
157
101
 
158
102
  if (__DEV__) {
159
- globalContext.HMRContext = createHMRContext()
103
+ globalContext.HMRContext = createHmrContext()
160
104
  globalContext.profilingContext = createProfilingContext()
161
- globalContext.stores = createReactiveMap()
162
105
  globalContext.fileRouterInstance = fileRouterInstance
163
- globalContext.getSchedulerInterface = (app) => {
164
- return contextToSchedulerInterface.get(app) ?? null
106
+
107
+ const debuggerEntries = new Set<DebuggerEntry>()
108
+ const subscribers = new Set<(debuggerEntries: Set<DebuggerEntry>) => void>()
109
+
110
+ globalContext.devtools = {
111
+ track: (signal, label) => {
112
+ debuggerEntries.add({
113
+ label: label ?? signal.displayName ?? "Unnamed Signal",
114
+ signal,
115
+ })
116
+ subscribers.forEach((cb) => cb(debuggerEntries))
117
+ },
118
+ untrack: (signal) => {
119
+ debuggerEntries.forEach((entry) => {
120
+ if (entry.signal === signal) {
121
+ debuggerEntries.delete(entry)
122
+ }
123
+ })
124
+ subscribers.forEach((cb) => cb(debuggerEntries))
125
+ },
126
+ subscribe: (cb) => {
127
+ subscribers.add(cb)
128
+ cb(debuggerEntries)
129
+ return () => subscribers.delete(cb)
130
+ },
165
131
  }
166
132
  }
167
133
 
package/src/globals.ts CHANGED
@@ -1,17 +1,36 @@
1
- export { node, hookIndex, renderMode, hydrationMode }
1
+ import { Setup } from "./hooks/index.js"
2
+ import { isBrowser } from "./env.js"
3
+ export { node, renderMode, hydrationMode, setups, postEffectCleanups }
2
4
 
5
+ /**
6
+ * A reference to the current VNode (always a component) being rendered.
7
+ */
3
8
  const node = {
4
9
  current: null as Kiru.VNode | null,
5
10
  }
6
11
 
7
- const hookIndex = {
8
- current: 0,
9
- }
10
-
12
+ /**
13
+ * The current render mode. Can be "dom" "string", "stream", or "hydrate".
14
+ */
11
15
  const renderMode = {
12
- current: ("window" in globalThis ? "dom" : "string") as Kiru.RenderMode,
16
+ current: (isBrowser ? "dom" : "string") as Kiru.RenderMode,
13
17
  }
14
18
 
19
+ /**
20
+ * The current hydration mode. Can be "static" or "dynamic".
21
+ * Used to indicate whether the page being hydrated will contain streamed content.
22
+ */
15
23
  const hydrationMode = {
16
24
  current: "dynamic" as "static" | "dynamic",
17
25
  }
26
+
27
+ /**
28
+ * A map of VNodes (components) to their setup functions.
29
+ */
30
+ const setups: WeakMap<Kiru.VNode, Setup<any>> = new WeakMap()
31
+
32
+ /**
33
+ * Cleanup functions from onMount() that run after components
34
+ * have been unmounted and the browser has painted.
35
+ */
36
+ const postEffectCleanups: (() => void)[] = []
@@ -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.Context<any>
19
17
 
20
18
  type HotVarDesc = {
21
19
  type: string
@@ -43,7 +41,8 @@ export function isGenericHmrAcceptor(
43
41
 
44
42
  type ModuleMemory = {
45
43
  hotVars: Map<string, HotVarDesc>
46
- unnamedWatchers: Array<WatchEffect>
44
+ unnamedEffects: Array<Effect>
45
+ hmrCallbacks: Array<() => void>
47
46
  }
48
47
 
49
48
  type HotVarRegistrationEntry = {
@@ -52,18 +51,22 @@ type HotVarRegistrationEntry = {
52
51
  link: string
53
52
  }
54
53
 
55
- export function createHMRContext() {
54
+ export function createHmrContext() {
56
55
  type FilePath = string
57
56
  const moduleMap = new Map<FilePath, ModuleMemory>()
58
57
  let currentModuleFilePath: string | null = null
59
58
  let currentModuleMemory: ModuleMemory | null = null
60
59
  let isModuleReplacementExecution = false
61
60
  const isReplacement = () => isModuleReplacementExecution
62
- let isWaitingForNextWatchCall = false
61
+ let isWaitingForNextEffect = false
63
62
 
64
- const onHmrCallbacks: Array<() => void> = []
63
+ const globalHmrCallbacks: Array<() => void> = []
65
64
  const onHmr = (callback: () => void) => {
66
- onHmrCallbacks.push(callback)
65
+ if (currentModuleMemory) {
66
+ currentModuleMemory.hmrCallbacks.push(callback)
67
+ return
68
+ }
69
+ globalHmrCallbacks.push(callback)
67
70
  }
68
71
 
69
72
  const prepare = (filePath: string) => {
@@ -72,14 +75,17 @@ export function createHMRContext() {
72
75
  if (!mod) {
73
76
  mod = {
74
77
  hotVars: new Map(),
75
- unnamedWatchers: [],
78
+ unnamedEffects: [],
79
+ hmrCallbacks: [],
76
80
  }
77
81
  moduleMap.set(filePath, mod)
78
82
  } else {
79
- while (onHmrCallbacks.length) onHmrCallbacks.shift()!()
80
- for (const prevWatcher of mod.unnamedWatchers.splice(0)) {
81
- prevWatcher.stop()
83
+ while (mod.hmrCallbacks.length) mod.hmrCallbacks.shift()!()
84
+ while (globalHmrCallbacks.length) globalHmrCallbacks.shift()!()
85
+ for (const effect of mod.unnamedEffects) {
86
+ effect.stop()
82
87
  }
88
+ mod.unnamedEffects.length = 0
83
89
  }
84
90
 
85
91
  currentModuleMemory = mod!
@@ -92,26 +98,20 @@ export function createHMRContext() {
92
98
  if (currentModuleMemory === null)
93
99
  throw new Error("[kiru]: HMR could not register: No active module")
94
100
 
95
- let dirtiedApps: Set<AppContext> = new Set()
101
+ let dirtyNodes = new Set<Kiru.VNode>()
96
102
  for (const [name, newEntry] of Object.entries(hotVarRegistrationEntries)) {
97
103
  const oldEntry = currentModuleMemory.hotVars.get(name)
98
104
 
99
105
  // @ts-ignore - this is how we tell devtools what file the hotvar is from
100
106
  newEntry.value[$DEV_FILE_LINK] = newEntry.link
101
107
 
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>)
108
+ if (oldEntry?.value) {
109
+ /**
110
+ * this is how, when the previous value has been stored somewhere else (eg. in a Map, or by Vike),
111
+ * we can trace it to its current version by using latest(value)
112
+ */
113
+ // @ts-ignore
114
+ oldEntry.value.__next = newEntry.value
115
115
  }
116
116
 
117
117
  currentModuleMemory.hotVars.set(name, newEntry)
@@ -127,20 +127,20 @@ export function createHMRContext() {
127
127
  continue
128
128
  }
129
129
  if (oldEntry.type === "component" && newEntry.type === "component") {
130
- window.__kiru.apps.forEach((ctx) => {
131
- traverseApply(ctx.rootNode, (vNode) => {
130
+ window.__kiru.apps.forEach((app) => {
131
+ traverseApply(app.rootNode, (vNode) => {
132
132
  if (vNode.type === oldEntry.value) {
133
133
  vNode.type = newEntry.value as any
134
- dirtiedApps.add(ctx)
134
+ dirtyNodes.add(vNode)
135
135
  }
136
136
  })
137
137
  })
138
138
  }
139
139
  }
140
140
 
141
- if (dirtiedApps.size) {
141
+ if (dirtyNodes.size) {
142
142
  _isHmrUpdate = true
143
- dirtiedApps.forEach((ctx) => requestUpdate(ctx.rootNode))
143
+ dirtyNodes.forEach((n) => requestUpdate(n))
144
144
  flushSync()
145
145
  _isHmrUpdate = false
146
146
  }
@@ -150,16 +150,14 @@ export function createHMRContext() {
150
150
  currentModuleFilePath = null
151
151
  }
152
152
 
153
- const signals = {
154
- registerNextWatch() {
155
- isWaitingForNextWatchCall = true
156
- },
157
- isWaitingForNextWatchCall() {
158
- return isWaitingForNextWatchCall
153
+ const moduleEffects = {
154
+ registerNext() {
155
+ isWaitingForNextEffect = true
159
156
  },
160
- pushWatch(watch: WatchEffect) {
161
- currentModuleMemory!.unnamedWatchers.push(watch)
162
- isWaitingForNextWatchCall = false
157
+ push(effect: Effect<any>) {
158
+ if (!isWaitingForNextEffect) return
159
+ currentModuleMemory!.unnamedEffects.push(effect)
160
+ isWaitingForNextEffect = false
163
161
  },
164
162
  }
165
163
 
@@ -167,10 +165,30 @@ export function createHMRContext() {
167
165
  register,
168
166
  prepare,
169
167
  isReplacement,
170
- signals,
168
+ moduleEffects,
171
169
  onHmr,
172
170
  getCurrentFilePath() {
173
171
  return currentModuleFilePath
174
172
  },
175
173
  }
176
174
  }
175
+
176
+ /**
177
+ * Queues a callback to be fired when HMR is triggered. This is a no-op in non-browser environments or in production.
178
+ * - If called during current module evaluation, the callback will be fired the next time the current module is evaluated.
179
+ * - If called at any other time, the callback will be fired the next time HMR is triggered.
180
+ * @see https://kirujs.dev/docs/api/lifecycles#onHmr
181
+ *
182
+ * ```ts
183
+ * import { onHmr } from "kiru"
184
+ * // start an interval in the module scope
185
+ * const interval = setInterval(() => {...}, 1000)
186
+ * // stop the interval when this file is reloaded
187
+ * onHmr(() => clearInterval(interval))
188
+ ```
189
+ */
190
+ export function onHmr(callback: () => void): void {
191
+ if ("window" in globalThis && window.__kiru.HMRContext) {
192
+ window.__kiru.HMRContext.onHmr(callback)
193
+ }
194
+ }
@@ -1,15 +1,5 @@
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"
4
+ export * from "./setup.js"
15
5
  export * from "./utils.js"
@@ -0,0 +1,18 @@
1
+ import { sideEffectsEnabled } from "../utils/index.js"
2
+ import { getVNodeLifecycleHooks, wrapLifecycleHookCallback } from "./utils.js"
3
+
4
+ /**
5
+ * Registers a callback that runs after the component is first mounted to the DOM, but before the DOM is painted.
6
+ * Optionally returns a cleanup function that will run when the component unmounts.
7
+ * Intended for use during component setup when the component returns a render function.
8
+ *
9
+ * @see https://kirujs.dev/docs/api/lifecycles#onBeforeMount
10
+ */
11
+ export function onBeforeMount(fn: () => (() => void) | void): void {
12
+ if (!sideEffectsEnabled()) return
13
+ const hooks = getVNodeLifecycleHooks()
14
+ if (!hooks) {
15
+ throw new Error("Cannot queue beforeMount effect outside of a component")
16
+ }
17
+ hooks.pre.push(wrapLifecycleHookCallback(fn, hooks.preCleanups))
18
+ }
@@ -0,0 +1,21 @@
1
+ import { node } from "../globals.js"
2
+ import {
3
+ generateRandomID,
4
+ registerVNodeCleanup,
5
+ sideEffectsEnabled,
6
+ } from "../utils/index.js"
7
+
8
+ /**
9
+ * Registers a cleanup function that runs when the component unmounts.
10
+ * Intended for use during component setup when the component returns a render function.
11
+ *
12
+ * @see https://kirujs.dev/docs/api/lifecycles#onCleanup
13
+ */
14
+ export function onCleanup(fn: () => void): void {
15
+ if (!sideEffectsEnabled()) return
16
+ const vNode = node.current!
17
+ if (!vNode) {
18
+ throw new Error("Cannot queue onCleanup effect outside of a component")
19
+ }
20
+ registerVNodeCleanup(vNode, generateRandomID(10), fn)
21
+ }
@@ -0,0 +1,18 @@
1
+ import { sideEffectsEnabled } from "../utils/index.js"
2
+ import { getVNodeLifecycleHooks, wrapLifecycleHookCallback } from "./utils.js"
3
+
4
+ /**
5
+ * Registers a callback that runs after the component is first mounted to the DOM.
6
+ * Optionally returns a cleanup function that will run after the component unmounts.
7
+ * Intended for use during component setup when the component returns a render function.
8
+ *
9
+ * @see https://kirujs.dev/docs/api/lifecycles#onMount
10
+ */
11
+ export function onMount(fn: () => (() => void) | void): void {
12
+ if (!sideEffectsEnabled()) return
13
+ const hooks = getVNodeLifecycleHooks()
14
+ if (!hooks) {
15
+ throw new Error("Cannot queue onMount effect outside of a component")
16
+ }
17
+ hooks.post.push(wrapLifecycleHookCallback(fn, hooks.postCleanups))
18
+ }