kiru 0.48.3 → 0.50.0-preview.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 (253) hide show
  1. package/dist/action.d.ts +22 -0
  2. package/dist/action.d.ts.map +1 -0
  3. package/dist/action.js +20 -0
  4. package/dist/action.js.map +1 -0
  5. package/dist/components/errorBoundary.d.ts +7 -0
  6. package/dist/components/errorBoundary.d.ts.map +1 -0
  7. package/dist/components/errorBoundary.js +6 -0
  8. package/dist/components/errorBoundary.js.map +1 -0
  9. package/dist/components/index.d.ts +7 -0
  10. package/dist/components/index.d.ts.map +1 -0
  11. package/dist/components/index.js +7 -0
  12. package/dist/components/index.js.map +1 -0
  13. package/dist/components/lazy.d.ts.map +1 -0
  14. package/dist/{lazy.js → components/lazy.js} +11 -11
  15. package/dist/components/lazy.js.map +1 -0
  16. package/dist/{memo.d.ts → components/memo.d.ts} +1 -1
  17. package/dist/components/memo.d.ts.map +1 -0
  18. package/dist/{memo.js → components/memo.js} +2 -2
  19. package/dist/components/memo.js.map +1 -0
  20. package/dist/components/portal.d.ts.map +1 -0
  21. package/dist/{portal.js → components/portal.js} +6 -6
  22. package/dist/components/portal.js.map +1 -0
  23. package/dist/components/router/index.d.ts.map +1 -0
  24. package/dist/components/router/index.js.map +1 -0
  25. package/dist/components/router/route.d.ts.map +1 -0
  26. package/dist/{router → components/router}/route.js +1 -1
  27. package/dist/components/router/route.js.map +1 -0
  28. package/dist/{router → components/router}/router.d.ts +1 -1
  29. package/dist/components/router/router.d.ts.map +1 -0
  30. package/dist/{router → components/router}/router.js +8 -8
  31. package/dist/components/router/router.js.map +1 -0
  32. package/dist/components/router/routerUtils.d.ts.map +1 -0
  33. package/dist/components/router/routerUtils.js.map +1 -0
  34. package/dist/components/suspense.d.ts +33 -0
  35. package/dist/components/suspense.d.ts.map +1 -0
  36. package/dist/components/suspense.js +113 -0
  37. package/dist/components/suspense.js.map +1 -0
  38. package/dist/components/transition.d.ts.map +1 -0
  39. package/dist/{transition.js → components/transition.js} +5 -5
  40. package/dist/components/transition.js.map +1 -0
  41. package/dist/constants.d.ts +6 -12
  42. package/dist/constants.d.ts.map +1 -1
  43. package/dist/constants.js +83 -12
  44. package/dist/constants.js.map +1 -1
  45. package/dist/context.js +1 -1
  46. package/dist/context.js.map +1 -1
  47. package/dist/dom.d.ts.map +1 -1
  48. package/dist/dom.js +9 -12
  49. package/dist/dom.js.map +1 -1
  50. package/dist/element.js +2 -2
  51. package/dist/element.js.map +1 -1
  52. package/dist/error.js +1 -1
  53. package/dist/error.js.map +1 -1
  54. package/dist/form/index.d.ts.map +1 -1
  55. package/dist/form/index.js +1 -2
  56. package/dist/form/index.js.map +1 -1
  57. package/dist/hmr.js +1 -1
  58. package/dist/hmr.js.map +1 -1
  59. package/dist/hooks/useAsync.d.ts.map +1 -1
  60. package/dist/hooks/useAsync.js +2 -2
  61. package/dist/hooks/useAsync.js.map +1 -1
  62. package/dist/hooks/useCallback.d.ts.map +1 -1
  63. package/dist/hooks/useCallback.js +2 -1
  64. package/dist/hooks/useCallback.js.map +1 -1
  65. package/dist/hooks/useEffect.d.ts.map +1 -1
  66. package/dist/hooks/useEffect.js +2 -1
  67. package/dist/hooks/useEffect.js.map +1 -1
  68. package/dist/hooks/useEffectEvent.d.ts.map +1 -1
  69. package/dist/hooks/useEffectEvent.js +2 -1
  70. package/dist/hooks/useEffectEvent.js.map +1 -1
  71. package/dist/hooks/useLayoutEffect.d.ts.map +1 -1
  72. package/dist/hooks/useLayoutEffect.js +2 -1
  73. package/dist/hooks/useLayoutEffect.js.map +1 -1
  74. package/dist/hooks/useMemo.d.ts.map +1 -1
  75. package/dist/hooks/useMemo.js +2 -1
  76. package/dist/hooks/useMemo.js.map +1 -1
  77. package/dist/hooks/useReducer.js +2 -2
  78. package/dist/hooks/useReducer.js.map +1 -1
  79. package/dist/hooks/useRef.d.ts.map +1 -1
  80. package/dist/hooks/useRef.js +2 -1
  81. package/dist/hooks/useRef.js.map +1 -1
  82. package/dist/hooks/useState.js +2 -2
  83. package/dist/hooks/useState.js.map +1 -1
  84. package/dist/hooks/useSyncExternalStore.js +2 -2
  85. package/dist/hooks/useSyncExternalStore.js.map +1 -1
  86. package/dist/hooks/useViewTransition.d.ts.map +1 -1
  87. package/dist/hooks/useViewTransition.js +1 -2
  88. package/dist/hooks/useViewTransition.js.map +1 -1
  89. package/dist/hooks/utils.d.ts +0 -1
  90. package/dist/hooks/utils.d.ts.map +1 -1
  91. package/dist/hooks/utils.js +2 -2
  92. package/dist/hooks/utils.js.map +1 -1
  93. package/dist/index.d.ts +3 -5
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +3 -5
  96. package/dist/index.js.map +1 -1
  97. package/dist/reconciler.js +8 -7
  98. package/dist/reconciler.js.map +1 -1
  99. package/dist/renderToString.d.ts.map +1 -1
  100. package/dist/renderToString.js +93 -38
  101. package/dist/renderToString.js.map +1 -1
  102. package/dist/scheduler.d.ts.map +1 -1
  103. package/dist/scheduler.js +48 -11
  104. package/dist/scheduler.js.map +1 -1
  105. package/dist/signals/base.d.ts.map +1 -1
  106. package/dist/signals/base.js +1 -2
  107. package/dist/signals/base.js.map +1 -1
  108. package/dist/signals/computed.js +1 -1
  109. package/dist/signals/computed.js.map +1 -1
  110. package/dist/signals/effect.js +1 -1
  111. package/dist/signals/effect.js.map +1 -1
  112. package/dist/signals/watch.d.ts.map +1 -1
  113. package/dist/signals/watch.js +2 -3
  114. package/dist/signals/watch.js.map +1 -1
  115. package/dist/ssr/server.d.ts +4 -1
  116. package/dist/ssr/server.d.ts.map +1 -1
  117. package/dist/ssr/server.js +136 -66
  118. package/dist/ssr/server.js.map +1 -1
  119. package/dist/store.d.ts +1 -1
  120. package/dist/store.d.ts.map +1 -1
  121. package/dist/store.js +2 -2
  122. package/dist/store.js.map +1 -1
  123. package/dist/swr.js +1 -1
  124. package/dist/swr.js.map +1 -1
  125. package/dist/types.d.ts +14 -5
  126. package/dist/types.d.ts.map +1 -1
  127. package/dist/types.dom.d.ts +2 -2
  128. package/dist/types.dom.d.ts.map +1 -1
  129. package/dist/types.utils.d.ts +7 -1
  130. package/dist/types.utils.d.ts.map +1 -1
  131. package/dist/utils/compare.d.ts +3 -0
  132. package/dist/utils/compare.d.ts.map +1 -0
  133. package/dist/utils/compare.js +123 -0
  134. package/dist/utils/compare.js.map +1 -0
  135. package/dist/utils/format.d.ts +20 -0
  136. package/dist/utils/format.d.ts.map +1 -0
  137. package/dist/utils/format.js +136 -0
  138. package/dist/utils/format.js.map +1 -0
  139. package/dist/utils/generateId.d.ts.map +1 -0
  140. package/dist/utils/generateId.js.map +1 -0
  141. package/dist/utils/index.d.ts +7 -0
  142. package/dist/utils/index.d.ts.map +1 -0
  143. package/dist/utils/index.js +7 -0
  144. package/dist/utils/index.js.map +1 -0
  145. package/dist/utils/runtime.d.ts +11 -0
  146. package/dist/utils/runtime.d.ts.map +1 -0
  147. package/dist/utils/runtime.js +23 -0
  148. package/dist/utils/runtime.js.map +1 -0
  149. package/dist/utils/vdom.d.ts +27 -0
  150. package/dist/utils/vdom.d.ts.map +1 -0
  151. package/dist/utils/vdom.js +128 -0
  152. package/dist/utils/vdom.js.map +1 -0
  153. package/package.json +6 -6
  154. package/src/action.ts +42 -0
  155. package/src/components/errorBoundary.ts +16 -0
  156. package/src/components/index.ts +6 -0
  157. package/src/{lazy.ts → components/lazy.ts} +12 -12
  158. package/src/{memo.ts → components/memo.ts} +3 -3
  159. package/src/{portal.ts → components/portal.ts} +6 -6
  160. package/src/{router → components/router}/route.ts +1 -1
  161. package/src/{router → components/router}/router.ts +9 -9
  162. package/src/components/suspense.ts +193 -0
  163. package/src/{transition.ts → components/transition.ts} +5 -5
  164. package/src/constants.ts +86 -13
  165. package/src/context.ts +1 -1
  166. package/src/customEvents.ts +22 -22
  167. package/src/dom.ts +8 -11
  168. package/src/element.ts +2 -2
  169. package/src/error.ts +1 -1
  170. package/src/form/index.ts +5 -2
  171. package/src/hmr.ts +1 -1
  172. package/src/hooks/useAsync.ts +5 -3
  173. package/src/hooks/useCallback.ts +2 -1
  174. package/src/hooks/useEffect.ts +2 -6
  175. package/src/hooks/useEffectEvent.ts +2 -1
  176. package/src/hooks/useLayoutEffect.ts +2 -6
  177. package/src/hooks/useMemo.ts +2 -1
  178. package/src/hooks/useReducer.ts +2 -2
  179. package/src/hooks/useRef.ts +2 -1
  180. package/src/hooks/useState.ts +2 -2
  181. package/src/hooks/useSyncExternalStore.ts +2 -2
  182. package/src/hooks/useViewTransition.ts +1 -2
  183. package/src/hooks/utils.ts +2 -2
  184. package/src/index.ts +3 -5
  185. package/src/reconciler.ts +13 -11
  186. package/src/renderToString.ts +108 -42
  187. package/src/scheduler.ts +61 -14
  188. package/src/signals/base.ts +6 -2
  189. package/src/signals/computed.ts +1 -1
  190. package/src/signals/effect.ts +1 -1
  191. package/src/signals/watch.ts +2 -3
  192. package/src/ssr/server.ts +163 -71
  193. package/src/store.ts +6 -2
  194. package/src/swr.ts +3 -3
  195. package/src/types.dom.ts +2 -1
  196. package/src/types.ts +20 -2
  197. package/src/types.utils.ts +8 -0
  198. package/src/utils/compare.ts +125 -0
  199. package/src/utils/format.ts +162 -0
  200. package/src/utils/index.ts +7 -0
  201. package/src/utils/runtime.ts +25 -0
  202. package/src/utils/vdom.ts +195 -0
  203. package/dist/cloneVNode.d.ts +0 -2
  204. package/dist/cloneVNode.d.ts.map +0 -1
  205. package/dist/cloneVNode.js +0 -14
  206. package/dist/cloneVNode.js.map +0 -1
  207. package/dist/generateId.d.ts.map +0 -1
  208. package/dist/generateId.js.map +0 -1
  209. package/dist/lazy.d.ts.map +0 -1
  210. package/dist/lazy.js.map +0 -1
  211. package/dist/memo.d.ts.map +0 -1
  212. package/dist/memo.js.map +0 -1
  213. package/dist/portal.d.ts.map +0 -1
  214. package/dist/portal.js.map +0 -1
  215. package/dist/props.d.ts +0 -4
  216. package/dist/props.d.ts.map +0 -1
  217. package/dist/props.js +0 -27
  218. package/dist/props.js.map +0 -1
  219. package/dist/router/index.d.ts.map +0 -1
  220. package/dist/router/index.js.map +0 -1
  221. package/dist/router/route.d.ts.map +0 -1
  222. package/dist/router/route.js.map +0 -1
  223. package/dist/router/router.d.ts.map +0 -1
  224. package/dist/router/router.js.map +0 -1
  225. package/dist/router/routerUtils.d.ts.map +0 -1
  226. package/dist/router/routerUtils.js.map +0 -1
  227. package/dist/transition.d.ts.map +0 -1
  228. package/dist/transition.js.map +0 -1
  229. package/dist/utils.d.ts +0 -52
  230. package/dist/utils.d.ts.map +0 -1
  231. package/dist/utils.js +0 -433
  232. package/dist/utils.js.map +0 -1
  233. package/dist/warning.d.ts +0 -2
  234. package/dist/warning.d.ts.map +0 -1
  235. package/dist/warning.js +0 -4
  236. package/dist/warning.js.map +0 -1
  237. package/src/cloneVNode.ts +0 -14
  238. package/src/props.ts +0 -34
  239. package/src/utils.ts +0 -518
  240. package/src/warning.ts +0 -9
  241. /package/dist/{lazy.d.ts → components/lazy.d.ts} +0 -0
  242. /package/dist/{portal.d.ts → components/portal.d.ts} +0 -0
  243. /package/dist/{router → components/router}/index.d.ts +0 -0
  244. /package/dist/{router → components/router}/index.js +0 -0
  245. /package/dist/{router → components/router}/route.d.ts +0 -0
  246. /package/dist/{router → components/router}/routerUtils.d.ts +0 -0
  247. /package/dist/{router → components/router}/routerUtils.js +0 -0
  248. /package/dist/{transition.d.ts → components/transition.d.ts} +0 -0
  249. /package/dist/{generateId.d.ts → utils/generateId.d.ts} +0 -0
  250. /package/dist/{generateId.js → utils/generateId.js} +0 -0
  251. /package/src/{router → components/router}/index.ts +0 -0
  252. /package/src/{router → components/router}/routerUtils.ts +0 -0
  253. /package/src/{generateId.ts → utils/generateId.ts} +0 -0
