@pauloevpr/solid-router 0.16.2-vt.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1097 -0
  3. package/dist/components.d.ts +31 -0
  4. package/dist/components.jsx +40 -0
  5. package/dist/data/action.d.ts +17 -0
  6. package/dist/data/action.js +166 -0
  7. package/dist/data/createAsync.d.ts +32 -0
  8. package/dist/data/createAsync.js +96 -0
  9. package/dist/data/events.d.ts +9 -0
  10. package/dist/data/events.js +123 -0
  11. package/dist/data/index.d.ts +4 -0
  12. package/dist/data/index.js +4 -0
  13. package/dist/data/query.d.ts +23 -0
  14. package/dist/data/query.js +232 -0
  15. package/dist/data/response.d.ts +4 -0
  16. package/dist/data/response.js +42 -0
  17. package/dist/index.d.ts +8 -0
  18. package/dist/index.js +2055 -0
  19. package/dist/index.jsx +7 -0
  20. package/dist/lifecycle.d.ts +5 -0
  21. package/dist/lifecycle.js +76 -0
  22. package/dist/routers/HashRouter.d.ts +9 -0
  23. package/dist/routers/HashRouter.js +41 -0
  24. package/dist/routers/MemoryRouter.d.ts +24 -0
  25. package/dist/routers/MemoryRouter.js +57 -0
  26. package/dist/routers/Router.d.ts +9 -0
  27. package/dist/routers/Router.js +45 -0
  28. package/dist/routers/StaticRouter.d.ts +6 -0
  29. package/dist/routers/StaticRouter.js +15 -0
  30. package/dist/routers/components.d.ts +29 -0
  31. package/dist/routers/components.jsx +122 -0
  32. package/dist/routers/createRouter.d.ts +10 -0
  33. package/dist/routers/createRouter.js +41 -0
  34. package/dist/routers/index.d.ts +11 -0
  35. package/dist/routers/index.js +6 -0
  36. package/dist/routing.d.ts +176 -0
  37. package/dist/routing.js +608 -0
  38. package/dist/types.d.ts +203 -0
  39. package/dist/types.js +1 -0
  40. package/dist/utils.d.ts +13 -0
  41. package/dist/utils.js +193 -0
  42. package/dist/viewTransitions.d.ts +20 -0
  43. package/dist/viewTransitions.js +118 -0
  44. package/package.json +71 -0
