swup 4.4.4 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Swup.cjs +1 -1
- package/dist/Swup.cjs.map +1 -1
- package/dist/Swup.modern.js +1 -1
- package/dist/Swup.modern.js.map +1 -1
- package/dist/Swup.module.js +1 -1
- package/dist/Swup.module.js.map +1 -1
- package/dist/Swup.umd.js +1 -1
- package/dist/Swup.umd.js.map +1 -1
- package/dist/types/Swup.d.ts +8 -4
- package/dist/types/Swup.d.ts.map +1 -1
- package/dist/types/helpers/Location.d.ts.map +1 -1
- package/dist/types/helpers/history.d.ts +14 -0
- package/dist/types/helpers/history.d.ts.map +1 -0
- package/dist/types/helpers.d.ts +1 -2
- package/dist/types/helpers.d.ts.map +1 -1
- package/dist/types/modules/Classes.d.ts.map +1 -1
- package/dist/types/modules/Hooks.d.ts +16 -8
- package/dist/types/modules/Hooks.d.ts.map +1 -1
- package/dist/types/modules/Visit.d.ts +28 -22
- package/dist/types/modules/Visit.d.ts.map +1 -1
- package/dist/types/modules/animatePageIn.d.ts +2 -1
- package/dist/types/modules/animatePageIn.d.ts.map +1 -1
- package/dist/types/modules/animatePageOut.d.ts +2 -1
- package/dist/types/modules/animatePageOut.d.ts.map +1 -1
- package/dist/types/modules/fetchPage.d.ts.map +1 -1
- package/dist/types/modules/navigate.d.ts +2 -2
- package/dist/types/modules/navigate.d.ts.map +1 -1
- package/dist/types/modules/renderPage.d.ts +2 -1
- package/dist/types/modules/renderPage.d.ts.map +1 -1
- package/dist/types/modules/replaceContent.d.ts.map +1 -1
- package/dist/types/modules/scrollToContent.d.ts +2 -1
- package/dist/types/modules/scrollToContent.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/Swup.ts +40 -37
- package/src/helpers/Location.ts +1 -0
- package/src/helpers/history.ts +37 -0
- package/src/helpers.ts +1 -2
- package/src/modules/Cache.ts +2 -2
- package/src/modules/Classes.ts +8 -1
- package/src/modules/Hooks.ts +77 -29
- package/src/modules/Visit.ts +86 -47
- package/src/modules/animatePageIn.ts +9 -8
- package/src/modules/animatePageOut.ts +7 -18
- package/src/modules/fetchPage.ts +9 -11
- package/src/modules/navigate.ts +78 -34
- package/src/modules/renderPage.ts +15 -13
- package/src/modules/replaceContent.ts +1 -0
- package/src/modules/scrollToContent.ts +6 -4
- package/dist/types/helpers/createHistoryRecord.d.ts +0 -10
- package/dist/types/helpers/createHistoryRecord.d.ts.map +0 -1
- package/dist/types/helpers/updateHistoryRecord.d.ts +0 -3
- package/dist/types/helpers/updateHistoryRecord.d.ts.map +0 -1
- package/src/helpers/createHistoryRecord.ts +0 -24
- package/src/helpers/updateHistoryRecord.ts +0 -19
package/src/modules/navigate.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import type Swup from '../Swup.js';
|
|
2
|
-
import { createHistoryRecord, updateHistoryRecord, getCurrentUrl, Location } from '../helpers.js';
|
|
3
2
|
import { FetchError, type FetchOptions, type PageData } from './fetchPage.js';
|
|
4
|
-
import type
|
|
3
|
+
import { type VisitInitOptions, type Visit, VisitState } from './Visit.js';
|
|
4
|
+
import {
|
|
5
|
+
createHistoryRecord,
|
|
6
|
+
updateHistoryRecord,
|
|
7
|
+
getCurrentUrl,
|
|
8
|
+
Location,
|
|
9
|
+
classify
|
|
10
|
+
} from '../helpers.js';
|
|
5
11
|
|
|
6
12
|
export type HistoryAction = 'push' | 'replace';
|
|
7
13
|
export type HistoryDirection = 'forwards' | 'backwards';
|
|
@@ -43,8 +49,9 @@ export function navigate(
|
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
const { url: to, hash } = Location.fromUrl(url);
|
|
46
|
-
|
|
47
|
-
this.
|
|
52
|
+
|
|
53
|
+
const visit = this.createVisit({ ...init, to, hash });
|
|
54
|
+
this.performNavigation(visit, options);
|
|
48
55
|
}
|
|
49
56
|
|
|
50
57
|
/**
|
|
@@ -60,12 +67,24 @@ export function navigate(
|
|
|
60
67
|
*/
|
|
61
68
|
export async function performNavigation(
|
|
62
69
|
this: Swup,
|
|
70
|
+
visit: Visit,
|
|
63
71
|
options: NavigationOptions & FetchOptions = {}
|
|
64
72
|
): Promise<void> {
|
|
73
|
+
if (this.navigating) {
|
|
74
|
+
if (this.visit.state >= VisitState.ENTERING) {
|
|
75
|
+
// Currently navigating and content already loaded? Finish and queue
|
|
76
|
+
visit.state = VisitState.QUEUED;
|
|
77
|
+
this.onVisitEnd = () => this.performNavigation(visit, options);
|
|
78
|
+
return;
|
|
79
|
+
} else {
|
|
80
|
+
// Currently navigating and content not loaded? Abort running visit
|
|
81
|
+
await this.hooks.call('visit:abort', this.visit, undefined);
|
|
82
|
+
this.visit.state = VisitState.ABORTED;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
65
86
|
this.navigating = true;
|
|
66
|
-
|
|
67
|
-
// and b) avoid unintended modifications to any newer visits
|
|
68
|
-
const visit = this.visit;
|
|
87
|
+
this.visit = visit;
|
|
69
88
|
|
|
70
89
|
const { el } = visit.trigger;
|
|
71
90
|
options.referrer = options.referrer || this.currentPageUrl;
|
|
@@ -102,10 +121,11 @@ export async function performNavigation(
|
|
|
102
121
|
delete options.cache;
|
|
103
122
|
|
|
104
123
|
try {
|
|
105
|
-
await this.hooks.call('visit:start', undefined);
|
|
124
|
+
await this.hooks.call('visit:start', visit, undefined);
|
|
125
|
+
visit.state = VisitState.STARTED;
|
|
106
126
|
|
|
107
127
|
// Begin loading page
|
|
108
|
-
const
|
|
128
|
+
const page = this.hooks.call('page:load', visit, { options }, async (visit, args) => {
|
|
109
129
|
// Read from cache
|
|
110
130
|
let cachedPage: PageData | undefined;
|
|
111
131
|
if (visit.cache.read) {
|
|
@@ -118,6 +138,12 @@ export async function performNavigation(
|
|
|
118
138
|
return args.page;
|
|
119
139
|
});
|
|
120
140
|
|
|
141
|
+
// When page loaded: mark visit as loaded, save html into visit object
|
|
142
|
+
page.then(({ html }) => {
|
|
143
|
+
visit.advance(VisitState.LOADED);
|
|
144
|
+
visit.to.html = html;
|
|
145
|
+
});
|
|
146
|
+
|
|
121
147
|
// Create/update history record if this is not a popstate call or leads to the same URL
|
|
122
148
|
if (!visit.history.popstate) {
|
|
123
149
|
// Add the hash directly from the trigger element
|
|
@@ -132,48 +158,66 @@ export async function performNavigation(
|
|
|
132
158
|
|
|
133
159
|
this.currentPageUrl = getCurrentUrl();
|
|
134
160
|
|
|
161
|
+
// Mark visit type with classes
|
|
162
|
+
if (visit.history.popstate) {
|
|
163
|
+
this.classes.add('is-popstate');
|
|
164
|
+
}
|
|
165
|
+
if (visit.animation.name) {
|
|
166
|
+
this.classes.add(`to-${classify(visit.animation.name)}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
135
169
|
// Wait for page before starting to animate out?
|
|
136
170
|
if (visit.animation.wait) {
|
|
137
|
-
|
|
138
|
-
visit.to.html = html;
|
|
171
|
+
await page;
|
|
139
172
|
}
|
|
140
173
|
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
// Start leave animation
|
|
144
|
-
const animationPromise = this.animatePageOut();
|
|
174
|
+
// Check if failed/aborted in the meantime
|
|
175
|
+
if (visit.done) return;
|
|
145
176
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
177
|
+
// Perform the actual transition: animate and replace content
|
|
178
|
+
await this.hooks.call('visit:transition', visit, undefined, async () => {
|
|
179
|
+
// No animation? Just await page and render
|
|
180
|
+
if (!visit.animation.animate) {
|
|
181
|
+
await this.hooks.call('animation:skip', undefined);
|
|
182
|
+
await this.renderPage(visit, await page);
|
|
183
|
+
return;
|
|
152
184
|
}
|
|
153
185
|
|
|
154
|
-
//
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
186
|
+
// Animate page out, render page, animate page in
|
|
187
|
+
visit.advance(VisitState.LEAVING);
|
|
188
|
+
await this.animatePageOut(visit);
|
|
189
|
+
if (visit.animation.native && document.startViewTransition) {
|
|
190
|
+
await document.startViewTransition(
|
|
191
|
+
async () => await this.renderPage(visit, await page)
|
|
192
|
+
).finished;
|
|
193
|
+
} else {
|
|
194
|
+
await this.renderPage(visit, await page);
|
|
195
|
+
}
|
|
196
|
+
await this.animatePageIn(visit);
|
|
161
197
|
});
|
|
162
198
|
|
|
163
|
-
//
|
|
164
|
-
|
|
199
|
+
// Check if failed/aborted in the meantime
|
|
200
|
+
if (visit.done) return;
|
|
165
201
|
|
|
166
|
-
//
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
// }
|
|
202
|
+
// Finalize visit
|
|
203
|
+
await this.hooks.call('visit:end', visit, undefined, () => this.classes.clear());
|
|
204
|
+
visit.state = VisitState.COMPLETED;
|
|
170
205
|
this.navigating = false;
|
|
206
|
+
|
|
207
|
+
/** Run eventually queued function */
|
|
208
|
+
if (this.onVisitEnd) {
|
|
209
|
+
this.onVisitEnd();
|
|
210
|
+
this.onVisitEnd = undefined;
|
|
211
|
+
}
|
|
171
212
|
} catch (error) {
|
|
172
213
|
// Return early if error is undefined or signals an aborted request
|
|
173
214
|
if (!error || (error as FetchError)?.aborted) {
|
|
215
|
+
visit.state = VisitState.ABORTED;
|
|
174
216
|
return;
|
|
175
217
|
}
|
|
176
218
|
|
|
219
|
+
visit.state = VisitState.FAILED;
|
|
220
|
+
|
|
177
221
|
// Log to console as we swallow almost all hook errors
|
|
178
222
|
console.error(error);
|
|
179
223
|
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { updateHistoryRecord, getCurrentUrl, classify } from '../helpers.js';
|
|
2
2
|
import type Swup from '../Swup.js';
|
|
3
3
|
import type { PageData } from './fetchPage.js';
|
|
4
|
+
import { VisitState, type Visit } from './Visit.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Render the next page: replace the content and update scroll position.
|
|
7
8
|
*/
|
|
8
|
-
export const renderPage = async function (this: Swup, page: PageData): Promise<void> {
|
|
9
|
-
|
|
9
|
+
export const renderPage = async function (this: Swup, visit: Visit, page: PageData): Promise<void> {
|
|
10
|
+
// Check if failed/aborted in the meantime
|
|
11
|
+
if (visit.done) return;
|
|
12
|
+
|
|
13
|
+
visit.advance(VisitState.ENTERING);
|
|
14
|
+
|
|
15
|
+
const { url } = page;
|
|
10
16
|
|
|
11
17
|
this.classes.remove('is-leaving');
|
|
12
18
|
|
|
@@ -14,26 +20,23 @@ export const renderPage = async function (this: Swup, page: PageData): Promise<v
|
|
|
14
20
|
if (!this.isSameResolvedUrl(getCurrentUrl(), url)) {
|
|
15
21
|
updateHistoryRecord(url);
|
|
16
22
|
this.currentPageUrl = getCurrentUrl();
|
|
17
|
-
|
|
23
|
+
visit.to.url = this.currentPageUrl;
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
// only add for animated page loads
|
|
21
|
-
if (
|
|
27
|
+
if (visit.animation.animate) {
|
|
22
28
|
this.classes.add('is-rendering');
|
|
23
29
|
}
|
|
24
30
|
|
|
25
|
-
// save html into visit context for easier retrieval
|
|
26
|
-
this.visit.to.html = html;
|
|
27
|
-
|
|
28
31
|
// replace content: allow handlers and plugins to overwrite paga data and containers
|
|
29
|
-
await this.hooks.call('content:replace', { page }, (visit, { page }) => {
|
|
32
|
+
await this.hooks.call('content:replace', visit, { page }, (visit, { page }) => {
|
|
30
33
|
const success = this.replaceContent(page, { containers: visit.containers });
|
|
31
34
|
if (!success) {
|
|
32
35
|
throw new Error('[swup] Container mismatch, aborting');
|
|
33
36
|
}
|
|
34
37
|
if (visit.animation.animate) {
|
|
35
38
|
// Make sure to add these classes to new containers as well
|
|
36
|
-
this.classes.add('is-
|
|
39
|
+
this.classes.add('is-changing', 'is-animating', 'is-rendering');
|
|
37
40
|
if (visit.animation.name) {
|
|
38
41
|
this.classes.add(`to-${classify(visit.animation.name)}`);
|
|
39
42
|
}
|
|
@@ -41,10 +44,9 @@ export const renderPage = async function (this: Swup, page: PageData): Promise<v
|
|
|
41
44
|
});
|
|
42
45
|
|
|
43
46
|
// scroll into view: either anchor or top of page
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return this.scrollToContent();
|
|
47
|
+
await this.hooks.call('content:scroll', visit, undefined, () => {
|
|
48
|
+
return this.scrollToContent(visit);
|
|
47
49
|
});
|
|
48
50
|
|
|
49
|
-
await this.hooks.call('page:view', { url: this.currentPageUrl, title: document.title });
|
|
51
|
+
await this.hooks.call('page:view', visit, { url: this.currentPageUrl, title: document.title });
|
|
50
52
|
};
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import type Swup from '../Swup.js';
|
|
2
|
+
import type { Visit } from './Visit.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Update the scroll position after page render.
|
|
5
6
|
* @returns Promise<boolean>
|
|
6
7
|
*/
|
|
7
|
-
export const scrollToContent = function (this: Swup): boolean {
|
|
8
|
+
export const scrollToContent = function (this: Swup, visit: Visit): boolean {
|
|
8
9
|
const options: ScrollIntoViewOptions = { behavior: 'auto' };
|
|
9
|
-
const { target, reset } =
|
|
10
|
-
const scrollTarget = target ??
|
|
10
|
+
const { target, reset } = visit.scroll;
|
|
11
|
+
const scrollTarget = target ?? visit.to.hash;
|
|
11
12
|
|
|
12
13
|
let scrolled = false;
|
|
13
14
|
|
|
14
15
|
if (scrollTarget) {
|
|
15
16
|
scrolled = this.hooks.callSync(
|
|
16
17
|
'scroll:anchor',
|
|
18
|
+
visit,
|
|
17
19
|
{ hash: scrollTarget, options },
|
|
18
20
|
(visit, { hash, options }) => {
|
|
19
21
|
const anchor = this.getAnchorElement(hash);
|
|
@@ -26,7 +28,7 @@ export const scrollToContent = function (this: Swup): boolean {
|
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
if (reset && !scrolled) {
|
|
29
|
-
scrolled = this.hooks.callSync('scroll:top', { options }, (visit, { options }) => {
|
|
31
|
+
scrolled = this.hooks.callSync('scroll:top', visit, { options }, (visit, { options }) => {
|
|
30
32
|
window.scrollTo({ top: 0, left: 0, ...options });
|
|
31
33
|
return true;
|
|
32
34
|
});
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export interface HistoryState {
|
|
2
|
-
url: string;
|
|
3
|
-
source: 'swup';
|
|
4
|
-
random: number;
|
|
5
|
-
index?: number;
|
|
6
|
-
[key: string]: unknown;
|
|
7
|
-
}
|
|
8
|
-
/** Create a new history record with a custom swup identifier. */
|
|
9
|
-
export declare const createHistoryRecord: (url: string, customData?: Record<string, unknown>) => void;
|
|
10
|
-
//# sourceMappingURL=createHistoryRecord.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createHistoryRecord.d.ts","sourceRoot":"","sources":["../../../src/helpers/createHistoryRecord.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED,iEAAiE;AACjE,eAAO,MAAM,mBAAmB,QAC1B,MAAM,eACC,OAAO,MAAM,EAAE,OAAO,CAAC,KACjC,IASF,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"updateHistoryRecord.d.ts","sourceRoot":"","sources":["../../../src/helpers/updateHistoryRecord.ts"],"names":[],"mappings":"AAGA,uEAAuE;AACvE,eAAO,MAAM,mBAAmB,SAC1B,MAAM,GAAG,IAAI,eACN,OAAO,MAAM,EAAE,OAAO,CAAC,KACjC,IAWF,CAAC"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { getCurrentUrl } from './getCurrentUrl.js';
|
|
2
|
-
|
|
3
|
-
export interface HistoryState {
|
|
4
|
-
url: string;
|
|
5
|
-
source: 'swup';
|
|
6
|
-
random: number;
|
|
7
|
-
index?: number;
|
|
8
|
-
[key: string]: unknown;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/** Create a new history record with a custom swup identifier. */
|
|
12
|
-
export const createHistoryRecord = (
|
|
13
|
-
url: string,
|
|
14
|
-
customData: Record<string, unknown> = {}
|
|
15
|
-
): void => {
|
|
16
|
-
url = url || getCurrentUrl({ hash: true });
|
|
17
|
-
const data: HistoryState = {
|
|
18
|
-
url,
|
|
19
|
-
random: Math.random(),
|
|
20
|
-
source: 'swup',
|
|
21
|
-
...customData
|
|
22
|
-
};
|
|
23
|
-
history.pushState(data, '', url);
|
|
24
|
-
};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { HistoryState } from './createHistoryRecord.js';
|
|
2
|
-
import { getCurrentUrl } from './getCurrentUrl.js';
|
|
3
|
-
|
|
4
|
-
/** Update the current history record with a custom swup identifier. */
|
|
5
|
-
export const updateHistoryRecord = (
|
|
6
|
-
url: string | null = null,
|
|
7
|
-
customData: Record<string, unknown> = {}
|
|
8
|
-
): void => {
|
|
9
|
-
url = url || getCurrentUrl({ hash: true });
|
|
10
|
-
const state = (history.state as HistoryState) || {};
|
|
11
|
-
const data: HistoryState = {
|
|
12
|
-
...state,
|
|
13
|
-
url,
|
|
14
|
-
random: Math.random(),
|
|
15
|
-
source: 'swup',
|
|
16
|
-
...customData
|
|
17
|
-
};
|
|
18
|
-
history.replaceState(data, '', url);
|
|
19
|
-
};
|