@sveltejs/kit 3.0.0-next.6 → 3.0.0-next.8
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/package.json +8 -3
- package/src/core/adapt/builder.js +11 -39
- package/src/core/config/index.js +76 -71
- package/src/core/config/options.js +280 -285
- package/src/core/config/types.d.ts +1 -1
- package/src/core/env.js +86 -1
- package/src/core/generate_manifest/index.js +12 -15
- package/src/core/sync/create_manifest_data/index.js +7 -45
- package/src/core/sync/sync.js +0 -2
- package/src/core/sync/write_client_manifest.js +7 -21
- package/src/core/sync/write_non_ambient.js +12 -9
- package/src/core/sync/write_server.js +0 -4
- package/src/core/sync/write_types/index.js +28 -24
- package/src/core/utils.js +2 -2
- package/src/exports/index.js +3 -3
- package/src/exports/internal/client.js +5 -0
- package/src/exports/internal/index.js +1 -91
- package/src/exports/internal/{event.js → server/event.js} +1 -2
- package/src/exports/internal/server/index.js +33 -0
- package/src/exports/internal/shared.js +89 -0
- package/src/exports/node/index.js +5 -9
- package/src/exports/params.js +63 -0
- package/src/exports/public.d.ts +103 -46
- package/src/exports/url.js +84 -0
- package/src/exports/vite/dev/index.js +31 -20
- package/src/exports/vite/index.js +280 -199
- package/src/exports/vite/preview/index.js +14 -15
- package/src/exports/vite/utils.js +8 -10
- package/src/runtime/app/env/internal.js +4 -4
- package/src/runtime/app/forms.js +2 -2
- package/src/runtime/app/paths/client.js +3 -7
- package/src/runtime/app/paths/internal/client.js +4 -2
- package/src/runtime/app/paths/internal/server.js +2 -23
- package/src/runtime/app/paths/server.js +3 -3
- package/src/runtime/app/server/remote/query.js +6 -12
- package/src/runtime/app/state/client.js +1 -2
- package/src/runtime/app/stores.js +13 -76
- package/src/runtime/client/bundle.js +1 -1
- package/src/runtime/client/client-entry.js +3 -0
- package/src/runtime/client/client.js +230 -238
- package/src/runtime/client/entry.js +24 -3
- package/src/runtime/client/payload.js +17 -0
- package/src/runtime/client/remote-functions/cache.svelte.js +3 -1
- package/src/runtime/client/remote-functions/form.svelte.js +11 -30
- package/src/runtime/client/remote-functions/prerender.svelte.js +10 -3
- package/src/runtime/client/remote-functions/query/instance.svelte.js +18 -9
- package/src/runtime/client/remote-functions/query-live/instance.svelte.js +16 -6
- package/src/runtime/client/remote-functions/shared.svelte.js +1 -2
- package/src/runtime/client/state.svelte.js +66 -49
- package/src/runtime/client/types.d.ts +3 -7
- package/src/runtime/client/utils.js +0 -96
- package/src/runtime/components/root.svelte +66 -0
- package/src/runtime/form-utils.js +16 -6
- package/src/runtime/server/cookie.js +17 -7
- package/src/runtime/server/index.js +1 -1
- package/src/runtime/server/page/index.js +7 -14
- package/src/runtime/server/page/load_data.js +1 -1
- package/src/runtime/server/page/render.js +72 -88
- package/src/runtime/server/page/server_routing.js +13 -9
- package/src/runtime/server/remote.js +23 -13
- package/src/runtime/server/respond.js +11 -8
- package/src/runtime/server/utils.js +28 -5
- package/src/runtime/telemetry/otel.js +1 -1
- package/src/runtime/types.d.ts +8 -0
- package/src/types/ambient.d.ts +5 -1
- package/src/types/global-private.d.ts +11 -18
- package/src/types/internal.d.ts +25 -30
- package/src/utils/error.js +1 -1
- package/src/utils/import.js +6 -1
- package/src/utils/mime.js +9 -0
- package/src/utils/params.js +66 -0
- package/src/utils/routing.js +90 -44
- package/src/utils/streaming.js +14 -4
- package/src/utils/url.js +0 -79
- package/src/version.js +1 -1
- package/types/index.d.ts +127 -125
- package/types/index.d.ts.map +12 -8
- package/src/core/sync/write_root.js +0 -148
- package/src/exports/internal/server.js +0 -22
- /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
/** @import { RemoteFunctionDataNode, ServerNodesResponse, ServerRedirectNode } from 'types' */
|
|
2
2
|
/** @import { NavigationIntent } from './types.js' */
|
|
3
|
+
/** @import { RenderNode } from '../types.js' */
|
|
3
4
|
/** @import { CacheEntry } from './remote-functions/cache.svelte.js' */
|
|
4
5
|
/** @import { Query } from './remote-functions/query/instance.svelte.js' */
|
|
5
6
|
/** @import { LiveQuery } from './remote-functions/query-live/instance.svelte.js' */
|
|
6
7
|
import { BROWSER, DEV } from 'esm-env';
|
|
7
8
|
import * as svelte from 'svelte';
|
|
8
9
|
import { HttpError, Redirect, SvelteKitError } from '@sveltejs/kit/internal';
|
|
9
|
-
|
|
10
|
-
// Svelte 4 and under don't have `untrack`, so we have to fallback if `untrack` is not exported
|
|
11
|
-
const untrack = svelte.untrack ?? ((value) => value());
|
|
12
|
-
import {
|
|
13
|
-
decode_params,
|
|
14
|
-
decode_pathname,
|
|
15
|
-
strip_hash,
|
|
16
|
-
make_trackable,
|
|
17
|
-
normalize_path
|
|
18
|
-
} from '../../utils/url.js';
|
|
10
|
+
import { decode_pathname, strip_hash, make_trackable, normalize_path } from '../../utils/url.js';
|
|
19
11
|
import { dev_fetch, initial_fetch, lock_fetch, subsequent_fetch, unlock_fetch } from './fetcher.js';
|
|
20
12
|
import { parse, parse_server_route } from './parse.js';
|
|
21
13
|
import * as storage from './session-storage.js';
|
|
@@ -27,8 +19,6 @@ import {
|
|
|
27
19
|
is_external_url,
|
|
28
20
|
origin,
|
|
29
21
|
scroll_state,
|
|
30
|
-
notifiable_store,
|
|
31
|
-
create_updated_store,
|
|
32
22
|
load_css
|
|
33
23
|
} from './utils.js';
|
|
34
24
|
import { base } from '$app/paths/internal/client';
|
|
@@ -44,7 +34,6 @@ import {
|
|
|
44
34
|
} from './constants.js';
|
|
45
35
|
import { validate_page_exports } from '../../utils/exports.js';
|
|
46
36
|
import { noop } from '../../utils/functions.js';
|
|
47
|
-
import { compact } from '../../utils/array.js';
|
|
48
37
|
import {
|
|
49
38
|
INVALIDATED_PARAM,
|
|
50
39
|
TRAILING_SLASH_PARAM,
|
|
@@ -53,11 +42,15 @@ import {
|
|
|
53
42
|
validate_load_response
|
|
54
43
|
} from '../shared.js';
|
|
55
44
|
import { get_message, get_status } from '../../utils/error.js';
|
|
56
|
-
import {
|
|
57
|
-
import {
|
|
45
|
+
import { page, update, navigating, updated } from './state.svelte.js';
|
|
46
|
+
import { payload } from './payload.js';
|
|
58
47
|
import { add_data_suffix, add_resolution_suffix } from '../pathname.js';
|
|
59
48
|
import { noop_span } from '../telemetry/noop.js';
|
|
60
49
|
import { read_ndjson } from './ndjson.js';
|
|
50
|
+
import RootModern from '../components/root.svelte';
|
|
51
|
+
import { asClassComponent } from 'svelte/legacy';
|
|
52
|
+
|
|
53
|
+
const Root = asClassComponent(RootModern);
|
|
61
54
|
|
|
62
55
|
export { load_css };
|
|
63
56
|
const ICON_REL_ATTRIBUTES = new Set(['icon', 'shortcut icon', 'apple-touch-icon']);
|
|
@@ -72,6 +65,17 @@ let errored = false;
|
|
|
72
65
|
*/
|
|
73
66
|
let rendering_error = null;
|
|
74
67
|
|
|
68
|
+
/**
|
|
69
|
+
* `reset` functions for `<svelte:boundary>`s in the generated root that have
|
|
70
|
+
* failed. A failed boundary stays failed until `reset()` is called — prop
|
|
71
|
+
* updates alone don't re-render its content — so without resetting, a client
|
|
72
|
+
* navigation away from a render error would leave the stale `+error.svelte`
|
|
73
|
+
* mounted. The boundary's `onerror` populates this array; `navigate` drains it
|
|
74
|
+
* after applying the new props. See sveltejs/kit#15694.
|
|
75
|
+
* @type {Array<(() => void) | undefined>}
|
|
76
|
+
*/
|
|
77
|
+
const resetters = [];
|
|
78
|
+
|
|
75
79
|
// We track the scroll position associated with each history entry in sessionStorage,
|
|
76
80
|
// rather than on history.state itself, because when navigation is driven by
|
|
77
81
|
// popstate it's too late to update the scroll position associated with the
|
|
@@ -88,6 +92,11 @@ const scroll_positions = storage.get(SCROLL_KEY) ?? {};
|
|
|
88
92
|
*/
|
|
89
93
|
const snapshots = storage.get(SNAPSHOT_KEY) ?? {};
|
|
90
94
|
|
|
95
|
+
/**
|
|
96
|
+
* @deprecated this is a temporary measure to avoid a regression, replace with nested `RenderNode` classes
|
|
97
|
+
*/
|
|
98
|
+
let current_tree = /** @type {RenderNode} */ ({});
|
|
99
|
+
|
|
91
100
|
if (DEV && BROWSER) {
|
|
92
101
|
let warned = false;
|
|
93
102
|
|
|
@@ -127,15 +136,6 @@ if (DEV && BROWSER) {
|
|
|
127
136
|
};
|
|
128
137
|
}
|
|
129
138
|
|
|
130
|
-
export const stores = {
|
|
131
|
-
url: /* @__PURE__ */ notifiable_store({}),
|
|
132
|
-
page: /* @__PURE__ */ notifiable_store({}),
|
|
133
|
-
navigating: /* @__PURE__ */ writable(
|
|
134
|
-
/** @type {import('@sveltejs/kit').Navigation | null} */ (null)
|
|
135
|
-
),
|
|
136
|
-
updated: /* @__PURE__ */ create_updated_store()
|
|
137
|
-
};
|
|
138
|
-
|
|
139
139
|
/** @param {number} index */
|
|
140
140
|
function update_scroll_positions(index) {
|
|
141
141
|
scroll_positions[index] = scroll_state();
|
|
@@ -344,8 +344,8 @@ export async function start(_app, _target, hydrate) {
|
|
|
344
344
|
);
|
|
345
345
|
}
|
|
346
346
|
|
|
347
|
-
if (
|
|
348
|
-
const { q = {}, p = {}, l = {}, f = {} } =
|
|
347
|
+
if (payload.data) {
|
|
348
|
+
const { q = {}, p = {}, l = {}, f = {} } = payload.data;
|
|
349
349
|
|
|
350
350
|
// store the whole nodes — error records seed the corresponding
|
|
351
351
|
// resources in a failed state when they are created during hydration
|
|
@@ -424,7 +424,7 @@ export async function start(_app, _target, hydrate) {
|
|
|
424
424
|
_start_router();
|
|
425
425
|
}
|
|
426
426
|
|
|
427
|
-
async function _invalidate(
|
|
427
|
+
async function _invalidate(reset_page_state = true) {
|
|
428
428
|
// Accept all invalidations as they come, don't swallow any while another invalidation
|
|
429
429
|
// is running because subsequent invalidations may make earlier ones outdated,
|
|
430
430
|
// but batch multiple synchronous invalidations.
|
|
@@ -463,39 +463,36 @@ async function _invalidate(include_load_functions = true, reset_page_state = tru
|
|
|
463
463
|
}
|
|
464
464
|
}
|
|
465
465
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
}
|
|
466
|
+
const prev_state = page.state;
|
|
467
|
+
const navigation_result = intent && (await load_route(intent));
|
|
468
|
+
if (!navigation_result || token !== invalidation_token || nav_token !== navigation_token) {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
472
471
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
472
|
+
if (navigation_result.type === 'redirect') {
|
|
473
|
+
return _goto(
|
|
474
|
+
new URL(navigation_result.location, current.url).href,
|
|
475
|
+
{ replaceState: true },
|
|
476
|
+
1,
|
|
477
|
+
token
|
|
478
|
+
);
|
|
479
|
+
}
|
|
481
480
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
481
|
+
// A navigation started before the invalidation and ended before it finished. The invalidation did not redirect,
|
|
482
|
+
// hence it likely contains outdated data now, so we ignore it.
|
|
483
|
+
if (navigating && !is_navigating) {
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
487
486
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
}
|
|
492
|
-
update(navigation_result.props.page);
|
|
493
|
-
current = { ...navigation_result.state, nav: current.nav };
|
|
494
|
-
reset_invalidation();
|
|
495
|
-
root.$set(navigation_result.props);
|
|
496
|
-
} else {
|
|
497
|
-
reset_invalidation();
|
|
487
|
+
// Preserve `page.state` when invalidating without resetting it (e.g. `refresh`/`refreshAll`)
|
|
488
|
+
if (!reset_page_state) {
|
|
489
|
+
navigation_result.props.page.state = prev_state;
|
|
498
490
|
}
|
|
491
|
+
update(navigation_result.props.page);
|
|
492
|
+
current_tree = navigation_result.props.tree;
|
|
493
|
+
current = { ...navigation_result.state, nav: current.nav };
|
|
494
|
+
reset_invalidation();
|
|
495
|
+
root.$set(navigation_result.props);
|
|
499
496
|
|
|
500
497
|
// only wait for promises that are connected to queries that still exist
|
|
501
498
|
/** @type {Promise<any>[]} */
|
|
@@ -548,7 +545,7 @@ function persist_state() {
|
|
|
548
545
|
|
|
549
546
|
/**
|
|
550
547
|
* @param {string | URL} url
|
|
551
|
-
* @param {{ replaceState?: boolean; noScroll?: boolean; keepFocus?: boolean;
|
|
548
|
+
* @param {{ replaceState?: boolean; noScroll?: boolean; keepFocus?: boolean; refreshAll?: boolean; invalidate?: Array<string | URL | ((url: URL) => boolean)>; state?: Record<string, any> }} options
|
|
552
549
|
* @param {number} redirect_count
|
|
553
550
|
* @param {{}} [nav_token]
|
|
554
551
|
* @param {NavigationIntent | undefined} [intent] navigation intent, when already known by the caller (avoids recomputing it)
|
|
@@ -560,9 +557,9 @@ export async function _goto(url, options, redirect_count, nav_token, intent) {
|
|
|
560
557
|
/** @type {Set<string>} */
|
|
561
558
|
let live_query_keys;
|
|
562
559
|
|
|
563
|
-
// Clear preload cache when
|
|
560
|
+
// Clear preload cache when refreshAll is true to ensure fresh data
|
|
564
561
|
// after form submissions or explicit invalidations
|
|
565
|
-
if (options.
|
|
562
|
+
if (options.refreshAll) {
|
|
566
563
|
discard_load_cache();
|
|
567
564
|
}
|
|
568
565
|
|
|
@@ -577,7 +574,7 @@ export async function _goto(url, options, redirect_count, nav_token, intent) {
|
|
|
577
574
|
nav_token,
|
|
578
575
|
intent,
|
|
579
576
|
accept: () => {
|
|
580
|
-
if (options.
|
|
577
|
+
if (options.refreshAll) {
|
|
581
578
|
force_invalidation = true;
|
|
582
579
|
query_keys = new Set();
|
|
583
580
|
for (const [id, entries] of query_map) {
|
|
@@ -603,7 +600,7 @@ export async function _goto(url, options, redirect_count, nav_token, intent) {
|
|
|
603
600
|
}
|
|
604
601
|
});
|
|
605
602
|
|
|
606
|
-
if (options.
|
|
603
|
+
if (options.refreshAll) {
|
|
607
604
|
// TODO the ticks shouldn't be necessary, something inside Svelte itself is buggy
|
|
608
605
|
// when a query in a layout that still exists after page change is refreshed earlier than this
|
|
609
606
|
void svelte
|
|
@@ -642,17 +639,14 @@ async function _preload_data(intent) {
|
|
|
642
639
|
load_cache = {
|
|
643
640
|
id: intent.id,
|
|
644
641
|
token: preload,
|
|
645
|
-
promise: load_route({ ...intent, preload }).
|
|
642
|
+
promise: load_route({ ...intent, preload }).finally(() => {
|
|
646
643
|
preload_tokens.delete(preload);
|
|
647
|
-
if (result.type === 'loaded' && result.state.error) {
|
|
648
|
-
// Don't cache errors, because they might be transient
|
|
649
|
-
discard_load_cache();
|
|
650
|
-
}
|
|
651
|
-
return result;
|
|
652
644
|
}),
|
|
653
645
|
fork: null
|
|
654
646
|
};
|
|
655
647
|
|
|
648
|
+
load_cache.promise.catch(discard_load_cache);
|
|
649
|
+
|
|
656
650
|
if (__SVELTEKIT_FORK_PRELOADS__ && svelte.fork) {
|
|
657
651
|
const lc = load_cache;
|
|
658
652
|
|
|
@@ -664,6 +658,7 @@ async function _preload_data(intent) {
|
|
|
664
658
|
return svelte.fork(() => {
|
|
665
659
|
root.$set(result.props);
|
|
666
660
|
update(result.props.page);
|
|
661
|
+
current_tree = result.props.tree;
|
|
667
662
|
});
|
|
668
663
|
} catch {
|
|
669
664
|
// if it errors, it's because the experimental flag isn't enabled in Svelte
|
|
@@ -722,23 +717,22 @@ async function initialize(result, target, hydrate) {
|
|
|
722
717
|
}
|
|
723
718
|
|
|
724
719
|
update(/** @type {import('@sveltejs/kit').Page} */ (result.props.page));
|
|
720
|
+
current_tree = result.props.tree;
|
|
725
721
|
|
|
726
|
-
|
|
722
|
+
// TODO: use mount()
|
|
723
|
+
root = new Root({
|
|
727
724
|
target,
|
|
728
|
-
props: { ...result.props,
|
|
725
|
+
props: { ...result.props, components, resetters },
|
|
729
726
|
hydrate,
|
|
730
|
-
//
|
|
727
|
+
// Svelte 5 specific: asynchronously instantiate the component, i.e. don't call flushSync
|
|
731
728
|
sync: false,
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
return error;
|
|
740
|
-
}
|
|
741
|
-
: undefined
|
|
729
|
+
transformError: /** @param {unknown} e */ async (e) => {
|
|
730
|
+
const error = await handle_error(e, current.nav);
|
|
731
|
+
rendering_error = { error, status: error.status };
|
|
732
|
+
page.error = error;
|
|
733
|
+
page.status = rendering_error.status;
|
|
734
|
+
return error;
|
|
735
|
+
}
|
|
742
736
|
});
|
|
743
737
|
|
|
744
738
|
// Wait for a microtask in case svelte experimental async is enabled,
|
|
@@ -817,35 +811,12 @@ async function get_navigation_result_from_branch({
|
|
|
817
811
|
route
|
|
818
812
|
},
|
|
819
813
|
props: {
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
page: clone_page(page)
|
|
814
|
+
page,
|
|
815
|
+
tree: /** @type {RenderNode} */ ({})
|
|
823
816
|
}
|
|
824
817
|
};
|
|
825
818
|
|
|
826
|
-
if (
|
|
827
|
-
let last_idx = -1;
|
|
828
|
-
result.props.errors = await Promise.all(
|
|
829
|
-
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
830
|
-
branch
|
|
831
|
-
.map((b, i) => {
|
|
832
|
-
if (i === 0) return undefined; // root layout wraps root error component, not the other way around
|
|
833
|
-
if (!b) return null;
|
|
834
|
-
|
|
835
|
-
i--;
|
|
836
|
-
// Find the closest error component up to the previous branch
|
|
837
|
-
while (i > last_idx + 1 && !errors[i]) i -= 1;
|
|
838
|
-
last_idx = i;
|
|
839
|
-
return errors[i]?.()
|
|
840
|
-
.then((e) => e.component)
|
|
841
|
-
.catch(() => undefined);
|
|
842
|
-
})
|
|
843
|
-
// filter out indexes where there was no branch, but keep indexes where there was a branch but no error component
|
|
844
|
-
.filter((e) => e !== null)
|
|
845
|
-
);
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
if (error && __SVELTEKIT_EXPERIMENTAL_USE_TRANSFORM_ERROR__) {
|
|
819
|
+
if (error) {
|
|
849
820
|
result.props.error = error;
|
|
850
821
|
}
|
|
851
822
|
|
|
@@ -856,23 +827,44 @@ async function get_navigation_result_from_branch({
|
|
|
856
827
|
let data = {};
|
|
857
828
|
let data_changed = !page;
|
|
858
829
|
|
|
859
|
-
let
|
|
830
|
+
let current_node = result.props.tree;
|
|
831
|
+
|
|
832
|
+
/** @type {RenderNode | undefined} */
|
|
833
|
+
let previous_node = current_tree;
|
|
860
834
|
|
|
861
|
-
for (let i = 0; i <
|
|
835
|
+
for (let i = 0; i < branch.length; i += 1) {
|
|
862
836
|
const node = branch[i];
|
|
863
837
|
const prev = current.branch[i];
|
|
864
838
|
|
|
865
|
-
if (node?.data !== prev?.data) data_changed = true;
|
|
866
839
|
if (!node) continue;
|
|
867
840
|
|
|
868
|
-
|
|
841
|
+
const error_loader = errors?.slice(0, i + 1).findLast((x) => x) ?? default_error_loader;
|
|
869
842
|
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
843
|
+
current_node.error = (await error_loader()).component;
|
|
844
|
+
current_node.component = node.node.component;
|
|
845
|
+
|
|
846
|
+
if (
|
|
847
|
+
// if an ancestor node in this path changed, `data_changed` is already true and the
|
|
848
|
+
// accumulated `data` differs from the previous render, so we must re-merge
|
|
849
|
+
data_changed ||
|
|
850
|
+
!previous_node ||
|
|
851
|
+
node?.data !== prev?.data
|
|
852
|
+
) {
|
|
853
|
+
current_node.data = { ...data, ...node.data };
|
|
854
|
+
data_changed = true;
|
|
855
|
+
} else {
|
|
856
|
+
// use existing object — prevents effects re-running unnecessarily
|
|
857
|
+
current_node.data = previous_node.data;
|
|
873
858
|
}
|
|
874
859
|
|
|
875
|
-
|
|
860
|
+
data = current_node.data;
|
|
861
|
+
|
|
862
|
+
if (i < branch.length - 1) {
|
|
863
|
+
current_node.child = /** @type {import('../types.js').RenderNode} */ ({});
|
|
864
|
+
current_node = current_node.child;
|
|
865
|
+
|
|
866
|
+
previous_node = previous_node?.child;
|
|
867
|
+
}
|
|
876
868
|
}
|
|
877
869
|
|
|
878
870
|
const page_changed =
|
|
@@ -893,8 +885,7 @@ async function get_navigation_result_from_branch({
|
|
|
893
885
|
status: status ?? error?.status ?? 200,
|
|
894
886
|
url: new URL(url),
|
|
895
887
|
form: form ?? null,
|
|
896
|
-
|
|
897
|
-
data: data_changed ? data : page.data
|
|
888
|
+
data
|
|
898
889
|
};
|
|
899
890
|
}
|
|
900
891
|
|
|
@@ -1172,31 +1163,6 @@ function diff_search_params(old_url, new_url) {
|
|
|
1172
1163
|
return changed;
|
|
1173
1164
|
}
|
|
1174
1165
|
|
|
1175
|
-
/**
|
|
1176
|
-
* @param {Omit<import('./types.js').NavigationFinished['state'], 'branch'> & { error: App.Error }} opts
|
|
1177
|
-
* @returns {import('./types.js').NavigationFinished}
|
|
1178
|
-
*/
|
|
1179
|
-
function preload_error({ error, url, route, params }) {
|
|
1180
|
-
// we skipped loading the error page, so we need to use the current page
|
|
1181
|
-
// store, but we still pass the updated status to the preloadData function
|
|
1182
|
-
const new_page = clone_page(page);
|
|
1183
|
-
new_page.status = error.status;
|
|
1184
|
-
return {
|
|
1185
|
-
type: 'loaded',
|
|
1186
|
-
state: {
|
|
1187
|
-
error,
|
|
1188
|
-
url,
|
|
1189
|
-
route,
|
|
1190
|
-
params,
|
|
1191
|
-
branch: []
|
|
1192
|
-
},
|
|
1193
|
-
props: {
|
|
1194
|
-
page: new_page,
|
|
1195
|
-
constructors: []
|
|
1196
|
-
}
|
|
1197
|
-
};
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
1166
|
/**
|
|
1201
1167
|
* @overload
|
|
1202
1168
|
* @param {import('./types.js').NavigationIntent} intent
|
|
@@ -1267,7 +1233,7 @@ async function load_route({ id, invalidating, url, params, route, preload }) {
|
|
|
1267
1233
|
const handled_error = await handle_error(error, { url, params, route: { id } });
|
|
1268
1234
|
|
|
1269
1235
|
if (preload && preload_tokens.has(preload)) {
|
|
1270
|
-
|
|
1236
|
+
throw handled_error;
|
|
1271
1237
|
}
|
|
1272
1238
|
|
|
1273
1239
|
return load_root_error_page({
|
|
@@ -1357,13 +1323,7 @@ async function load_route({ id, invalidating, url, params, route, preload }) {
|
|
|
1357
1323
|
}
|
|
1358
1324
|
|
|
1359
1325
|
if (preload && preload_tokens.has(preload)) {
|
|
1360
|
-
|
|
1361
|
-
return preload_error({
|
|
1362
|
-
error,
|
|
1363
|
-
url,
|
|
1364
|
-
params,
|
|
1365
|
-
route
|
|
1366
|
-
});
|
|
1326
|
+
throw await handle_error(err, { params, url, route: { id: route.id } });
|
|
1367
1327
|
}
|
|
1368
1328
|
|
|
1369
1329
|
/** @type {App.Error} */
|
|
@@ -1377,8 +1337,7 @@ async function load_route({ id, invalidating, url, params, route, preload }) {
|
|
|
1377
1337
|
error = err.body;
|
|
1378
1338
|
} else {
|
|
1379
1339
|
// Referenced node could have been removed due to redeploy, check
|
|
1380
|
-
|
|
1381
|
-
if (updated) {
|
|
1340
|
+
if (await updated.check()) {
|
|
1382
1341
|
// Before reloading, try to update the service worker if it exists
|
|
1383
1342
|
await update_service_worker();
|
|
1384
1343
|
return await native_navigation(url);
|
|
@@ -1631,7 +1590,7 @@ export async function get_navigation_intent(url, invalidating) {
|
|
|
1631
1590
|
id: get_page_key(url),
|
|
1632
1591
|
invalidating,
|
|
1633
1592
|
route,
|
|
1634
|
-
params
|
|
1593
|
+
params,
|
|
1635
1594
|
url
|
|
1636
1595
|
};
|
|
1637
1596
|
}
|
|
@@ -1780,7 +1739,7 @@ async function navigate({
|
|
|
1780
1739
|
is_navigating = true;
|
|
1781
1740
|
|
|
1782
1741
|
if (started && nav.navigation.type !== 'enter') {
|
|
1783
|
-
|
|
1742
|
+
navigating.current = nav.navigation;
|
|
1784
1743
|
}
|
|
1785
1744
|
|
|
1786
1745
|
let navigation_result = intent && (await load_route(intent));
|
|
@@ -1867,8 +1826,7 @@ async function navigate({
|
|
|
1867
1826
|
|
|
1868
1827
|
if (!navigation_result) return;
|
|
1869
1828
|
} else if (/** @type {number} */ (navigation_result.props.page.status) >= 400) {
|
|
1870
|
-
|
|
1871
|
-
if (updated) {
|
|
1829
|
+
if (await updated.check()) {
|
|
1872
1830
|
// Before reloading, try to update the service worker if it exists
|
|
1873
1831
|
await update_service_worker();
|
|
1874
1832
|
return await native_navigation(url, replace_state);
|
|
@@ -1980,9 +1938,24 @@ async function navigate({
|
|
|
1980
1938
|
|
|
1981
1939
|
if (fork) {
|
|
1982
1940
|
commit_promise = fork.commit();
|
|
1941
|
+
// `fork.commit()` applies the preloaded state synchronously before the
|
|
1942
|
+
// first `await`, so reset any previously-failed boundaries now so the
|
|
1943
|
+
// stale `+error.svelte` is torn down. See sveltejs/kit#15694.
|
|
1944
|
+
for (const reset of resetters) {
|
|
1945
|
+
reset?.();
|
|
1946
|
+
}
|
|
1947
|
+
resetters.length = 0;
|
|
1983
1948
|
} else {
|
|
1984
1949
|
rendering_error = null; // TODO this can break with forks, rethink for SvelteKit 3 where we can assume Svelte 5
|
|
1985
1950
|
root.$set(navigation_result.props);
|
|
1951
|
+
current_tree = navigation_result.props.tree;
|
|
1952
|
+
// Reset any boundaries that failed on a previous navigation now that the
|
|
1953
|
+
// new props are applied, otherwise the stale `+error.svelte` stays
|
|
1954
|
+
// mounted above the new route's content. See sveltejs/kit#15694.
|
|
1955
|
+
for (const reset of resetters) {
|
|
1956
|
+
reset?.();
|
|
1957
|
+
}
|
|
1958
|
+
resetters.length = 0;
|
|
1986
1959
|
// Check for sync rendering error
|
|
1987
1960
|
if (rendering_error) {
|
|
1988
1961
|
Object.assign(navigation_result.props.page, rendering_error);
|
|
@@ -1999,13 +1972,7 @@ async function navigate({
|
|
|
1999
1972
|
|
|
2000
1973
|
const { activeElement } = document;
|
|
2001
1974
|
|
|
2002
|
-
await commit_promise;
|
|
2003
|
-
|
|
2004
|
-
// TODO 3.0 remote — the double tick is probably necessary because
|
|
2005
|
-
// of some store shenanigans. `settled()` and `f.commit()`
|
|
2006
|
-
// should resolve after DOM updates in newer versions
|
|
2007
|
-
await svelte.tick();
|
|
2008
|
-
await svelte.tick();
|
|
1975
|
+
await (commit_promise ?? svelte.tick());
|
|
2009
1976
|
|
|
2010
1977
|
if (navigation_token !== nav_token) {
|
|
2011
1978
|
// a new navigation happened while we were waiting for the DOM to update, so abort
|
|
@@ -2069,7 +2036,7 @@ async function navigate({
|
|
|
2069
2036
|
restore_snapshot(current_navigation_index);
|
|
2070
2037
|
}
|
|
2071
2038
|
|
|
2072
|
-
|
|
2039
|
+
navigating.current = null;
|
|
2073
2040
|
|
|
2074
2041
|
updating = false;
|
|
2075
2042
|
}
|
|
@@ -2122,22 +2089,63 @@ let current_a = { element: undefined, href: undefined };
|
|
|
2122
2089
|
function setup_preload() {
|
|
2123
2090
|
/** @type {NodeJS.Timeout} */
|
|
2124
2091
|
let mousemove_timeout;
|
|
2092
|
+
/** @type {HTMLAnchorElement | SVGAElement | undefined} */
|
|
2093
|
+
let hovered_a;
|
|
2125
2094
|
/** @type {PreloadDataPriority} */
|
|
2126
2095
|
let current_priority;
|
|
2127
2096
|
|
|
2128
|
-
|
|
2129
|
-
|
|
2097
|
+
function clear_hover_preload() {
|
|
2098
|
+
clearTimeout(mousemove_timeout);
|
|
2099
|
+
hovered_a?.removeEventListener('mousemove', start_hover_preload);
|
|
2100
|
+
hovered_a?.removeEventListener('mouseleave', clear_hover_preload);
|
|
2101
|
+
hovered_a = undefined;
|
|
2102
|
+
}
|
|
2130
2103
|
|
|
2104
|
+
function start_hover_preload() {
|
|
2131
2105
|
clearTimeout(mousemove_timeout);
|
|
2132
2106
|
mousemove_timeout = setTimeout(() => {
|
|
2133
|
-
|
|
2107
|
+
if (!hovered_a) return;
|
|
2108
|
+
void preload(hovered_a, PRELOAD_PRIORITIES.hover);
|
|
2134
2109
|
}, 20);
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2112
|
+
// Use mouseover initially instead of mousemove to avoid cluttering the event queue
|
|
2113
|
+
container.addEventListener('mouseover', (event) => {
|
|
2114
|
+
if (!(event.target instanceof Element)) return;
|
|
2115
|
+
|
|
2116
|
+
const a = find_anchor(event.target, container);
|
|
2117
|
+
if (!a || a === hovered_a) return;
|
|
2118
|
+
|
|
2119
|
+
clear_hover_preload();
|
|
2120
|
+
hovered_a = a;
|
|
2121
|
+
|
|
2122
|
+
const options = get_router_options(a);
|
|
2123
|
+
|
|
2124
|
+
if (
|
|
2125
|
+
options.preload_code < PRELOAD_PRIORITIES.hover &&
|
|
2126
|
+
options.preload_data < PRELOAD_PRIORITIES.hover
|
|
2127
|
+
) {
|
|
2128
|
+
// don't add event listeners if no preloading will happen
|
|
2129
|
+
return;
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
// Instead of just preloading right away, we start a mousemove listener to implement
|
|
2133
|
+
// "mouse comes to a rest" behavior. This avoid false positives when you just move
|
|
2134
|
+
// your mouse across the screen and happen to pass over a link.
|
|
2135
|
+
a.addEventListener('mousemove', start_hover_preload);
|
|
2136
|
+
a.addEventListener('mouseleave', clear_hover_preload, { once: true });
|
|
2137
|
+
|
|
2138
|
+
start_hover_preload();
|
|
2135
2139
|
});
|
|
2136
2140
|
|
|
2137
2141
|
/** @param {Event} event */
|
|
2138
2142
|
function tap(event) {
|
|
2139
2143
|
if (event.defaultPrevented) return;
|
|
2140
|
-
|
|
2144
|
+
|
|
2145
|
+
const a = find_anchor(/** @type {Element} */ (event.composedPath()[0]), container);
|
|
2146
|
+
if (!a) return;
|
|
2147
|
+
|
|
2148
|
+
void preload(a, PRELOAD_PRIORITIES.tap);
|
|
2141
2149
|
}
|
|
2142
2150
|
|
|
2143
2151
|
container.addEventListener('mousedown', tap);
|
|
@@ -2156,12 +2164,10 @@ function setup_preload() {
|
|
|
2156
2164
|
);
|
|
2157
2165
|
|
|
2158
2166
|
/**
|
|
2159
|
-
* @param {
|
|
2167
|
+
* @param {HTMLAnchorElement | SVGAElement} a
|
|
2160
2168
|
* @param {PreloadDataPriority} priority
|
|
2161
2169
|
*/
|
|
2162
|
-
async function preload(
|
|
2163
|
-
const a = find_anchor(element, container);
|
|
2164
|
-
|
|
2170
|
+
async function preload(a, priority) {
|
|
2165
2171
|
// we don't want to preload data again if the user has already hovered/tapped
|
|
2166
2172
|
const interacted =
|
|
2167
2173
|
a === current_a.element && a?.href === current_a.href && priority >= current_priority;
|
|
@@ -2185,15 +2191,13 @@ function setup_preload() {
|
|
|
2185
2191
|
if (!intent) return;
|
|
2186
2192
|
|
|
2187
2193
|
if (DEV) {
|
|
2188
|
-
void _preload_data(intent).
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
);
|
|
2196
|
-
}
|
|
2194
|
+
void _preload_data(intent).catch((error) => {
|
|
2195
|
+
console.warn(
|
|
2196
|
+
`Preloading data for ${intent.url.pathname} failed with the following error: ${error.message}\n` +
|
|
2197
|
+
'If this error is transient, you can ignore it. Otherwise, consider disabling preloading for this route. ' +
|
|
2198
|
+
'This route was preloaded due to a data-sveltekit-preload-data attribute. ' +
|
|
2199
|
+
'See https://svelte.dev/docs/kit/link-options for more info'
|
|
2200
|
+
);
|
|
2197
2201
|
});
|
|
2198
2202
|
} else {
|
|
2199
2203
|
void _preload_data(intent);
|
|
@@ -2257,7 +2261,7 @@ export async function handle_error(error, event) {
|
|
|
2257
2261
|
* @param {T} callback
|
|
2258
2262
|
*/
|
|
2259
2263
|
function add_navigation_callback(callbacks, callback) {
|
|
2260
|
-
onMount(() => {
|
|
2264
|
+
svelte.onMount(() => {
|
|
2261
2265
|
callbacks.add(callback);
|
|
2262
2266
|
|
|
2263
2267
|
return () => {
|
|
@@ -2328,6 +2332,8 @@ export function disableScrollHandling() {
|
|
|
2328
2332
|
}
|
|
2329
2333
|
}
|
|
2330
2334
|
|
|
2335
|
+
let warned_on_invalidate_all = false;
|
|
2336
|
+
|
|
2331
2337
|
/**
|
|
2332
2338
|
* Allows you to navigate programmatically to a given route, with options such as keeping the current element focused.
|
|
2333
2339
|
* Returns a Promise that resolves when SvelteKit navigates (or fails to navigate, in which case the promise rejects) to the specified `url`.
|
|
@@ -2341,8 +2347,9 @@ export function disableScrollHandling() {
|
|
|
2341
2347
|
* @param {boolean} [opts.replaceState] If `true`, will replace the current `history` entry rather than creating a new one with `pushState`
|
|
2342
2348
|
* @param {boolean} [opts.noScroll] If `true`, the browser will maintain its scroll position rather than scrolling to the top of the page after navigation
|
|
2343
2349
|
* @param {boolean} [opts.keepFocus] If `true`, the currently focused element will retain focus after navigation. Otherwise, focus will be reset to the body
|
|
2344
|
-
* @param {boolean} [opts.
|
|
2350
|
+
* @param {boolean} [opts.refreshAll] If `true`, all `load` functions and queries of the page will be rerun. See https://svelte.dev/docs/kit/load#rerunning-load-functions for more info on invalidation.
|
|
2345
2351
|
* @param {Array<string | URL | ((url: URL) => boolean)>} [opts.invalidate] Causes any load functions to re-run if they depend on one of the urls
|
|
2352
|
+
* @param {boolean} [opts.invalidateAll] Deprecated in favour of opts.refreshAll.
|
|
2346
2353
|
* @param {App.PageState} [opts.state] An optional object that will be available as `page.state`
|
|
2347
2354
|
* @returns {Promise<void>}
|
|
2348
2355
|
*/
|
|
@@ -2371,6 +2378,14 @@ export async function goto(url, opts = {}) {
|
|
|
2371
2378
|
);
|
|
2372
2379
|
}
|
|
2373
2380
|
|
|
2381
|
+
if (DEV && 'invalidateAll' in opts && !warned_on_invalidate_all) {
|
|
2382
|
+
warned_on_invalidate_all = true;
|
|
2383
|
+
console.warn(
|
|
2384
|
+
`The \`goto(..., { invalidateAll: ${opts.invalidateAll} })\` option has been deprecated in favour of \`refreshAll\``
|
|
2385
|
+
);
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
opts.refreshAll = opts.refreshAll ?? opts.invalidateAll;
|
|
2374
2389
|
return _goto(url, opts, 0, {}, intent);
|
|
2375
2390
|
}
|
|
2376
2391
|
|
|
@@ -2390,16 +2405,17 @@ export async function goto(url, opts = {}) {
|
|
|
2390
2405
|
* invalidate((url) => url.pathname === '/path');
|
|
2391
2406
|
* ```
|
|
2392
2407
|
* @param {string | URL | ((url: URL) => boolean)} resource The invalidated URL
|
|
2408
|
+
* @param {boolean} [keepState] If `true`, the current `page.state` will be preserved. Otherwise, it will be reset to an empty object. `false` by default.
|
|
2393
2409
|
* @returns {Promise<void>}
|
|
2394
2410
|
*/
|
|
2395
|
-
export function invalidate(resource) {
|
|
2411
|
+
export function invalidate(resource, keepState = false) {
|
|
2396
2412
|
if (!BROWSER) {
|
|
2397
2413
|
throw new Error('Cannot call invalidate(...) on the server');
|
|
2398
2414
|
}
|
|
2399
2415
|
|
|
2400
2416
|
push_invalidated(resource);
|
|
2401
2417
|
|
|
2402
|
-
return _invalidate();
|
|
2418
|
+
return _invalidate(!keepState);
|
|
2403
2419
|
}
|
|
2404
2420
|
|
|
2405
2421
|
/**
|
|
@@ -2416,6 +2432,10 @@ function push_invalidated(resource) {
|
|
|
2416
2432
|
|
|
2417
2433
|
/**
|
|
2418
2434
|
* Causes all `load` and `query` functions belonging to the currently active page to re-run. Returns a `Promise` that resolves when the page is subsequently updated.
|
|
2435
|
+
*
|
|
2436
|
+
* Note that this resets `page.state` to an empty object. If you want to preserve `page.state` (for example when using [shallow routing](https://svelte.dev/docs/kit/shallow-routing)), use `refreshAll` instead.
|
|
2437
|
+
*
|
|
2438
|
+
* @deprecated Use [`refreshAll`](https://svelte.dev/docs/kit/$app-navigation#refreshAll) instead. Unlike `invalidateAll`, `refreshAll` does not reset `page.state`.
|
|
2419
2439
|
* @returns {Promise<void>}
|
|
2420
2440
|
*/
|
|
2421
2441
|
export function invalidateAll() {
|
|
@@ -2428,18 +2448,17 @@ export function invalidateAll() {
|
|
|
2428
2448
|
}
|
|
2429
2449
|
|
|
2430
2450
|
/**
|
|
2431
|
-
* Causes all currently active remote functions to refresh, and all `load` functions belonging to the currently active page to re-run
|
|
2451
|
+
* Causes all currently active remote functions to refresh, and all `load` functions belonging to the currently active page to re-run.
|
|
2432
2452
|
* Returns a `Promise` that resolves when the page is subsequently updated.
|
|
2433
|
-
* @param {{ includeLoadFunctions?: boolean }} [options]
|
|
2434
2453
|
* @returns {Promise<void>}
|
|
2435
2454
|
*/
|
|
2436
|
-
export function refreshAll(
|
|
2455
|
+
export function refreshAll() {
|
|
2437
2456
|
if (!BROWSER) {
|
|
2438
2457
|
throw new Error('Cannot call refreshAll() on the server');
|
|
2439
2458
|
}
|
|
2440
2459
|
|
|
2441
2460
|
force_invalidation = true;
|
|
2442
|
-
return _invalidate(
|
|
2461
|
+
return _invalidate(false);
|
|
2443
2462
|
}
|
|
2444
2463
|
|
|
2445
2464
|
/**
|
|
@@ -2466,7 +2485,22 @@ export async function preloadData(href) {
|
|
|
2466
2485
|
throw new Error(`Attempted to preload a URL that does not belong to this app: ${url}`);
|
|
2467
2486
|
}
|
|
2468
2487
|
|
|
2469
|
-
|
|
2488
|
+
/** @type {Awaited<ReturnType<typeof _preload_data>>} */
|
|
2489
|
+
let result;
|
|
2490
|
+
|
|
2491
|
+
try {
|
|
2492
|
+
result = await _preload_data(intent);
|
|
2493
|
+
} catch (error) {
|
|
2494
|
+
// `load_route` throws the handled error (an `App.Error` with a `status`)
|
|
2495
|
+
// when a preload fails, so surface it in the documented `{ type: 'error' }` shape
|
|
2496
|
+
const handled = /** @type {App.Error & { status?: number }} */ (error);
|
|
2497
|
+
return {
|
|
2498
|
+
type: 'error',
|
|
2499
|
+
status: handled?.status ?? 500,
|
|
2500
|
+
error: handled
|
|
2501
|
+
};
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2470
2504
|
if (result.type === 'redirect') {
|
|
2471
2505
|
return {
|
|
2472
2506
|
type: result.type,
|
|
@@ -2477,14 +2511,6 @@ export async function preloadData(href) {
|
|
|
2477
2511
|
|
|
2478
2512
|
const { status, data } = result.props.page ?? page;
|
|
2479
2513
|
|
|
2480
|
-
if (result.type === 'loaded' && result.state.error) {
|
|
2481
|
-
return {
|
|
2482
|
-
type: 'error',
|
|
2483
|
-
status,
|
|
2484
|
-
error: result.state.error
|
|
2485
|
-
};
|
|
2486
|
-
}
|
|
2487
|
-
|
|
2488
2514
|
return { type: result.type, status, data };
|
|
2489
2515
|
}
|
|
2490
2516
|
|
|
@@ -2572,10 +2598,6 @@ export function pushState(url, state) {
|
|
|
2572
2598
|
has_navigated = true;
|
|
2573
2599
|
|
|
2574
2600
|
page.state = state;
|
|
2575
|
-
root.$set({
|
|
2576
|
-
// we need to assign a new page object so that subscribers are correctly notified
|
|
2577
|
-
page: untrack(() => clone_page(page))
|
|
2578
|
-
});
|
|
2579
2601
|
|
|
2580
2602
|
clear_onward_history(current_history_index, current_navigation_index);
|
|
2581
2603
|
}
|
|
@@ -2616,9 +2638,6 @@ export function replaceState(url, state) {
|
|
|
2616
2638
|
history.replaceState(opts, '', resolve_url(url));
|
|
2617
2639
|
|
|
2618
2640
|
page.state = state;
|
|
2619
|
-
root.$set({
|
|
2620
|
-
page: untrack(() => clone_page(page))
|
|
2621
|
-
});
|
|
2622
2641
|
}
|
|
2623
2642
|
|
|
2624
2643
|
/**
|
|
@@ -2637,7 +2656,7 @@ export async function applyAction(result) {
|
|
|
2637
2656
|
if (result.type === 'error') {
|
|
2638
2657
|
await set_nearest_error_page(result.error);
|
|
2639
2658
|
} else if (result.type === 'redirect') {
|
|
2640
|
-
await _goto(result.location, {
|
|
2659
|
+
await _goto(result.location, { refreshAll: true }, 0);
|
|
2641
2660
|
} else {
|
|
2642
2661
|
page.form = result.data;
|
|
2643
2662
|
page.status = result.status;
|
|
@@ -2646,16 +2665,15 @@ export async function applyAction(result) {
|
|
|
2646
2665
|
root.$set({
|
|
2647
2666
|
// this brings Svelte's view of the world in line with SvelteKit's
|
|
2648
2667
|
// after use:enhance reset the form....
|
|
2649
|
-
form: null
|
|
2650
|
-
page: clone_page(page)
|
|
2668
|
+
form: null
|
|
2651
2669
|
});
|
|
2652
2670
|
|
|
2653
2671
|
// ...so that setting the `form` prop takes effect and isn't ignored
|
|
2654
|
-
await tick();
|
|
2672
|
+
await svelte.tick();
|
|
2655
2673
|
root.$set({ form: result.data });
|
|
2656
2674
|
|
|
2657
2675
|
if (result.type === 'success') {
|
|
2658
|
-
reset_focus(page.url);
|
|
2676
|
+
reset_focus(/** @type {URL} */ (page.url));
|
|
2659
2677
|
}
|
|
2660
2678
|
}
|
|
2661
2679
|
}
|
|
@@ -2683,9 +2701,10 @@ export async function set_nearest_error_page(error) {
|
|
|
2683
2701
|
current = { ...navigation_result.state, nav: current.nav };
|
|
2684
2702
|
|
|
2685
2703
|
root.$set(navigation_result.props);
|
|
2704
|
+
current_tree = navigation_result.props.tree;
|
|
2686
2705
|
update(navigation_result.props.page);
|
|
2687
2706
|
|
|
2688
|
-
void tick().then(() => reset_focus(current.url));
|
|
2707
|
+
void svelte.tick().then(() => reset_focus(current.url));
|
|
2689
2708
|
}
|
|
2690
2709
|
}
|
|
2691
2710
|
|
|
@@ -3010,7 +3029,7 @@ function _start_router() {
|
|
|
3010
3029
|
// the navigation away from it was successful.
|
|
3011
3030
|
// Info about bfcache here: https://web.dev/bfcache
|
|
3012
3031
|
if (event.persisted) {
|
|
3013
|
-
|
|
3032
|
+
navigating.current = null;
|
|
3014
3033
|
}
|
|
3015
3034
|
});
|
|
3016
3035
|
|
|
@@ -3019,8 +3038,6 @@ function _start_router() {
|
|
|
3019
3038
|
*/
|
|
3020
3039
|
function update_url(url) {
|
|
3021
3040
|
current.url = page.url = url;
|
|
3022
|
-
stores.page.set(clone_page(page));
|
|
3023
|
-
stores.page.notify();
|
|
3024
3041
|
}
|
|
3025
3042
|
}
|
|
3026
3043
|
|
|
@@ -3309,9 +3326,6 @@ function reset_focus(url, scroll = true) {
|
|
|
3309
3326
|
const tabindex = root.getAttribute('tabindex');
|
|
3310
3327
|
|
|
3311
3328
|
root.tabIndex = -1;
|
|
3312
|
-
// TODO: remove this when we switch to TypeScript 6
|
|
3313
|
-
// @ts-ignore options.focusVisible is only typed in TypeScript 6
|
|
3314
|
-
// See https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#browser_compatibility
|
|
3315
3329
|
root.focus({ preventScroll: true, focusVisible: false });
|
|
3316
3330
|
|
|
3317
3331
|
// restore `tabindex` as to prevent `root` from stealing input from elements
|
|
@@ -3414,28 +3428,6 @@ function create_navigation(current, intent, url, type, target_scroll = null) {
|
|
|
3414
3428
|
};
|
|
3415
3429
|
}
|
|
3416
3430
|
|
|
3417
|
-
/**
|
|
3418
|
-
* TODO: remove this in 3.0 when the page store is also removed
|
|
3419
|
-
*
|
|
3420
|
-
* We need to assign a new page object so that subscribers are correctly notified.
|
|
3421
|
-
* However, spreading `{ ...page }` returns an empty object so we manually
|
|
3422
|
-
* assign to each property instead.
|
|
3423
|
-
*
|
|
3424
|
-
* @param {import('@sveltejs/kit').Page} page
|
|
3425
|
-
*/
|
|
3426
|
-
function clone_page(page) {
|
|
3427
|
-
return {
|
|
3428
|
-
data: page.data,
|
|
3429
|
-
error: page.error,
|
|
3430
|
-
form: page.form,
|
|
3431
|
-
params: page.params,
|
|
3432
|
-
route: page.route,
|
|
3433
|
-
state: page.state,
|
|
3434
|
-
status: page.status,
|
|
3435
|
-
url: page.url
|
|
3436
|
-
};
|
|
3437
|
-
}
|
|
3438
|
-
|
|
3439
3431
|
/**
|
|
3440
3432
|
* @param {URL} url
|
|
3441
3433
|
* @returns {URL}
|