Skip to content

Commit 7de6f37

Browse files
committed
Refactor to not use afterNavigate
1 parent 6e6fc57 commit 7de6f37

File tree

1 file changed

+44
-37
lines changed

1 file changed

+44
-37
lines changed

src/lib/page-transition.js

+44-37
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,65 @@
1-
import { afterNavigate, beforeNavigate } from '$app/navigation';
1+
import { beforeNavigate } from '$app/navigation';
2+
import { navigating } from '$app/stores';
23
import { onDestroy } from 'svelte';
3-
import { writable } from 'svelte/store';
44
import reducedMotion from './reduced-motion';
55

6+
function getNavigationStore() {
7+
/** @type {((val?: any) => void)[]} */
8+
let callbacks = [];
9+
10+
const navigation = {
11+
...navigating,
12+
complete: async () => {
13+
await new Promise((res, _) => {
14+
callbacks.push(res);
15+
});
16+
}
17+
};
18+
19+
// This used to subscribe inside the callback, but that resolved the promise too early
20+
const unsub = navigating.subscribe((n) => {
21+
if (n === null) {
22+
while (callbacks.length > 0) {
23+
const res = callbacks.pop();
24+
res();
25+
}
26+
}
27+
});
28+
29+
onDestroy(() => {
30+
unsub();
31+
});
32+
33+
return navigation;
34+
}
35+
636
export const preparePageTransition = () => {
7-
const transitionStore = writable({});
8-
let unsub;
37+
const navigation = getNavigationStore();
938
let isReducedMotionEnabled;
1039

1140
let unsubReducedMotion = reducedMotion.subscribe((val) => (isReducedMotionEnabled = val));
1241

13-
function updateStore(key, value) {
14-
transitionStore.update((current) => ({
15-
...current,
16-
[key]: value
17-
}));
18-
}
19-
2042
// before navigating, start a new transition
21-
beforeNavigate(({ to }) => {
22-
unsub?.(); // clean up previous subscription
23-
43+
beforeNavigate(() => {
2444
// Feature detection
2545
if (!document.createDocumentTransition || isReducedMotionEnabled) {
2646
return;
2747
}
2848

29-
const transitionKey = to.pathname;
30-
const transition = document.createDocumentTransition();
31-
transition.start(async () => {
32-
// set transition data for afterNavigate hook to pick up
33-
await new Promise((resolver) => {
34-
updateStore(transitionKey, { transition, resolver });
49+
try {
50+
const transition = document.createDocumentTransition();
51+
// init before transition.start so the promise doesn't resolve early
52+
const navigationComplete = navigation.complete();
53+
transition.start(async () => {
54+
await navigationComplete;
3555
});
36-
updateStore(transitionKey, null);
37-
});
38-
});
39-
40-
afterNavigate(({ to }) => {
41-
const transitionKey = to.pathname;
42-
// we need to subscribe to prevent race conditions
43-
// sometimes this runs before the store is updated with the new transition
44-
unsub = transitionStore.subscribe((transitions) => {
45-
const transition = transitions[transitionKey];
46-
if (!transition) {
47-
return;
48-
}
49-
const { resolver } = transition;
50-
resolver();
51-
});
56+
} catch (e) {
57+
// without the catch, we could throw in beforeNavigate and prevent navigation
58+
console.error(e);
59+
}
5260
});
5361

5462
onDestroy(() => {
55-
unsub?.();
5663
unsubReducedMotion();
5764
});
5865
};

0 commit comments

Comments
 (0)