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
package/src/store.ts CHANGED
@@ -1,9 +1,13 @@
1
1
  import type { Prettify } from "./types.utils.js"
2
2
  import { __DEV__ } from "./env.js"
3
- import { sideEffectsEnabled, useHook } from "./hooks/utils.js"
4
- import { safeStringify, shallowCompare } from "./utils.js"
3
+ import { useHook } from "./hooks/utils.js"
5
4
  import { $HMR_ACCEPT } from "./constants.js"
6
5
  import { HMRAccept } from "./hmr.js"
6
+ import {
7
+ safeStringify,
8
+ shallowCompare,
9
+ sideEffectsEnabled,
10
+ } from "./utils/index.js"
7
11
 
8
12
  export { createStore }
9
13
  export type { Store, MethodFactory }
package/src/swr.ts CHANGED
@@ -3,12 +3,12 @@ import { useHook } from "./hooks/utils.js"
3
3
  import { Signal } from "./signals/base.js"
4
4
  import { AsyncTaskState } from "./types.utils.js"
5
5
  import {
6
- noop,
7
6
  deepCompare,
7
+ noop,
8
8
  safeStringify,
9
- sideEffectsEnabled,
10
9
  shallowCompare,
11
- } from "./utils.js"
10
+ sideEffectsEnabled,
11
+ } from "./utils/index.js"
12
12
 
13
13
  export type UseSWRState<T> = AsyncTaskState<T, UseSWRError> & {
14
14
  mutate: (callback: () => Promise<T>) => void
package/src/types.dom.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Signal } from "./signals"
1
+ import type { Signal } from "./signals"
2
2
  import type { Prettify, Signalable } from "./types.utils"
3
3
 
