swup 4.4.3 → 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/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/modules/Classes.d.ts.map +1 -1
- package/dist/types/modules/Hooks.d.ts +22 -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/index.ts +3 -1
- package/src/modules/Cache.ts +2 -2
- package/src/modules/Classes.ts +8 -1
- package/src/modules/Hooks.ts +91 -30
- 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/Swup.ts
CHANGED
|
@@ -21,7 +21,7 @@ import { renderPage } from './modules/renderPage.js';
|
|
|
21
21
|
import { use, unuse, findPlugin, type Plugin } from './modules/plugins.js';
|
|
22
22
|
import { isSameResolvedUrl, resolveUrl } from './modules/resolveUrl.js';
|
|
23
23
|
import { nextTick } from './utils.js';
|
|
24
|
-
import { type HistoryState } from './helpers/
|
|
24
|
+
import { type HistoryState } from './helpers/history.js';
|
|
25
25
|
|
|
26
26
|
/** Options for customizing swup's behavior. */
|
|
27
27
|
export type Options = {
|
|
@@ -41,6 +41,8 @@ export type Options = {
|
|
|
41
41
|
linkSelector: string;
|
|
42
42
|
/** How swup handles links to the same page. Default: `scroll` */
|
|
43
43
|
linkToSelf: NavigationToSelfAction;
|
|
44
|
+
/** Enable native animations using the View Transitions API. */
|
|
45
|
+
native: boolean;
|
|
44
46
|
/** Plugins to register on startup. */
|
|
45
47
|
plugins: Plugin[];
|
|
46
48
|
/** Custom headers sent along with fetch requests. */
|
|
@@ -62,6 +64,7 @@ const defaults: Options = {
|
|
|
62
64
|
ignoreVisit: (url, { el } = {}) => !!el?.closest('[data-no-swup]'),
|
|
63
65
|
linkSelector: 'a[href]',
|
|
64
66
|
linkToSelf: 'scroll',
|
|
67
|
+
native: false,
|
|
65
68
|
plugins: [],
|
|
66
69
|
resolveUrl: (url) => url,
|
|
67
70
|
requestHeaders: {
|
|
@@ -98,6 +101,8 @@ export default class Swup {
|
|
|
98
101
|
protected clickDelegate?: DelegateEventUnsubscribe;
|
|
99
102
|
/** Navigation status */
|
|
100
103
|
protected navigating: boolean = false;
|
|
104
|
+
/** Run anytime a visit ends */
|
|
105
|
+
protected onVisitEnd?: () => Promise<unknown>;
|
|
101
106
|
|
|
102
107
|
/** Install a plugin */
|
|
103
108
|
use = use;
|
|
@@ -185,6 +190,9 @@ export default class Swup {
|
|
|
185
190
|
// https://github.com/swup/swup/issues/475
|
|
186
191
|
}
|
|
187
192
|
|
|
193
|
+
// Sanitize/check native option
|
|
194
|
+
this.options.native = this.options.native && !!document.startViewTransition;
|
|
195
|
+
|
|
188
196
|
// Mount plugins
|
|
189
197
|
this.options.plugins.forEach((plugin) => this.use(plugin));
|
|
190
198
|
|
|
@@ -197,9 +205,10 @@ export default class Swup {
|
|
|
197
205
|
await nextTick();
|
|
198
206
|
|
|
199
207
|
// Trigger enable hook
|
|
200
|
-
await this.hooks.call('enable', undefined, () => {
|
|
201
|
-
|
|
202
|
-
|
|
208
|
+
await this.hooks.call('enable', undefined, undefined, () => {
|
|
209
|
+
const html = document.documentElement;
|
|
210
|
+
html.classList.add('swup-enabled');
|
|
211
|
+
html.classList.toggle('swup-native', this.options.native);
|
|
203
212
|
});
|
|
204
213
|
}
|
|
205
214
|
|
|
@@ -218,9 +227,10 @@ export default class Swup {
|
|
|
218
227
|
this.options.plugins.forEach((plugin) => this.unuse(plugin));
|
|
219
228
|
|
|
220
229
|
// trigger disable hook
|
|
221
|
-
await this.hooks.call('disable', undefined, () => {
|
|
222
|
-
|
|
223
|
-
|
|
230
|
+
await this.hooks.call('disable', undefined, undefined, () => {
|
|
231
|
+
const html = document.documentElement;
|
|
232
|
+
html.classList.remove('swup-enabled');
|
|
233
|
+
html.classList.remove('swup-native');
|
|
224
234
|
});
|
|
225
235
|
|
|
226
236
|
// remove handlers
|
|
@@ -265,11 +275,11 @@ export default class Swup {
|
|
|
265
275
|
return;
|
|
266
276
|
}
|
|
267
277
|
|
|
268
|
-
|
|
278
|
+
const visit = this.createVisit({ to: url, hash, el, event });
|
|
269
279
|
|
|
270
280
|
// Exit early if control key pressed
|
|
271
281
|
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
|
|
272
|
-
this.hooks.
|
|
282
|
+
this.hooks.callSync('link:newtab', visit, { href });
|
|
273
283
|
return;
|
|
274
284
|
}
|
|
275
285
|
|
|
@@ -278,8 +288,8 @@ export default class Swup {
|
|
|
278
288
|
return;
|
|
279
289
|
}
|
|
280
290
|
|
|
281
|
-
this.hooks.callSync('link:click', { el, event }, () => {
|
|
282
|
-
const from =
|
|
291
|
+
this.hooks.callSync('link:click', visit, { el, event }, () => {
|
|
292
|
+
const from = visit.from.url ?? '';
|
|
283
293
|
|
|
284
294
|
event.preventDefault();
|
|
285
295
|
|
|
@@ -287,20 +297,18 @@ export default class Swup {
|
|
|
287
297
|
if (!url || url === from) {
|
|
288
298
|
if (hash) {
|
|
289
299
|
// With hash: scroll to anchor
|
|
290
|
-
this.hooks.callSync('link:anchor', { hash }, () => {
|
|
300
|
+
this.hooks.callSync('link:anchor', visit, { hash }, () => {
|
|
291
301
|
updateHistoryRecord(url + hash);
|
|
292
|
-
this.scrollToContent();
|
|
302
|
+
this.scrollToContent(visit);
|
|
293
303
|
});
|
|
294
304
|
} else {
|
|
295
305
|
// Without hash: scroll to top or load/reload page
|
|
296
|
-
this.hooks.callSync('link:self', undefined, () => {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
updateHistoryRecord(url);
|
|
303
|
-
return this.scrollToContent();
|
|
306
|
+
this.hooks.callSync('link:self', visit, undefined, () => {
|
|
307
|
+
if (this.options.linkToSelf === 'navigate') {
|
|
308
|
+
this.performNavigation(visit);
|
|
309
|
+
} else {
|
|
310
|
+
updateHistoryRecord(url);
|
|
311
|
+
this.scrollToContent(visit);
|
|
304
312
|
}
|
|
305
313
|
});
|
|
306
314
|
}
|
|
@@ -313,7 +321,7 @@ export default class Swup {
|
|
|
313
321
|
}
|
|
314
322
|
|
|
315
323
|
// Finally, proceed with loading the page
|
|
316
|
-
this.performNavigation();
|
|
324
|
+
this.performNavigation(visit);
|
|
317
325
|
});
|
|
318
326
|
}
|
|
319
327
|
|
|
@@ -332,37 +340,32 @@ export default class Swup {
|
|
|
332
340
|
|
|
333
341
|
const { url, hash } = Location.fromUrl(href);
|
|
334
342
|
|
|
335
|
-
|
|
343
|
+
const visit = this.createVisit({ to: url, hash, event });
|
|
336
344
|
|
|
337
345
|
// Mark as history visit
|
|
338
|
-
|
|
346
|
+
visit.history.popstate = true;
|
|
339
347
|
|
|
340
348
|
// Determine direction of history visit
|
|
341
349
|
const index = (event.state as HistoryState)?.index ?? 0;
|
|
342
350
|
if (index && index !== this.currentHistoryIndex) {
|
|
343
351
|
const direction = index - this.currentHistoryIndex > 0 ? 'forwards' : 'backwards';
|
|
344
|
-
|
|
352
|
+
visit.history.direction = direction;
|
|
345
353
|
this.currentHistoryIndex = index;
|
|
346
354
|
}
|
|
347
355
|
|
|
348
356
|
// Disable animation & scrolling for history visits
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
357
|
+
visit.animation.animate = false;
|
|
358
|
+
visit.scroll.reset = false;
|
|
359
|
+
visit.scroll.target = false;
|
|
352
360
|
|
|
353
361
|
// Animated history visit: re-enable animation & scroll reset
|
|
354
362
|
if (this.options.animateHistoryBrowsing) {
|
|
355
|
-
|
|
356
|
-
|
|
363
|
+
visit.animation.animate = true;
|
|
364
|
+
visit.scroll.reset = true;
|
|
357
365
|
}
|
|
358
366
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
// event.preventDefault();
|
|
362
|
-
// }
|
|
363
|
-
|
|
364
|
-
this.hooks.callSync('history:popstate', { event }, () => {
|
|
365
|
-
this.performNavigation();
|
|
367
|
+
this.hooks.callSync('history:popstate', visit, { event }, () => {
|
|
368
|
+
this.performNavigation(visit);
|
|
366
369
|
});
|
|
367
370
|
}
|
|
368
371
|
|
package/src/helpers/Location.ts
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
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
|
+
type HistoryData = Record<string, unknown>;
|
|
12
|
+
|
|
13
|
+
/** Create a new history record with a custom swup identifier. */
|
|
14
|
+
export const createHistoryRecord = (url: string, data: HistoryData = {}): void => {
|
|
15
|
+
url = url || getCurrentUrl({ hash: true });
|
|
16
|
+
const state: HistoryState = {
|
|
17
|
+
url,
|
|
18
|
+
random: Math.random(),
|
|
19
|
+
source: 'swup',
|
|
20
|
+
...data
|
|
21
|
+
};
|
|
22
|
+
history.pushState(state, '', url);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/** Update the current history record with a custom swup identifier. */
|
|
26
|
+
export const updateHistoryRecord = (url: string | null = null, data: HistoryData = {}): void => {
|
|
27
|
+
url = url || getCurrentUrl({ hash: true });
|
|
28
|
+
const currentState = (history.state as HistoryState) || {};
|
|
29
|
+
const state: HistoryState = {
|
|
30
|
+
...currentState,
|
|
31
|
+
url,
|
|
32
|
+
random: Math.random(),
|
|
33
|
+
source: 'swup',
|
|
34
|
+
...data
|
|
35
|
+
};
|
|
36
|
+
history.replaceState(state, '', url);
|
|
37
|
+
};
|
package/src/helpers.ts
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
// e.g. import { updateHistoryRecord } from 'swup'
|
|
3
3
|
|
|
4
4
|
export { classify } from './helpers/classify.js';
|
|
5
|
-
export { createHistoryRecord } from './helpers/
|
|
6
|
-
export { updateHistoryRecord } from './helpers/updateHistoryRecord.js';
|
|
5
|
+
export { createHistoryRecord, updateHistoryRecord } from './helpers/history.js';
|
|
7
6
|
export { delegateEvent } from './helpers/delegateEvent.js';
|
|
8
7
|
export { getCurrentUrl } from './helpers/getCurrentUrl.js';
|
|
9
8
|
export { Location } from './helpers/Location.js';
|
package/src/index.ts
CHANGED
|
@@ -21,7 +21,8 @@ import type {
|
|
|
21
21
|
HookHandler,
|
|
22
22
|
HookDefaultHandler,
|
|
23
23
|
HookOptions,
|
|
24
|
-
HookUnregister
|
|
24
|
+
HookUnregister,
|
|
25
|
+
HookEvent
|
|
25
26
|
} from './modules/Hooks.js';
|
|
26
27
|
import type { Plugin } from './modules/plugins.js';
|
|
27
28
|
|
|
@@ -50,6 +51,7 @@ export type {
|
|
|
50
51
|
HookDefaultHandler,
|
|
51
52
|
HookOptions,
|
|
52
53
|
HookUnregister,
|
|
54
|
+
HookEvent,
|
|
53
55
|
DelegateEvent,
|
|
54
56
|
DelegateEventHandler,
|
|
55
57
|
DelegateEventUnsubscribe
|
package/src/modules/Cache.ts
CHANGED
|
@@ -49,7 +49,7 @@ export class Cache {
|
|
|
49
49
|
url = this.resolve(url);
|
|
50
50
|
page = { ...page, url };
|
|
51
51
|
this.pages.set(url, page);
|
|
52
|
-
this.swup.hooks.callSync('cache:set', { page });
|
|
52
|
+
this.swup.hooks.callSync('cache:set', undefined, { page });
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/** Update a cache record, overwriting or adding custom data. */
|
|
@@ -67,7 +67,7 @@ export class Cache {
|
|
|
67
67
|
/** Empty the cache. */
|
|
68
68
|
clear(): void {
|
|
69
69
|
this.pages.clear();
|
|
70
|
-
this.swup.hooks.callSync('cache:clear', undefined);
|
|
70
|
+
this.swup.hooks.callSync('cache:clear', undefined, undefined);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/** Remove all cache entries that return true for a given predicate function. */
|
package/src/modules/Classes.ts
CHANGED
|
@@ -3,7 +3,14 @@ import { queryAll } from '../utils.js';
|
|
|
3
3
|
|
|
4
4
|
export class Classes {
|
|
5
5
|
protected swup: Swup;
|
|
6
|
-
protected swupClasses = [
|
|
6
|
+
protected swupClasses = [
|
|
7
|
+
'to-',
|
|
8
|
+
'is-changing',
|
|
9
|
+
'is-rendering',
|
|
10
|
+
'is-popstate',
|
|
11
|
+
'is-animating',
|
|
12
|
+
'is-leaving'
|
|
13
|
+
];
|
|
7
14
|
|
|
8
15
|
constructor(swup: Swup) {
|
|
9
16
|
this.swup = swup;
|
package/src/modules/Hooks.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { DelegateEvent } from 'delegate-it';
|
|
|
2
2
|
|
|
3
3
|
import type Swup from '../Swup.js';
|
|
4
4
|
import { isPromise, runAsPromise } from '../utils.js';
|
|
5
|
-
import
|
|
5
|
+
import { Visit } from './Visit.js';
|
|
6
6
|
import type { FetchOptions, PageData } from './fetchPage.js';
|
|
7
7
|
|
|
8
8
|
export interface HookDefinitions {
|
|
@@ -33,16 +33,16 @@ export interface HookDefinitions {
|
|
|
33
33
|
'scroll:anchor': { hash: string; options: ScrollIntoViewOptions };
|
|
34
34
|
'visit:start': undefined;
|
|
35
35
|
'visit:transition': undefined;
|
|
36
|
+
'visit:abort': undefined;
|
|
36
37
|
'visit:end': undefined;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
export interface HookReturnValues {
|
|
40
|
-
'content:scroll': Promise<boolean
|
|
41
|
+
'content:scroll': Promise<boolean> | boolean;
|
|
41
42
|
'fetch:request': Promise<Response>;
|
|
42
43
|
'page:load': Promise<PageData>;
|
|
43
44
|
'scroll:top': boolean;
|
|
44
45
|
'scroll:anchor': boolean;
|
|
45
|
-
'visit:transition': Promise<boolean>;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
export type HookArguments<T extends HookName> = HookDefinitions[T];
|
|
@@ -96,6 +96,14 @@ export type HookRegistration<
|
|
|
96
96
|
defaultHandler?: HookDefaultHandler<T>;
|
|
97
97
|
} & HookOptions;
|
|
98
98
|
|
|
99
|
+
type HookEventDetail = {
|
|
100
|
+
hook: HookName;
|
|
101
|
+
args: unknown;
|
|
102
|
+
visit: Visit;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export type HookEvent = CustomEvent<HookEventDetail>;
|
|
106
|
+
|
|
99
107
|
type HookLedger<T extends HookName> = Map<HookHandler<T>, HookRegistration<T>>;
|
|
100
108
|
|
|
101
109
|
interface HookRegistry extends Map<HookName, HookLedger<HookName>> {
|
|
@@ -146,6 +154,7 @@ export class Hooks {
|
|
|
146
154
|
'scroll:anchor',
|
|
147
155
|
'visit:start',
|
|
148
156
|
'visit:transition',
|
|
157
|
+
'visit:abort',
|
|
149
158
|
'visit:end'
|
|
150
159
|
];
|
|
151
160
|
|
|
@@ -325,20 +334,29 @@ export class Hooks {
|
|
|
325
334
|
* Trigger a hook asynchronously, executing its default handler and all registered handlers.
|
|
326
335
|
* Will execute all handlers in order and `await` any `Promise`s they return.
|
|
327
336
|
* @param hook Name of the hook to trigger
|
|
337
|
+
* @param visit The visit object this hook belongs to
|
|
328
338
|
* @param args Arguments to pass to the handler
|
|
329
339
|
* @param defaultHandler A default implementation of this hook to execute
|
|
330
340
|
* @returns The resolved return value of the executed default handler
|
|
331
341
|
*/
|
|
342
|
+
// Overload: default order of arguments
|
|
343
|
+
async call<T extends HookName>(hook: T, visit: Visit | undefined, args: HookArguments<T>, defaultHandler?: HookDefaultHandler<T>): Promise<Awaited<ReturnType<HookDefaultHandler<T>>>>; // prettier-ignore
|
|
344
|
+
// Overload: legacy order of arguments, with visit missing
|
|
345
|
+
async call<T extends HookName>(hook: T, args: HookArguments<T>, defaultHandler?: HookDefaultHandler<T>): Promise<Awaited<ReturnType<HookDefaultHandler<T>>>>; // prettier-ignore
|
|
346
|
+
// Implementation
|
|
332
347
|
async call<T extends HookName>(
|
|
333
348
|
hook: T,
|
|
334
|
-
|
|
335
|
-
|
|
349
|
+
arg1: Visit | HookArguments<T>,
|
|
350
|
+
arg2: HookArguments<T> | HookDefaultHandler<T>,
|
|
351
|
+
arg3?: HookDefaultHandler<T>
|
|
336
352
|
): Promise<Awaited<ReturnType<HookDefaultHandler<T>>>> {
|
|
353
|
+
const [visit, args, defaultHandler] = this.parseCallArgs(hook, arg1, arg2, arg3);
|
|
354
|
+
|
|
337
355
|
const { before, handler, after } = this.getHandlers(hook, defaultHandler);
|
|
338
|
-
await this.run(before, args);
|
|
339
|
-
const [result] = await this.run(handler, args);
|
|
340
|
-
await this.run(after, args);
|
|
341
|
-
this.dispatchDomEvent(hook, args);
|
|
356
|
+
await this.run(before, visit, args);
|
|
357
|
+
const [result] = await this.run(handler, visit, args);
|
|
358
|
+
await this.run(after, visit, args);
|
|
359
|
+
this.dispatchDomEvent(hook, visit, args);
|
|
342
360
|
return result;
|
|
343
361
|
}
|
|
344
362
|
|
|
@@ -346,23 +364,51 @@ export class Hooks {
|
|
|
346
364
|
* Trigger a hook synchronously, executing its default handler and all registered handlers.
|
|
347
365
|
* Will execute all handlers in order, but will **not** `await` any `Promise`s they return.
|
|
348
366
|
* @param hook Name of the hook to trigger
|
|
367
|
+
* @param visit The visit object this hook belongs to
|
|
349
368
|
* @param args Arguments to pass to the handler
|
|
350
369
|
* @param defaultHandler A default implementation of this hook to execute
|
|
351
370
|
* @returns The (possibly unresolved) return value of the executed default handler
|
|
352
371
|
*/
|
|
372
|
+
// Overload: default order of arguments
|
|
373
|
+
callSync<T extends HookName>(hook: T, visit: Visit | undefined, args: HookArguments<T>, defaultHandler?: HookDefaultHandler<T>): ReturnType<HookDefaultHandler<T>>; // prettier-ignore
|
|
374
|
+
// Overload: legacy order of arguments, with visit missing
|
|
375
|
+
callSync<T extends HookName>(hook: T, args: HookArguments<T>, defaultHandler?: HookDefaultHandler<T>): ReturnType<HookDefaultHandler<T>>; // prettier-ignore
|
|
376
|
+
// Implementation
|
|
353
377
|
callSync<T extends HookName>(
|
|
354
378
|
hook: T,
|
|
355
|
-
|
|
356
|
-
|
|
379
|
+
arg1: Visit | HookArguments<T>,
|
|
380
|
+
arg2: HookArguments<T> | HookDefaultHandler<T>,
|
|
381
|
+
arg3?: HookDefaultHandler<T>
|
|
357
382
|
): ReturnType<HookDefaultHandler<T>> {
|
|
383
|
+
const [visit, args, defaultHandler] = this.parseCallArgs(hook, arg1, arg2, arg3);
|
|
358
384
|
const { before, handler, after } = this.getHandlers(hook, defaultHandler);
|
|
359
|
-
this.runSync(before, args);
|
|
360
|
-
const [result] = this.runSync(handler, args);
|
|
361
|
-
this.runSync(after, args);
|
|
362
|
-
this.dispatchDomEvent(hook, args);
|
|
385
|
+
this.runSync(before, visit, args);
|
|
386
|
+
const [result] = this.runSync(handler, visit, args);
|
|
387
|
+
this.runSync(after, visit, args);
|
|
388
|
+
this.dispatchDomEvent(hook, visit, args);
|
|
363
389
|
return result;
|
|
364
390
|
}
|
|
365
391
|
|
|
392
|
+
/**
|
|
393
|
+
* Parse the call arguments for call() and callSync() to allow legacy argument order.
|
|
394
|
+
*/
|
|
395
|
+
protected parseCallArgs<T extends HookName>(
|
|
396
|
+
hook: T,
|
|
397
|
+
arg1: Visit | HookArguments<T> | undefined,
|
|
398
|
+
arg2: HookArguments<T> | HookDefaultHandler<T>,
|
|
399
|
+
arg3?: HookDefaultHandler<T>
|
|
400
|
+
): [Visit | undefined, HookArguments<T>, HookDefaultHandler<T> | undefined] {
|
|
401
|
+
const isLegacyOrder =
|
|
402
|
+
!(arg1 instanceof Visit) && (typeof arg1 === 'object' || typeof arg2 === 'function');
|
|
403
|
+
if (isLegacyOrder) {
|
|
404
|
+
// Legacy positioning: arguments in second or handler passed in third place
|
|
405
|
+
return [undefined, arg1 as HookArguments<T>, arg2 as HookDefaultHandler<T>];
|
|
406
|
+
} else {
|
|
407
|
+
// Default positioning: visit passed in as first argument
|
|
408
|
+
return [arg1, arg2 as HookArguments<T>, arg3];
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
366
412
|
/**
|
|
367
413
|
* Execute the handlers for a hook, in order, as `Promise`s that will be `await`ed.
|
|
368
414
|
* @param registrations The registrations (handler + options) to execute
|
|
@@ -370,21 +416,25 @@ export class Hooks {
|
|
|
370
416
|
*/
|
|
371
417
|
|
|
372
418
|
// Overload: running HookDefaultHandler: expect HookDefaultHandler return type
|
|
373
|
-
protected async run<T extends HookName>(registrations: HookRegistration<T, HookDefaultHandler<T>>[], args: HookArguments<T>): Promise<Awaited<ReturnType<HookDefaultHandler<T>>>[]>; // prettier-ignore
|
|
419
|
+
protected async run<T extends HookName>(registrations: HookRegistration<T, HookDefaultHandler<T>>[], visit: Visit | undefined, args: HookArguments<T>): Promise<Awaited<ReturnType<HookDefaultHandler<T>>>[]>; // prettier-ignore
|
|
374
420
|
// Overload: running user handler: expect no specific type
|
|
375
|
-
protected async run<T extends HookName>(registrations: HookRegistration<T>[], args: HookArguments<T>): Promise<unknown[]>; // prettier-ignore
|
|
421
|
+
protected async run<T extends HookName>(registrations: HookRegistration<T>[], visit: Visit | undefined, args: HookArguments<T>): Promise<unknown[]>; // prettier-ignore
|
|
376
422
|
// Implementation
|
|
377
423
|
protected async run<T extends HookName, R extends HookRegistration<T>[]>(
|
|
378
424
|
registrations: R,
|
|
425
|
+
visit: Visit | undefined,
|
|
379
426
|
args: HookArguments<T>
|
|
380
427
|
): Promise<Awaited<ReturnType<HookDefaultHandler<T>>> | unknown[]> {
|
|
381
428
|
const results = [];
|
|
382
429
|
for (const { hook, handler, defaultHandler, once } of registrations) {
|
|
383
|
-
|
|
430
|
+
if (visit?.done) continue;
|
|
431
|
+
if (once) this.off(hook, handler);
|
|
432
|
+
const result = await runAsPromise(handler, [
|
|
433
|
+
visit || this.swup.visit,
|
|
434
|
+
args,
|
|
435
|
+
defaultHandler
|
|
436
|
+
]);
|
|
384
437
|
results.push(result);
|
|
385
|
-
if (once) {
|
|
386
|
-
this.off(hook, handler);
|
|
387
|
-
}
|
|
388
438
|
}
|
|
389
439
|
return results;
|
|
390
440
|
}
|
|
@@ -396,17 +446,20 @@ export class Hooks {
|
|
|
396
446
|
*/
|
|
397
447
|
|
|
398
448
|
// Overload: running HookDefaultHandler: expect HookDefaultHandler return type
|
|
399
|
-
protected runSync<T extends HookName>(registrations: HookRegistration<T, HookDefaultHandler<T>>[], args: HookArguments<T> ): ReturnType<HookDefaultHandler<T>>[]; // prettier-ignore
|
|
449
|
+
protected runSync<T extends HookName>(registrations: HookRegistration<T, HookDefaultHandler<T>>[], visit: Visit | undefined, args: HookArguments<T> ): ReturnType<HookDefaultHandler<T>>[]; // prettier-ignore
|
|
400
450
|
// Overload: running user handler: expect no specific type
|
|
401
|
-
protected runSync<T extends HookName>(registrations: HookRegistration<T>[], args: HookArguments<T>): unknown[]; // prettier-ignore
|
|
451
|
+
protected runSync<T extends HookName>(registrations: HookRegistration<T>[], visit: Visit | undefined, args: HookArguments<T>): unknown[]; // prettier-ignore
|
|
402
452
|
// Implementation
|
|
403
453
|
protected runSync<T extends HookName, R extends HookRegistration<T>[]>(
|
|
404
454
|
registrations: R,
|
|
455
|
+
visit: Visit | undefined,
|
|
405
456
|
args: HookArguments<T>
|
|
406
457
|
): (ReturnType<HookDefaultHandler<T>> | unknown)[] {
|
|
407
458
|
const results = [];
|
|
408
459
|
for (const { hook, handler, defaultHandler, once } of registrations) {
|
|
409
|
-
|
|
460
|
+
if (visit?.done) continue;
|
|
461
|
+
if (once) this.off(hook, handler);
|
|
462
|
+
const result = (handler as HookDefaultHandler<T>)(visit || this.swup.visit, args, defaultHandler); // prettier-ignore
|
|
410
463
|
results.push(result);
|
|
411
464
|
if (isPromise(result)) {
|
|
412
465
|
console.warn(
|
|
@@ -414,9 +467,6 @@ export class Hooks {
|
|
|
414
467
|
`Swup will not wait for it to resolve.`
|
|
415
468
|
);
|
|
416
469
|
}
|
|
417
|
-
if (once) {
|
|
418
|
-
this.off(hook, handler);
|
|
419
|
-
}
|
|
420
470
|
}
|
|
421
471
|
return results;
|
|
422
472
|
}
|
|
@@ -492,8 +542,19 @@ export class Hooks {
|
|
|
492
542
|
* Dispatch a custom event on the `document` for a hook. Prefixed with `swup:`
|
|
493
543
|
* @param hook Name of the hook.
|
|
494
544
|
*/
|
|
495
|
-
protected dispatchDomEvent<T extends HookName>(
|
|
496
|
-
|
|
497
|
-
|
|
545
|
+
protected dispatchDomEvent<T extends HookName>(
|
|
546
|
+
hook: T,
|
|
547
|
+
visit: Visit | undefined,
|
|
548
|
+
args?: HookArguments<T>
|
|
549
|
+
): void {
|
|
550
|
+
if (visit?.done) return;
|
|
551
|
+
|
|
552
|
+
const detail: HookEventDetail = { hook, args, visit: visit || this.swup.visit };
|
|
553
|
+
document.dispatchEvent(
|
|
554
|
+
new CustomEvent<HookEventDetail>(`swup:any`, { detail, bubbles: true })
|
|
555
|
+
);
|
|
556
|
+
document.dispatchEvent(
|
|
557
|
+
new CustomEvent<HookEventDetail>(`swup:${hook}`, { detail, bubbles: true })
|
|
558
|
+
);
|
|
498
559
|
}
|
|
499
560
|
}
|