@@ -0,0 +1,193 @@
1
+ import { requestUpdate } from "../scheduler.js"
2
+ import { renderMode } from "../globals.js"
3
+ import {
4
+ cleanupHook,
5
+ depsRequireChange,
6
+ useHook,
7
+ useId,
8
+ } from "../hooks/index.js"
9
+ import { __DEV__ } from "../env.js"
10
+ import { getCurrentVNode } from "../utils/index.js"
11
+ import { $SUSPENSE_THROW, PREFETCHED_DATA_EVENT } from "../constants.js"
12
+ import { Signal, useSignal } from "../signals/index.js"
13
+
14
+ export type { SuspenseProps, UsePromiseState }
15
+ export { Suspense, isSuspenseThrowValue, usePromise }
16
+
17
+ type StatefulPromiseValues<T extends readonly Kiru.StatefulPromise<unknown>[]> =
18
+ {
19
+ [I in keyof T]: T[I] extends Kiru.StatefulPromise<infer V> ? V : never
20
+ }
21
+
22
+ type SuspenseChildrenArgs<
23
+ T extends Kiru.StatefulPromise<any> | Kiru.StatefulPromise<any>[]
24
+ > = T extends Kiru.StatefulPromise<any>[]
25
+ ? StatefulPromiseValues<T>
26
+ : [T extends Kiru.StatefulPromise<infer V> ? V : never]
27
+
28
+ interface SuspenseProps<
29
+ T extends Kiru.StatefulPromise<any> | Kiru.StatefulPromise<any>[]
30
+ > {
31
+ data: T
32
+ children: (...data: SuspenseChildrenArgs<T>) => JSX.Element
33
+ fallback?: JSX.Element
34
+ }
35
+
36
+ function Suspense<
37
+ const T extends
38
+ | Kiru.StatefulPromise<unknown>
39
+ | Kiru.StatefulPromise<unknown>[]
40
+ >({ data, children, fallback }: SuspenseProps<T>) {
41
+ const promiseArray: Kiru.StatefulPromise<unknown>[] = Array.isArray(data)
42
+ ? data
43
+ : [data]
44
+
45
+ switch (renderMode.current) {
46
+ case "stream":
47
+ case "string":
48
+ throw {
49
+ fallback,
50
+ pendingData: promiseArray,
51
+ [$SUSPENSE_THROW]: true,
52
+ } satisfies SuspenseThrowValue
53
+
54
+ case "dom":
55
+ case "hydrate":
56
+ for (const p of promiseArray) {
57
+ if (p.state === "rejected") throw p.error
58
+ if (p.state === "pending") {
59
+ const n = getCurrentVNode()!
60
+ Promise.allSettled(promiseArray).then(() => requestUpdate(n))
61
+ return fallback
62
+ }
63
+ }
64
+ const values = promiseArray.map((p) => p.value) as SuspenseChildrenArgs<T>
65
+
66
+ return children(...values)
67
+ }
68
+ }
69
+
70
+ interface SuspenseThrowValue {
71
+ fallback?: JSX.Element
72
+ pendingData?: Kiru.StatefulPromise<unknown>[]
73
+ [$SUSPENSE_THROW]: true
74
+ }
75
+
76
+ /**
77
+ * Returns true if the value was thrown by a Suspense component.
78
+ */
79
+ function isSuspenseThrowValue(value: unknown): value is SuspenseThrowValue {
80
+ return typeof value === "object" && !!value && $SUSPENSE_THROW in value
81
+ }
82
+
83
+ interface PromiseResolveEventDetail<T> {
84
+ id: string
85
+ data?: T
86
+ error?: string
87
+ }
88
+
89
+ function resolveHydrationPromise<T>(
90
+ id: string,
91
+ signal: AbortSignal
92
+ ): Promise<T> {
93
+ return new Promise<T>((resolve, reject) => {
94
+ const prefetchCache: Map<string, { data?: T; error?: string }> = // @ts-ignore
95
+ (window[PREFETCHED_DATA_EVENT] ??= new Map())
96
+
97
+ const existing = prefetchCache.get(id)
98
+ if (existing) {
99
+ const { data, error } = existing
100
+ prefetchCache.delete(id)
101
+ if (error) return reject(error)
102
+ return resolve(data!)
103
+ }
104
+
105
+ const onDataEvent = (event: Event) => {
106
+ const { detail } = event as CustomEvent<PromiseResolveEventDetail<T>>
107
+ if (detail.id === id) {
108
+ prefetchCache.delete(id)
109
+ window.removeEventListener(PREFETCHED_DATA_EVENT, onDataEvent)
110
+ const { data, error } = detail
111
+ if (error) return reject(error)
112
+ resolve(data!)
113
+ }
114
+ }
115
+
116
+ console.log("listening for prefetch event")
117
+ window.addEventListener(PREFETCHED_DATA_EVENT, onDataEvent)
118
+ signal.addEventListener("abort", () => {
119
+ window.removeEventListener(PREFETCHED_DATA_EVENT, onDataEvent)
120
+ reject()
121
+ })
122
+ })
123
+ }
124
+
125
+ const nodeToPromiseIndex = new WeakMap<Kiru.VNode, number>()
126
+
127
+ interface UsePromiseContext {
128
+ signal: AbortSignal
129
+ }
130
+
131
+ interface UsePromiseState<T> {
132
+ data: Kiru.StatefulPromise<T>
133
+ refresh: () => void
134
+ pending: Signal<boolean>
135
+ }
136
+
137
+ function usePromise<T>(
138
+ callback: (ctx: UsePromiseContext) => Promise<T>,
139
+ deps: unknown[]
140
+ ): UsePromiseState<T> {
141
+ const id = useId()
142
+ const pending = useSignal(true)
143
+
144
+ return useHook(
145
+ "usePromise",
146
+ {} as {
147
+ promise: Kiru.StatefulPromise<T>
148
+ abortController?: AbortController
149
+ deps?: unknown[]
150
+ },
151
+ ({ hook, isInit, vNode }) => {
152
+ if (isInit || depsRequireChange(deps, hook.deps)) {
153
+ pending.value = true
154
+ hook.deps = deps
155
+ cleanupHook(hook)
156
+
157
+ const controller = (hook.abortController = new AbortController())
158
+ hook.cleanup = () => controller.abort()
159
+
160
+ const index = nodeToPromiseIndex.get(vNode) ?? 0
161
+ nodeToPromiseIndex.set(vNode, index + 1)
162
+
163
+ const promiseId = `${id}:data:${index}`
164
+ const state: Kiru.PromiseState<T> = { id: promiseId, state: "pending" }
165
+ const promise =
166
+ renderMode.current === "hydrate"
167
+ ? resolveHydrationPromise<T>(promiseId, controller.signal)
168
+ : callback({ signal: controller.signal })
169
+
170
+ const p = (hook.promise = Object.assign(promise, state))
171
+ p.then((value) => {
172
+ p.state = "fulfilled"
173
+ p.value = value
174
+ })
175
+ .catch((error) => {
176
+ p.state = "rejected"
177
+ p.error = error instanceof Error ? error : new Error(error)
178
+ })
179
+ .finally(() => {
180
+ pending.value = false
181
+ })
182
+ }
183
+ return {
184
+ data: hook.promise,
185
+ refresh: () => {
186
+ hook.deps = undefined
187
+ requestUpdate(vNode)
188
+ },
189
+ pending,
190
+ }
191
+ }
192
+ )
193
+ }
@@ -1,8 +1,8 @@
1
- import { useCallback } from "./hooks/useCallback.js"
2
- import { useEffect } from "./hooks/useEffect.js"
3
- import { useLayoutEffect } from "./hooks/useLayoutEffect.js"
4
- import { useRef } from "./hooks/useRef.js"
5
- import { useState } from "./hooks/useState.js"
1
+ import { useCallback } from "../hooks/useCallback.js"
2
+ import { useEffect } from "../hooks/useEffect.js"
3
+ import { useLayoutEffect } from "../hooks/useLayoutEffect.js"
4
+ import { useRef } from "../hooks/useRef.js"
5
+ import { useState } from "../hooks/useState.js"
6
6
 
