kiru 0.50.0 → 0.50.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/appContext.d.ts.map +1 -1
- package/dist/appContext.js +11 -6
- package/dist/appContext.js.map +1 -1
- package/dist/context.js.map +1 -1
- package/dist/dom.js +4 -4
- package/dist/dom.js.map +1 -1
- package/dist/globalContext.d.ts +3 -3
- package/dist/globalContext.d.ts.map +1 -1
- package/dist/globalContext.js +3 -15
- package/dist/globalContext.js.map +1 -1
- package/dist/hmr.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -8
- package/dist/index.js.map +1 -1
- package/dist/reconciler.js +2 -2
- package/dist/reconciler.js.map +1 -1
- package/dist/router/fileRouter.d.ts +1 -28
- package/dist/router/fileRouter.d.ts.map +1 -1
- package/dist/router/fileRouter.js +2 -302
- package/dist/router/fileRouter.js.map +1 -1
- package/dist/router/fileRouterController.d.ts +28 -0
- package/dist/router/fileRouterController.d.ts.map +1 -0
- package/dist/router/fileRouterController.js +418 -0
- package/dist/router/fileRouterController.js.map +1 -0
- package/dist/router/globals.d.ts +1 -1
- package/dist/router/globals.d.ts.map +1 -1
- package/dist/router/index.d.ts +3 -3
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +2 -3
- package/dist/router/index.js.map +1 -1
- package/dist/router/{config.d.ts → pageConfig.d.ts} +1 -1
- package/dist/router/pageConfig.d.ts.map +1 -0
- package/dist/router/{config.js → pageConfig.js} +1 -1
- package/dist/router/pageConfig.js.map +1 -0
- package/dist/scheduler.js +7 -7
- package/dist/scheduler.js.map +1 -1
- package/dist/signals/watch.d.ts.map +1 -1
- package/dist/signals/watch.js +1 -2
- package/dist/signals/watch.js.map +1 -1
- package/dist/swr.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/appContext.ts +13 -7
- package/src/context.ts +1 -1
- package/src/dom.ts +4 -4
- package/src/globalContext.ts +7 -20
- package/src/hmr.ts +2 -2
- package/src/index.ts +0 -9
- package/src/reconciler.ts +2 -2
- package/src/router/fileRouter.ts +4 -442
- package/src/router/fileRouterController.ts +591 -0
- package/src/router/globals.ts +1 -1
- package/src/router/index.ts +3 -3
- package/src/scheduler.ts +8 -8
- package/src/signals/watch.ts +2 -5
- package/src/swr.ts +1 -1
- package/src/types.ts +1 -1
- package/dist/router/config.d.ts.map +0 -1
- package/dist/router/config.js.map +0 -1
- /package/src/router/{config.ts → pageConfig.ts} +0 -0
package/src/router/fileRouter.ts
CHANGED
|
@@ -1,349 +1,9 @@
|
|
|
1
|
-
import { Signal, computed, flushSync } from "../index.js"
|
|
2
1
|
import { __DEV__ } from "../env.js"
|
|
3
2
|
import { createElement } from "../element.js"
|
|
4
3
|
import { useState, useEffect } from "../hooks/index.js"
|
|
5
|
-
import { RouterContext
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import type {
|
|
9
|
-
ErrorPageProps,
|
|
10
|
-
FileRouterConfig,
|
|
11
|
-
PageConfig,
|
|
12
|
-
PageProps,
|
|
13
|
-
RouteQuery,
|
|
14
|
-
RouterState,
|
|
15
|
-
} from "./types.js"
|
|
16
|
-
import type {
|
|
17
|
-
DefaultComponentModule,
|
|
18
|
-
PageModule,
|
|
19
|
-
ViteImportMap,
|
|
20
|
-
} from "./types.internal.js"
|
|
21
|
-
|
|
22
|
-
export class FileRouterController {
|
|
23
|
-
private enableTransitions: boolean
|
|
24
|
-
private pages: ViteImportMap
|
|
25
|
-
private layouts: ViteImportMap
|
|
26
|
-
private abortController: AbortController
|
|
27
|
-
private currentPage: Signal<{
|
|
28
|
-
component: Kiru.FC<any>
|
|
29
|
-
config?: PageConfig
|
|
30
|
-
route: string
|
|
31
|
-
} | null>
|
|
32
|
-
private currentPageProps: Signal<PageProps<PageConfig>>
|
|
33
|
-
private currentLayouts: Signal<Kiru.FC[]>
|
|
34
|
-
private loading: Signal<boolean>
|
|
35
|
-
private state: Signal<RouterState>
|
|
36
|
-
private contextValue: Signal<FileRouterContextType>
|
|
37
|
-
private cleanups: (() => void)[] = []
|
|
38
|
-
private filePathToPageRoute: Map<
|
|
39
|
-
string,
|
|
40
|
-
{
|
|
41
|
-
route: string
|
|
42
|
-
config: PageConfig
|
|
43
|
-
}
|
|
44
|
-
>
|
|
45
|
-
private pageRouteToConfig: Map<string, PageConfig>
|
|
46
|
-
private currentRoute: string | null
|
|
47
|
-
|
|
48
|
-
constructor(props: FileRouterProps) {
|
|
49
|
-
fileRouterInstance.current = this
|
|
50
|
-
this.pages = {}
|
|
51
|
-
this.layouts = {}
|
|
52
|
-
this.abortController = new AbortController()
|
|
53
|
-
this.currentPage = new Signal(null)
|
|
54
|
-
this.currentPageProps = new Signal({})
|
|
55
|
-
this.currentLayouts = new Signal([])
|
|
56
|
-
this.loading = new Signal(true)
|
|
57
|
-
this.state = new Signal<RouterState>({
|
|
58
|
-
path: window.location.pathname,
|
|
59
|
-
params: {},
|
|
60
|
-
query: {},
|
|
61
|
-
signal: this.abortController.signal,
|
|
62
|
-
})
|
|
63
|
-
this.contextValue = computed<FileRouterContextType>(() => ({
|
|
64
|
-
state: this.state.value,
|
|
65
|
-
navigate: this.navigate.bind(this),
|
|
66
|
-
setQuery: this.setQuery.bind(this),
|
|
67
|
-
reload: (options?: { transition?: boolean }) =>
|
|
68
|
-
this.loadRoute(void 0, void 0, options?.transition),
|
|
69
|
-
}))
|
|
70
|
-
this.filePathToPageRoute = new Map()
|
|
71
|
-
this.pageRouteToConfig = new Map()
|
|
72
|
-
this.currentRoute = null
|
|
73
|
-
|
|
74
|
-
const {
|
|
75
|
-
pages,
|
|
76
|
-
layouts,
|
|
77
|
-
dir = "/pages",
|
|
78
|
-
baseUrl = "/",
|
|
79
|
-
transition,
|
|
80
|
-
} = props.config
|
|
81
|
-
this.enableTransitions = !!transition
|
|
82
|
-
const [normalizedDir, normalizedBaseUrl] = [
|
|
83
|
-
normalizePrefixPath(dir),
|
|
84
|
-
normalizePrefixPath(baseUrl),
|
|
85
|
-
]
|
|
86
|
-
this.pages = formatViteImportMap(
|
|
87
|
-
pages as ViteImportMap,
|
|
88
|
-
normalizedDir,
|
|
89
|
-
normalizedBaseUrl
|
|
90
|
-
)
|
|
91
|
-
this.layouts = formatViteImportMap(
|
|
92
|
-
layouts as ViteImportMap,
|
|
93
|
-
normalizedDir,
|
|
94
|
-
normalizedBaseUrl
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
this.loadRoute()
|
|
98
|
-
|
|
99
|
-
const handlePopState = () => this.loadRoute()
|
|
100
|
-
window.addEventListener("popstate", handlePopState)
|
|
101
|
-
this.cleanups.push(() =>
|
|
102
|
-
window.removeEventListener("popstate", handlePopState)
|
|
103
|
-
)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
public onPageConfigDefined<T extends PageConfig>(fp: string, config: T) {
|
|
107
|
-
const existing = this.filePathToPageRoute.get(fp)
|
|
108
|
-
if (existing === undefined) {
|
|
109
|
-
const route = this.currentRoute
|
|
110
|
-
if (!route) return
|
|
111
|
-
this.filePathToPageRoute.set(fp, { route, config })
|
|
112
|
-
return
|
|
113
|
-
}
|
|
114
|
-
const curPage = this.currentPage.value
|
|
115
|
-
if (curPage?.route === existing.route && config.loader) {
|
|
116
|
-
const p = this.currentPageProps.value
|
|
117
|
-
let transition = this.enableTransitions
|
|
118
|
-
if (config.loader.transition !== undefined) {
|
|
119
|
-
transition = config.loader.transition
|
|
120
|
-
}
|
|
121
|
-
const props = {
|
|
122
|
-
...p,
|
|
123
|
-
loading: true,
|
|
124
|
-
data: null,
|
|
125
|
-
error: null,
|
|
126
|
-
}
|
|
127
|
-
handleStateTransition(this.state.value.signal, transition, () => {
|
|
128
|
-
this.currentPageProps.value = props
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
this.loadRouteData(config.loader, props, this.state.value, transition)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
this.pageRouteToConfig.set(existing.route, config)
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
public getContextValue() {
|
|
138
|
-
return this.contextValue.value
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
public getChildren() {
|
|
142
|
-
const page = this.currentPage.value,
|
|
143
|
-
props = this.currentPageProps.value,
|
|
144
|
-
layouts = this.currentLayouts.value
|
|
145
|
-
|
|
146
|
-
if (page) {
|
|
147
|
-
// Wrap component with layouts (outermost first)
|
|
148
|
-
return layouts.reduceRight(
|
|
149
|
-
(children, Layout) => createElement(Layout, { children }),
|
|
150
|
-
createElement(page.component, props)
|
|
151
|
-
)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return null
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
public dispose() {
|
|
158
|
-
this.cleanups.forEach((cleanup) => cleanup())
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
private matchRoute(pathSegments: string[]) {
|
|
162
|
-
outer: for (const [route, pageModuleLoader] of Object.entries(this.pages)) {
|
|
163
|
-
const routeSegments = route.split("/").filter(Boolean)
|
|
164
|
-
|
|
165
|
-
const pathMatchingSegments = routeSegments.filter(
|
|
166
|
-
(seg) => !seg.startsWith("(") && !seg.endsWith(")")
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
if (pathMatchingSegments.length !== pathSegments.length) {
|
|
170
|
-
continue
|
|
171
|
-
}
|
|
172
|
-
const params: Record<string, string> = {}
|
|
173
|
-
|
|
174
|
-
for (let i = 0; i < pathMatchingSegments.length; i++) {
|
|
175
|
-
const routeSeg = pathMatchingSegments[i]
|
|
176
|
-
if (routeSeg.startsWith(":")) {
|
|
177
|
-
const key = routeSeg.slice(1)
|
|
178
|
-
params[key] = pathSegments[i]
|
|
179
|
-
continue
|
|
180
|
-
}
|
|
181
|
-
if (routeSeg !== pathSegments[i]) {
|
|
182
|
-
continue outer
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return { route, pageModuleLoader, params, routeSegments }
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return null
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
private async loadRoute(
|
|
193
|
-
path: string = window.location.pathname,
|
|
194
|
-
props: PageProps<PageConfig> = {},
|
|
195
|
-
enableTransition = this.enableTransitions
|
|
196
|
-
): Promise<void> {
|
|
197
|
-
this.loading.value = true
|
|
198
|
-
this.abortController?.abort()
|
|
199
|
-
|
|
200
|
-
const query = parseQuery(window.location.search)
|
|
201
|
-
const controller = (this.abortController = new AbortController())
|
|
202
|
-
const signal = controller.signal
|
|
203
|
-
|
|
204
|
-
try {
|
|
205
|
-
const pathSegments = path.split("/").filter(Boolean)
|
|
206
|
-
const routeMatch = this.matchRoute(pathSegments)
|
|
207
|
-
|
|
208
|
-
if (!routeMatch) {
|
|
209
|
-
const _404 = this.matchRoute(["404"])
|
|
210
|
-
if (!_404) {
|
|
211
|
-
if (__DEV__) {
|
|
212
|
-
console.error(
|
|
213
|
-
`No 404 route defined (path: ${path}). See https://kirujs.dev/404 for more information.`
|
|
214
|
-
)
|
|
215
|
-
}
|
|
216
|
-
return
|
|
217
|
-
}
|
|
218
|
-
const errorProps = {
|
|
219
|
-
source: { path },
|
|
220
|
-
} satisfies ErrorPageProps
|
|
221
|
-
|
|
222
|
-
return this.navigate("/404", { replace: true, props: errorProps })
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const { route, pageModuleLoader, params, routeSegments } = routeMatch
|
|
226
|
-
|
|
227
|
-
this.currentRoute = route
|
|
228
|
-
const pagePromise = pageModuleLoader()
|
|
229
|
-
|
|
230
|
-
const layoutPromises = ["/", ...routeSegments].reduce((acc, _, i) => {
|
|
231
|
-
const layoutPath = "/" + routeSegments.slice(0, i).join("/")
|
|
232
|
-
const layoutLoad = this.layouts[layoutPath]
|
|
233
|
-
|
|
234
|
-
if (!layoutLoad) {
|
|
235
|
-
return acc
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return [...acc, layoutLoad()]
|
|
239
|
-
}, [] as Promise<DefaultComponentModule>[])
|
|
240
|
-
|
|
241
|
-
const [page, ...layouts] = await Promise.all([
|
|
242
|
-
pagePromise,
|
|
243
|
-
...layoutPromises,
|
|
244
|
-
])
|
|
245
|
-
|
|
246
|
-
this.currentRoute = null
|
|
247
|
-
if (controller.signal.aborted) return
|
|
248
|
-
|
|
249
|
-
if (typeof page.default !== "function") {
|
|
250
|
-
throw new Error("Route component must be a default exported function")
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const routerState: RouterState = {
|
|
254
|
-
path,
|
|
255
|
-
params,
|
|
256
|
-
query,
|
|
257
|
-
signal,
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
let config = (page as unknown as PageModule).config
|
|
261
|
-
if (this.pageRouteToConfig.has(route)) {
|
|
262
|
-
config = this.pageRouteToConfig.get(route)
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
if (config?.loader) {
|
|
266
|
-
props = { ...props, loading: true, data: null, error: null }
|
|
267
|
-
this.loadRouteData(config.loader, props, routerState, enableTransition)
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
handleStateTransition(signal, enableTransition, () => {
|
|
271
|
-
this.currentPage.value = {
|
|
272
|
-
component: page.default,
|
|
273
|
-
config,
|
|
274
|
-
route: "/" + routeSegments.join("/"),
|
|
275
|
-
}
|
|
276
|
-
this.state.value = routerState
|
|
277
|
-
this.currentPageProps.value = props
|
|
278
|
-
this.currentLayouts.value = layouts
|
|
279
|
-
.filter((m) => typeof m.default === "function")
|
|
280
|
-
.map((m) => m.default)
|
|
281
|
-
})
|
|
282
|
-
} catch (error) {
|
|
283
|
-
console.error("Failed to load route component:", error)
|
|
284
|
-
this.currentPage.value = null
|
|
285
|
-
} finally {
|
|
286
|
-
this.loading.value = false
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
private async loadRouteData(
|
|
291
|
-
loader: NonNullable<PageConfig["loader"]>,
|
|
292
|
-
props: PageProps<PageConfig>,
|
|
293
|
-
routerState: RouterState,
|
|
294
|
-
enableTransition = this.enableTransitions
|
|
295
|
-
) {
|
|
296
|
-
loader
|
|
297
|
-
.load(routerState)
|
|
298
|
-
.then(
|
|
299
|
-
(data) => ({ data, error: null }),
|
|
300
|
-
(error) => ({
|
|
301
|
-
data: null,
|
|
302
|
-
error: new FileRouterDataLoadError(error),
|
|
303
|
-
})
|
|
304
|
-
)
|
|
305
|
-
.then(({ data, error }) => {
|
|
306
|
-
if (routerState.signal.aborted) return
|
|
307
|
-
|
|
308
|
-
let transition = enableTransition
|
|
309
|
-
if (loader.transition !== undefined) {
|
|
310
|
-
transition = loader.transition
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
handleStateTransition(routerState.signal, transition, () => {
|
|
314
|
-
this.currentPageProps.value = {
|
|
315
|
-
...props,
|
|
316
|
-
loading: false,
|
|
317
|
-
data,
|
|
318
|
-
error,
|
|
319
|
-
}
|
|
320
|
-
})
|
|
321
|
-
})
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
private async navigate(
|
|
325
|
-
path: string,
|
|
326
|
-
options?: {
|
|
327
|
-
replace?: boolean
|
|
328
|
-
transition?: boolean
|
|
329
|
-
props?: Record<string, unknown>
|
|
330
|
-
}
|
|
331
|
-
) {
|
|
332
|
-
const f = options?.replace ? "replaceState" : "pushState"
|
|
333
|
-
window.history[f]({}, "", path)
|
|
334
|
-
window.dispatchEvent(new PopStateEvent("popstate", { state: {} }))
|
|
335
|
-
return this.loadRoute(path, options?.props, options?.transition)
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
private setQuery(query: RouteQuery) {
|
|
339
|
-
const queryString = buildQueryString(query)
|
|
340
|
-
const newUrl = `${this.state.value.path}${
|
|
341
|
-
queryString ? `?${queryString}` : ""
|
|
342
|
-
}`
|
|
343
|
-
window.history.pushState(null, "", newUrl)
|
|
344
|
-
this.state.value = { ...this.state.value, query }
|
|
345
|
-
}
|
|
346
|
-
}
|
|
4
|
+
import { RouterContext } from "./context.js"
|
|
5
|
+
import { FileRouterController } from "./fileRouterController.js"
|
|
6
|
+
import type { FileRouterConfig } from "./types.js"
|
|
347
7
|
|
|
348
8
|
export interface FileRouterProps {
|
|
349
9
|
/**
|
|
@@ -365,7 +25,7 @@ export interface FileRouterProps {
|
|
|
365
25
|
}
|
|
366
26
|
|
|
367
27
|
export function FileRouter(props: FileRouterProps): JSX.Element {
|
|
368
|
-
const [controller] = useState(() => new FileRouterController(props))
|
|
28
|
+
const [controller] = useState(() => new FileRouterController(props.config))
|
|
369
29
|
useEffect(() => () => controller.dispose(), [controller])
|
|
370
30
|
|
|
371
31
|
return createElement(
|
|
@@ -374,101 +34,3 @@ export function FileRouter(props: FileRouterProps): JSX.Element {
|
|
|
374
34
|
controller.getChildren()
|
|
375
35
|
)
|
|
376
36
|
}
|
|
377
|
-
|
|
378
|
-
// Utility functions
|
|
379
|
-
|
|
380
|
-
function parseQuery(
|
|
381
|
-
search: string
|
|
382
|
-
): Record<string, string | string[] | undefined> {
|
|
383
|
-
const params = new URLSearchParams(search)
|
|
384
|
-
const query: Record<string, string | string[] | undefined> = {}
|
|
385
|
-
|
|
386
|
-
for (const [key, value] of params.entries()) {
|
|
387
|
-
if (query[key]) {
|
|
388
|
-
// Convert to array if multiple values
|
|
389
|
-
if (Array.isArray(query[key])) {
|
|
390
|
-
;(query[key] as string[]).push(value)
|
|
391
|
-
} else {
|
|
392
|
-
query[key] = [query[key] as string, value]
|
|
393
|
-
}
|
|
394
|
-
} else {
|
|
395
|
-
query[key] = value
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
return query
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
function buildQueryString(
|
|
403
|
-
query: Record<string, string | string[] | undefined>
|
|
404
|
-
): string {
|
|
405
|
-
const params = new URLSearchParams()
|
|
406
|
-
|
|
407
|
-
for (const [key, value] of Object.entries(query)) {
|
|
408
|
-
if (value !== undefined) {
|
|
409
|
-
if (Array.isArray(value)) {
|
|
410
|
-
value.forEach((v) => params.append(key, v))
|
|
411
|
-
} else {
|
|
412
|
-
params.set(key, value)
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
return params.toString()
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
function formatViteImportMap(
|
|
421
|
-
map: ViteImportMap,
|
|
422
|
-
dir: string,
|
|
423
|
-
baseUrl: string
|
|
424
|
-
): ViteImportMap {
|
|
425
|
-
return Object.keys(map).reduce((acc, key) => {
|
|
426
|
-
let k = key
|
|
427
|
-
const dirIndex = k.indexOf(dir)
|
|
428
|
-
if (dirIndex === -1) {
|
|
429
|
-
return acc
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
k = k.slice(dirIndex + dir.length)
|
|
433
|
-
while (k.startsWith("/")) {
|
|
434
|
-
k = k.slice(1)
|
|
435
|
-
}
|
|
436
|
-
k = k.split("/").slice(0, -1).join("/") // remove filename
|
|
437
|
-
k = k.replace(/\[([^\]]+)\]/g, ":$1") // replace [param] with :param
|
|
438
|
-
|
|
439
|
-
return {
|
|
440
|
-
...acc,
|
|
441
|
-
[baseUrl + k]: map[key],
|
|
442
|
-
}
|
|
443
|
-
}, {})
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
function normalizePrefixPath(path: string) {
|
|
447
|
-
while (path.startsWith(".")) {
|
|
448
|
-
path = path.slice(1)
|
|
449
|
-
}
|
|
450
|
-
path = `/${path}/`
|
|
451
|
-
while (path.startsWith("//")) {
|
|
452
|
-
path = path.slice(1)
|
|
453
|
-
}
|
|
454
|
-
while (path.endsWith("//")) {
|
|
455
|
-
path = path.slice(0, -1)
|
|
456
|
-
}
|
|
457
|
-
return path
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
function handleStateTransition(
|
|
461
|
-
signal: AbortSignal,
|
|
462
|
-
enableTransition: boolean,
|
|
463
|
-
callback: () => void
|
|
464
|
-
) {
|
|
465
|
-
if (!enableTransition || typeof document.startViewTransition !== "function") {
|
|
466
|
-
return callback()
|
|
467
|
-
}
|
|
468
|
-
const vt = document.startViewTransition(() => {
|
|
469
|
-
callback()
|
|
470
|
-
flushSync()
|
|
471
|
-
})
|
|
472
|
-
|
|
473
|
-
signal.addEventListener("abort", () => vt.skipTransition())
|
|
474
|
-
}
|