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
@@ -0,0 +1,12 @@
1
+ import { queueSetupEffect } from "./utils.js"
2
+
3
+ /**
4
+ * Registers a callback that runs after the component is first mounted to the DOM, but before the DOM is painted.
5
+ * Optionally returns a cleanup function that will run when the component unmounts.
6
+ * Intended for use during component setup when the component returns a render function.
7
+ *
8
+ * @see https://kirujs.dev/docs/hooks/onBeforeMount
9
+ */
10
+ export function onBeforeMount(fn: () => (() => void) | void): void {
11
+ queueSetupEffect(fn, { immediate: true })
12
+ }
@@ -0,0 +1,15 @@
1
+ import { node } from "../globals.js"
2
+ import { generateRandomID, registerVNodeCleanup } from "../utils/index.js"
3
+
4
+ /**
5
+ * Registers a cleanup function that runs when the component unmounts.
6
+ * Intended for use during component setup when the component returns a render function.
7
+ *
8
+ * @see https://kirujs.dev/docs/hooks/onCleanup
9
+ */
10
+ export function onCleanup(fn: () => void): void {
11
+ const vNode = node.current!
12
+ if (!vNode)
13
+ throw new Error("Cannot queue cleanup effect outside of a component")
14
+ registerVNodeCleanup(vNode, generateRandomID(10), fn)
15
+ }
@@ -0,0 +1,12 @@
1
+ import { queueSetupEffect } from "./utils.js"
2
+
3
+ /**
4
+ * Registers a callback that runs after the component is first mounted to the DOM.
5
+ * Optionally returns a cleanup function that will run when the component unmounts.
6
+ * Intended for use during component setup when the component returns a render function.
7
+ *
8
+ * @see https://kirujs.dev/docs/hooks/onMount
9
+ */
10
+ export function onMount(fn: () => (() => void) | void): void {
11
+ queueSetupEffect(fn)
12
+ }
@@ -1,242 +1,32 @@
1
- import { KiruError } from "../error.js"
2
- import { __DEV__ } from "../env.js"
3
- import { hookIndex, node } from "../globals.js"
4
- import { noop } from "../utils/index.js"
5
- import { requestUpdate } from "../scheduler.js"
6
- import { isHmrUpdate } from "../hmr.js"
7
- export {
8
- cleanupHook,
9
- depsRequireChange,
10
- useHook,
11
- useVNode,
12
- useHookDebugGroup,
13
- useRequestUpdate,
14
- HookDebugGroupAction,
15
- type HookState,
16
- type HookCallback,
17
- type HookCallbackContext as HookCallbackState,
18
- }
19
-
20
- type HookState<T> = Kiru.Hook<T>
21
-
22
- enum HookDebugGroupAction {
23
- Start = "start",
24
- End = "end",
25
- }
26
-
27
- /**
28
- * **dev only - this is a no-op in production.**
29
- *
30
- * Used to create 'groups' of hooks in the devtools.
31
- * Useful for debugging and profiling.
32
- */
33
- const useHookDebugGroup = (name: string, action: HookDebugGroupAction) => {
34
- if (__DEV__) {
35
- return useHook(
36
- "devtools:useHookDebugGroup",
37
- { displayName: name, action },
38
- noop
39
- )
40
- }
41
- }
42
-
43
- /**
44
- * Used obtain an 'requestUpdate' function for the current component.
45
- */
46
- const useRequestUpdate = () => {
47
- const vNode = getVNodeOrError("useRequestUpdate")
48
- return () => requestUpdate(vNode)
49
- }
50
-
51
- /**
52
- * Used to obtain the 'VNode' for the current component.
53
- */
54
- const useVNode = () => {
55
- return getVNodeOrError("useVNode")
56
- }
57
-
58
- type HookCallbackContext<T> = {
59
- /**
60
- * The current state of the hook
61
- */
62
- hook: HookState<T>
63
- /**
64
- * Indicates if this is the first time the hook has been initialized
65
- */
66
- isInit: boolean
67
- /**
68
- * Dev mode only - indicates if the hook is being run as a result of a HMR update.
69
- * This is the time to clean up the previous version of the hook if necessary, ie. initial arguments changed.
70
- */
71
- isHMR?: boolean
72
- /**
73
- * Queues the current component to be re-rendered
74
- */
75
- update: () => void
76
- /**
77
- * Queues an effect to be run, either immediately or on the next render
78
- */
79
- queueEffect: (callback: Function, opts?: { immediate?: boolean }) => void
80
- /**
81
- * The VNode associated with the current component
82
- */
83
- vNode: Kiru.VNode
84
- /**
85
- * The index of the current hook.
86
- * You can count on this being stable across renders,
87
- * and unique across separate hooks in the same component.
88
- */
89
- index: number
90
- }
91
- type HookCallback<T> = (state: HookCallbackContext<T>) => any
92
-
93
- let currentHookName: string | null = null
94
- const nestedHookWarnings = new Set<string>()
95
-
96
- function useHook<
97
- T extends () => Record<string, unknown>,
98
- U extends HookCallback<ReturnType<T>>
99
- >(hookName: string, hookInitializer: T, callback: U): ReturnType<U>
100
-
101
- function useHook<T extends Record<string, unknown>, U extends HookCallback<T>>(
102
- hookName: string,
103
- hookData: T,
104
- callback: U
105
- ): ReturnType<U>
106
-
107
- function useHook<
108
- T,
109
- U extends T extends () => Record<string, unknown>
110
- ? HookCallback<ReturnType<T>>
111
- : HookCallback<T>
112
- >(
113
- hookName: string,
114
- hookDataOrInitializer: HookState<T> | (() => HookState<T>),
115
- callback: U
116
- ): ReturnType<U> {
117
- const vNode = getVNodeOrError(hookName)
118
-
119
- if (
120
- __DEV__ &&
121
- currentHookName !== null &&
122
- !nestedHookWarnings.has(hookName + currentHookName)
123
- ) {
124
- nestedHookWarnings.add(hookName + currentHookName)
125
- throw new KiruError({
126
- message: `Nested primitive "useHook" calls are not supported. "${hookName}" was called inside "${currentHookName}". Strange will most certainly happen.`,
127
- vNode,
128
- })
129
- }
130
-
131
- const queueEffect = (callback: Function, opts?: { immediate?: boolean }) => {
132
- if (opts?.immediate) {
133
- ;(vNode.immediateEffects ??= []).push(callback)
134
- return
1
+ import { node } from "../globals.js"
2
+ import { sideEffectsEnabled } from "../utils/index.js"
3
+
4
+ export function queueSetupEffect(
5
+ effect: Kiru.LifecycleHookCallback,
6
+ opts?: { immediate?: boolean }
7
+ ): void {
8
+ if (!sideEffectsEnabled()) return
9
+ const vNode = node.current!
10
+ if (!vNode)
11
+ throw new Error("Cannot queue setup effect outside of a component")
12
+
13
+ const hooks = (vNode.hooks ??= {
14
+ pre: [],
15
+ preCleanups: [],
16
+ post: [],
17
+ postCleanups: [],
18
+ })
19
+
20
+ const [bag, cleanups] = opts?.immediate
21
+ ? [hooks.pre, hooks.preCleanups]
22
+ : [hooks.post, hooks.postCleanups]
23
+
24
+ const wrapped = () => {
25
+ const ret = effect()
26
+ if (typeof ret === "function") {
27
+ cleanups.push(ret)
135
28
  }
136
- ;(vNode.effects ??= []).push(callback)
137
29
  }
138
30
 
139
- const index = hookIndex.current++
140
-
141
- let oldHook = vNode.hooks?.at(index) as HookState<T> | undefined
142
-
143
- if (__DEV__) {
144
- currentHookName = hookName
145
-
146
- vNode.hooks ??= []
147
- vNode.hookSig ??= []
148
-
149
- if (!vNode.hookSig[index]) {
150
- vNode.hookSig[index] = hookName
151
- } else {
152
- if (vNode.hookSig[index] !== hookName) {
153
- console.warn(
154
- `[kiru]: hooks must be called in the same order. Hook "${hookName}" was called in place of "${vNode.hookSig[index]}". Strange things may happen.`
155
- )
156
- oldHook?.cleanup?.()
157
- vNode.hooks.length = index
158
- vNode.hookSig.length = index
159
- oldHook = undefined
160
- }
161
- }
162
-
163
- let hook: HookState<T>
164
- if (!oldHook) {
165
- hook =
166
- typeof hookDataOrInitializer === "function"
167
- ? hookDataOrInitializer()
168
- : { ...hookDataOrInitializer }
169
- hook.name = hookName
170
- } else {
171
- hook = oldHook
172
- }
173
-
174
- vNode.hooks[index] = hook
175
-
176
- try {
177
- const res = (callback as HookCallback<T>)({
178
- hook,
179
- isInit: !oldHook,
180
- isHMR: isHmrUpdate(),
181
- update: () => requestUpdate(vNode),
182
- queueEffect,
183
- vNode,
184
- index,
185
- })
186
- return res
187
- } catch (error) {
188
- throw error
189
- } finally {
190
- currentHookName = null
191
- }
192
- }
193
-
194
- try {
195
- const hook: HookState<T> =
196
- oldHook ??
197
- (typeof hookDataOrInitializer === "function"
198
- ? hookDataOrInitializer()
199
- : { ...hookDataOrInitializer })
200
-
201
- vNode.hooks ??= []
202
- vNode.hooks[index] = hook
203
-
204
- const res = (callback as HookCallback<T>)({
205
- hook,
206
- isInit: !oldHook,
207
- update: () => requestUpdate(vNode),
208
- queueEffect,
209
- vNode,
210
- index,
211
- })
212
- return res
213
- } catch (error) {
214
- throw error
215
- }
216
- }
217
-
218
- function getVNodeOrError(hookName: string) {
219
- const vNode = node.current
220
- if (!vNode) {
221
- throw new KiruError(
222
- `Hook "${hookName}" must be used at the top level of a component or inside another composite hook.`
223
- )
224
- }
225
- return vNode
226
- }
227
-
228
- function cleanupHook(hook: { cleanup?: () => void }) {
229
- if (hook.cleanup) {
230
- hook.cleanup()
231
- hook.cleanup = undefined
232
- }
233
- }
234
-
235
- function depsRequireChange(a?: unknown[], b?: unknown[]) {
236
- return (
237
- a === undefined ||
238
- b === undefined ||
239
- a.length !== b.length ||
240
- (a.length > 0 && b.some((dep, i) => !Object.is(dep, a[i])))
241
- )
31
+ bag.push(wrapped)
242
32
  }
package/src/index.ts CHANGED
@@ -3,18 +3,26 @@ import { createKiruGlobalContext } from "./globalContext.js"
3
3
  export type * from "./types"
4
4
  export * from "./signals/index.js"
5
5
  export * from "./action.js"
6
- export * from "./appContext.js"
6
+ export * from "./appHandle.js"
7
+ export * from "./components/index.js"
7
8
  export * from "./context.js"
8
9
  export * from "./customEvents.js"
10
+ export * from "./devtools.js"
9
11
  export * from "./element.js"
10
12
  export * from "./error.js"
11
13
  export * from "./hooks/index.js"
12
- export * from "./components/index.js"
14
+ export type { ProfilingEvent, AppStats } from "./profiling.js"
13
15
  export * from "./renderToString.js"
14
- export { nextIdle, flushSync, requestUpdate } from "./scheduler.js"
15
- export * from "./store.js"
16
+ export * from "./ref.js"
17
+ export {
18
+ nextIdle,
19
+ flushSync,
20
+ requestUpdate,
21
+ useRequestUpdate,
22
+ } from "./scheduler.js"
23
+ export * from "./statefulPromise.js"
24
+ export * from "./viewTransitions.js"
16
25
 
17
- // @ts-ignore
18
- if ("window" in globalThis && !globalThis.__KIRU_DEVTOOLS__) {
26
+ if ("window" in globalThis) {
19
27
  globalThis.window.__kiru ??= createKiruGlobalContext()
20
28
  }
package/src/profiling.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { AppContext } from "./appContext"
1
+ import type { AppHandle } from "./appHandle"
2
2
 
3
3
  const MAX_TICKS = 100
4
4
 
@@ -13,27 +13,25 @@ const ProfilingEvents = [
13
13
  ] as const
14
14
 
15
15
  export type ProfilingEvent = (typeof ProfilingEvents)[number]
16
+ export interface AppStats {
17
+ timestamps: TickTS[]
18
+ mountDuration: number
19
+ totalTicks: number
20
+ }
16
21
 
17
22
  interface TickTS {
18
23
  start: number
19
24
  end: number
20
25
  }
21
26
 
22
- type ProfilingEventListener = (app: AppContext) => void
27
+ type ProfilingEventListener = (app: AppHandle) => void
23
28
 
24
29
  export function createProfilingContext() {
25
30
  const eventListeners = new Map<ProfilingEvent, Set<ProfilingEventListener>>()
26
- const appStats: Map<
27
- AppContext,
28
- {
29
- timestamps: TickTS[]
30
- mountDuration: number
31
- totalTicks: number
32
- }
33
- > = new Map()
31
+ const appStats: Map<AppHandle, AppStats> = new Map()
34
32
  return {
35
33
  appStats,
36
- emit: (event: ProfilingEvent, app: AppContext) => {
34
+ emit: (event: ProfilingEvent, app: AppHandle) => {
37
35
  eventListeners.get(event)?.forEach((listener) => listener(app))
38
36
  },
39
37
  addEventListener: (
@@ -52,23 +50,28 @@ export function createProfilingContext() {
52
50
  if (!eventListeners.has(event)) return
53
51
  eventListeners.get(event)!.delete(listener)
54
52
  },
55
- mountDuration: (app: AppContext) => {
53
+ mountDuration: (app: AppHandle) => {
56
54
  const stats = appStats.get(app)
57
55
  if (!stats) return 0
58
56
  return stats.mountDuration
59
57
  },
60
- totalTicks: (app: AppContext) => {
58
+ totalTicks: (app: AppHandle) => {
61
59
  const stats = appStats.get(app)
62
60
  if (!stats) return 0
63
61
  return stats.totalTicks
64
62
  },
65
- lastTickDuration: (app: AppContext) => {
63
+ lastTickDuration: (app: AppHandle) => {
66
64
  const stats = appStats.get(app)
67
- if (!stats) return 0
68
- const last = stats.timestamps[stats.timestamps.length - 1]
65
+ if (!stats) return Infinity
66
+ let last = stats.timestamps[stats.timestamps.length - 1]
67
+ if (!last) return Infinity
68
+ if (last.end === Infinity) {
69
+ last = stats.timestamps[stats.timestamps.length - 2]
70
+ }
71
+ if (!last) return Infinity
69
72
  return last.end - last.start
70
73
  },
71
- averageTickDuration: (app: AppContext) => {
74
+ averageTickDuration: (app: AppHandle) => {
72
75
  const stats = appStats.get(app)
73
76
  if (!stats) return 0
74
77
  const completeTicks = stats.timestamps.filter((ts) => ts.end !== Infinity)
@@ -77,7 +80,7 @@ export function createProfilingContext() {
77
80
  completeTicks.length
78
81
  )
79
82
  },
80
- beginTick: (app: AppContext) => {
83
+ beginTick: (app: AppHandle) => {
81
84
  if (!appStats.has(app)) {
82
85
  appStats.set(app, {
83
86
  mountDuration: Infinity,
@@ -89,8 +92,7 @@ export function createProfilingContext() {
89
92
  stats.totalTicks++
90
93
  stats.timestamps.push({ start: performance.now(), end: Infinity })
91
94
  },
92
- endTick: (app: AppContext) => {
93
- if (!appStats.has(app)) return
95
+ endTick: (app: AppHandle) => {
94
96
  const stats = appStats.get(app)!
95
97
 
96
98
  const last = stats.timestamps[stats.timestamps.length - 1]
package/src/reconciler.ts CHANGED
@@ -1,31 +1,26 @@
1
+ import { $FRAGMENT, FLAG_PLACEMENT, FLAG_UPDATE } from "./constants.js"
1
2
  import {
2
- $FRAGMENT,
3
- FLAG_MEMO,
4
- FLAG_PLACEMENT,
5
- FLAG_UPDATE,
6
- } from "./constants.js"
7
- import {
8
- getVNodeAppContext,
3
+ getVNodeApp,
9
4
  isElement,
10
5
  isValidTextChild,
11
6
  latest,
7
+ propsChanged,
12
8
  } from "./utils/index.js"
13
9
  import { Signal } from "./signals/base.js"
14
10
  import { __DEV__ } from "./env.js"
15
- import type { AppContext } from "./appContext.js"
16
- import { isMemoFn } from "./components/memo.js"
11
+ import type { AppHandle } from "./appHandle.js"
17
12
  import { createVNode as createBaseVNode } from "./vNode.js"
18
13
 
19
14
  type VNode = Kiru.VNode
20
15
  type KElement = Kiru.Element
21
- let appCtx: AppContext
16
+ let app: AppHandle
22
17
 
23
18
  export function reconcileChildren(
24
19
  parent: VNode,
25
20
  children: unknown
26
21
  ): VNode | null {
27
22
  if (__DEV__) {
28
- appCtx = getVNodeAppContext(parent)!
23
+ app = getVNodeApp(parent)!
29
24
  }
30
25
  if (Array.isArray(children)) {
31
26
  if (__DEV__) {
@@ -238,7 +233,7 @@ function updateNode(parent: VNode, oldChild: VNode | null, newChild: KElement) {
238
233
  oldChild.index = 0
239
234
  oldChild.sibling = null
240
235
  if (typeof type === "string") {
241
- if (propsChanged(oldChild.props, props)) {
236
+ if (domNodePropsChanged(oldChild.props, props)) {
242
237
  oldChild.flags |= FLAG_UPDATE
243
238
  }
244
239
  } else {
@@ -344,7 +339,7 @@ function updateFromMap(
344
339
  dev_emitUpdateNode()
345
340
  }
346
341
  if (typeof type === "string") {
347
- if (propsChanged(oldChild.props, props)) {
342
+ if (domNodePropsChanged(oldChild.props, props)) {
348
343
  oldChild.flags |= FLAG_UPDATE
349
344
  }
350
345
  } else {
@@ -380,20 +375,9 @@ function updateFromMap(
380
375
  return null
381
376
  }
382
377
 
383
- function propsChanged(oldProps: VNode["props"], newProps: VNode["props"]) {
384
- const aKeys = Object.keys(oldProps)
385
- const bKeys = Object.keys(newProps)
386
- if (aKeys.length !== bKeys.length) return true
387
- for (let key of aKeys) {
388
- if (key === "children" || key === "key") continue
389
- if (oldProps[key] !== newProps[key]) return true
390
- }
391
- return false
392
- }
393
-
394
378
  function dev_emitUpdateNode() {
395
379
  if (!("window" in globalThis)) return
396
- window.__kiru.profilingContext?.emit("updateNode", appCtx)
380
+ window.__kiru.profilingContext?.emit("updateNode", app)
397
381
  }
398
382
 
399
383
  const $LIST_CHILD = Symbol("kiru:marked-list-child")
@@ -495,12 +479,16 @@ function createVNode(
495
479
  const node = createBaseVNode(type, parent, props, key, index)
496
480
  node.flags |= FLAG_PLACEMENT
497
481
 
498
- if (typeof type === "function" && isMemoFn(type)) {
499
- node.flags |= FLAG_MEMO
500
- }
501
-
502
482
  if (__DEV__ && "window" in globalThis) {
503
- window.__kiru.profilingContext?.emit("createNode", appCtx)
483
+ window.__kiru.profilingContext?.emit("createNode", app)
504
484
  }
505
485
  return node
506
486
  }
487
+
488
+ const IGNORED_DOM_NODE_PROPS = ["children", "key"]
489
+ function domNodePropsChanged(
490
+ oldProps: Kiru.VNode["props"],
491
+ newProps: Kiru.VNode["props"]
492
+ ) {
493
+ return propsChanged(oldProps, newProps, IGNORED_DOM_NODE_PROPS)
494
+ }
package/src/ref.ts ADDED
@@ -0,0 +1,6 @@
1
+ export function ref<T>(initialValue: T): Kiru.RefObject<T>
2
+ export function ref<T>(initialValue: T | null): Kiru.RefObject<T | null>
3
+ export function ref<T = undefined>(): Kiru.RefObject<T | undefined>
4
+ export function ref<T>(initialValue?: T | null) {
5
+ return { current: initialValue }
6
+ }
@@ -1,6 +1,6 @@
1
1
  import { renderMode } from "./globals.js"
2
2
  import { Fragment } from "./element.js"
3
- import { headlessRender, HeadlessRenderContext } from "./recursiveRender.js"
3
+ import { headlessRender, HeadlessRenderContext } from "./headlessRender.js"
4
4
 
5
5
  export function renderToString(element: JSX.Element) {
6
6
  const prev = renderMode.current
@@ -1,6 +1,5 @@
1
- import { createContext } from "../context.js"
1
+ import { createContext, useContext } from "../context.js"
2
2
  import { __DEV__ } from "../env.js"
3
- import { useContext } from "../hooks/index.js"
4
3
  import type { RouteQuery, RouterState } from "./types.js"
5
4
 
6
5
  export interface ReloadOptions {
@@ -1,9 +1,9 @@
1
1
  import { createElement } from "../element.js"
2
- import { useState, useEffect } from "../hooks/index.js"
3
2
  import { RouterContext } from "./context.js"
4
3
  import { FileRouterController } from "./fileRouterController.js"
5
4
  import type { FileRouterConfig } from "./types.js"
6
5
  import { fileRouterInstance } from "./globals.js"
6
+ import { onCleanup } from "../hooks/onCleanup.js"
7
7
 
8
8
  export interface FileRouterProps {
9
9
  /**
@@ -24,18 +24,28 @@ export interface FileRouterProps {
24
24
  config: FileRouterConfig
25
25
  }
26
26
 
27
- export function FileRouter({ config }: FileRouterProps): JSX.Element {
28
- const [controller] = useState(() => {
29
- fileRouterInstance.current?.dispose()
30
- const router = (fileRouterInstance.current = new FileRouterController())
31
- router.init(config)
32
- return router
33
- })
34
- useEffect(() => () => controller.dispose(), [controller])
27
+ export const FileRouter: Kiru.FC<FileRouterProps> = ({ config }) => {
28
+ fileRouterInstance.current?.dispose()
29
+ let router = (fileRouterInstance.current = new FileRouterController())
30
+ let configStr = ""
35
31
 
36
- return createElement(
37
- RouterContext.Provider,
38
- { value: controller.contextValue },
39
- controller.getChildren()
32
+ onCleanup(() => router.dispose())
33
+
34
+ const onUpdate = (props: FileRouterProps) => {
35
+ const newConfigStr = JSON.stringify(props.config)
36
+ if (newConfigStr !== configStr) {
37
+ config = props.config
38
+ configStr = newConfigStr
39
+ router.init(config)
40
+ }
41
+ }
42
+
43
+ return (nextProps) => (
44
+ onUpdate(nextProps),
45
+ createElement(
46
+ RouterContext,
47
+ { value: router.contextValue },
48
+ router.getChildren()
49
+ )
40
50
  )
41
51
  }