7
7
  export type TransitionState = "entering" | "entered" | "exiting" | "exited"
8
8
  interface TransitionProps {
package/src/constants.ts CHANGED
@@ -6,9 +6,11 @@ export {
6
6
  $KIRU_ERROR,
7
7
  $HMR_ACCEPT,
8
8
  $MEMO,
9
+ $ERROR_BOUNDARY,
9
10
  $HYDRATION_BOUNDARY,
11
+ $SUSPENSE_THROW,
10
12
  CONSECUTIVE_DIRTY_LIMIT,
11
- REGEX_UNIT,
13
+ PREFETCHED_DATA_EVENT,
12
14
  EVENT_PREFIX_REGEX,
13
15
  FLAG_UPDATE,
14
16
  FLAG_PLACEMENT,
@@ -19,7 +21,7 @@ export {
19
21
  FLAG_DIRTY,
20
22
  }
21
23
 
22
- export { voidElements, svgTags, booleanAttributes }
24
+ export { voidElements, svgTags, booleanAttributes, snakeCaseAttributes }
23
25
 
24
26
  const $SIGNAL = Symbol.for("kiru.signal")
25
27
  const $CONTEXT = Symbol.for("kiru.context")
@@ -28,9 +30,12 @@ const $FRAGMENT = Symbol.for("kiru.fragment")
28
30
  const $KIRU_ERROR = Symbol.for("kiru.error")
29
31
  const $HMR_ACCEPT = Symbol.for("kiru.hmrAccept")
30
32
  const $MEMO = Symbol.for("kiru.memo")
33
+ const $ERROR_BOUNDARY = Symbol.for("kiru.errorBoundary")
31
34
  const $HYDRATION_BOUNDARY = Symbol.for("kiru.hydrationBoundary")
35
+ const $SUSPENSE_THROW = Symbol.for("kiru.suspenseThrow")
32
36
 
33
37
  const CONSECUTIVE_DIRTY_LIMIT = 50
38
+ const PREFETCHED_DATA_EVENT = "kiru:prefetched"
34
39
 
35
40
  const FLAG_UPDATE = 1 << 1
36
41
  const FLAG_PLACEMENT = 1 << 2
@@ -40,17 +45,6 @@ const FLAG_MEMO = 1 << 5
40
45
  const FLAG_NOOP = 1 << 6
41
46
  const FLAG_DIRTY = 1 << 7
42
47
 
43
- const REGEX_UNIT = {
44
- AMP_G: /&/g,
45
- LT_G: /</g,
46
- GT_G: />/g,
47
- SQT_G: /'/g,
48
- DBLQT_G: /"/g,
49
- SLASH_G: /\//g,
50
- SLASHN_SLASHR_G: /[\n\r]+/g,
51
- ALPHA_UPPER_G: /[A-Z]/g,
52
- } as const
53
-
54
48
  const EVENT_PREFIX_REGEX = /^on:?/
55
49
 
56
50
  const voidElements = new Set([
@@ -155,3 +149,82 @@ const booleanAttributes = new Set([
155
149
  "translate",
156
150
  "wrap",
157
151
  ])
152
+
153
+ const snakeCaseAttributes = new Map([
154
+ ["acceptCharset", "accept-charset"],
155
+ ["accentHeight", "accent-height"],
156
+ ["alignmentBaseline", "alignment-baseline"],
157
+ ["arabicForm", "arabic-form"],
158
+ ["baselineShift", "baseline-shift"],
159
+ ["capHeight", "cap-height"],
160
+ ["clipPath", "clip-path"],
161
+ ["clipRule", "clip-rule"],
162
+ ["colorInterpolation", "color-interpolation"],
163
+ ["colorInterpolationFilters", "color-interpolation-filters"],
164
+ ["colorProfile", "color-profile"],
165
+ ["colorRendering", "color-rendering"],
166
+ ["dominantBaseline", "dominant-baseline"],
167
+ ["enableBackground", "enable-background"],
168
+ ["fillOpacity", "fill-opacity"],
169
+ ["fillRule", "fill-rule"],
170
+ ["floodColor", "flood-color"],
171
+ ["floodOpacity", "flood-opacity"],
172
+ ["fontFamily", "font-family"],
173
+ ["fontSize", "font-size"],
174
+ ["fontSizeAdjust", "font-size-adjust"],
175
+ ["fontStretch", "font-stretch"],
176
+ ["fontStyle", "font-style"],
177
+ ["fontVariant", "font-variant"],
178
+ ["fontWeight", "font-weight"],
179
+ ["glyphName", "glyph-name"],
180
+ ["glyphOrientationHorizontal", "glyph-orientation-horizontal"],
181
+ ["glyphOrientationVertical", "glyph-orientation-vertical"],
182
+ ["horizAdvX", "horiz-adv-x"],
183
+ ["horizOriginX", "horiz-origin-x"],
184
+ ["httpEquiv", "http-equiv"],
185
+ ["imageRendering", "image-rendering"],
186
+ ["letterSpacing", "letter-spacing"],
187
+ ["lightingColor", "lighting-color"],
188
+ ["markerEnd", "marker-end"],
189
+ ["markerMid", "marker-mid"],
190
+ ["markerStart", "marker-start"],
191
+ ["overlinePosition", "overline-position"],
192
+ ["overlineThickness", "overline-thickness"],
193
+ ["paintOrder", "paint-order"],
194
+ ["panose-1", "panose-1"],
195
+ ["pointerEvents", "pointer-events"],
196
+ ["renderingIntent", "rendering-intent"],
197
+ ["shapeRendering", "shape-rendering"],
198
+ ["stopColor", "stop-color"],
199
+ ["stopOpacity", "stop-opacity"],
200
+ ["strikethroughPosition", "strikethrough-position"],
201
+ ["strikethroughThickness", "strikethrough-thickness"],
202
+ ["strokeDasharray", "stroke-dasharray"],
203
+ ["strokeDashoffset", "stroke-dashoffset"],
204
+ ["strokeLinecap", "stroke-linecap"],
205
+ ["strokeLinejoin", "stroke-linejoin"],
206
+ ["strokeMiterlimit", "stroke-miterlimit"],
207
+ ["strokeOpacity", "stroke-opacity"],
208
+ ["strokeWidth", "stroke-width"],
209
+ ["textAnchor", "text-anchor"],
210
+ ["textDecoration", "text-decoration"],
211
+ ["textRendering", "text-rendering"],
212
+ ["transformOrigin", "transform-origin"],
213
+ ["underlinePosition", "underline-position"],
214
+ ["underlineThickness", "underline-thickness"],
215
+ ["unicodeBidi", "unicode-bidi"],
216
+ ["unicodeRange", "unicode-range"],
217
+ ["unitsPerEm", "units-per-em"],
218
+ ["vAlphabetic", "v-alphabetic"],
219
+ ["vHanging", "v-hanging"],
220
+ ["vIdeographic", "v-ideographic"],
221
+ ["vMathematical", "v-mathematical"],
222
+ ["vectorEffect", "vector-effect"],
223
+ ["vertAdvY", "vert-adv-y"],
224
+ ["vertOriginX", "vert-origin-x"],
225
+ ["vertOriginY", "vert-origin-y"],
226
+ ["wordSpacing", "word-spacing"],
227
+ ["writingMode", "writing-mode"],
228
+ ["xmlnsXlink", "xmlns:xlink"],
229
+ ["xHeight", "x-height"],
230
+ ])
package/src/context.ts CHANGED
@@ -4,7 +4,7 @@ import { __DEV__ } from "./env.js"
4
4
  import { GenericHMRAcceptor } from "./hmr.js"
5
5
  import { useState } from "./hooks/useState.js"
6
6
  import { requestUpdate } from "./scheduler.js"
7
- import { traverseApply } from "./utils.js"
7
+ import { traverseApply } from "./utils/index.js"
8
8
 
9
9
  export function createContext<T>(defaultValue: T): Kiru.Context<T> {
10
10
  const ctx: Kiru.Context<T> = {
@@ -1,22 +1,22 @@
1
- export class CustomEvents {
2
- private constructor() {}
3
-
4
- static on<K extends keyof Kiru.CustomEvents & string>(
5
- type: K,
6
- callback: (event: CustomEvent<Kiru.CustomEvents[K]>) => void
7
- ) {
8
- window.addEventListener(type, callback as unknown as EventListener)
9
- return () =>
10
- window.removeEventListener(type, callback as unknown as EventListener)
11
- }
12
-
13
- static dispatch<K extends keyof Kiru.CustomEvents & string>(
14
- type: K,
15
- detail: Kiru.CustomEvents[K],
16
- target?: Element
17
- ) {
18
- ;(target || document).dispatchEvent(
19
- new CustomEvent(type, { detail, bubbles: true })
20
- )
21
- }
22
- }
1
+ export class CustomEvents {
2
+ private constructor() {}
3
+
4
+ static on<K extends keyof Kiru.CustomEvents & string>(
5
+ type: K,
6
+ callback: (event: CustomEvent<Kiru.CustomEvents[K]>) => void
7
+ ) {
8
+ window.addEventListener(type, callback as unknown as EventListener)
9
+ return () =>
10
+ window.removeEventListener(type, callback as unknown as EventListener)
11
+ }
12
+
13
+ static dispatch<K extends keyof Kiru.CustomEvents & string>(
14
+ type: K,
15
+ detail: Kiru.CustomEvents[K],
16
+ target?: Element
17
+ ) {
18
+ ;(target || document).dispatchEvent(
19
+ new CustomEvent(type, { detail, bubbles: true })
20
+ )
21
+ }
22
+ }
package/src/dom.ts CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  propFilters,
5
5
  propToHtmlAttr,
6
6
  getVNodeAppContext,
7
- } from "./utils.js"
7
+ } from "./utils/index.js"
8
8
  import {
9
9
  booleanAttributes,
10
10
  FLAG_PLACEMENT,
@@ -100,15 +100,14 @@ function createDom(vNode: DomVNode): SomeDom {
100
100
  return dom
101
101
  }
102
102
  function createTextNode(vNode: VNode): Text {
103
- const nodeValue = vNode.props.nodeValue
104
- if (Signal.isSignal(nodeValue)) {
105
- const value = nodeValue.peek()
106
- const textNode = document.createTextNode(value)
107
- subTextNode(vNode, textNode, nodeValue)
108
- return textNode
103
+ const { nodeValue } = vNode.props
104
+ if (!Signal.isSignal(nodeValue)) {
105
+ return document.createTextNode(nodeValue)
109
106
  }
110
107
 
111
- const textNode = document.createTextNode(nodeValue)
108
+ const value = nodeValue.peek() ?? ""
109
+ const textNode = document.createTextNode(value)
110
+ subTextNode(vNode, textNode, nodeValue)
112
111
  return textNode
113
112
  }
114
113
 
@@ -720,9 +719,7 @@ function placeAndCommitNoopChildren(
720
719
  const nextSiblingDom = getNextSiblingDom(parent, node)
721
720
  const parentDom = node.dom
722
721
  if (nextSiblingDom) {
723
- const [first, ...rest] = domChildren
724
- parentDom.insertBefore(first, nextSiblingDom)
725
- first.after(...rest)
722
+ nextSiblingDom.before(...domChildren)
726
723
  } else {
727
724
  parentDom.append(...domChildren)
728
725
  }
package/src/element.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { $FRAGMENT, $MEMO, FLAG_MEMO } from "./constants.js"
2
- import { isMemoFn } from "./memo.js"
3
- import { isValidElementKeyProp, isValidElementRefProp } from "./props.js"
2
+ import { isMemoFn } from "./components/memo.js"
3
+ import { isValidElementKeyProp, isValidElementRefProp } from "./utils/index.js"
4
4
 
5
5
  export function createElement<T extends Kiru.VNode["type"]>(
6
6
  type: T,
package/src/error.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { $KIRU_ERROR } from "./constants.js"
2
2
  import { __DEV__ } from "./env.js"
3
- import { findParent, noop } from "./utils.js"
3
+ import { findParent, noop } from "./utils/index.js"
4
4
 
5
5
  type KiruErrorOptions =
6
6
  | string
package/src/form/index.ts CHANGED
@@ -1,7 +1,10 @@
1
1
  import { __DEV__ } from "../env.js"
2
2
  import { Fragment } from "../element.js"
3
- import { generateRandomID } from "../generateId.js"
4
- import { safeStringify, shallowCompare } from "../utils.js"
3
+ import {
4
+ safeStringify,
5
+ shallowCompare,
6
+ generateRandomID,
7
+ } from "../utils/index.js"
5
8
  import { useEffect } from "../hooks/useEffect.js"
6
9
  import { useMemo } from "../hooks/useMemo.js"
7
10
  import { useRef } from "../hooks/useRef.js"
package/src/hmr.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { $HMR_ACCEPT } from "./constants.js"
2
2
  import { __DEV__ } from "./env.js"
3
- import { traverseApply } from "./utils.js"
3
+ import { traverseApply } from "./utils/index.js"
4
4
  import { requestUpdate } from "./scheduler.js"
5
5
  import { Signal } from "./signals/base.js"
6
6
  import type { WatchEffect } from "./signals/watch.js"
@@ -1,6 +1,6 @@
1
1
  import { __DEV__ } from "../env.js"
2
- import { noop } from "../utils.js"
3
- import { depsRequireChange, sideEffectsEnabled, useHook } from "./utils.js"
2
+ import { noop, sideEffectsEnabled } from "../utils/index.js"
3
+ import { depsRequireChange, useHook } from "./utils.js"
4
4
  import type { AsyncTaskState } from "../types.utils.js"
5
5
 
6
6
  export type UseAsyncState<T> = AsyncTaskState<T, UseAsyncError> & {
@@ -48,7 +48,9 @@ export function useAsync<T>(
48
48
  deps,
49
49
  id: 0,
50
50
  task: null as any as InternalTaskState<T>,
51
- load: noop as (func: (ctx: UseAsyncCallbackContext) => Promise<T>) => void,
51
+ load: noop as (
52
+ func: (ctx: UseAsyncCallbackContext) => Promise<T>
53
+ ) => void,
52
54
  },
53
55
  ({ hook, isInit, isHMR, update }) => {
54
56
  if (__DEV__) {
@@ -1,5 +1,6 @@
1
1
  import { __DEV__ } from "../env.js"
2
- import { depsRequireChange, useHook, sideEffectsEnabled } from "./utils.js"
2
+ import { sideEffectsEnabled } from "../utils/index.js"
3
+ import { depsRequireChange, useHook } from "./utils.js"
3
4
 
4
5
  /**
5
6
  * Creates a memoized callback function.
@@ -1,10 +1,6 @@
1
+ import { sideEffectsEnabled } from "../utils/index.js"
1
2
  import { __DEV__ } from "../env.js"
2
- import {
3
- cleanupHook,
4
- depsRequireChange,
5
- sideEffectsEnabled,
6
- useHook,
7
- } from "./utils.js"
3
+ import { cleanupHook, depsRequireChange, useHook } from "./utils.js"
8
4
 
9
5
  /**
10
6
  * Runs a function after the component is rendered, or when a value provided in the optional [dependency
@@ -1,6 +1,7 @@
1
+ import { sideEffectsEnabled } from "../utils/index.js"
1
2
  import { node } from "../globals.js"
2
3
  import { __DEV__ } from "../env.js"
3
- import { sideEffectsEnabled, useHook } from "./utils.js"
4
+ import { useHook } from "./utils.js"
4
5
 
5
6
  /**
6
7
  * Wraps a function to be called within effects and other callbacks.
@@ -1,10 +1,6 @@
1
+ import { sideEffectsEnabled } from "../utils/index.js"
1
2
  import { __DEV__ } from "../env.js"
2
- import {
3
- cleanupHook,
4
- depsRequireChange,
5
- sideEffectsEnabled,
6
- useHook,
7
- } from "./utils.js"
3
+ import { cleanupHook, depsRequireChange, useHook } from "./utils.js"
8
4
 
9
5
  /**
10
6
  * Runs a function before the component is rendered, or when a value provided in the optional [dependency
@@ -1,5 +1,6 @@
1
+ import { sideEffectsEnabled } from "../utils/index.js"
1
2
  import { __DEV__ } from "../env.js"
2
- import { depsRequireChange, sideEffectsEnabled, useHook } from "./utils.js"
3
+ import { depsRequireChange, useHook } from "./utils.js"
3
4
 
4
5
  /**
5
6
  * Creates a memoized value that only changes when the [dependency
@@ -1,6 +1,6 @@
1
1
  import { __DEV__ } from "../env.js"
2
- import { noop } from "../utils.js"
3
- import { sideEffectsEnabled, useHook } from "./utils.js"
2
+ import { noop, sideEffectsEnabled } from "../utils/index.js"
3
+ import { useHook } from "./utils.js"
4
4
 
5
5
  /**
6
6
  * Creates 'dispatcher-driven' state.
@@ -1,5 +1,6 @@
1
1
  import { __DEV__ } from "../env.js"
2
- import { sideEffectsEnabled, useHook } from "./utils.js"
2
+ import { sideEffectsEnabled } from "../utils/index.js"
3
+ import { useHook } from "./utils.js"
3
4
 
4
5
  /**
5
6
  * Creates a ref object. Useful for persisting values between renders or getting
@@ -1,6 +1,6 @@
1
1
  import { __DEV__ } from "../env.js"
2
- import { noop } from "../utils.js"
3
- import { sideEffectsEnabled, useHook } from "./utils.js"
2
+ import { noop, sideEffectsEnabled } from "../utils/index.js"
3
+ import { useHook } from "./utils.js"
4
4
 
5
5
  /**
6
6
  * Creates a stateful value, and returns the current value and a function to update it.
@@ -1,7 +1,7 @@
1
1
  import { node } from "../globals.js"
2
2
  import { KiruError } from "../error.js"
3
- import { noop } from "../utils.js"
4
- import { sideEffectsEnabled, useHook } from "./utils.js"
3
+ import { noop, sideEffectsEnabled } from "../utils/index.js"
4
+ import { useHook } from "./utils.js"
5
5
  import { __DEV__ } from "../env.js"
6
6
 
7
7
  /**
@@ -1,7 +1,6 @@
1
1
  import { flushSync } from "../scheduler.js"
2
2
  import { node } from "../globals.js"
3
- import { noop } from "../utils.js"
4
- import { sideEffectsEnabled } from "./utils.js"
3
+ import { noop, sideEffectsEnabled } from "../utils/index.js"
5
4
 
6
5
  /**
7
6
  * Allows you to easily use the [View Transition API](https://developer.mozilla.org/en-US/docs/Web/API/Document/startViewTransition)
@@ -1,9 +1,8 @@
1
1
  import { KiruError } from "../error.js"
2
2
  import { __DEV__ } from "../env.js"
3
3
  import { hookIndex, node } from "../globals.js"
4
- import { noop } from "../utils.js"
4
+ import { noop } from "../utils/index.js"
5
5
  import { requestUpdate } from "../scheduler.js"
6
- export { sideEffectsEnabled } from "../utils.js"
7
6
  export {
8
7
  cleanupHook,
9
8
  depsRequireChange,
@@ -158,6 +157,7 @@ function useHook<
158
157
  console.warn(
159
158
  `[kiru]: hooks must be called in the same order. Hook "${hookName}" was called in place of "${vNode.hookSig[index]}". Strange things may happen.`
160
159
  )
160
+ oldHook?.cleanup?.()
161
161
  vNode.hooks.length = index
162
162
  vNode.hookSig.length = index
163
163
  oldHook = undefined
package/src/index.ts CHANGED
@@ -3,19 +3,17 @@ import { createKiruGlobalContext } from "./globalContext.js"
3
3
 
4
4
  export type * from "./types"
5
5
  export * from "./signals/index.js"
6
+ export * from "./action.js"
6
7
  export * from "./appContext.js"
7
- export * from "./cloneVNode.js"
8
8
  export * from "./context.js"
9
9
  export * from "./customEvents.js"
10
10
  export * from "./element.js"
11
+ export * from "./error.js"
11
12
  export * from "./hooks/index.js"
12
- export * from "./lazy.js"
13
- export { memo } from "./memo.js"
14
- export * from "./portal.js"
13
+ export * from "./components/index.js"
15
14
  export * from "./renderToString.js"
16
15
  export { nextIdle, flushSync, requestUpdate } from "./scheduler.js"
17
16
  export * from "./store.js"
18
- export * from "./transition.js"
19
17
 
20
18
  if (__DEV__) {
21
19
  if ("window" in globalThis) {