4
4
  export type {
@@ -60,6 +60,7 @@ type NumericStyleKeys =
60
60
  | "width"
61
61
 
62
62
  // Flexbox
63
+ | "flex"
63
64
  | "flexBasis"
64
65
  | "flexGrow"
65
66
  | "flexShrink"
package/src/types.ts CHANGED
@@ -2,6 +2,7 @@ import type { ReadonlySignal, Signal as SignalClass } from "./signals"
2
2
  import type {
3
3
  $CONTEXT,
4
4
  $CONTEXT_PROVIDER,
5
+ $ERROR_BOUNDARY,
5
6
  $FRAGMENT,
6
7
  $HYDRATION_BOUNDARY,
7
8
  } from "./constants"
@@ -16,7 +17,12 @@ import type {
16
17
  HTMLTagToElement,
17
18
  SVGTagToElement,
18
19
  } from "./types.dom"
19
- import { AsyncTaskState, Prettify, Signalable, SomeDom } from "./types.utils"
20
+ import type {
21
+ AsyncTaskState,
22
+ Prettify,
23
+ Signalable,
24
+ SomeDom,
25
+ } from "./types.utils"
20
26
  import type { AppContext } from "./appContext"
21
27
 
22
28
  export type { AsyncTaskState, ElementProps, Prettify, Signalable, StyleObject }
@@ -128,10 +134,12 @@ declare global {
128
134
  displayName?: string
129
135
  }
130
136
 
131
- type FC<T = {}> = ((props: FCProps<T>) => JSX.Element) & {
137
+ interface FC<T = {}> {
138
+ (props: FCProps<T>): JSX.Element
132
139
  /** Used to display the name of the component in devtools */
133
140
  displayName?: string
134
141
  }
142
+
135
143
  type FCProps<T = {}> = T & { children?: JSX.Children }
136
144
  type InferProps<T> = T extends Kiru.FC<infer P> ? P : never
137
145
 
@@ -160,6 +168,15 @@ declare global {
160
168
 
161
169
  type Ref<T> = RefCallback<T> | RefObject<T> | null | undefined
162
170
 
171
+ interface PromiseState<T> {
172
+ id: string
173
+ state: "pending" | "fulfilled" | "rejected"
174
+ value?: T
175
+ error?: Error
176
+ }
177
+
178
+ interface StatefulPromise<T> extends Promise<T>, PromiseState<T> {}
179
+
163
180
  type RenderMode = "dom" | "hydrate" | "string" | "stream"
164
181
 
165
182
  type StateSetter<T> = T | ((prev: T) => T)
@@ -169,6 +186,7 @@ declare global {
169
186
  type ExoticSymbol =
170
187
  | typeof $FRAGMENT
171
188
  | typeof $CONTEXT_PROVIDER
189
+ | typeof $ERROR_BOUNDARY
172
190
  | typeof $HYDRATION_BOUNDARY
173
191
 
174
192
  interface VNode {
@@ -1,10 +1,12 @@
1
1
  import type {
2
2
  $CONTEXT_PROVIDER,
3
+ $ERROR_BOUNDARY,
3
4
  $FRAGMENT,
4
5
  $HYDRATION_BOUNDARY,
5
6
  } from "./constants"
6
7
  import type { HydrationBoundaryMode } from "./ssr/hydrationBoundary"
7
8
  import type { Signal } from "./signals"
9
+ import type { ErrorBoundaryProps } from "./components/errorBoundary"
8
10
 
9
11
  export type SomeElement = HTMLElement | SVGElement
10
12
  export type SomeDom = HTMLElement | SVGElement | Text
@@ -33,6 +35,12 @@ export interface ContextProviderNode<T> extends Kiru.VNode {
33
35
  }
34
36
  }
35
37
 
38
+ export interface ErrorBoundaryNode extends Kiru.VNode {
39
+ type: typeof $ERROR_BOUNDARY
40
+ props: ErrorBoundaryProps
41
+ error?: Error
42
+ }
43
+
36
44
  export interface HydrationBoundaryNode extends Kiru.VNode {
37
45
  type: typeof $HYDRATION_BOUNDARY
38
46
  props: Kiru.VNode["props"] & {
@@ -0,0 +1,125 @@
1
+ export function deepCompare<T>(a: T, b: T): boolean {
2
+ return compare(a, b, true)
3
+ }
4
+
5
+ export function shallowCompare<T>(a: T, b: T): boolean {
6
+ return compare(a, b, false)
7
+ }
8
+
9
+ function compare<T>(a: T, b: T, deep = false): boolean {
10
+ // Fast path: identity comparison
11
+ if (a === b) return true
12
+
13
+ // Handle primitive types and null/undefined
14
+ if (
15
+ a == null ||
16
+ b == null ||
17
+ typeof a !== "object" ||
18
+ typeof b !== "object"
19
+ ) {
20
+ return false
21
+ }
22
+
23
+ // Handle arrays efficiently
24
+ if (Array.isArray(a) && Array.isArray(b)) {
25
+ if (a.length !== b.length) return false
26
+
27
+ if (deep) {
28
+ for (let i = 0; i < a.length; i++) {
29
+ if (!compare(a[i], b[i], true)) return false
30
+ }
31
+ } else {
32
+ for (let i = 0; i < a.length; i++) {
33
+ if (!Object.is(a[i], b[i])) return false
34
+ }
35
+ }
36
+ return true
37
+ }
38
+
39
+ // Handle Maps
40
+ if (a instanceof Map && b instanceof Map) {
41
+ if (a.size !== b.size) return false
42
+
43
+ for (const [key, valueA] of a) {
44
+ if (!b.has(key)) return false
45
+
46
+ const valueB = b.get(key)
47
+ if (deep) {
48
+ if (!compare(valueA, valueB, true)) return false
49
+ } else {
50
+ if (!Object.is(valueA, valueB)) return false
51
+ }
52
+ }
53
+ return true
54
+ }
55
+
56
+ // Handle Sets more efficiently
57
+ if (a instanceof Set && b instanceof Set) {
58
+ if (a.size !== b.size) return false
59
+
60
+ if (deep) {
61
+ // For deep equality of Sets, we need to compare the values themselves
62
+ // Convert to arrays and sort for comparison
63
+ const aValues = Array.from(a)
64
+ const bValues = Array.from(b)
65
+
66
+ if (aValues.length !== bValues.length) return false
67
+
68
+ // Simple compare doesn't work for objects in Sets with deep comparison
69
+ // Using a matching algorithm instead
70
+ for (const valueA of aValues) {
71
+ // Find matching element in bValues
72
+ let found = false
73
+ for (let i = 0; i < bValues.length; i++) {
74
+ if (compare(valueA, bValues[i], true)) {
75
+ bValues.splice(i, 1) // Remove the matched element
76
+ found = true
77
+ break
78
+ }
79
+ }
80
+ if (!found) return false
81
+ }
82
+ return true
83
+ } else {
84
+ // Regular Set comparison
85
+ for (const valueA of a) {
86
+ if (!b.has(valueA)) return false
87
+ }
88
+ return true
89
+ }
90
+ }
91
+
92
+ // Handle Date objects
93
+ if (a instanceof Date && b instanceof Date) {
94
+ return a.getTime() === b.getTime()
95
+ }
96
+
97
+ // Handle RegExp objects
98
+ if (a instanceof RegExp && b instanceof RegExp) {
99
+ return a.toString() === b.toString()
100
+ }
101
+
102
+ // Handle plain objects
103
+ const keysA = Object.keys(a)
104
+ const keysB = Object.keys(b)
105
+
106
+ if (keysA.length !== keysB.length) return false
107
+
108
+ // Use a Set for faster key lookup
109
+ const keySet = new Set(keysB)
110
+
111
+ for (const key of keysA) {
112
+ if (!keySet.has(key)) return false
113
+
114
+ const valueA = a[key as keyof T]
115
+ const valueB = b[key as keyof T]
116
+
117
+ if (deep) {
118
+ if (!compare(valueA, valueB, true)) return false
119
+ } else {
120
+ if (!Object.is(valueA, valueB)) return false
121
+ }
122
+ }
123
+
124
+ return true
125
+ }
@@ -0,0 +1,162 @@
1
+ import { unwrap } from "../signals/index.js"
2
+ import { booleanAttributes, snakeCaseAttributes } from "../constants.js"
3
+
4
+ export {
5
+ className,
6
+ encodeHtmlEntities,
7
+ propFilters,
8
+ propToHtmlAttr,
9
+ styleObjectToString,
10
+ propValueToHtmlAttrValue,
11
+ propsToElementAttributes,
12
+ safeStringify,
13
+ }
14
+
15
+ const REGEX_AMP = /&/g
16
+ const REGEX_LT = /</g
17
+ const REGEX_GT = />/g
18
+ const REGEX_SQT = /'/g
19
+ const REGEX_DBLQT = /"/g
20
+ const REGEX_SLASH = /\//g
21
+ const REGEX_ALPHA_UPPER = /[A-Z]/g
22
+
23
+ function className(...classes: (string | false | null | undefined)[]): string {
24
+ return classes.filter(Boolean).join(" ")
25
+ }
26
+
27
+ function encodeHtmlEntities(text: string): string {
28
+ return text
29
+ .replace(REGEX_AMP, "&amp;")
30
+ .replace(REGEX_LT, "&lt;")
31
+ .replace(REGEX_GT, "&gt;")
32
+ .replace(REGEX_DBLQT, "&quot;")
33
+ .replace(REGEX_SQT, "&#039;")
34
+ .replace(REGEX_SLASH, "&#47;")
35
+ }
36
+
37
+ const propFilters = {
38
+ internalProps: ["children", "ref", "key", "innerHTML"],
39
+ isEvent: (key: string) => key.startsWith("on"),
40
+ isProperty: (key: string) =>
41
+ !propFilters.internalProps.includes(key) && !propFilters.isEvent(key),
42
+ }
43
+
44
+ function propToHtmlAttr(key: string): string {
45
+ switch (key) {
46
+ case "className":
47
+ return "class"
48
+ case "htmlFor":
49
+ return "for"
50
+ case "tabIndex":
51
+ case "formAction":
52
+ case "formMethod":
53
+ case "formEncType":
54
+ case "contentEditable":
55
+ case "spellCheck":
56
+ case "allowFullScreen":
57
+ case "autoPlay":
58
+ case "disablePictureInPicture":
59
+ case "disableRemotePlayback":
60
+ case "formNoValidate":
61
+ case "noModule":
62
+ case "noValidate":
63
+ case "popoverTarget":
64
+ case "popoverTargetAction":
65
+ case "playsInline":
66
+ case "readOnly":
67
+ case "itemscope":
68
+ case "rowSpan":
69
+ case "crossOrigin":
70
+ return key.toLowerCase()
71
+
72
+ default:
73
+ if (key.indexOf("-") > -1) return key
74
+ if (key.startsWith("aria"))
75
+ return "aria-" + key.substring(4).toLowerCase()
76
+
77
+ return snakeCaseAttributes.get(key) || key
78
+ }
79
+ }
80
+
81
+ function styleObjectToString(obj: Partial<CSSStyleDeclaration>): string {
82
+ let cssString = ""
83
+ for (const key in obj) {
84
+ const cssKey = key.replace(REGEX_ALPHA_UPPER, "-$&").toLowerCase()
85
+ cssString += `${cssKey}:${obj[key]};`
86
+ }
87
+ return cssString
88
+ }
89
+
90
+ function stylePropToString(style: unknown) {
91
+ if (typeof style === "string") return style
92
+ if (typeof style === "object" && !!style) return styleObjectToString(style)
93
+ return ""
94
+ }
95
+
96
+ function propValueToHtmlAttrValue(key: string, value: unknown): string {
97
+ return key === "style" && typeof value === "object" && !!value
98
+ ? styleObjectToString(value)
99
+ : String(value)
100
+ }
101
+ function propsToElementAttributes(props: Record<string, unknown>): string {
102
+ const attrs: string[] = []
103
+ const { className, style, ...rest } = props
104
+ if (className) {
105
+ const val = unwrap(className)
106
+ if (!!val) attrs.push(`class="${val}"`)
107
+ }
108
+ if (style) {
109
+ const val = unwrap(style)
110
+ if (!!val) attrs.push(`style="${stylePropToString(val)}"`)
111
+ }
112
+
113
+ const keys = Object.keys(rest).filter(propFilters.isProperty)
114
+ for (let i = 0; i < keys.length; i++) {
115
+ let k = keys[i]
116
+ let val = unwrap(props[k])
117
+ if (val === null || val === undefined) continue
118
+
119
+ k = k.split("bind:")[1] ?? k // normalize bind props
120
+ const key = propToHtmlAttr(k)
121
+
122
+ switch (typeof val) {
123
+ case "function":
124
+ case "symbol":
125
+ continue
126
+ case "boolean":
127
+ if (booleanAttributes.has(key)) {
128
+ if (val) attrs.push(key)
129
+ continue
130
+ }
131
+ }
132
+ attrs.push(`${key}="${val}"`)
133
+ }
134
+ return attrs.join(" ")
135
+ }
136
+
137
+ type SafeStringifyOptions = {
138
+ /**
139
+ * By default, functions are stringified. Specify `false` to instead produce `[FUNCTION (${fn.name})]`.
140
+ */
141
+ functions: boolean
142
+ }
143
+
144
+ function safeStringify(
145
+ value: unknown,
146
+ opts: SafeStringifyOptions = { functions: true }
147
+ ): string {
148
+ const seen = new WeakSet()
149
+ return JSON.stringify(value, (_, value) => {
150
+ if (typeof value === "object" && value !== null) {
151
+ if (seen.has(value)) {
152
+ return "[CIRCULAR]"
153
+ }
154
+ seen.add(value)
155
+ }
156
+ if (typeof value === "function") {
157
+ if (!opts.functions) return `[FUNCTION (${value.name || "anonymous"})]`
158
+ return value.toString()
159
+ }
160
+ return value
161
+ })
162
+ }
@@ -0,0 +1,7 @@
1
+ export * from "./compare.js"
2
+ export * from "./format.js"
3
+ export * from "./runtime.js"
4
+ export * from "./vdom.js"
5
+ export * from "./generateId.js"
6
+
7
+ export const noop = Object.freeze(() => {})
@@ -0,0 +1,25 @@
1
+ import { __DEV__ } from "../env.js"
2
+ import { renderMode } from "../globals.js"
3
+
4
+ export { latest, sideEffectsEnabled }
5
+
6
+ /**
7
+ * This is a no-op in production. It is used to get the latest
8
+ * iteration of a component or signal after HMR has happened.
9
+ */
10
+ function latest<T extends Exclude<object, null>>(thing: T): T {
11
+ let tgt: any = thing
12
+ if (__DEV__) {
13
+ while ("__next" in tgt) {
14
+ tgt = tgt.__next as typeof tgt
15
+ }
16
+ }
17
+ return tgt
18
+ }
19
+
20
+ /**
21
+ * Returns false if called during "stream" or "string" render modes.
22
+ */
23
+ function sideEffectsEnabled(): boolean {
24
+ return renderMode.current === "dom" || renderMode.current === "hydrate"
25
+ }
@@ -0,0 +1,195 @@
1
+ import { Signal } from "../signals/index.js"
2
+ import {
3
+ FLAG_DELETION,
4
+ $FRAGMENT,
5
+ $CONTEXT_PROVIDER,
6
+ $HYDRATION_BOUNDARY,
7
+ FLAG_PLACEMENT,
8
+ FLAG_UPDATE,
9
+ $ERROR_BOUNDARY,
10
+ } from "../constants.js"
11
+ import { createElement } from "../index.js"
12
+ import { KiruError } from "../error.js"
13
+ import { node } from "../globals.js"
14
+ import type { AppContext } from "../appContext.js"
15
+ import type { ErrorBoundaryNode } from "../types.utils.js"
16
+
17
+ export {
18
+ cloneVNode,
19
+ isVNodeDeleted,
20
+ isVNode,
21
+ isExoticType,
22
+ isFragment,
23
+ isLazy,
24
+ isMemo,
25
+ isContextProvider,
26
+ vNodeContains,
27
+ getCurrentVNode,
28
+ getVNodeAppContext,
29
+ commitSnapshot,
30
+ traverseApply,
31
+ findParent,
32
+ findParentErrorBoundary,
33
+ assertValidElementProps,
34
+ isValidElementKeyProp,
35
+ isValidElementRefProp,
36
+ }
37
+
38
+ function cloneVNode(vNode: Kiru.VNode): Kiru.VNode {
39
+ const children = vNode.props.children
40
+ let clonedChildren: unknown
41
+ if (isVNode(children)) {
42
+ clonedChildren = cloneVNode(children)
43
+ } else if (Array.isArray(children)) {
44
+ clonedChildren = children.map((c) => (isVNode(c) ? cloneVNode(c) : c))
45
+ }
46
+
47
+ return createElement(vNode.type, { ...vNode.props, children: clonedChildren })
48
+ }
49
+
50
+ function isVNodeDeleted(vNode: Kiru.VNode): boolean {
51
+ return (vNode.flags & FLAG_DELETION) !== 0
52
+ }
53
+
54
+ function isVNode(thing: unknown): thing is Kiru.VNode {
55
+ return typeof thing === "object" && thing !== null && "type" in thing
56
+ }
57
+
58
+ function isExoticType(type: Kiru.VNode["type"]): type is Kiru.ExoticSymbol {
59
+ return (
60
+ type === $FRAGMENT ||
61
+ type === $CONTEXT_PROVIDER ||
62
+ type === $ERROR_BOUNDARY ||
63
+ type === $HYDRATION_BOUNDARY
64
+ )
65
+ }
66
+
67
+ function isFragment(
68
+ vNode: Kiru.VNode
69
+ ): vNode is Kiru.VNode & { type: typeof $FRAGMENT } {
70
+ return vNode.type === $FRAGMENT
71
+ }
72
+
73
+ function isLazy(vNode: Kiru.VNode): boolean {
74
+ return (
75
+ typeof vNode.type === "function" &&
76
+ "displayName" in vNode.type &&
77
+ vNode.type.displayName === "Kiru.lazy"
78
+ )
79
+ }
80
+
81
+ function isMemo(vNode: Kiru.VNode): boolean {
82
+ return (
83
+ typeof vNode.type === "function" &&
84
+ "displayName" in vNode.type &&
85
+ vNode.type.displayName === "Kiru.memo"
86
+ )
87
+ }
88
+
89
+ function isContextProvider(
90
+ thing: unknown
91
+ ): thing is Kiru.VNode & { type: typeof $CONTEXT_PROVIDER } {
92
+ return isVNode(thing) && thing.type === $CONTEXT_PROVIDER
93
+ }
94
+
95
+ function getCurrentVNode(): Kiru.VNode | null {
96
+ return node.current
97
+ }
98
+
99
+ function getVNodeAppContext(vNode: Kiru.VNode): AppContext | null {
100
+ let n: Kiru.VNode | null = vNode
101
+ while (n) {
102
+ if (n.app) {
103
+ return (vNode.app = n.app)
104
+ }
105
+ n = n.parent
106
+ }
107
+
108
+ return null
109
+ }
110
+
111
+ function commitSnapshot(vNode: Kiru.VNode): void {
112
+ const {
113
+ props: { children, ...props },
114
+ memoizedProps,
115
+ index,
116
+ } = vNode
117
+ vNode.prev = { props, memoizedProps, index }
118
+ vNode.flags &= ~(FLAG_UPDATE | FLAG_PLACEMENT | FLAG_DELETION)
119
+ }
120
+
121
+ function vNodeContains(haystack: Kiru.VNode, needle: Kiru.VNode): boolean {
122
+ if (needle.depth < haystack.depth) return false
123
+ if (haystack === needle) return true
124
+ let checkSiblings = false
125
+ const stack: Kiru.VNode[] = [haystack]
126
+ while (stack.length) {
127
+ const n = stack.pop()!
128
+ if (n === needle) return true
129
+ n.child && stack.push(n.child)
130
+ checkSiblings && n.sibling && stack.push(n.sibling)
131
+ checkSiblings = true
132
+ }
133
+ return false
134
+ }
135
+
136
+ function traverseApply(
137
+ vNode: Kiru.VNode,
138
+ func: (node: Kiru.VNode) => void
139
+ ): void {
140
+ func(vNode)
141
+ let child = vNode.child
142
+ while (child) {
143
+ func(child)
144
+ if (child.child) {
145
+ traverseApply(child, func)
146
+ }
147
+ child = child.sibling
148
+ }
149
+ }
150
+
151
+ function findParent(vNode: Kiru.VNode, predicate: (n: Kiru.VNode) => boolean) {
152
+ let n: Kiru.VNode | null = vNode.parent
153
+ while (n) {
154
+ if (predicate(n)) return n
155
+ n = n.parent
156
+ }
157
+ return null
158
+ }
159
+
160
+ function findParentErrorBoundary(vNode: Kiru.VNode): ErrorBoundaryNode | null {
161
+ return findParent(
162
+ vNode,
163
+ (n) => n.type === $ERROR_BOUNDARY
164
+ ) as ErrorBoundaryNode | null
165
+ }
166
+
167
+ function assertValidElementProps(vNode: Kiru.VNode) {
168
+ if ("children" in vNode.props && vNode.props.innerHTML) {
169
+ throw new KiruError({
170
+ message: "Cannot use both children and innerHTML on an element",
171
+ vNode,
172
+ })
173
+ }
174
+
175
+ for (const key in vNode.props) {
176
+ if ("bind:" + key in vNode.props) {
177
+ throw new KiruError({
178
+ message: `Cannot use both bind:${key} and ${key} on an element`,
179
+ vNode,
180
+ })
181
+ }
182
+ }
183
+ }
184
+
185
+ function isValidElementKeyProp(thing: unknown): thing is string | number {
186
+ return typeof thing === "string" || typeof thing === "number"
187
+ }
188
+
189
+ function isValidElementRefProp(thing: unknown): thing is Kiru.Ref<any> {
190
+ return (
191
+ typeof thing === "function" ||
192
+ (typeof thing === "object" && !!thing && "current" in thing) ||
193
+ Signal.isSignal(thing)
194
+ )
195
+ }
@@ -1,2 +0,0 @@
1
- export declare function cloneVNode(vNode: Kiru.VNode): Kiru.VNode;
2
- //# sourceMappingURL=cloneVNode.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cloneVNode.d.ts","sourceRoot":"","sources":["../src/cloneVNode.ts"],"names":[],"mappings":"AAGA,wBAAgB,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAUxD"}
@@ -1,14 +0,0 @@
1
- import { createElement } from "./element.js";
2
- import { isVNode } from "./utils.js";
3
- export function cloneVNode(vNode) {
4
- const children = vNode.props.children;
5
- let clonedChildren;
6
- if (isVNode(children)) {
7
- clonedChildren = cloneVNode(children);
8
- }
9
- else if (Array.isArray(children)) {
10
- clonedChildren = children.map((c) => (isVNode(c) ? cloneVNode(c) : c));
11
- }
12
- return createElement(vNode.type, { ...vNode.props, children: clonedChildren });
13
- }
14
- //# sourceMappingURL=cloneVNode.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cloneVNode.js","sourceRoot":"","sources":["../src/cloneVNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEpC,MAAM,UAAU,UAAU,CAAC,KAAiB;IAC1C,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAA;IACrC,IAAI,cAAuB,CAAA;IAC3B,IAAI,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtB,cAAc,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAA;IACvC,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnC,cAAc,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACxE,CAAC;IAED,OAAO,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAA;AAChF,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"generateId.d.ts","sourceRoot":"","sources":["../src/generateId.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,GAAE,MAAW,EACjB,YAAY,GAAE,MAA2B,GACxC,MAAM,CAMR"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"generateId.js","sourceRoot":"","sources":["../src/generateId.ts"],"names":[],"mappings":"AAAA,MAAM,kBAAkB,GACtB,kEAA2E,CAAA;AAE7E;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAe,EAAE,EACjB,eAAuB,kBAAkB;IAEzC,IAAI,EAAE,GAAG,EAAE,CAAA;IACX,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9B,EAAE,IAAI,YAAY,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA,CAAC,+CAA+C;IAC/G,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../src/lazy.ts"],"names":[],"mappings":"AAgBA,UAAU,QAAQ;IAChB,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;CACtB;AAED,KAAK,eAAe,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAA;AAE9C,KAAK,oBAAoB,CAAC,CAAC,SAAS,eAAe,IAAI,CAAC,SAAS,QAAQ,GACrE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,GAC7B,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;AAQtB,KAAK,kBAAkB,CAAC,CAAC,SAAS,eAAe,IAAI,oBAAoB,CAAC,CAAC,CAAC,GAAG;IAC7E,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;CACvB,CAAA;AAqDD,wBAAgB,IAAI,CAAC,CAAC,SAAS,eAAe,EAC5C,kBAAkB,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnC,IAAI,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CA2IhC"}