package/dist/index.js ADDED
@@ -0,0 +1,2055 @@
1
+ import { isServer, getRequestEvent, createComponent as createComponent$1, memo, delegateEvents, spread, mergeProps as mergeProps$1, template } from 'solid-js/web';
2
+ import { getOwner, runWithOwner, createMemo, createContext, onCleanup, useContext, untrack, createSignal, createRenderEffect, on, createComponent, startTransition, resetErrorBoundaries, batch, children, mergeProps, Show, createRoot, sharedConfig, getListener, $TRACK, splitProps, createResource, catchError, createEffect } from 'solid-js';
3
+ import { createStore, reconcile, unwrap } from 'solid-js/store';
4
+
5
+ function createBeforeLeave() {
6
+ let listeners = new Set();
7
+ function subscribe(listener) {
8
+ listeners.add(listener);
9
+ return () => listeners.delete(listener);
10
+ }
11
+ let ignore = false;
12
+ function confirm(to, options) {
13
+ if (ignore) return !(ignore = false);
14
+ const e = {
15
+ to,
16
+ options,
17
+ defaultPrevented: false,
18
+ preventDefault: () => e.defaultPrevented = true
19
+ };
20
+ for (const l of listeners) l.listener({
21
+ to,
22
+ options,
23
+ // delegate to the shared event so later listeners' preventDefault
24
+ // calls are observable from earlier listeners
25
+ get defaultPrevented() {
26
+ return e.defaultPrevented;
27
+ },
28
+ preventDefault: e.preventDefault,
29
+ from: l.location,
30
+ retry: force => {
31
+ force && (ignore = true);
32
+ l.navigate(to, {
33
+ ...options,
34
+ resolve: false
35
+ });
36
+ }
37
+ });
38
+ return !e.defaultPrevented;
39
+ }
40
+ return {
41
+ subscribe,
42
+ confirm
43
+ };
44
+ }
45
+
46
+ // The following supports browser initiated blocking (eg back/forward)
47
+
48
+ let depth;
49
+ function saveCurrentDepth() {
50
+ if (!window.history.state || window.history.state._depth == null) {
51
+ window.history.replaceState({
52
+ ...window.history.state,
53
+ _depth: window.history.length - 1
54
+ }, "");
55
+ }
56
+ depth = window.history.state._depth;
57
+ }
58
+ if (!isServer) {
59
+ saveCurrentDepth();
60
+ }
61
+ function keepDepth(state) {
62
+ return {
63
+ ...state,
64
+ _depth: window.history.state && window.history.state._depth
65
+ };
66
+ }
67
+ function notifyIfNotBlocked(notify, block) {
68
+ let ignore = false;
69
+ return () => {
70
+ const prevDepth = depth;
71
+ saveCurrentDepth();
72
+ const delta = prevDepth == null ? null : depth - prevDepth;
73
+ if (ignore) {
74
+ ignore = false;
75
+ return;
76
+ }
77
+ if (delta && block(delta)) {
78
+ ignore = true;
79
+ window.history.go(-delta);
80
+ } else {
81
+ notify();
82
+ }
83
+ };
84
+ }
85
+
86
+ const hasSchemeRegex = /^(?:[a-z0-9]+:)?\/\//i;
87
+ const trimPathRegex = /^\/+|(\/)\/+$/g;
88
+ const mockBase = "http://sr";
89
+ function normalizePath(path, omitSlash = false) {
90
+ const s = path.replace(trimPathRegex, "$1");
91
+ return s ? omitSlash || /^[?#]/.test(s) ? s : "/" + s : "";
92
+ }
93
+ function resolvePath(base, path, from) {
94
+ if (hasSchemeRegex.test(path)) {
95
+ return undefined;
96
+ }
97
+ const basePath = normalizePath(base);
98
+ const fromPath = from && normalizePath(from);
99
+ let result = "";
100
+ if (!fromPath || path.startsWith("/")) {
101
+ result = basePath;
102
+ } else if (fromPath.toLowerCase().indexOf(basePath.toLowerCase()) !== 0) {
103
+ result = basePath + fromPath;
104
+ } else {
105
+ result = fromPath;
106
+ }
107
+ return (result || "/") + normalizePath(path, !result);
108
+ }
109
+ function invariant(value, message) {
110
+ if (value == null) {
111
+ throw new Error(message);
112
+ }
113
+ return value;
114
+ }
115
+ function joinPaths(from, to) {
116
+ return normalizePath(from).replace(/\/*(\*.*)?$/g, "") + normalizePath(to);
117
+ }
118
+ function extractSearchParams(url) {
119
+ const params = {};
120
+ url.searchParams.forEach((value, key) => {
121
+ if (key in params) {
122
+ if (Array.isArray(params[key])) params[key].push(value);else params[key] = [params[key], value];
123
+ } else params[key] = value;
124
+ });
125
+ return params;
126
+ }
127
+ function createMatcher(path, partial, matchFilters) {
128
+ const [pattern, splat] = path.split("/*", 2);
129
+ const segments = pattern.split("/").filter(Boolean);
130
+ const len = segments.length;
131
+ return location => {
132
+ const locSegments = location.split("/");
133
+ // tolerate a single leading and trailing slash, but reject empty interior
134
+ // segments so `/foo//bar` doesn't silently match `/foo/bar` (#567)
135
+ if (locSegments[0] === "") locSegments.shift();
136
+ if (locSegments.length && locSegments[locSegments.length - 1] === "") locSegments.pop();
137
+ if (locSegments.includes("")) return null;
138
+ const lenDiff = locSegments.length - len;
139
+ if (lenDiff < 0 || lenDiff > 0 && splat === undefined && !partial) {
140
+ return null;
141
+ }
142
+ const match = {
143
+ path: len ? "" : "/",
144
+ params: {}
145
+ };
146
+ const matchFilter = s => matchFilters === undefined ? undefined : matchFilters[s];
147
+ for (let i = 0; i < len; i++) {
148
+ const segment = segments[i];
149
+ const dynamic = segment[0] === ":";
150
+ const locSegment = dynamic ? locSegments[i] : locSegments[i].toLowerCase();
151
+ const key = dynamic ? segment.slice(1) : segment.toLowerCase();
152
+ if (dynamic && matchSegment(locSegment, matchFilter(key))) {
153
+ match.params[key] = locSegment;
154
+ } else if (dynamic || !matchSegment(locSegment, key)) {
155
+ return null;
156
+ }
157
+ match.path += `/${locSegment}`;
158
+ }
159
+ if (splat) {
160
+ const remainder = lenDiff ? locSegments.slice(-lenDiff).join("/") : "";
161
+ if (matchSegment(remainder, matchFilter(splat))) {
162
+ match.params[splat] = remainder;
163
+ } else {
164
+ return null;
165
+ }
166
+ }
167
+ return match;
168
+ };
169
+ }
170
+ function matchSegment(input, filter) {
171
+ const isEqual = s => s === input;
172
+ if (filter === undefined) {
173
+ return true;
174
+ } else if (typeof filter === "string") {
175
+ return isEqual(filter);
176
+ } else if (typeof filter === "function") {
177
+ return filter(input);
178
+ } else if (Array.isArray(filter)) {
179
+ return filter.some(isEqual);
180
+ } else if (filter instanceof RegExp) {
181
+ return filter.test(input);
182
+ }
183
+ return false;
184
+ }
185
+ function scoreRoute(route) {
186
+ const [pattern, splat] = route.pattern.split("/*", 2);
187
+ const segments = pattern.split("/").filter(Boolean);
188
+ return segments.reduce((score, segment) => score + (segment.startsWith(":") ? 2 : 3), segments.length - (splat === undefined ? 0 : 1));
189
+ }
190
+ function createMemoObject(fn) {
191
+ const map = new Map();
192
+ const owner = getOwner();
193
+ return new Proxy({}, {
194
+ get(_, property) {
195
+ if (!map.has(property)) {
196
+ runWithOwner(owner, () => map.set(property, createMemo(() => fn()[property])));
197
+ }
198
+ return map.get(property)();
199
+ },
200
+ getOwnPropertyDescriptor() {
201
+ return {
202
+ enumerable: true,
203
+ configurable: true
204
+ };
205
+ },
206
+ ownKeys() {
207
+ return Reflect.ownKeys(fn());
208
+ },
209
+ has(_, property) {
210
+ return property in fn();
211
+ }
212
+ });
213
+ }
214
+ function mergeSearchString(search, params) {
215
+ const merged = new URLSearchParams(search);
216
+ Object.entries(params).forEach(([key, value]) => {
217
+ if (value == null || value === "" || value instanceof Array && !value.length) {
218
+ merged.delete(key);
219
+ } else {
220
+ if (value instanceof Array) {
221
+ // Delete all instances of the key before appending
222
+ merged.delete(key);
223
+ value.forEach(v => {
224
+ merged.append(key, String(v));
225
+ });
226
+ } else {
227
+ merged.set(key, String(value));
228
+ }
229
+ }
230
+ });
231
+ const s = merged.toString();
232
+ return s ? `?${s}` : "";
233
+ }
234
+ function expandOptionals(pattern) {
235
+ let match = /(\/?\:[^\/]+)\?/.exec(pattern);
236
+ if (!match) return [pattern];
237
+ let prefix = pattern.slice(0, match.index);
238
+ let suffix = pattern.slice(match.index + match[0].length);
239
+ const prefixes = [prefix, prefix += match[1]];
240
+
241
+ // This section handles adjacent optional params. We don't actually want all permuations since
242
+ // that will lead to equivalent routes which have the same number of params. For example
243
+ // `/:a?/:b?/:c`? only has the unique expansion: `/`, `/:a`, `/:a/:b`, `/:a/:b/:c` and we can
244
+ // discard `/:b`, `/:c`, `/:b/:c` by building them up in order and not recursing. This also helps
245
+ // ensure predictability where earlier params have precidence.
246
+ while (match = /^(\/\:[^\/]+)\?/.exec(suffix)) {
247
+ prefixes.push(prefix += match[1]);
248
+ suffix = suffix.slice(match[0].length);
249
+ }
250
+ return expandOptionals(suffix).reduce((results, expansion) => [...results, ...prefixes.map(p => p + expansion)], []);
251
+ }
252
+ function setFunctionName(obj, value) {
253
+ Object.defineProperty(obj, "name", {
254
+ value,
255
+ writable: false,
256
+ configurable: false
257
+ });
258
+ return obj;
259
+ }
260
+
261
+ const MAX_REDIRECTS = 100;
262
+ const VIEW_TRANSITION_TIMEOUT_MS = 3000;
263
+
264
+ /** Consider this API opaque and internal. It is likely to change in the future. */
265
+ const RouterContextObj = createContext();
266
+ const RouteContextObj = createContext();
267
+ const useRouter = () => invariant(useContext(RouterContextObj), "<A> and 'use' router primitives can be only used inside a Route.");
268
+ const useRoute = () => useContext(RouteContextObj) || useRouter().base;
269
+ const useResolvedPath = path => {
270
+ const route = useRoute();
271
+ return createMemo(() => route.resolvePath(path()));
272
+ };
273
+ const useHref = to => {
274
+ const router = useRouter();
275
+ return createMemo(() => {
276
+ const to_ = to();
277
+ return to_ !== undefined ? router.renderPath(to_) : to_;
278
+ });
279
+ };
280
+
281
+ /**
282
+ * Retrieves method to do navigation. The method accepts a path to navigate to and an optional object with the following options:
283
+ *
284
+ * - resolve (*boolean*, default `true`): resolve the path against the current route
285
+ * - replace (*boolean*, default `false`): replace the history entry
286
+ * - scroll (*boolean*, default `true`): scroll to top after navigation
287
+ * - state (*any*, default `undefined`): pass custom state to `location.state`
288
+ *
289
+ * **Note**: The state is serialized using the structured clone algorithm which does not support all object types.
290
+ *
291
+ * @example
292
+ * ```js
293
+ * const navigate = useNavigate();
294
+ *
295
+ * if (unauthorized) {
296
+ * navigate("/login", { replace: true });
297
+ * }
298
+ * ```
299
+ */
300
+ const useNavigate = () => useRouter().navigatorFactory();
301
+
302
+ /**
303
+ * Retrieves reactive `location` object useful for getting things like `pathname`.
304
+ *
305
+ * @example
306
+ * ```js
307
+ * const location = useLocation();
308
+ *
309
+ * const pathname = createMemo(() => parsePath(location.pathname));
310
+ * ```
311
+ */
312
+ const useLocation = () => useRouter().location;
313
+
314
+ /**
315
+ * Retrieves signal that indicates whether the route is currently in a *Transition*.
316
+ * Useful for showing stale/pending state when the route resolution is *Suspended* during concurrent rendering.
317
+ *
318
+ * @example
319
+ * ```js
320
+ * const isRouting = useIsRouting();
321
+ *
322
+ * return (
323
+ * <div classList={{ "grey-out": isRouting() }}>
324
+ * <MyAwesomeContent />
325
+ * </div>
326
+ * );
327
+ * ```
328
+ */
329
+ const useIsRouting = () => useRouter().isRouting;
330
+
331
+ /**
332
+ * usePreloadRoute returns a function that can be used to preload a route manual.
333
+ * This is what happens automatically with link hovering and similar focus based behavior, but it is available here as an API.
334
+ *
335
+ * @example
336
+ * ```js
337
+ * const preload = usePreloadRoute();
338
+ *
339
+ * preload(`/users/settings`, { preloadData: true });
340
+ * ```
341
+ */
342
+ const usePreloadRoute = () => {
343
+ const pre = useRouter().preloadRoute;
344
+ return (url, options = {}) => pre(url instanceof URL ? url : new URL(url, mockBase), options.preloadData);
345
+ };
346
+
347
+ /**
348
+ * `useMatch` takes an accessor that returns the path and creates a `Memo` that returns match information if the current path matches the provided path.
349
+ * Useful for determining if a given path matches the current route.
350
+ *
351
+ * @example
352
+ * ```js
353
+ * const match = useMatch(() => props.href);
354
+ *
355
+ * return <div classList={{ active: Boolean(match()) }} />;
356
+ * ```
357
+ */
358
+ const useMatch = (path, matchFilters) => {
359
+ const location = useLocation();
360
+ const matchers = createMemo(() => expandOptionals(path()).map(path => createMatcher(path, undefined, matchFilters)));
361
+ return createMemo(() => {
362
+ for (const matcher of matchers()) {
363
+ const match = matcher(location.pathname);
364
+ if (match) return match;
365
+ }
366
+ });
367
+ };
368
+
369
+ /**
370
+ * `useCurrentMatches` returns all the matches for the current matched route.
371
+ * Useful for getting all the route information.
372
+ *
373
+ * @example
374
+ * ```js
375
+ * const matches = useCurrentMatches();
376
+ *
377
+ * const breadcrumbs = createMemo(() => matches().map(m => m.route.info.breadcrumb))
378
+ * ```
379
+ */
380
+ const useCurrentMatches = () => {
381
+ const router = useRouter();
382
+ // return a copy so user mutations (eg. `.reverse()`) can't corrupt router state
383
+ return () => router.matches().slice();
384
+ };
385
+
386
+ /**
387
+ * Retrieves a reactive, store-like object containing the current route path parameters as defined in the Route.
388
+ *
389
+ * @example
390
+ * ```js
391
+ * const params = useParams();
392
+ *
393
+ * // fetch user based on the id path parameter
394
+ * const [user] = createResource(() => params.id, fetchUser);
395
+ * ```
396
+ */
397
+ const useParams = () => useRouter().params;
398
+
399
+ /**
400
+ * Retrieves a tuple containing a reactive object to read the current location's query parameters and a method to update them.
401
+ * The object is a proxy so you must access properties to subscribe to reactive updates.
402
+ * **Note** that values will be strings and property names will retain their casing.
403
+ *
404
+ * The setter method accepts an object whose entries will be merged into the current query string.
405
+ * Values `''`, `undefined` and `null` will remove the key from the resulting query string.
406
+ * Updates will behave just like a navigation and the setter accepts the same optional second parameter as `navigate` and auto-scrolling is disabled by default.
407
+ *
408
+ * @examples
409
+ * ```js
410
+ * const [searchParams, setSearchParams] = useSearchParams();
411
+ *
412
+ * return (
413
+ * <div>
414
+ * <span>Page: {searchParams.page}</span>
415
+ * <button
416
+ * onClick={() =>
417
+ * setSearchParams({ page: (parseInt(searchParams.page) || 0) + 1 })
418
+ * }
419
+ * >
420
+ * Next Page
421
+ * </button>
422
+ * </div>
423
+ * );
424
+ * ```
425
+ */
426
+ const useSearchParams = () => {
427
+ const router = useRouter();
428
+ const location = router.location;
429
+ const navigate = useNavigate();
430
+ const setSearchParams = (params, options) => {
431
+ const to = untrack(() => {
432
+ // merge onto the in-flight navigation target (if any) so consecutive
433
+ // synchronous calls compose instead of the later one winning
434
+ const pending = router.pendingTarget && new URL(router.pendingTarget.value, mockBase);
435
+ const pathname = pending ? pending.pathname : location.pathname;
436
+ const search = pending ? pending.search : location.search;
437
+ const hash = pending ? pending.hash : location.hash;
438
+ return pathname + mergeSearchString(search, params) + hash;
439
+ });
440
+ navigate(to, {
441
+ scroll: false,
442
+ resolve: false,
443
+ ...options
444
+ });
445
+ };
446
+ return [location.query, setSearchParams];
447
+ };
448
+
449
+ /**
450
+ * useBeforeLeave takes a function that will be called prior to leaving a route.
451
+ * The function will be called with:
452
+ *
453
+ * - from (*Location*): current location (before change).
454
+ * - to (*string | number*): path passed to `navigate`.
455
+ * - options (*NavigateOptions*): options passed to navigate.
456
+ * - preventDefault (*function*): call to block the route change.
457
+ * - defaultPrevented (*readonly boolean*): `true` if any previously called leave handlers called `preventDefault`.
458
+ * - retry (*function*, force?: boolean ): call to retry the same navigation, perhaps after confirming with the user. Pass `true` to skip running the leave handlers again (i.e. force navigate without confirming).
459
+ *
460
+ * @example
461
+ * ```js
462
+ * useBeforeLeave((e: BeforeLeaveEventArgs) => {
463
+ * if (form.isDirty && !e.defaultPrevented) {
464
+ * // preventDefault to block immediately and prompt user async
465
+ * e.preventDefault();
466
+ * setTimeout(() => {
467
+ * if (window.confirm("Discard unsaved changes - are you sure?")) {
468
+ * // user wants to proceed anyway so retry with force=true
469
+ * e.retry(true);
470
+ * }
471
+ * }, 100);
472
+ * }
473
+ * });
474
+ * ```
475
+ */
476
+ const useBeforeLeave = listener => {
477
+ const s = useRouter().beforeLeave.subscribe({
478
+ listener,
479
+ location: useLocation(),
480
+ navigate: useNavigate()
481
+ });
482
+ onCleanup(s);
483
+ };
484
+
485
+ // Encodes a static path segment like `encodeURIComponent`, but leaves RFC 3986
486
+ // pchar characters (sub-delims / ":" / "@") literal, matching how browsers
487
+ // report them in `location.pathname`. Non-ASCII characters (eg. CJK paths) are
488
+ // still percent-encoded exactly as before, since browsers encode those too.
489
+ const encodeSegment = s => encodeURIComponent(s).replace(/%(2B|40|3A|24|26|2C|3B|3D)/g, m => decodeURIComponent(m));
490
+ function createRoutes(routeDef, base = "") {
491
+ const {
492
+ component,
493
+ preload,
494
+ load,
495
+ children,
496
+ info
497
+ } = routeDef;
498
+ const isLeaf = !children || Array.isArray(children) && !children.length;
499
+ const shared = {
500
+ key: routeDef,
501
+ component,
502
+ preload: preload || load,
503
+ info
504
+ };
505
+ return asArray(routeDef.path).reduce((acc, originalPath) => {
506
+ for (const expandedPath of expandOptionals(originalPath)) {
507
+ const path = joinPaths(base, expandedPath);
508
+ let pattern = isLeaf ? path : path.split("/*", 1)[0];
509
+ pattern = pattern.split("/").map(s => {
510
+ return s.startsWith(":") || s.startsWith("*") ? s : encodeSegment(s);
511
+ }).join("/");
512
+ acc.push({
513
+ ...shared,
514
+ originalPath,
515
+ pattern,
516
+ matcher: createMatcher(pattern, !isLeaf, routeDef.matchFilters)
517
+ });
518
+ }
519
+ return acc;
520
+ }, []);
521
+ }
522
+ function createBranch(routes, index = 0) {
523
+ return {
524
+ routes,
525
+ score: scoreRoute(routes[routes.length - 1]) * 10000 - index,
526
+ matcher(location) {
527
+ const matches = [];
528
+ for (let i = routes.length - 1; i >= 0; i--) {
529
+ const route = routes[i];
530
+ const match = route.matcher(location);
531
+ if (!match) {
532
+ return null;
533
+ }
534
+ matches.unshift({
535
+ ...match,
536
+ route
537
+ });
538
+ }
539
+ return matches;
540
+ }
541
+ };
542
+ }
543
+ function asArray(value) {
544
+ return Array.isArray(value) ? value : [value];
545
+ }
546
+ function createBranches(routeDef, base = "", stack = [], branches = []) {
547
+ const routeDefs = asArray(routeDef);
548
+ for (let i = 0, len = routeDefs.length; i < len; i++) {
549
+ const def = routeDefs[i];
550
+ if (def && typeof def === "object") {
551
+ if (!def.hasOwnProperty("path")) def.path = "";
552
+ const routes = createRoutes(def, base);
553
+ for (const route of routes) {
554
+ stack.push(route);
555
+ const isEmptyArray = Array.isArray(def.children) && def.children.length === 0;
556
+ if (def.children && !isEmptyArray) {
557
+ createBranches(def.children, route.pattern, stack, branches);
558
+ } else {
559
+ const branch = createBranch([...stack], branches.length);
560
+ branches.push(branch);
561
+ }
562
+ stack.pop();
563
+ }
564
+ }
565
+ }
566
+
567
+ // Stack will be empty on final return
568
+ return stack.length ? branches : branches.sort((a, b) => b.score - a.score);
569
+ }
570
+ function getRouteMatches(branches, location) {
571
+ for (let i = 0, len = branches.length; i < len; i++) {
572
+ const match = branches[i].matcher(location);
573
+ if (match) {
574
+ return match;
575
+ }
576
+ }
577
+ return [];
578
+ }
579
+ function createLocation(path, state, queryWrapper) {
580
+ const origin = new URL(mockBase);
581
+ const url = createMemo(prev => {
582
+ const path_ = path();
583
+ try {
584
+ // anchor rooted paths against the origin explicitly - a path with
585
+ // doubled leading slashes would otherwise parse as protocol-relative
586
+ return new URL(path_[0] === "/" ? mockBase + path_ : path_, origin);
587
+ } catch (err) {
588
+ console.error(`Invalid path ${path_}`);
589
+ return prev;
590
+ }
591
+ }, origin, {
592
+ equals: (a, b) => a.href === b.href
593
+ });
594
+ const pathname = createMemo(() => url().pathname);
595
+ const search = createMemo(() => url().search, true);
596
+ const hash = createMemo(() => url().hash);
597
+ const key = () => "";
598
+ const queryFn = on(search, () => extractSearchParams(url()));
599
+ return {
600
+ get pathname() {
601
+ return pathname();
602
+ },
603
+ get search() {
604
+ return search();
605
+ },
606
+ get hash() {
607
+ return hash();
608
+ },
609
+ get state() {
610
+ return state();
611
+ },
612
+ get key() {
613
+ return key();
614
+ },
615
+ query: queryWrapper ? queryWrapper(queryFn) : createMemoObject(queryFn)
616
+ };
617
+ }
618
+ let intent;
619
+ function getIntent() {
620
+ return intent;
621
+ }
622
+ let inPreloadFn = false;
623
+ function getInPreloadFn() {
624
+ return inPreloadFn;
625
+ }
626
+ function setInPreloadFn(value) {
627
+ inPreloadFn = value;
628
+ }
629
+ function createRouterContext(integration, branches, getContext, options = {}) {
630
+ const {
631
+ signal: [source, setSource],
632
+ utils = {}
633
+ } = integration;
634
+ const parsePath = utils.parsePath || (p => p);
635
+ const renderPath = utils.renderPath || (p => p);
636
+ const beforeLeave = utils.beforeLeave || createBeforeLeave();
637
+ const basePath = resolvePath("", options.base || "");
638
+ if (basePath === undefined) {
639
+ throw new Error(`${basePath} is not a valid base path`);
640
+ } else if (basePath && !source().value) {
641
+ setSource({
642
+ value: basePath,
643
+ replace: true,
644
+ scroll: false
645
+ });
646
+ }
647
+ const [isRouting, setIsRouting] = createSignal(false);
648
+
649
+ // Keep track of last target, so that last call to transition wins
650
+ let lastTransitionTarget;
651
+ let activeViewTransition;
652
+
653
+ // Transition the location to a new value
654
+ const transition = (newIntent, newTarget) => {
655
+ if (newTarget.value === reference() && newTarget.state === state()) return;
656
+ if (lastTransitionTarget === undefined) setIsRouting(true);
657
+ intent = newIntent;
658
+ lastTransitionTarget = newTarget;
659
+ const runSolidTransition = () => startTransition(() => {
660
+ if (lastTransitionTarget !== newTarget) return;
661
+ setReference(lastTransitionTarget.value);
662
+ setState(lastTransitionTarget.state);
663
+ resetErrorBoundaries();
664
+ if (!isServer) submissions[1](subs => subs.filter(s => s.pending));
665
+ }).finally(() => {
666
+ if (lastTransitionTarget !== newTarget) return;
667
+
668
+ // Batch, in order for isRouting and final source update to happen together
669
+ batch(() => {
670
+ intent = undefined;
671
+ if (newIntent === "navigate") navigateEnd(lastTransitionTarget);
672
+ setIsRouting(false);
673
+ lastTransitionTarget = undefined;
674
+ });
675
+ });
676
+ if (shouldUseViewTransition(newIntent)) {
677
+ activeViewTransition?.skipTransition();
678
+ const viewTransition = document.startViewTransition(() => runSolidTransition());
679
+ activeViewTransition = viewTransition;
680
+ const timeout = setTimeout(() => viewTransition.skipTransition(), VIEW_TRANSITION_TIMEOUT_MS);
681
+ viewTransition.finished.finally(() => {
682
+ clearTimeout(timeout);
683
+ if (activeViewTransition === viewTransition) activeViewTransition = undefined;
684
+ }).catch(() => {});
685
+ } else {
686
+ runSolidTransition();
687
+ }
688
+ };
689
+ const [reference, setReference] = createSignal(source().value);
690
+ const [state, setState] = createSignal(source().state);
691
+ const location = createLocation(reference, state, utils.queryWrapper);
692
+ const referrers = [];
693
+ const submissions = createSignal(isServer ? initFromFlash() : []);
694
+ const matches = createMemo(() => {
695
+ if (typeof options.transformUrl === "function") {
696
+ return getRouteMatches(branches(), options.transformUrl(location.pathname));
697
+ }
698
+ return getRouteMatches(branches(), location.pathname);
699
+ });
700
+ const buildParams = () => {
701
+ const m = matches();
702
+ const params = {};
703
+ for (let i = 0; i < m.length; i++) {
704
+ Object.assign(params, m[i].params);
705
+ }
706
+ return params;
707
+ };
708
+ const params = utils.paramsWrapper ? utils.paramsWrapper(buildParams, branches) : createMemoObject(buildParams);
709
+ const baseRoute = {
710
+ pattern: basePath,
711
+ path: () => basePath,
712
+ outlet: () => null,
713
+ resolvePath(to) {
714
+ return resolvePath(basePath, to);
715
+ }
716
+ };
717
+
718
+ // Create a native transition, when source updates
719
+ createRenderEffect(on(source, source => transition("native", source), {
720
+ defer: true
721
+ }));
722
+ return {
723
+ base: baseRoute,
724
+ location,
725
+ params,
726
+ isRouting,
727
+ get pendingTarget() {
728
+ return lastTransitionTarget;
729
+ },
730
+ renderPath,
731
+ parsePath,
732
+ navigatorFactory,
733
+ matches,
734
+ beforeLeave,
735
+ preloadRoute,
736
+ singleFlight: options.singleFlight === undefined ? true : options.singleFlight,
737
+ submissions
738
+ };
739
+ function navigateFromRoute(route, to, options) {
740
+ // Untrack in case someone navigates in an effect - don't want to track `reference` or route paths
741
+ untrack(() => {
742
+ if (typeof to === "number") {
743
+ if (!to) ; else if (utils.go) {
744
+ utils.go(to);
745
+ } else {
746
+ console.warn("Router integration does not support relative routing");
747
+ }
748
+ return;
749
+ }
750
+ const queryOnly = !to || to[0] === "?";
751
+ const {
752
+ replace,
753
+ resolve,
754
+ scroll,
755
+ state: nextState
756
+ } = {
757
+ replace: false,
758
+ resolve: !queryOnly,
759
+ scroll: true,
760
+ ...options
761
+ };
762
+ const resolvedTo = resolve ? route.resolvePath(to) : resolvePath(queryOnly && location.pathname || "", to);
763
+ if (resolvedTo === undefined) {
764
+ throw new Error(`Path '${to}' is not a routable path`);
765
+ } else if (referrers.length >= MAX_REDIRECTS) {
766
+ throw new Error("Too many redirects");
767
+ }
768
+ const current = reference();
769
+ if (resolvedTo !== current || nextState !== state()) {
770
+ if (isServer) {
771
+ const e = getRequestEvent();
772
+ e && (e.response = {
773
+ status: 302,
774
+ headers: new Headers({
775
+ Location: resolvedTo
776
+ })
777
+ });
778
+ setSource({
779
+ value: resolvedTo,
780
+ replace,
781
+ scroll,
782
+ state: nextState
783
+ });
784
+ } else if (beforeLeave.confirm(resolvedTo, options)) {
785
+ referrers.push({
786
+ value: current,
787
+ replace,
788
+ scroll,
789
+ state: state()
790
+ });
791
+ transition("navigate", {
792
+ value: resolvedTo,
793
+ state: nextState
794
+ });
795
+ }
796
+ }
797
+ });
798
+ }
799
+ function navigatorFactory(route) {
800
+ // Workaround for vite issue (https://github.com/vitejs/vite/issues/3803)
801
+ route = route || useContext(RouteContextObj) || baseRoute;
802
+ return (to, options) => navigateFromRoute(route, to, options);
803
+ }
804
+ function navigateEnd(next) {
805
+ const first = referrers[0];
806
+ if (first) {
807
+ setSource({
808
+ ...next,
809
+ replace: first.replace,
810
+ scroll: first.scroll
811
+ });
812
+ referrers.length = 0;
813
+ }
814
+ }
815
+ function preloadRoute(url, preloadData) {
816
+ const matches = getRouteMatches(branches(), url.pathname);
817
+ const prevIntent = intent;
818
+ intent = "preload";
819
+ for (let match in matches) {
820
+ const {
821
+ route,
822
+ params
823
+ } = matches[match];
824
+ route.component && route.component.preload && route.component.preload();
825
+ const {
826
+ preload
827
+ } = route;
828
+ inPreloadFn = true;
829
+ preloadData && preload && runWithOwner(getContext(), () => preload({
830
+ params,
831
+ location: {
832
+ pathname: url.pathname,
833
+ search: url.search,
834
+ hash: url.hash,
835
+ query: extractSearchParams(url),
836
+ state: null,
837
+ key: ""
838
+ },
839
+ intent: "preload"
840
+ }));
841
+ inPreloadFn = false;
842
+ }
843
+ intent = prevIntent;
844
+ }
845
+ function initFromFlash() {
846
+ const e = getRequestEvent();
847
+ return e && e.router && e.router.submission ? [e.router.submission] : [];
848
+ }
849
+ function shouldUseViewTransition(newIntent) {
850
+ return !!(options.viewTransitions && (newIntent === "navigate" || newIntent === "native") && !isServer && typeof document !== "undefined" && document.startViewTransition);
851
+ }
852
+ }
853
+ function createRouteContext(router, parent, outlet, match) {
854
+ const {
855
+ base,
856
+ location,
857
+ params
858
+ } = router;
859
+ const {
860
+ pattern,
861
+ component,
862
+ preload
863
+ } = match().route;
864
+ const path = createMemo(() => match().path);
865
+ component && component.preload && component.preload();
866
+ inPreloadFn = true;
867
+ const data = preload ? preload({
868
+ params,
869
+ location,
870
+ intent: intent || "initial"
871
+ }) : undefined;
872
+ inPreloadFn = false;
873
+ const route = {
874
+ parent,
875
+ pattern,
876
+ path,
877
+ outlet: () => component ? createComponent(component, {
878
+ params,
879
+ location,
880
+ data,
881
+ get children() {
882
+ return outlet();
883
+ }
884
+ }) : outlet(),
885
+ resolvePath(to) {
886
+ return resolvePath(base.path(), to, path());
887
+ }
888
+ };
889
+ return route;
890
+ }
891
+
892
+ const createRouterComponent = router => props => {
893
+ const {
894
+ base
895
+ } = props;
896
+ const routeDefs = children(() => props.children);
897
+ const branches = createMemo(() => createBranches(routeDefs(), props.base || ""));
898
+ let context;
899
+ const routerState = createRouterContext(router, branches, () => context, {
900
+ base,
901
+ singleFlight: props.singleFlight,
902
+ transformUrl: props.transformUrl,
903
+ viewTransitions: props.viewTransitions
904
+ });
905
+ router.create && router.create(routerState);
906
+ return createComponent$1(RouterContextObj.Provider, {
907
+ value: routerState,
908
+ get children() {
909
+ return createComponent$1(Root, {
910
+ routerState: routerState,
911
+ get root() {
912
+ return props.root;
913
+ },
914
+ get preload() {
915
+ return props.rootPreload || props.rootLoad;
916
+ },
917
+ get children() {
918
+ return [memo(() => (context = getOwner()) && null), createComponent$1(Routes, {
919
+ routerState: routerState,
920
+ get branches() {
921
+ return branches();
922
+ }
923
+ })];
924
+ }
925
+ });
926
+ }
927
+ });
928
+ };
929
+ function Root(props) {
930
+ const location = props.routerState.location;
931
+ const params = props.routerState.params;
932
+ const data = createMemo(() => props.preload && untrack(() => {
933
+ setInPreloadFn(true);
934
+ props.preload({
935
+ params,
936
+ location,
937
+ intent: getIntent() || "initial"
938
+ });
939
+ setInPreloadFn(false);
940
+ }));
941
+ return createComponent$1(Show, {
942
+ get when() {
943
+ return props.root;
944
+ },
945
+ keyed: true,
946
+ get fallback() {
947
+ return props.children;
948
+ },
949
+ children: Root => createComponent$1(Root, {
950
+ params: params,
951
+ location: location,
952
+ get data() {
953
+ return data();
954
+ },
955
+ get children() {
956
+ return props.children;
957
+ }
958
+ })
959
+ });
960
+ }
961
+ function Routes(props) {
962
+ if (isServer) {
963
+ const e = getRequestEvent();
964
+ if (e && e.router && e.router.dataOnly) {
965
+ dataOnly(e, props.routerState, props.branches);
966
+ return;
967
+ }
968
+ e && ((e.router || (e.router = {})).matches || (e.router.matches = props.routerState.matches().map(({
969
+ route,
970
+ path,
971
+ params
972
+ }) => ({
973
+ path: route.originalPath,
974
+ pattern: route.pattern,
975
+ match: path,
976
+ params,
977
+ info: route.info
978
+ }))));
979
+ }
980
+ const disposers = [];
981
+ let root;
982
+ // dispose the detached per-route roots when this component unmounts, otherwise
983
+ // they stay subscribed to `matches` and crash on a later navigation (#451)
984
+ onCleanup(() => disposers.forEach(dispose => dispose()));
985
+ const routeStates = createMemo(on(props.routerState.matches, (nextMatches, prevMatches, prev) => {
986
+ let equal = prevMatches && nextMatches.length === prevMatches.length;
987
+ const next = [];
988
+ for (let i = 0, len = nextMatches.length; i < len; i++) {
989
+ const prevMatch = prevMatches && prevMatches[i];
990
+ const nextMatch = nextMatches[i];
991
+ if (prev && prevMatch && nextMatch.route.key === prevMatch.route.key) {
992
+ next[i] = prev[i];
993
+ } else {
994
+ equal = false;
995
+ if (disposers[i]) {
996
+ disposers[i]();
997
+ }
998
+ createRoot(dispose => {
999
+ disposers[i] = dispose;
1000
+ next[i] = createRouteContext(props.routerState, next[i - 1] || props.routerState.base, createOutlet(() => routeStates()[i + 1]), () => {
1001
+ const routeMatches = props.routerState.matches();
1002
+ return routeMatches[i] ?? routeMatches[0];
1003
+ });
1004
+ });
1005
+ }
1006
+ }
1007
+ disposers.splice(nextMatches.length).forEach(dispose => dispose());
1008
+ if (prev && equal) {
1009
+ return prev;
1010
+ }
1011
+ root = next[0];
1012
+ return next;
1013
+ }));
1014
+ return createOutlet(() => routeStates() && root)();
1015
+ }
1016
+ const createOutlet = child => {
1017
+ return () => createComponent$1(Show, {
1018
+ get when() {
1019
+ return child();
1020
+ },
1021
+ keyed: true,
1022
+ children: child => createComponent$1(RouteContextObj.Provider, {
1023
+ value: child,
1024
+ get children() {
1025
+ return child.outlet();
1026
+ }
1027
+ })
1028
+ });
1029
+ };
1030
+ const Route = props => {
1031
+ const childRoutes = children(() => props.children);
1032
+ return mergeProps(props, {
1033
+ get children() {
1034
+ return childRoutes();
1035
+ }
1036
+ });
1037
+ };
1038
+
1039
+ // for data only mode with single flight mutations
1040
+ function dataOnly(event, routerState, branches) {
1041
+ const url = new URL(event.request.url);
1042
+ const prevMatches = getRouteMatches(branches, new URL(event.router.previousUrl || event.request.url).pathname);
1043
+ const matches = getRouteMatches(branches, url.pathname);
1044
+ for (let match = 0; match < matches.length; match++) {
1045
+ if (!prevMatches[match] || matches[match].route !== prevMatches[match].route) event.router.dataOnly = true;
1046
+ const {
1047
+ route,
1048
+ params
1049
+ } = matches[match];
1050
+ route.preload && route.preload({
1051
+ params,
1052
+ location: routerState.location,
1053
+ intent: "preload"
1054
+ });
1055
+ }
1056
+ }
1057
+
1058
+ function intercept([value, setValue], get, set) {
1059
+ return [value, set ? v => setValue(set(v)) : setValue];
1060
+ }
1061
+ function createRouter(config) {
1062
+ let ignore = false;
1063
+ const wrap = value => typeof value === "string" ? {
1064
+ value
1065
+ } : value;
1066
+ const signal = intercept(createSignal(wrap(config.get()), {
1067
+ equals: (a, b) => a.value === b.value && a.state === b.state
1068
+ }), undefined, next => {
1069
+ !ignore && config.set(next);
1070
+ if (sharedConfig.registry && !sharedConfig.done) sharedConfig.done = true;
1071
+ return next;
1072
+ });
1073
+ config.init && onCleanup(config.init((value = config.get()) => {
1074
+ ignore = true;
1075
+ signal[1](wrap(value));
1076
+ ignore = false;
1077
+ }));
1078
+ return createRouterComponent({
1079
+ signal,
1080
+ create: config.create,
1081
+ utils: config.utils
1082
+ });
1083
+ }
1084
+ function bindEvent(target, type, handler) {
1085
+ target.addEventListener(type, handler);
1086
+ return () => target.removeEventListener(type, handler);
1087
+ }
1088
+ function scrollToHash(hash, fallbackTop) {
1089
+ const el = hash && document.getElementById(hash);
1090
+ if (el) {
1091
+ el.scrollIntoView();
1092
+ } else if (fallbackTop) {
1093
+ window.scrollTo(0, 0);
1094
+ }
1095
+ }
1096
+
1097
+ function getPath(url) {
1098
+ const u = new URL(url);
1099
+ return u.pathname + u.search;
1100
+ }
1101
+ function StaticRouter(props) {
1102
+ let e;
1103
+ const obj = {
1104
+ value: props.url || (e = getRequestEvent()) && getPath(e.request.url) || ""
1105
+ };
1106
+ return createRouterComponent({
1107
+ signal: [() => obj, next => Object.assign(obj, next)]
1108
+ })(props);
1109
+ }
1110
+
1111
+ const LocationHeader = "Location";
1112
+ const PRELOAD_TIMEOUT = 5000;
1113
+ const CACHE_TIMEOUT = 180000;
1114
+ let cacheMap = new Map();
1115
+
1116
+ // cleanup forward/back cache
1117
+ if (!isServer) {
1118
+ setInterval(() => {
1119
+ const now = Date.now();
1120
+ for (let [k, v] of cacheMap.entries()) {
1121
+ if (!v[4].count && now - v[0] > CACHE_TIMEOUT) {
1122
+ cacheMap.delete(k);
1123
+ }
1124
+ }
1125
+ }, 300000);
1126
+ }
1127
+ function getCache() {
1128
+ if (!isServer) return cacheMap;
1129
+ const req = getRequestEvent();
1130
+ if (!req) throw new Error("Cannot find cache context");
1131
+ return (req.router || (req.router = {})).cache || (req.router.cache = new Map());
1132
+ }
1133
+
1134
+ /**
1135
+ * Revalidates the given cache entry/entries.
1136
+ */
1137
+ function revalidate(key, force = true) {
1138
+ const now = Date.now();
1139
+ // force the cache miss synchronously so a `refetch` in the same tick sees it —
1140
+ // startTransition defers its callback to a microtask (#497)
1141
+ force && cacheKeyOp(key, entry => entry[0] = 0);
1142
+ return startTransition(() => {
1143
+ cacheKeyOp(key, entry => entry[4][1](now)); // retrigger live signals
1144
+ });
1145
+ }
1146
+ function cacheKeyOp(key, fn) {
1147
+ key && !Array.isArray(key) && (key = [key]);
1148
+ for (let k of cacheMap.keys()) {
1149
+ if (key === undefined || matchKey(k, key)) fn(cacheMap.get(k));
1150
+ }
1151
+ }
1152
+ function query(fn, name) {
1153
+ // prioritize GET for server functions
1154
+ if (fn.GET) fn = fn.GET;
1155
+ const cachedFn = (...args) => {
1156
+ const cache = getCache();
1157
+ const intent = getIntent();
1158
+ const inPreloadFn = getInPreloadFn();
1159
+ const owner = getOwner();
1160
+ const navigate = owner ? useNavigate() : undefined;
1161
+ const now = Date.now();
1162
+ const key = name + hashKey(args);
1163
+ let cached = cache.get(key);
1164
+ let tracking;
1165
+ if (isServer) {
1166
+ const e = getRequestEvent();
1167
+ if (e) {
1168
+ const dataOnly = (e.router || (e.router = {})).dataOnly;
1169
+ if (dataOnly) {
1170
+ const data = e && (e.router.data || (e.router.data = {}));
1171
+ if (data && key in data) return data[key];
1172
+ if (Array.isArray(dataOnly) && !matchKey(key, dataOnly)) {
1173
+ data[key] = undefined;
1174
+ return Promise.resolve();
1175
+ }
1176
+ }
1177
+ }
1178
+ }
1179
+ if (getListener() && !isServer) {
1180
+ tracking = true;
1181
+ onCleanup(() => cached[4].count--);
1182
+ }
1183
+ if (cached && cached[0] && (isServer || intent === "native" || cached[4].count || Date.now() - cached[0] < PRELOAD_TIMEOUT)) {
1184
+ if (tracking) {
1185
+ cached[4].count++;
1186
+ cached[4][0](); // track
1187
+ }
1188
+ if (cached[3] === "preload" && intent !== "preload") {
1189
+ cached[0] = now;
1190
+ }
1191
+ let res = cached[1];
1192
+ if (intent !== "preload") {
1193
+ res = "then" in cached[1] ? cached[1].then(handleResponse(false), handleResponse(true)) : handleResponse(false)(cached[1]);
1194
+ !isServer && intent === "navigate" && startTransition(() => cached[4][1](cached[0])); // update version
1195
+ }
1196
+ inPreloadFn && "then" in res && res.catch(() => {});
1197
+ return res;
1198
+ }
1199
+ let res;
1200
+ if (!isServer && sharedConfig.has && sharedConfig.has(key)) {
1201
+ res = sharedConfig.load(key); // hydrating
1202
+ // @ts-ignore at least until we add a delete method to sharedConfig
1203
+ delete globalThis._$HY.r[key];
1204
+ } else res = fn(...args);
1205
+ if (cached) {
1206
+ cached[0] = now;
1207
+ cached[1] = res;
1208
+ cached[3] = intent;
1209
+ !isServer && intent === "navigate" && startTransition(() => cached[4][1](cached[0])); // update version
1210
+ } else {
1211
+ cache.set(key, cached = [now, res,, intent, createSignal(now)]);
1212
+ cached[4].count = 0;
1213
+ }
1214
+ if (tracking) {
1215
+ cached[4].count++;
1216
+ cached[4][0](); // track
1217
+ }
1218
+ if (isServer) {
1219
+ const e = getRequestEvent();
1220
+ if (e && e.router.dataOnly) return e.router.data[key] = res;
1221
+ }
1222
+ if (intent !== "preload") {
1223
+ res = "then" in res ? res.then(handleResponse(false), handleResponse(true)) : handleResponse(false)(res);
1224
+ }
1225
+ inPreloadFn && "then" in res && res.catch(() => {});
1226
+ // serialize on server
1227
+ if (isServer && sharedConfig.context && sharedConfig.context.async && !sharedConfig.context.noHydrate) {
1228
+ const e = getRequestEvent();
1229
+ (!e || !e.serverOnly) && sharedConfig.context.serialize(key, res);
1230
+ }
1231
+ return res;
1232
+ function handleResponse(error) {
1233
+ return async v => {
1234
+ if (v instanceof Response) {
1235
+ const e = getRequestEvent();
1236
+ if (e) {
1237
+ for (const [key, value] of v.headers) {
1238
+ if (key == "set-cookie") e.response.headers.append("set-cookie", value);else e.response.headers.set(key, value);
1239
+ }
1240
+ }
1241
+ const url = v.headers.get(LocationHeader);
1242
+ if (url !== null) {
1243
+ // client + server relative redirect
1244
+ if (navigate && url.startsWith("/")) startTransition(() => {
1245
+ navigate(url, {
1246
+ replace: true
1247
+ });
1248
+ });else if (!isServer) window.location.href = url;else if (e) e.response.status = 302;
1249
+ return;
1250
+ }
1251
+ if (v.customBody) v = await v.customBody();
1252
+ }
1253
+ if (error) throw v;
1254
+ cached[2] = v;
1255
+ return v;
1256
+ };
1257
+ }
1258
+ };
1259
+ cachedFn.keyFor = (...args) => name + hashKey(args);
1260
+ cachedFn.key = name;
1261
+ return cachedFn;
1262
+ }
1263
+ query.get = key => {
1264
+ const cached = getCache().get(key);
1265
+ return cached[2];
1266
+ };
1267
+ query.set = (key, value) => {
1268
+ const cache = getCache();
1269
+ const now = Date.now();
1270
+ let cached = cache.get(key);
1271
+ if (cached) {
1272
+ cached[0] = now;
1273
+ cached[1] = Promise.resolve(value);
1274
+ cached[2] = value;
1275
+ cached[3] = "preload";
1276
+ } else {
1277
+ cache.set(key, cached = [now, Promise.resolve(value), value, "preload", createSignal(now)]);
1278
+ cached[4].count = 0;
1279
+ }
1280
+ };
1281
+ query.delete = key => getCache().delete(key);
1282
+ query.clear = () => getCache().clear();
1283
+
1284
+ /** @deprecated use query instead */
1285
+ const cache = query;
1286
+ function matchKey(key, keys) {
1287
+ for (let k of keys) {
1288
+ if (k && key.startsWith(k)) return true;
1289
+ }
1290
+ return false;
1291
+ }
1292
+
1293
+ // Modified from the amazing Tanstack Query library (MIT)
1294
+ // https://github.com/TanStack/query/blob/main/packages/query-core/src/utils.ts#L168
1295
+ function hashKey(args) {
1296
+ return JSON.stringify(args, (_, val) => isPlainObject(val) ? Object.keys(val).sort().reduce((result, key) => {
1297
+ result[key] = val[key];
1298
+ return result;
1299
+ }, {}) : val);
1300
+ }
1301
+ function isPlainObject(obj) {
1302
+ let proto;
1303
+ return obj != null && typeof obj === "object" && (!(proto = Object.getPrototypeOf(obj)) || proto === Object.prototype);
1304
+ }
1305
+
1306
+ const actions = /* #__PURE__ */new Map();
1307
+ function useSubmissions(fn, filter) {
1308
+ const router = useRouter();
1309
+ const subs = createMemo(() => router.submissions[0]().filter(s => s.url === fn.base && (!filter || filter(s.input))));
1310
+ return new Proxy([], {
1311
+ get(_, property) {
1312
+ if (property === $TRACK) return subs();
1313
+ if (property === "pending") return subs().some(sub => !sub.result);
1314
+ return subs()[property];
1315
+ },
1316
+ has(_, property) {
1317
+ return property in subs();
1318
+ }
1319
+ });
1320
+ }
1321
+ function useSubmission(fn, filter) {
1322
+ const submissions = useSubmissions(fn, filter);
1323
+ return new Proxy({}, {
1324
+ get(_, property) {
1325
+ if (submissions.length === 0 && (property === "clear" || property === "retry")) return () => {};
1326
+ return submissions[submissions.length - 1]?.[property];
1327
+ }
1328
+ });
1329
+ }
1330
+ function useAction(action) {
1331
+ const r = useRouter();
1332
+ return (...args) => action.apply({
1333
+ r
1334
+ }, args);
1335
+ }
1336
+ function action(fn, options = {}) {
1337
+ function mutate(...variables) {
1338
+ const router = this.r;
1339
+ const form = this.f;
1340
+ const p = (router.singleFlight && fn.withOptions ? fn.withOptions({
1341
+ headers: {
1342
+ "X-Single-Flight": "true"
1343
+ }
1344
+ }) : fn)(...variables);
1345
+ const [result, setResult] = createSignal();
1346
+ let submission;
1347
+ function handler(error) {
1348
+ return async res => {
1349
+ const result = await handleResponse(res, error, router.navigatorFactory());
1350
+ let retry = null;
1351
+ o.onComplete?.({
1352
+ ...submission,
1353
+ result: result?.data,
1354
+ error: result?.error,
1355
+ pending: false,
1356
+ retry() {
1357
+ return retry = submission.retry();
1358
+ }
1359
+ });
1360
+ if (retry) return retry;
1361
+ if (!result) return submission.clear();
1362
+ setResult(result);
1363
+ if (result.error && !form) throw result.error;
1364
+ return result.data;
1365
+ };
1366
+ }
1367
+ router.submissions[1](s => [...s, submission = {
1368
+ input: variables,
1369
+ url,
1370
+ get result() {
1371
+ return result()?.data;
1372
+ },
1373
+ get error() {
1374
+ return result()?.error;
1375
+ },
1376
+ get pending() {
1377
+ return !result();
1378
+ },
1379
+ clear() {
1380
+ router.submissions[1](v => v.filter(i => i !== submission));
1381
+ },
1382
+ retry() {
1383
+ setResult(undefined);
1384
+ const p = fn(...variables);
1385
+ return p.then(handler(), handler(true));
1386
+ }
1387
+ }]);
1388
+ return p.then(handler(), handler(true));
1389
+ }
1390
+ const o = typeof options === "string" ? {
1391
+ name: options
1392
+ } : options;
1393
+ const name = o.name || (!isServer ? String(hashString(fn.toString())) : undefined);
1394
+ const url = fn.url || name && `https://action/${name}` || "";
1395
+ mutate.base = url;
1396
+ if (name) setFunctionName(mutate, name);
1397
+ return toAction(mutate, url);
1398
+ }
1399
+ function toAction(fn, url) {
1400
+ fn.toString = () => {
1401
+ if (!url) throw new Error("Client Actions need explicit names if server rendered");
1402
+ return url;
1403
+ };
1404
+ fn.with = function (...args) {
1405
+ const newFn = function (...passedArgs) {
1406
+ return fn.call(this, ...args, ...passedArgs);
1407
+ };
1408
+ newFn.base = fn.base;
1409
+ const uri = new URL(url, mockBase);
1410
+ uri.searchParams.set("args", hashKey(args));
1411
+ return toAction(newFn, (uri.origin === "https://action" ? uri.origin : "") + uri.pathname + uri.search);
1412
+ };
1413
+ fn.url = url;
1414
+ if (!isServer) {
1415
+ actions.set(url, fn);
1416
+ // Only remove the registration if it still belongs to this instance —
1417
+ // a re-created action (e.g. a new `.with()` binding after revalidation)
1418
+ // may have registered itself under the same URL since.
1419
+ getOwner() && onCleanup(() => actions.get(url) === fn && actions.delete(url));
1420
+ }
1421
+ return fn;
1422
+ }
1423
+ const hashString = s => s.split("").reduce((a, b) => (a << 5) - a + b.charCodeAt(0) | 0, 0);
1424
+ async function handleResponse(response, error, navigate) {
1425
+ let data;
1426
+ let custom;
1427
+ let keys;
1428
+ let flightKeys;
1429
+ if (response instanceof Response) {
1430
+ if (response.headers.has("X-Revalidate")) keys = response.headers.get("X-Revalidate").split(",");
1431
+ if (response.customBody) {
1432
+ data = custom = await response.customBody();
1433
+ if (response.headers.has("X-Single-Flight")) {
1434
+ data = data._$value;
1435
+ delete custom._$value;
1436
+ flightKeys = Object.keys(custom);
1437
+ }
1438
+ }
1439
+ if (response.headers.has("Location")) {
1440
+ const locationUrl = response.headers.get("Location") || "/";
1441
+ if (locationUrl.startsWith("http")) {
1442
+ window.location.href = locationUrl;
1443
+ } else {
1444
+ navigate(locationUrl);
1445
+ }
1446
+ }
1447
+ } else if (error) return {
1448
+ error: response
1449
+ };else data = response;
1450
+ // invalidate
1451
+ cacheKeyOp(keys, entry => entry[0] = 0);
1452
+ // set cache
1453
+ flightKeys && flightKeys.forEach(k => query.set(k, custom[k]));
1454
+ // trigger revalidation
1455
+ await revalidate(keys, false);
1456
+ return data != null ? {
1457
+ data
1458
+ } : undefined;
1459
+ }
1460
+
1461
+ function setupNativeEvents({
1462
+ preload = true,
1463
+ explicitLinks = false,
1464
+ actionBase = "/_server",
1465
+ transformUrl
1466
+ } = {}) {
1467
+ return router => {
1468
+ const basePath = router.base.path();
1469
+ const navigateFromRoute = router.navigatorFactory(router.base);
1470
+ let preloadTimeout;
1471
+ let lastElement;
1472
+ function isSvg(el) {
1473
+ return el.namespaceURI === "http://www.w3.org/2000/svg";
1474
+ }
1475
+ function handleAnchor(evt) {
1476
+ if (evt.defaultPrevented || evt.button !== 0 || evt.metaKey || evt.altKey || evt.ctrlKey || evt.shiftKey) return;
1477
+ const a = evt.composedPath().find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
1478
+ if (!a || explicitLinks && !a.hasAttribute("link")) return;
1479
+ const svg = isSvg(a);
1480
+ const href = svg ? a.href.baseVal : a.href;
1481
+ const target = svg ? a.target.baseVal : a.target;
1482
+ if (target || !href && !a.hasAttribute("state")) return;
1483
+ const rel = (a.getAttribute("rel") || "").split(/\s+/);
1484
+ if (a.hasAttribute("download") || rel && rel.includes("external")) return;
1485
+ const url = svg ? new URL(href, document.baseURI) : new URL(href);
1486
+ if (url.origin !== window.location.origin || basePath && url.pathname && !url.pathname.toLowerCase().startsWith(basePath.toLowerCase())) return;
1487
+ return [a, url];
1488
+ }
1489
+ function handleAnchorClick(evt) {
1490
+ const res = handleAnchor(evt);
1491
+ if (!res) return;
1492
+ const [a, url] = res;
1493
+ const to = router.parsePath(url.pathname + url.search + url.hash);
1494
+ const state = a.getAttribute("state");
1495
+ evt.preventDefault();
1496
+ navigateFromRoute(to, {
1497
+ resolve: false,
1498
+ replace: a.hasAttribute("replace"),
1499
+ scroll: !a.hasAttribute("noscroll"),
1500
+ state: state ? JSON.parse(state) : undefined
1501
+ });
1502
+ }
1503
+ function handleAnchorPreload(evt) {
1504
+ const res = handleAnchor(evt);
1505
+ if (!res) return;
1506
+ const [a, url] = res;
1507
+ transformUrl && (url.pathname = transformUrl(url.pathname));
1508
+ router.preloadRoute(url, a.getAttribute("preload") !== "false");
1509
+ }
1510
+ function handleAnchorMove(evt) {
1511
+ clearTimeout(preloadTimeout);
1512
+ const res = handleAnchor(evt);
1513
+ if (!res) return lastElement = null;
1514
+ const [a, url] = res;
1515
+ if (lastElement === a) return;
1516
+ transformUrl && (url.pathname = transformUrl(url.pathname));
1517
+ preloadTimeout = setTimeout(() => {
1518
+ router.preloadRoute(url, a.getAttribute("preload") !== "false");
1519
+ lastElement = a;
1520
+ }, 20);
1521
+ }
1522
+ function handleFormSubmit(evt) {
1523
+ if (evt.defaultPrevented) return;
1524
+ let actionRef = evt.submitter && evt.submitter.hasAttribute("formaction") ? evt.submitter.getAttribute("formaction") : evt.target.getAttribute("action");
1525
+ if (!actionRef) return;
1526
+ if (!actionRef.startsWith("https://action/")) {
1527
+ // normalize server actions
1528
+ const url = new URL(actionRef, mockBase);
1529
+ actionRef = router.parsePath(url.pathname + url.search);
1530
+ if (!actionRef.startsWith(actionBase)) return;
1531
+ }
1532
+ if (evt.target.method.toUpperCase() !== "POST") throw new Error("Only POST forms are supported for Actions");
1533
+ const handler = actions.get(actionRef);
1534
+ if (handler) {
1535
+ evt.preventDefault();
1536
+ const data = new FormData(evt.target, evt.submitter);
1537
+ handler.call({
1538
+ r: router,
1539
+ f: evt.target
1540
+ }, evt.target.enctype === "multipart/form-data" ? data : new URLSearchParams(data));
1541
+ }
1542
+ }
1543
+
1544
+ // ensure delegated event run first
1545
+ delegateEvents(["click", "submit"]);
1546
+ document.addEventListener("click", handleAnchorClick);
1547
+ if (preload) {
1548
+ document.addEventListener("mousemove", handleAnchorMove, {
1549
+ passive: true
1550
+ });
1551
+ document.addEventListener("focusin", handleAnchorPreload, {
1552
+ passive: true
1553
+ });
1554
+ document.addEventListener("touchstart", handleAnchorPreload, {
1555
+ passive: true
1556
+ });
1557
+ }
1558
+ document.addEventListener("submit", handleFormSubmit);
1559
+ onCleanup(() => {
1560
+ document.removeEventListener("click", handleAnchorClick);
1561
+ if (preload) {
1562
+ document.removeEventListener("mousemove", handleAnchorMove);
1563
+ document.removeEventListener("focusin", handleAnchorPreload);
1564
+ document.removeEventListener("touchstart", handleAnchorPreload);
1565
+ }
1566
+ document.removeEventListener("submit", handleFormSubmit);
1567
+ });
1568
+ };
1569
+ }
1570
+
1571
+ function Router(props) {
1572
+ if (isServer) return StaticRouter(props);
1573
+ const getSource = () => {
1574
+ const url = window.location.pathname + window.location.search;
1575
+ const state = window.history.state && window.history.state._depth && Object.keys(window.history.state).length === 1 ? undefined : window.history.state;
1576
+ return {
1577
+ value: url + window.location.hash,
1578
+ state
1579
+ };
1580
+ };
1581
+ const beforeLeave = createBeforeLeave();
1582
+ return createRouter({
1583
+ get: getSource,
1584
+ set({
1585
+ value,
1586
+ replace,
1587
+ scroll,
1588
+ state
1589
+ }) {
1590
+ if (replace) {
1591
+ window.history.replaceState(keepDepth(state), "", value);
1592
+ } else {
1593
+ window.history.pushState(state, "", value);
1594
+ }
1595
+ scrollToHash(decodeURIComponent(window.location.hash.slice(1)), scroll);
1596
+ saveCurrentDepth();
1597
+ },
1598
+ init: notify => bindEvent(window, "popstate", notifyIfNotBlocked(notify, delta => {
1599
+ if (delta) {
1600
+ return !beforeLeave.confirm(delta);
1601
+ } else {
1602
+ const s = getSource();
1603
+ return !beforeLeave.confirm(s.value, {
1604
+ state: s.state
1605
+ });
1606
+ }
1607
+ })),
1608
+ create: setupNativeEvents({
1609
+ preload: props.preload,
1610
+ explicitLinks: props.explicitLinks,
1611
+ actionBase: props.actionBase,
1612
+ transformUrl: props.transformUrl
1613
+ }),
1614
+ utils: {
1615
+ go: delta => window.history.go(delta),
1616
+ beforeLeave
1617
+ }
1618
+ })(props);
1619
+ }
1620
+
1621
+ function hashParser(str) {
1622
+ const to = str.replace(/^.*?#/, "");
1623
+ // Hash-only hrefs like `#foo` from plain anchors will come in as `/#foo` whereas a link to
1624
+ // `/foo` will be `/#/foo`. Check if the to starts with a `/` and if not append it as a hash
1625
+ // to the current path so we can handle these in-page anchors correctly.
1626
+ if (!to.startsWith("/")) {
1627
+ const [, path = "/"] = window.location.hash.split("#", 2);
1628
+ return `${path}#${to}`;
1629
+ }
1630
+ return to;
1631
+ }
1632
+ function HashRouter(props) {
1633
+ const getSource = () => window.location.hash.slice(1);
1634
+ const beforeLeave = createBeforeLeave();
1635
+ return createRouter({
1636
+ get: getSource,
1637
+ set({
1638
+ value,
1639
+ replace,
1640
+ scroll,
1641
+ state
1642
+ }) {
1643
+ if (replace) {
1644
+ window.history.replaceState(keepDepth(state), "", "#" + value);
1645
+ } else {
1646
+ window.history.pushState(state, "", "#" + value);
1647
+ }
1648
+ const hashIndex = value.indexOf("#");
1649
+ const hash = hashIndex >= 0 ? value.slice(hashIndex + 1) : "";
1650
+ scrollToHash(hash, scroll);
1651
+ saveCurrentDepth();
1652
+ },
1653
+ init: notify => bindEvent(window, "hashchange", notifyIfNotBlocked(notify, delta => !beforeLeave.confirm(delta && delta < 0 ? delta : getSource()))),
1654
+ create: setupNativeEvents({
1655
+ preload: props.preload,
1656
+ explicitLinks: props.explicitLinks,
1657
+ actionBase: props.actionBase
1658
+ }),
1659
+ utils: {
1660
+ go: delta => window.history.go(delta),
1661
+ renderPath: path => `#${path}`,
1662
+ parsePath: hashParser,
1663
+ beforeLeave
1664
+ }
1665
+ })(props);
1666
+ }
1667
+
1668
+ function createMemoryHistory() {
1669
+ const entries = ["/"];
1670
+ let index = 0;
1671
+ const listeners = [];
1672
+ const go = n => {
1673
+ // https://github.com/remix-run/react-router/blob/682810ca929d0e3c64a76f8d6e465196b7a2ac58/packages/router/history.ts#L245
1674
+ index = Math.max(0, Math.min(index + n, entries.length - 1));
1675
+ const value = entries[index];
1676
+ listeners.forEach(listener => listener(value));
1677
+ };
1678
+ return {
1679
+ get: () => entries[index],
1680
+ set: ({
1681
+ value,
1682
+ scroll,
1683
+ replace
1684
+ }) => {
1685
+ if (replace) {
1686
+ entries[index] = value;
1687
+ } else {
1688
+ entries.splice(index + 1, entries.length - index, value);
1689
+ index++;
1690
+ }
1691
+ listeners.forEach(listener => listener(value));
1692
+ setTimeout(() => {
1693
+ if (scroll) {
1694
+ scrollToHash(value.split("#")[1] || "", true);
1695
+ }
1696
+ }, 0);
1697
+ },
1698
+ back: () => {
1699
+ go(-1);
1700
+ },
1701
+ forward: () => {
1702
+ go(1);
1703
+ },
1704
+ go,
1705
+ listen: listener => {
1706
+ listeners.push(listener);
1707
+ return () => {
1708
+ const index = listeners.indexOf(listener);
1709
+ listeners.splice(index, 1);
1710
+ };
1711
+ }
1712
+ };
1713
+ }
1714
+ function MemoryRouter(props) {
1715
+ const memoryHistory = props.history || createMemoryHistory();
1716
+ return createRouter({
1717
+ get: memoryHistory.get,
1718
+ set: memoryHistory.set,
1719
+ init: memoryHistory.listen,
1720
+ create: setupNativeEvents({
1721
+ preload: props.preload,
1722
+ explicitLinks: props.explicitLinks,
1723
+ actionBase: props.actionBase
1724
+ }),
1725
+ utils: {
1726
+ go: memoryHistory.go
1727
+ }
1728
+ })(props);
1729
+ }
1730
+
1731
+ var _tmpl$ = /*#__PURE__*/template(`<a>`);
1732
+ function A(props) {
1733
+ props = mergeProps({
1734
+ inactiveClass: "inactive",
1735
+ activeClass: "active"
1736
+ }, props);
1737
+ const [, rest] = splitProps(props, ["href", "state", "class", "activeClass", "inactiveClass", "end"]);
1738
+ const to = useResolvedPath(() => props.href);
1739
+ const href = useHref(to);
1740
+ const location = useLocation();
1741
+ const isActive = createMemo(() => {
1742
+ const to_ = to();
1743
+ if (to_ === undefined) return [false, false];
1744
+ // trailing slashes are ignored so `/route` and `/route/` share active state
1745
+ const path = normalizePath(to_.split(/[?#]/, 1)[0]).toLowerCase().replace(/\/$/, "");
1746
+ const loc = decodeURI(normalizePath(location.pathname).toLowerCase().replace(/\/$/, ""));
1747
+ return [props.end ? path === loc : loc.startsWith(path + "/") || loc === path, path === loc];
1748
+ });
1749
+ return (() => {
1750
+ var _el$ = _tmpl$();
1751
+ spread(_el$, mergeProps$1(rest, {
1752
+ get href() {
1753
+ return href() || props.href;
1754
+ },
1755
+ get state() {
1756
+ return JSON.stringify(props.state);
1757
+ },
1758
+ get classList() {
1759
+ return {
1760
+ ...(props.class && {
1761
+ [props.class]: true
1762
+ }),
1763
+ [props.inactiveClass]: !isActive()[0],
1764
+ [props.activeClass]: isActive()[0],
1765
+ ...rest.classList
1766
+ };
1767
+ },
1768
+ "link": "",
1769
+ get ["aria-current"]() {
1770
+ return isActive()[1] ? "page" : undefined;
1771
+ }
1772
+ }), false, false);
1773
+ return _el$;
1774
+ })();
1775
+ }
1776
+ function Navigate(props) {
1777
+ const navigate = useNavigate();
1778
+ const location = useLocation();
1779
+ const {
1780
+ href,
1781
+ state
1782
+ } = props;
1783
+ const path = typeof href === "function" ? href({
1784
+ navigate,
1785
+ location
1786
+ }) : href;
1787
+ navigate(path, {
1788
+ replace: true,
1789
+ state
1790
+ });
1791
+ return null;
1792
+ }
1793
+
1794
+ /**
1795
+ * This is mock of the eventual Solid 2.0 primitive. It is not fully featured.
1796
+ */
1797
+
1798
+ /**
1799
+ * As `createAsync` and `createAsyncStore` are wrappers for `createResource`,
1800
+ * this type allows to support `latest` field for these primitives.
1801
+ * It will be removed in the future.
1802
+ */
1803
+
1804
+ function createAsync(fn, options) {
1805
+ let resource;
1806
+ let prev = () => !resource || resource.state === "unresolved" ? undefined : resource.latest;
1807
+ [resource] = createResource(() => subFetch(fn, catchError(() => untrack(prev), () => undefined)), v => v, options);
1808
+ const resultAccessor = () => resource();
1809
+ if (options?.name) setFunctionName(resultAccessor, options.name);
1810
+ Object.defineProperty(resultAccessor, "latest", {
1811
+ get() {
1812
+ return resource.latest;
1813
+ }
1814
+ });
1815
+ return resultAccessor;
1816
+ }
1817
+ function createAsyncStore(fn, options = {}) {
1818
+ let resource;
1819
+ let prev = () => !resource || resource.state === "unresolved" ? undefined : unwrap(resource.latest);
1820
+ [resource] = createResource(() => subFetch(fn, catchError(() => untrack(prev), () => undefined)), v => v, {
1821
+ ...options,
1822
+ storage: init => createDeepSignal(init, options.reconcile)
1823
+ });
1824
+ const resultAccessor = () => resource();
1825
+ Object.defineProperty(resultAccessor, "latest", {
1826
+ get() {
1827
+ return resource.latest;
1828
+ }
1829
+ });
1830
+ return resultAccessor;
1831
+ }
1832
+ function createDeepSignal(value, options) {
1833
+ const [store, setStore] = createStore({
1834
+ value: structuredClone(value)
1835
+ });
1836
+ return [() => store.value, v => {
1837
+ typeof v === "function" && (v = v());
1838
+ setStore("value", reconcile(structuredClone(v), options));
1839
+ return store.value;
1840
+ }];
1841
+ }
1842
+
1843
+ // mock promise while hydrating to prevent fetching
1844
+ class MockPromise {
1845
+ static all() {
1846
+ return new MockPromise();
1847
+ }
1848
+ static allSettled() {
1849
+ return new MockPromise();
1850
+ }
1851
+ static any() {
1852
+ return new MockPromise();
1853
+ }
1854
+ static race() {
1855
+ return new MockPromise();
1856
+ }
1857
+ static reject() {
1858
+ return new MockPromise();
1859
+ }
1860
+ static resolve() {
1861
+ return new MockPromise();
1862
+ }
1863
+ catch() {
1864
+ return new MockPromise();
1865
+ }
1866
+ then() {
1867
+ return new MockPromise();
1868
+ }
1869
+ finally() {
1870
+ return new MockPromise();
1871
+ }
1872
+ }
1873
+ function subFetch(fn, prev) {
1874
+ if (isServer || !sharedConfig.context) return fn(prev);
1875
+ const ogFetch = fetch;
1876
+ const ogPromise = Promise;
1877
+ try {
1878
+ window.fetch = () => new MockPromise();
1879
+ Promise = MockPromise;
1880
+ return fn(prev);
1881
+ } finally {
1882
+ window.fetch = ogFetch;
1883
+ Promise = ogPromise;
1884
+ }
1885
+ }
1886
+
1887
+ function redirect(url, init = 302) {
1888
+ let responseInit;
1889
+ let revalidate;
1890
+ if (typeof init === "number") {
1891
+ responseInit = {
1892
+ status: init
1893
+ };
1894
+ } else {
1895
+ ({
1896
+ revalidate,
1897
+ ...responseInit
1898
+ } = init);
1899
+ if (typeof responseInit.status === "undefined") {
1900
+ responseInit.status = 302;
1901
+ }
1902
+ }
1903
+ const headers = new Headers(responseInit.headers);
1904
+ headers.set("Location", url);
1905
+ revalidate !== undefined && headers.set("X-Revalidate", revalidate.toString());
1906
+ const response = new Response(null, {
1907
+ ...responseInit,
1908
+ headers: headers
1909
+ });
1910
+ return response;
1911
+ }
1912
+ function reload(init = {}) {
1913
+ const {
1914
+ revalidate,
1915
+ ...responseInit
1916
+ } = init;
1917
+ const headers = new Headers(responseInit.headers);
1918
+ revalidate !== undefined && headers.set("X-Revalidate", revalidate.toString());
1919
+ return new Response(null, {
1920
+ ...responseInit,
1921
+ headers
1922
+ });
1923
+ }
1924
+ function json(data, init = {}) {
1925
+ const {
1926
+ revalidate,
1927
+ ...responseInit
1928
+ } = init;
1929
+ const headers = new Headers(responseInit.headers);
1930
+ revalidate !== undefined && headers.set("X-Revalidate", revalidate.toString());
1931
+ headers.set("Content-Type", "application/json");
1932
+ const response = new Response(JSON.stringify(data), {
1933
+ ...responseInit,
1934
+ headers
1935
+ });
1936
+ response.customBody = () => data;
1937
+ return response;
1938
+ }
1939
+
1940
+ function viewTransitionSource(element, options) {
1941
+ function select() {
1942
+ const source = options();
1943
+ setActiveNames(typeof source === "string" ? [source] : [source.name, ...(source.include ?? [])]);
1944
+ }
1945
+ element.addEventListener("click", select);
1946
+ createEffect(() => {
1947
+ const source = options();
1948
+ const name = getName(source);
1949
+ registerAnimation(name, getAnimation(source));
1950
+ element.style.setProperty("view-transition-name", activeNames().includes(name) ? name : "none");
1951
+ });
1952
+ onCleanup(() => {
1953
+ element.removeEventListener("click", select);
1954
+ element.style.removeProperty("view-transition-name");
1955
+ });
1956
+ }
1957
+ function viewTransitionTarget(element, options) {
1958
+ createEffect(() => {
1959
+ const target = options();
1960
+ const name = getName(target);
1961
+ registerAnimation(name, getAnimation(target));
1962
+ element.style.setProperty("view-transition-name", name);
1963
+ });
1964
+ onCleanup(() => element.style.removeProperty("view-transition-name"));
1965
+ }
1966
+ const [activeNames, setActiveNames] = createSignal([]);
1967
+ const animationNames = new Set();
1968
+ let style;
1969
+ function getName(options) {
1970
+ return typeof options === "string" ? options : options.name;
1971
+ }
1972
+ function getAnimation(options) {
1973
+ return typeof options === "string" ? undefined : options.animation;
1974
+ }
1975
+ function registerAnimation(name, animation) {
1976
+ if (!animation) return;
1977
+ animationNames.add(name);
1978
+ updateAnimationStyles();
1979
+ }
1980
+ function updateAnimationStyles() {
1981
+ if (typeof document === "undefined" || animationNames.size === 0) return;
1982
+ style ??= document.createElement("style");
1983
+ style.id = "solid-view-transition-animations";
1984
+ if (!style.parentNode) document.head.append(style);
1985
+ const animations = Array.from(animationNames, name => {
1986
+ const transitionName = CSS.escape(name);
1987
+ return `
1988
+ ::view-transition-group(${transitionName}) {
1989
+ animation-duration: var(--solid-vt-exponential-duration);
1990
+ animation-timing-function: var(--solid-vt-exponential-ease);
1991
+ }
1992
+
1993
+ ::view-transition-old(${transitionName}) {
1994
+ animation: solid-vt-exponential-fade-out var(--solid-vt-exponential-duration) var(--solid-vt-exponential-ease) both;
1995
+ }
1996
+
1997
+ ::view-transition-new(${transitionName}) {
1998
+ animation: solid-vt-exponential-fade-in var(--solid-vt-exponential-duration) var(--solid-vt-exponential-ease) both;
1999
+ }`;
2000
+ }).join("\n");
2001
+ style.textContent = `
2002
+ :root {
2003
+ --solid-vt-exponential-duration: 320ms;
2004
+ --solid-vt-exponential-ease: cubic-bezier(0.16, 1, 0.3, 1);
2005
+ }
2006
+
2007
+ @supports (animation-timing-function: linear(0, 1)) {
2008
+ :root {
2009
+ --solid-vt-exponential-ease: linear(
2010
+ 0,
2011
+ 0.336 10%,
2012
+ 0.561 20%,
2013
+ 0.711 30%,
2014
+ 0.813 40%,
2015
+ 0.881 50%,
2016
+ 0.927 60%,
2017
+ 0.956 70%,
2018
+ 0.976 80%,
2019
+ 0.991 90%,
2020
+ 1
2021
+ );
2022
+ }
2023
+ }
2024
+
2025
+ ::view-transition-group(root),
2026
+ ::view-transition-old(root),
2027
+ ::view-transition-new(root) {
2028
+ animation: none;
2029
+ }
2030
+
2031
+ @keyframes solid-vt-exponential-fade-out {
2032
+ from {
2033
+ opacity: 1;
2034
+ }
2035
+
2036
+ to {
2037
+ opacity: 0;
2038
+ }
2039
+ }
2040
+
2041
+ @keyframes solid-vt-exponential-fade-in {
2042
+ from {
2043
+ opacity: 0;
2044
+ }
2045
+
2046
+ to {
2047
+ opacity: 1;
2048
+ }
2049
+ }
2050
+
2051
+ ${animations}
2052
+ `;
2053
+ }
2054
+
2055
+ export { A, HashRouter, MemoryRouter, Navigate, Route, Router, RouterContextObj as RouterContext, StaticRouter, mergeSearchString as _mergeSearchString, action, cache, createAsync, createAsyncStore, createBeforeLeave, createMemoryHistory, createRouter, json, keepDepth, notifyIfNotBlocked, query, redirect, reload, revalidate, saveCurrentDepth, useAction, useBeforeLeave, useCurrentMatches, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, usePreloadRoute, useResolvedPath, useSearchParams, useSubmission, useSubmissions, viewTransitionSource, viewTransitionTarget };