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.
- package/dist/action.d.ts +22 -0
- package/dist/action.d.ts.map +1 -0
- package/dist/action.js +20 -0
- package/dist/action.js.map +1 -0
- package/dist/components/errorBoundary.d.ts +7 -0
- package/dist/components/errorBoundary.d.ts.map +1 -0
- package/dist/components/errorBoundary.js +6 -0
- package/dist/components/errorBoundary.js.map +1 -0
- package/dist/components/index.d.ts +7 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +7 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/lazy.d.ts.map +1 -0
- package/dist/{lazy.js → components/lazy.js} +11 -11
- package/dist/components/lazy.js.map +1 -0
- package/dist/{memo.d.ts → components/memo.d.ts} +1 -1
- package/dist/components/memo.d.ts.map +1 -0
- package/dist/{memo.js → components/memo.js} +2 -2
- package/dist/components/memo.js.map +1 -0
- package/dist/components/portal.d.ts.map +1 -0
- package/dist/{portal.js → components/portal.js} +6 -6
- package/dist/components/portal.js.map +1 -0
- package/dist/components/router/index.d.ts.map +1 -0
- package/dist/components/router/index.js.map +1 -0
- package/dist/components/router/route.d.ts.map +1 -0
- package/dist/{router → components/router}/route.js +1 -1
- package/dist/components/router/route.js.map +1 -0
- package/dist/{router → components/router}/router.d.ts +1 -1
- package/dist/components/router/router.d.ts.map +1 -0
- package/dist/{router → components/router}/router.js +8 -8
- package/dist/components/router/router.js.map +1 -0
- package/dist/components/router/routerUtils.d.ts.map +1 -0
- package/dist/components/router/routerUtils.js.map +1 -0
- package/dist/components/suspense.d.ts +33 -0
- package/dist/components/suspense.d.ts.map +1 -0
- package/dist/components/suspense.js +113 -0
- package/dist/components/suspense.js.map +1 -0
- package/dist/components/transition.d.ts.map +1 -0
- package/dist/{transition.js → components/transition.js} +5 -5
- package/dist/components/transition.js.map +1 -0
- package/dist/constants.d.ts +6 -12
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +83 -12
- package/dist/constants.js.map +1 -1
- package/dist/context.js +1 -1
- package/dist/context.js.map +1 -1
- package/dist/dom.d.ts.map +1 -1
- package/dist/dom.js +9 -12
- package/dist/dom.js.map +1 -1
- package/dist/element.js +2 -2
- package/dist/element.js.map +1 -1
- package/dist/error.js +1 -1
- package/dist/error.js.map +1 -1
- package/dist/form/index.d.ts.map +1 -1
- package/dist/form/index.js +1 -2
- package/dist/form/index.js.map +1 -1
- package/dist/hmr.js +1 -1
- package/dist/hmr.js.map +1 -1
- package/dist/hooks/useAsync.d.ts.map +1 -1
- package/dist/hooks/useAsync.js +2 -2
- package/dist/hooks/useAsync.js.map +1 -1
- package/dist/hooks/useCallback.d.ts.map +1 -1
- package/dist/hooks/useCallback.js +2 -1
- package/dist/hooks/useCallback.js.map +1 -1
- package/dist/hooks/useEffect.d.ts.map +1 -1
- package/dist/hooks/useEffect.js +2 -1
- package/dist/hooks/useEffect.js.map +1 -1
- package/dist/hooks/useEffectEvent.d.ts.map +1 -1
- package/dist/hooks/useEffectEvent.js +2 -1
- package/dist/hooks/useEffectEvent.js.map +1 -1
- package/dist/hooks/useLayoutEffect.d.ts.map +1 -1
- package/dist/hooks/useLayoutEffect.js +2 -1
- package/dist/hooks/useLayoutEffect.js.map +1 -1
- package/dist/hooks/useMemo.d.ts.map +1 -1
- package/dist/hooks/useMemo.js +2 -1
- package/dist/hooks/useMemo.js.map +1 -1
- package/dist/hooks/useReducer.js +2 -2
- package/dist/hooks/useReducer.js.map +1 -1
- package/dist/hooks/useRef.d.ts.map +1 -1
- package/dist/hooks/useRef.js +2 -1
- package/dist/hooks/useRef.js.map +1 -1
- package/dist/hooks/useState.js +2 -2
- package/dist/hooks/useState.js.map +1 -1
- package/dist/hooks/useSyncExternalStore.js +2 -2
- package/dist/hooks/useSyncExternalStore.js.map +1 -1
- package/dist/hooks/useViewTransition.d.ts.map +1 -1
- package/dist/hooks/useViewTransition.js +1 -2
- package/dist/hooks/useViewTransition.js.map +1 -1
- package/dist/hooks/utils.d.ts +0 -1
- package/dist/hooks/utils.d.ts.map +1 -1
- package/dist/hooks/utils.js +2 -2
- package/dist/hooks/utils.js.map +1 -1
- package/dist/index.d.ts +3 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -5
- package/dist/index.js.map +1 -1
- package/dist/reconciler.js +8 -7
- package/dist/reconciler.js.map +1 -1
- package/dist/renderToString.d.ts.map +1 -1
- package/dist/renderToString.js +93 -38
- package/dist/renderToString.js.map +1 -1
- package/dist/scheduler.d.ts.map +1 -1
- package/dist/scheduler.js +48 -11
- package/dist/scheduler.js.map +1 -1
- package/dist/signals/base.d.ts.map +1 -1
- package/dist/signals/base.js +1 -2
- package/dist/signals/base.js.map +1 -1
- package/dist/signals/computed.js +1 -1
- package/dist/signals/computed.js.map +1 -1
- package/dist/signals/effect.js +1 -1
- package/dist/signals/effect.js.map +1 -1
- package/dist/signals/watch.d.ts.map +1 -1
- package/dist/signals/watch.js +2 -3
- package/dist/signals/watch.js.map +1 -1
- package/dist/ssr/server.d.ts +4 -1
- package/dist/ssr/server.d.ts.map +1 -1
- package/dist/ssr/server.js +136 -66
- package/dist/ssr/server.js.map +1 -1
- package/dist/store.d.ts +1 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +2 -2
- package/dist/store.js.map +1 -1
- package/dist/swr.js +1 -1
- package/dist/swr.js.map +1 -1
- package/dist/types.d.ts +14 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.dom.d.ts +2 -2
- package/dist/types.dom.d.ts.map +1 -1
- package/dist/types.utils.d.ts +7 -1
- package/dist/types.utils.d.ts.map +1 -1
- package/dist/utils/compare.d.ts +3 -0
- package/dist/utils/compare.d.ts.map +1 -0
- package/dist/utils/compare.js +123 -0
- package/dist/utils/compare.js.map +1 -0
- package/dist/utils/format.d.ts +20 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +136 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/generateId.d.ts.map +1 -0
- package/dist/utils/generateId.js.map +1 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/runtime.d.ts +11 -0
- package/dist/utils/runtime.d.ts.map +1 -0
- package/dist/utils/runtime.js +23 -0
- package/dist/utils/runtime.js.map +1 -0
- package/dist/utils/vdom.d.ts +27 -0
- package/dist/utils/vdom.d.ts.map +1 -0
- package/dist/utils/vdom.js +128 -0
- package/dist/utils/vdom.js.map +1 -0
- package/package.json +6 -6
- package/src/action.ts +42 -0
- package/src/components/errorBoundary.ts +16 -0
- package/src/components/index.ts +6 -0
- package/src/{lazy.ts → components/lazy.ts} +12 -12
- package/src/{memo.ts → components/memo.ts} +3 -3
- package/src/{portal.ts → components/portal.ts} +6 -6
- package/src/{router → components/router}/route.ts +1 -1
- package/src/{router → components/router}/router.ts +9 -9
- package/src/components/suspense.ts +193 -0
- package/src/{transition.ts → components/transition.ts} +5 -5
- package/src/constants.ts +86 -13
- package/src/context.ts +1 -1
- package/src/customEvents.ts +22 -22
- package/src/dom.ts +8 -11
- package/src/element.ts +2 -2
- package/src/error.ts +1 -1
- package/src/form/index.ts +5 -2
- package/src/hmr.ts +1 -1
- package/src/hooks/useAsync.ts +5 -3
- package/src/hooks/useCallback.ts +2 -1
- package/src/hooks/useEffect.ts +2 -6
- package/src/hooks/useEffectEvent.ts +2 -1
- package/src/hooks/useLayoutEffect.ts +2 -6
- package/src/hooks/useMemo.ts +2 -1
- package/src/hooks/useReducer.ts +2 -2
- package/src/hooks/useRef.ts +2 -1
- package/src/hooks/useState.ts +2 -2
- package/src/hooks/useSyncExternalStore.ts +2 -2
- package/src/hooks/useViewTransition.ts +1 -2
- package/src/hooks/utils.ts +2 -2
- package/src/index.ts +3 -5
- package/src/reconciler.ts +13 -11
- package/src/renderToString.ts +108 -42
- package/src/scheduler.ts +61 -14
- package/src/signals/base.ts +6 -2
- package/src/signals/computed.ts +1 -1
- package/src/signals/effect.ts +1 -1
- package/src/signals/watch.ts +2 -3
- package/src/ssr/server.ts +163 -71
- package/src/store.ts +6 -2
- package/src/swr.ts +3 -3
- package/src/types.dom.ts +2 -1
- package/src/types.ts +20 -2
- package/src/types.utils.ts +8 -0
- package/src/utils/compare.ts +125 -0
- package/src/utils/format.ts +162 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/runtime.ts +25 -0
- package/src/utils/vdom.ts +195 -0
- package/dist/cloneVNode.d.ts +0 -2
- package/dist/cloneVNode.d.ts.map +0 -1
- package/dist/cloneVNode.js +0 -14
- package/dist/cloneVNode.js.map +0 -1
- package/dist/generateId.d.ts.map +0 -1
- package/dist/generateId.js.map +0 -1
- package/dist/lazy.d.ts.map +0 -1
- package/dist/lazy.js.map +0 -1
- package/dist/memo.d.ts.map +0 -1
- package/dist/memo.js.map +0 -1
- package/dist/portal.d.ts.map +0 -1
- package/dist/portal.js.map +0 -1
- package/dist/props.d.ts +0 -4
- package/dist/props.d.ts.map +0 -1
- package/dist/props.js +0 -27
- package/dist/props.js.map +0 -1
- package/dist/router/index.d.ts.map +0 -1
- package/dist/router/index.js.map +0 -1
- package/dist/router/route.d.ts.map +0 -1
- package/dist/router/route.js.map +0 -1
- package/dist/router/router.d.ts.map +0 -1
- package/dist/router/router.js.map +0 -1
- package/dist/router/routerUtils.d.ts.map +0 -1
- package/dist/router/routerUtils.js.map +0 -1
- package/dist/transition.d.ts.map +0 -1
- package/dist/transition.js.map +0 -1
- package/dist/utils.d.ts +0 -52
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js +0 -433
- package/dist/utils.js.map +0 -1
- package/dist/warning.d.ts +0 -2
- package/dist/warning.d.ts.map +0 -1
- package/dist/warning.js +0 -4
- package/dist/warning.js.map +0 -1
- package/src/cloneVNode.ts +0 -14
- package/src/props.ts +0 -34
- package/src/utils.ts +0 -518
- package/src/warning.ts +0 -9
- /package/dist/{lazy.d.ts → components/lazy.d.ts} +0 -0
- /package/dist/{portal.d.ts → components/portal.d.ts} +0 -0
- /package/dist/{router → components/router}/index.d.ts +0 -0
- /package/dist/{router → components/router}/index.js +0 -0
- /package/dist/{router → components/router}/route.d.ts +0 -0
- /package/dist/{router → components/router}/routerUtils.d.ts +0 -0
- /package/dist/{router → components/router}/routerUtils.js +0 -0
- /package/dist/{transition.d.ts → components/transition.d.ts} +0 -0
- /package/dist/{generateId.d.ts → utils/generateId.d.ts} +0 -0
- /package/dist/{generateId.js → utils/generateId.js} +0 -0
- /package/src/{router → components/router}/index.ts +0 -0
- /package/src/{router → components/router}/routerUtils.ts +0 -0
- /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 "
|
|
2
|
-
import { useEffect } from "
|
|
3
|
-
import { useLayoutEffect } from "
|
|
4
|
-
import { useRef } from "
|
|
5
|
-
import { useState } from "
|
|
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
|
-
|
|
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> = {
|
package/src/customEvents.ts
CHANGED
|
@@ -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
|
|
104
|
-
if (Signal.isSignal(nodeValue)) {
|
|
105
|
-
|
|
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
|
|
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
|
-
|
|
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 "./
|
|
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
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 {
|
|
4
|
-
|
|
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"
|
package/src/hooks/useAsync.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __DEV__ } from "../env.js"
|
|
2
|
-
import { noop } from "../utils.js"
|
|
3
|
-
import { depsRequireChange,
|
|
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 (
|
|
51
|
+
load: noop as (
|
|
52
|
+
func: (ctx: UseAsyncCallbackContext) => Promise<T>
|
|
53
|
+
) => void,
|
|
52
54
|
},
|
|
53
55
|
({ hook, isInit, isHMR, update }) => {
|
|
54
56
|
if (__DEV__) {
|
package/src/hooks/useCallback.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { __DEV__ } from "../env.js"
|
|
2
|
-
import {
|
|
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.
|
package/src/hooks/useEffect.ts
CHANGED
|
@@ -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 {
|
|
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
|
package/src/hooks/useMemo.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { sideEffectsEnabled } from "../utils/index.js"
|
|
1
2
|
import { __DEV__ } from "../env.js"
|
|
2
|
-
import { depsRequireChange,
|
|
3
|
+
import { depsRequireChange, useHook } from "./utils.js"
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Creates a memoized value that only changes when the [dependency
|
package/src/hooks/useReducer.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __DEV__ } from "../env.js"
|
|
2
|
-
import { noop } from "../utils.js"
|
|
3
|
-
import {
|
|
2
|
+
import { noop, sideEffectsEnabled } from "../utils/index.js"
|
|
3
|
+
import { useHook } from "./utils.js"
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Creates 'dispatcher-driven' state.
|
package/src/hooks/useRef.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { __DEV__ } from "../env.js"
|
|
2
|
-
import { sideEffectsEnabled
|
|
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
|
package/src/hooks/useState.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __DEV__ } from "../env.js"
|
|
2
|
-
import { noop } from "../utils.js"
|
|
3
|
-
import {
|
|
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 {
|
|
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)
|
package/src/hooks/utils.ts
CHANGED
|
@@ -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 "./
|
|
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) {
|