swup 4.0.0-rc.21 → 4.0.0-rc.23
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 +2 -2
- package/dist/types/modules/Cache.d.ts +15 -0
- package/dist/types/modules/Context.d.ts +4 -4
- package/dist/types/modules/{enterPage.d.ts → animatePageIn.d.ts} +1 -1
- package/dist/types/modules/{leavePage.d.ts → animatePageOut.d.ts} +1 -1
- package/dist/types/utils/index.d.ts +6 -0
- package/package.json +1 -1
- package/src/Swup.ts +8 -24
- package/src/modules/Cache.ts +17 -1
- package/src/modules/Context.ts +4 -4
- package/src/modules/Hooks.ts +1 -1
- package/src/modules/{enterPage.ts → animatePageIn.ts} +1 -1
- package/src/modules/{leavePage.ts → animatePageOut.ts} +1 -1
- package/src/modules/visit.ts +17 -10
- package/src/utils/index.ts +10 -0
package/dist/types/Swup.d.ts
CHANGED
|
@@ -58,12 +58,12 @@ export default class Swup {
|
|
|
58
58
|
private clickDelegate?;
|
|
59
59
|
visit: typeof visit;
|
|
60
60
|
performVisit: typeof performVisit;
|
|
61
|
-
|
|
61
|
+
animatePageOut: (this: Swup) => Promise<void>;
|
|
62
62
|
renderPage: (this: Swup, requestedUrl: string, page: import("./modules/fetchPage.js").PageData) => Promise<void>;
|
|
63
63
|
replaceContent: (this: Swup, { html }: import("./modules/fetchPage.js").PageData, { containers }?: {
|
|
64
64
|
containers: string[];
|
|
65
65
|
}) => boolean;
|
|
66
|
-
|
|
66
|
+
animatePageIn: (this: Swup) => Promise<void>;
|
|
67
67
|
delegateEvent: <Selector extends string, TEvent extends keyof GlobalEventHandlersEventMap>(selector: Selector, type: TEvent, callback: import("delegate-it").DelegateEventHandler<GlobalEventHandlersEventMap[TEvent], Element>, options?: import("delegate-it").DelegateOptions | undefined) => DelegateEventUnsubscribe;
|
|
68
68
|
fetchPage: typeof fetchPage;
|
|
69
69
|
awaitAnimations: typeof awaitAnimations;
|
|
@@ -2,18 +2,33 @@ import Swup from '../Swup.js';
|
|
|
2
2
|
import { PageData } from './fetchPage.js';
|
|
3
3
|
export interface CacheData extends PageData {
|
|
4
4
|
}
|
|
5
|
+
/**
|
|
6
|
+
* In-memory page cache.
|
|
7
|
+
*/
|
|
5
8
|
export declare class Cache {
|
|
9
|
+
/** Swup instance this cache belongs to */
|
|
6
10
|
private swup;
|
|
11
|
+
/** Cached pages, indexed by URL */
|
|
7
12
|
private pages;
|
|
8
13
|
constructor(swup: Swup);
|
|
14
|
+
/** Number of cached pages in memory. */
|
|
9
15
|
get size(): number;
|
|
16
|
+
/** All cached pages. */
|
|
10
17
|
get all(): Map<string, CacheData>;
|
|
18
|
+
/** Check if the given URL has been cached. */
|
|
11
19
|
has(url: string): boolean;
|
|
20
|
+
/** Return the cached page object if cached. */
|
|
12
21
|
get(url: string): CacheData | undefined;
|
|
22
|
+
/** Create a cache record for the specified URL. */
|
|
13
23
|
set(url: string, page: CacheData): void;
|
|
24
|
+
/** Update a cache record, overwriting or adding custom data. */
|
|
14
25
|
update(url: string, page: CacheData): void;
|
|
26
|
+
/** Delete a cache record. */
|
|
15
27
|
delete(url: string): void;
|
|
28
|
+
/** Empty the cache. */
|
|
16
29
|
clear(): void;
|
|
30
|
+
/** Remove all cache entries that return true for a given predicate function. */
|
|
17
31
|
prune(predicate: (url: string, page: CacheData) => boolean): void;
|
|
32
|
+
/** Resolve URLs by making them local and letting swup resolve them. */
|
|
18
33
|
private resolve;
|
|
19
34
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Swup, { Options } from '../Swup.js';
|
|
2
2
|
import { HistoryAction, HistoryDirection } from './visit.js';
|
|
3
|
-
export interface Context
|
|
3
|
+
export interface Context {
|
|
4
4
|
/** The previous page, about to leave */
|
|
5
5
|
from: FromContext;
|
|
6
6
|
/** The next page, about to enter */
|
|
@@ -10,7 +10,7 @@ export interface Context<TEvent = Event> {
|
|
|
10
10
|
/** Information about animated page transitions */
|
|
11
11
|
animation: AnimationContext;
|
|
12
12
|
/** What triggered this visit */
|
|
13
|
-
trigger: TriggerContext
|
|
13
|
+
trigger: TriggerContext;
|
|
14
14
|
/** Browser history behavior on this visit */
|
|
15
15
|
history: HistoryContext;
|
|
16
16
|
/** Scroll behavior on this visit */
|
|
@@ -44,11 +44,11 @@ export interface ScrollContext {
|
|
|
44
44
|
/** Anchor element to scroll to on the next page. */
|
|
45
45
|
target?: string;
|
|
46
46
|
}
|
|
47
|
-
export interface TriggerContext
|
|
47
|
+
export interface TriggerContext {
|
|
48
48
|
/** DOM element that triggered this visit. */
|
|
49
49
|
el?: Element;
|
|
50
50
|
/** DOM event that triggered this visit. */
|
|
51
|
-
event?:
|
|
51
|
+
event?: Event;
|
|
52
52
|
}
|
|
53
53
|
export interface HistoryContext {
|
|
54
54
|
/** History action to perform: `push` for creating a new history entry, `replace` for replacing the current entry. Default: `push` */
|
|
@@ -3,5 +3,11 @@ export declare const queryAll: (selector: string, context?: Document | Element)
|
|
|
3
3
|
export declare const nextTick: () => Promise<void>;
|
|
4
4
|
export declare function isPromise<T>(obj: any): obj is PromiseLike<T>;
|
|
5
5
|
export declare function runAsPromise(func: Function, args?: any[], ctx?: any): Promise<any>;
|
|
6
|
+
/**
|
|
7
|
+
* Force a layout reflow, e.g. after adding classnames
|
|
8
|
+
* @returns The offset height, just here so it doesn't get optimized away by the JS engine
|
|
9
|
+
* @see https://stackoverflow.com/a/21665117/3759615
|
|
10
|
+
*/
|
|
11
|
+
export declare function forceReflow(element?: HTMLElement): number;
|
|
6
12
|
export declare const escapeCssIdentifier: (ident: string) => string;
|
|
7
13
|
export declare const toMs: (s: string) => number;
|
package/package.json
CHANGED
package/src/Swup.ts
CHANGED
|
@@ -13,9 +13,9 @@ import { getAnchorElement } from './modules/getAnchorElement.js';
|
|
|
13
13
|
import { awaitAnimations } from './modules/awaitAnimations.js';
|
|
14
14
|
import { visit, performVisit, HistoryAction } from './modules/visit.js';
|
|
15
15
|
import { fetchPage } from './modules/fetchPage.js';
|
|
16
|
-
import {
|
|
16
|
+
import { animatePageOut } from './modules/animatePageOut.js';
|
|
17
17
|
import { replaceContent } from './modules/replaceContent.js';
|
|
18
|
-
import {
|
|
18
|
+
import { animatePageIn } from './modules/animatePageIn.js';
|
|
19
19
|
import { renderPage } from './modules/renderPage.js';
|
|
20
20
|
import { use, unuse, findPlugin, Plugin } from './modules/plugins.js';
|
|
21
21
|
import { nextTick } from './utils.js';
|
|
@@ -69,10 +69,10 @@ export default class Swup {
|
|
|
69
69
|
|
|
70
70
|
visit = visit;
|
|
71
71
|
performVisit = performVisit;
|
|
72
|
-
|
|
72
|
+
animatePageOut = animatePageOut;
|
|
73
73
|
renderPage = renderPage;
|
|
74
74
|
replaceContent = replaceContent;
|
|
75
|
-
|
|
75
|
+
animatePageIn = animatePageIn;
|
|
76
76
|
delegateEvent = delegateEvent;
|
|
77
77
|
fetchPage = fetchPage;
|
|
78
78
|
awaitAnimations = awaitAnimations;
|
|
@@ -148,14 +148,15 @@ export default class Swup {
|
|
|
148
148
|
// Modify initial history record
|
|
149
149
|
updateHistoryRecord(null, { index: 1 });
|
|
150
150
|
|
|
151
|
+
// Give consumers a chance to hook into enable and page:view
|
|
152
|
+
await nextTick();
|
|
153
|
+
|
|
151
154
|
// Trigger enable hook
|
|
152
155
|
await this.hooks.trigger('enable', undefined, () => {
|
|
153
156
|
// Add swup-enabled class to html tag
|
|
154
157
|
document.documentElement.classList.add('swup-enabled');
|
|
155
158
|
});
|
|
156
159
|
|
|
157
|
-
await nextTick();
|
|
158
|
-
|
|
159
160
|
// Trigger page view hook
|
|
160
161
|
await this.hooks.trigger('page:view', { url: this.currentPageUrl, title: document.title });
|
|
161
162
|
}
|
|
@@ -209,29 +210,12 @@ export default class Swup {
|
|
|
209
210
|
const el = event.delegateTarget as HTMLAnchorElement;
|
|
210
211
|
const { href, url, hash } = Location.fromElement(el);
|
|
211
212
|
|
|
212
|
-
// Get the animation name, if specified
|
|
213
|
-
const animation = el.getAttribute('data-swup-animation') || undefined;
|
|
214
|
-
|
|
215
|
-
// Get the history action, if specified
|
|
216
|
-
let historyAction: HistoryAction | undefined;
|
|
217
|
-
const historyAttr = el.getAttribute('data-swup-history');
|
|
218
|
-
if (historyAttr && ['push', 'replace'].includes(historyAttr)) {
|
|
219
|
-
historyAction = historyAttr as HistoryAction;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
213
|
// Exit early if the link should be ignored
|
|
223
214
|
if (this.shouldIgnoreVisit(href, { el, event })) {
|
|
224
215
|
return;
|
|
225
216
|
}
|
|
226
217
|
|
|
227
|
-
this.context = this.createContext({
|
|
228
|
-
to: url,
|
|
229
|
-
hash,
|
|
230
|
-
animation,
|
|
231
|
-
el,
|
|
232
|
-
event,
|
|
233
|
-
action: historyAction
|
|
234
|
-
});
|
|
218
|
+
this.context = this.createContext({ to: url, hash, el, event });
|
|
235
219
|
|
|
236
220
|
// Exit early if control key pressed
|
|
237
221
|
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
|
package/src/modules/Cache.ts
CHANGED
|
@@ -4,30 +4,41 @@ import { PageData } from './fetchPage.js';
|
|
|
4
4
|
|
|
5
5
|
export interface CacheData extends PageData {}
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* In-memory page cache.
|
|
9
|
+
*/
|
|
7
10
|
export class Cache {
|
|
11
|
+
/** Swup instance this cache belongs to */
|
|
8
12
|
private swup: Swup;
|
|
13
|
+
|
|
14
|
+
/** Cached pages, indexed by URL */
|
|
9
15
|
private pages: Map<string, CacheData> = new Map();
|
|
10
16
|
|
|
11
17
|
constructor(swup: Swup) {
|
|
12
18
|
this.swup = swup;
|
|
13
19
|
}
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
/** Number of cached pages in memory. */
|
|
22
|
+
get size(): number {
|
|
16
23
|
return this.pages.size;
|
|
17
24
|
}
|
|
18
25
|
|
|
26
|
+
/** All cached pages. */
|
|
19
27
|
get all() {
|
|
20
28
|
return this.pages;
|
|
21
29
|
}
|
|
22
30
|
|
|
31
|
+
/** Check if the given URL has been cached. */
|
|
23
32
|
public has(url: string): boolean {
|
|
24
33
|
return this.pages.has(this.resolve(url));
|
|
25
34
|
}
|
|
26
35
|
|
|
36
|
+
/** Return the cached page object if cached. */
|
|
27
37
|
public get(url: string): CacheData | undefined {
|
|
28
38
|
return this.pages.get(this.resolve(url));
|
|
29
39
|
}
|
|
30
40
|
|
|
41
|
+
/** Create a cache record for the specified URL. */
|
|
31
42
|
public set(url: string, page: CacheData) {
|
|
32
43
|
url = this.resolve(url);
|
|
33
44
|
page = { ...page, url };
|
|
@@ -35,21 +46,25 @@ export class Cache {
|
|
|
35
46
|
this.swup.hooks.triggerSync('cache:set', { page });
|
|
36
47
|
}
|
|
37
48
|
|
|
49
|
+
/** Update a cache record, overwriting or adding custom data. */
|
|
38
50
|
public update(url: string, page: CacheData) {
|
|
39
51
|
url = this.resolve(url);
|
|
40
52
|
page = { ...this.get(url), ...page, url };
|
|
41
53
|
this.pages.set(url, page);
|
|
42
54
|
}
|
|
43
55
|
|
|
56
|
+
/** Delete a cache record. */
|
|
44
57
|
public delete(url: string): void {
|
|
45
58
|
this.pages.delete(this.resolve(url));
|
|
46
59
|
}
|
|
47
60
|
|
|
61
|
+
/** Empty the cache. */
|
|
48
62
|
public clear(): void {
|
|
49
63
|
this.pages.clear();
|
|
50
64
|
this.swup.hooks.triggerSync('cache:clear');
|
|
51
65
|
}
|
|
52
66
|
|
|
67
|
+
/** Remove all cache entries that return true for a given predicate function. */
|
|
53
68
|
public prune(predicate: (url: string, page: CacheData) => boolean): void {
|
|
54
69
|
this.pages.forEach((page, url) => {
|
|
55
70
|
if (predicate(url, page)) {
|
|
@@ -58,6 +73,7 @@ export class Cache {
|
|
|
58
73
|
});
|
|
59
74
|
}
|
|
60
75
|
|
|
76
|
+
/** Resolve URLs by making them local and letting swup resolve them. */
|
|
61
77
|
private resolve(urlToResolve: string): string {
|
|
62
78
|
const { url } = Location.fromUrl(urlToResolve);
|
|
63
79
|
return this.swup.resolveUrl(url);
|
package/src/modules/Context.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Swup, { Options } from '../Swup.js';
|
|
2
2
|
import { HistoryAction, HistoryDirection } from './visit.js';
|
|
3
3
|
|
|
4
|
-
export interface Context
|
|
4
|
+
export interface Context {
|
|
5
5
|
/** The previous page, about to leave */
|
|
6
6
|
from: FromContext;
|
|
7
7
|
/** The next page, about to enter */
|
|
@@ -11,7 +11,7 @@ export interface Context<TEvent = Event> {
|
|
|
11
11
|
/** Information about animated page transitions */
|
|
12
12
|
animation: AnimationContext;
|
|
13
13
|
/** What triggered this visit */
|
|
14
|
-
trigger: TriggerContext
|
|
14
|
+
trigger: TriggerContext;
|
|
15
15
|
/** Browser history behavior on this visit */
|
|
16
16
|
history: HistoryContext;
|
|
17
17
|
/** Scroll behavior on this visit */
|
|
@@ -50,11 +50,11 @@ export interface ScrollContext {
|
|
|
50
50
|
target?: string;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export interface TriggerContext
|
|
53
|
+
export interface TriggerContext {
|
|
54
54
|
/** DOM element that triggered this visit. */
|
|
55
55
|
el?: Element;
|
|
56
56
|
/** DOM event that triggered this visit. */
|
|
57
|
-
event?:
|
|
57
|
+
event?: Event;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
export interface HistoryContext {
|
package/src/modules/Hooks.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DelegateEvent } from 'delegate-it';
|
|
2
2
|
|
|
3
|
-
import Swup
|
|
3
|
+
import Swup from '../Swup.js';
|
|
4
4
|
import { isPromise, runAsPromise } from '../utils.js';
|
|
5
5
|
import { Context } from './Context.js';
|
|
6
6
|
import { FetchOptions, PageData } from './fetchPage.js';
|
|
@@ -5,7 +5,7 @@ import { nextTick } from '../utils.js';
|
|
|
5
5
|
* Perform the in/enter animation of the next page.
|
|
6
6
|
* @returns Promise<void>
|
|
7
7
|
*/
|
|
8
|
-
export const
|
|
8
|
+
export const animatePageIn = async function (this: Swup) {
|
|
9
9
|
if (!this.context.animation.animate) {
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
@@ -5,7 +5,7 @@ import { classify } from '../helpers.js';
|
|
|
5
5
|
* Perform the out/leave animation of the current page.
|
|
6
6
|
* @returns Promise<void>
|
|
7
7
|
*/
|
|
8
|
-
export const
|
|
8
|
+
export const animatePageOut = async function (this: Swup) {
|
|
9
9
|
if (!this.context.animation.animate) {
|
|
10
10
|
await this.hooks.trigger('animation:skip');
|
|
11
11
|
return;
|
package/src/modules/visit.ts
CHANGED
|
@@ -58,21 +58,28 @@ export async function performVisit(
|
|
|
58
58
|
throw new Error(`swup.visit() requires a URL parameter`);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
const { el } = this.context.trigger;
|
|
61
62
|
this.context.to.url = Location.fromUrl(url).url;
|
|
62
|
-
const { animation, animate, history: historyAction } = options;
|
|
63
63
|
options.referrer = options.referrer || this.currentPageUrl;
|
|
64
64
|
|
|
65
|
-
if (animate === false) {
|
|
65
|
+
if (options.animate === false) {
|
|
66
66
|
this.context.animation.animate = false;
|
|
67
67
|
}
|
|
68
|
-
if (historyAction) {
|
|
69
|
-
this.context.history.action = historyAction;
|
|
70
|
-
}
|
|
71
68
|
|
|
72
|
-
// Clean up old animation classes
|
|
69
|
+
// Clean up old animation classes
|
|
73
70
|
if (!this.context.animation.animate) {
|
|
74
71
|
this.classes.clear();
|
|
75
|
-
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Get history action from option or attribute on trigger element
|
|
75
|
+
const history = options.history || el?.getAttribute('data-swup-history') || undefined;
|
|
76
|
+
if (history && ['push', 'replace'].includes(history)) {
|
|
77
|
+
this.context.history.action = history as HistoryAction;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Get custom animation name from option or attribute on trigger element
|
|
81
|
+
const animation = options.animation || el?.getAttribute('data-swup-animation') || undefined;
|
|
82
|
+
if (animation) {
|
|
76
83
|
this.context.animation.name = animation;
|
|
77
84
|
}
|
|
78
85
|
|
|
@@ -106,14 +113,14 @@ export async function performVisit(
|
|
|
106
113
|
}
|
|
107
114
|
|
|
108
115
|
// Wait for page to load and leave animation to finish
|
|
109
|
-
const animationPromise = this.
|
|
116
|
+
const animationPromise = this.animatePageOut();
|
|
110
117
|
const [page] = await Promise.all([pagePromise, animationPromise]);
|
|
111
118
|
|
|
112
119
|
// Render page: replace content and scroll to top/fragment
|
|
113
120
|
await this.renderPage(this.context.to.url, page);
|
|
114
121
|
|
|
115
122
|
// Wait for enter animation
|
|
116
|
-
await this.
|
|
123
|
+
await this.animatePageIn();
|
|
117
124
|
|
|
118
125
|
// Finalize visit
|
|
119
126
|
await this.hooks.trigger('visit:end', undefined, () => this.classes.clear());
|
|
@@ -138,6 +145,6 @@ export async function performVisit(
|
|
|
138
145
|
};
|
|
139
146
|
|
|
140
147
|
// Go back to the actual page we're still at
|
|
141
|
-
history.go(-1);
|
|
148
|
+
window.history.go(-1);
|
|
142
149
|
}
|
|
143
150
|
}
|
package/src/utils/index.ts
CHANGED
|
@@ -38,6 +38,16 @@ export function runAsPromise(func: Function, args: any[] = [], ctx: any = {}): P
|
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Force a layout reflow, e.g. after adding classnames
|
|
43
|
+
* @returns The offset height, just here so it doesn't get optimized away by the JS engine
|
|
44
|
+
* @see https://stackoverflow.com/a/21665117/3759615
|
|
45
|
+
*/
|
|
46
|
+
export function forceReflow(element?: HTMLElement) {
|
|
47
|
+
element = element || document.body;
|
|
48
|
+
return element?.offsetHeight;
|
|
49
|
+
}
|
|
50
|
+
|
|
41
51
|
export const escapeCssIdentifier = (ident: string) => {
|
|
42
52
|
// @ts-ignore this is for support check, so it's correct that TS complains
|
|
43
53
|
if (window.CSS && window.CSS.escape) {
|