swup 4.2.0 → 4.3.1

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.
Files changed (66) hide show
  1. package/dist/Swup.cjs +1 -1
  2. package/dist/Swup.cjs.map +1 -1
  3. package/dist/Swup.modern.js +1 -1
  4. package/dist/Swup.modern.js.map +1 -1
  5. package/dist/Swup.module.js +1 -1
  6. package/dist/Swup.module.js.map +1 -1
  7. package/dist/Swup.umd.js +1 -1
  8. package/dist/Swup.umd.js.map +1 -1
  9. package/dist/types/Swup.d.ts +119 -119
  10. package/dist/types/__test__/index.test.d.ts +1 -1
  11. package/dist/types/config/version.d.ts +5 -5
  12. package/dist/types/helpers/Location.d.ts +24 -24
  13. package/dist/types/helpers/__test__/matchPath.test.d.ts +1 -1
  14. package/dist/types/helpers/classify.d.ts +2 -2
  15. package/dist/types/helpers/createHistoryRecord.d.ts +9 -2
  16. package/dist/types/helpers/delegateEvent.d.ts +7 -7
  17. package/dist/types/helpers/getCurrentUrl.d.ts +4 -4
  18. package/dist/types/helpers/matchPath.d.ts +4 -4
  19. package/dist/types/helpers/updateHistoryRecord.d.ts +2 -2
  20. package/dist/types/helpers.d.ts +7 -7
  21. package/dist/types/index.d.ts +14 -14
  22. package/dist/types/modules/Cache.d.ts +34 -34
  23. package/dist/types/modules/Classes.d.ts +13 -13
  24. package/dist/types/modules/Hooks.d.ts +268 -250
  25. package/dist/types/modules/Visit.d.ts +80 -77
  26. package/dist/types/modules/__test__/cache.test.d.ts +1 -1
  27. package/dist/types/modules/__test__/{delegateEvent.d.ts → delegateEvent.test.d.ts} +1 -1
  28. package/dist/types/modules/__test__/hooks.test.d.ts +1 -1
  29. package/dist/types/modules/__test__/plugins.test.d.ts +1 -1
  30. package/dist/types/modules/__test__/replaceContent.test.d.ts +1 -1
  31. package/dist/types/modules/animatePageIn.d.ts +6 -6
  32. package/dist/types/modules/animatePageOut.d.ts +6 -6
  33. package/dist/types/modules/awaitAnimations.d.ts +19 -19
  34. package/dist/types/modules/fetchPage.d.ts +27 -29
  35. package/dist/types/modules/getAnchorElement.d.ts +9 -9
  36. package/dist/types/modules/navigate.d.ts +41 -35
  37. package/dist/types/modules/plugins.d.ts +26 -26
  38. package/dist/types/modules/renderPage.d.ts +7 -7
  39. package/dist/types/modules/replaceContent.d.ts +13 -13
  40. package/dist/types/modules/resolveUrl.d.ts +14 -14
  41. package/dist/types/modules/scrollToContent.d.ts +6 -6
  42. package/dist/types/utils/index.d.ts +20 -20
  43. package/dist/types/utils.d.ts +1 -1
  44. package/package.json +9 -3
  45. package/src/Swup.ts +26 -17
  46. package/src/config/version.ts +1 -2
  47. package/src/helpers/createHistoryRecord.ts +9 -1
  48. package/src/helpers/matchPath.ts +1 -1
  49. package/src/helpers/updateHistoryRecord.ts +4 -2
  50. package/src/modules/Cache.ts +2 -2
  51. package/src/modules/Classes.ts +1 -1
  52. package/src/modules/Hooks.ts +91 -39
  53. package/src/modules/Visit.ts +19 -21
  54. package/src/modules/__test__/cache.test.ts +3 -3
  55. package/src/modules/__test__/hooks.test.ts +12 -13
  56. package/src/modules/animatePageIn.ts +1 -1
  57. package/src/modules/animatePageOut.ts +2 -2
  58. package/src/modules/awaitAnimations.ts +1 -1
  59. package/src/modules/fetchPage.ts +7 -5
  60. package/src/modules/navigate.ts +23 -4
  61. package/src/modules/plugins.ts +3 -3
  62. package/src/modules/renderPage.ts +1 -5
  63. package/src/modules/replaceContent.ts +13 -0
  64. package/src/modules/scrollToContent.ts +1 -1
  65. package/src/utils/index.ts +5 -4
  66. /package/src/modules/__test__/{delegateEvent.ts → delegateEvent.test.ts} +0 -0
@@ -10,13 +10,11 @@ export interface PageData {
10
10
  }
11
11
 
12
12
  /** Define how a page is fetched. */
13
- export interface FetchOptions extends RequestInit {
13
+ export interface FetchOptions extends Omit<RequestInit, 'cache'> {
14
14
  /** The request method. */
15
15
  method?: 'GET' | 'POST';
16
16
  /** The body of the request: raw string, form data object or URL params. */
17
17
  body?: string | FormData | URLSearchParams;
18
- /** The headers of the request: key/value object. */
19
- headers?: Record<string, string>;
20
18
  }
21
19
 
22
20
  export class FetchError extends Error {
@@ -66,8 +64,12 @@ export async function fetchPage(
66
64
  const { url: finalUrl } = Location.fromUrl(responseUrl);
67
65
  const page = { url: finalUrl, html };
68
66
 
69
- // Only save cache entry for non-redirects
70
- if (url === finalUrl) {
67
+ // Write to cache for safe methods and non-redirects
68
+ if (
69
+ this.visit.cache.write &&
70
+ (!options.method || options.method === 'GET') &&
71
+ url === finalUrl
72
+ ) {
71
73
  this.cache.set(page.url, page);
72
74
  }
73
75
 
@@ -1,11 +1,12 @@
1
1
  import Swup from '../Swup.js';
2
2
  import { createHistoryRecord, updateHistoryRecord, getCurrentUrl, Location } from '../helpers.js';
3
- import { FetchOptions } from './fetchPage.js';
3
+ import { FetchOptions, PageData } from './fetchPage.js';
4
4
  import { VisitInitOptions } from './Visit.js';
5
5
 
6
6
  export type HistoryAction = 'push' | 'replace';
7
7
  export type HistoryDirection = 'forwards' | 'backwards';
8
8
  export type NavigationToSelfAction = 'scroll' | 'navigate';
9
+ export type CacheControl = Partial<{ read: boolean; write: boolean }>;
9
10
 
10
11
  /** Define how to navigate to a page. */
11
12
  type NavigationOptions = {
@@ -15,6 +16,8 @@ type NavigationOptions = {
15
16
  animation?: string;
16
17
  /** History action to perform: `push` for creating a new history entry, `replace` for replacing the current entry. Default: `push` */
17
18
  history?: HistoryAction;
19
+ /** Whether this visit should read from or write to the cache. */
20
+ cache?: CacheControl;
18
21
  };
19
22
 
20
23
  /**
@@ -83,14 +86,30 @@ export async function performNavigation(
83
86
  this.visit.animation.name = animation;
84
87
  }
85
88
 
89
+ // Sanitize cache option
90
+ if (typeof options.cache === 'object') {
91
+ this.visit.cache.read = options.cache.read ?? this.visit.cache.read;
92
+ this.visit.cache.write = options.cache.write ?? this.visit.cache.write;
93
+ } else if (options.cache !== undefined) {
94
+ this.visit.cache = { read: !!options.cache, write: !!options.cache };
95
+ }
96
+ // Delete this so that window.fetch doesn't mis-interpret it
97
+ delete options.cache;
98
+
86
99
  try {
87
- await this.hooks.call('visit:start');
100
+ await this.hooks.call('visit:start', undefined);
88
101
 
89
102
  // Begin loading page
90
103
  const pagePromise = this.hooks.call('page:load', { options }, async (visit, args) => {
91
- const cachedPage = this.cache.get(visit.to.url!);
92
- args.page = cachedPage || (await this.fetchPage(visit.to.url!, args.options));
104
+ // Read from cache
105
+ let cachedPage: PageData | undefined;
106
+ if (this.visit.cache.read) {
107
+ cachedPage = this.cache.get(visit.to.url);
108
+ }
109
+
110
+ args.page = cachedPage || (await this.fetchPage(visit.to.url, args.options));
93
111
  args.cache = !!cachedPage;
112
+
94
113
  return args.page;
95
114
  });
96
115
 
@@ -21,8 +21,8 @@ export type Plugin = {
21
21
  };
22
22
 
23
23
  const isSwupPlugin = (maybeInvalidPlugin: unknown): maybeInvalidPlugin is Plugin => {
24
- // @ts-ignore
25
- return maybeInvalidPlugin?.isSwupPlugin;
24
+ // @ts-ignore: this might be anything, object or no
25
+ return Boolean(maybeInvalidPlugin?.isSwupPlugin);
26
26
  };
27
27
 
28
28
  /** Install a plugin. */
@@ -72,6 +72,6 @@ export function findPlugin(this: Swup, pluginOrName: Plugin | string) {
72
72
  (plugin) =>
73
73
  plugin === pluginOrName ||
74
74
  plugin.name === pluginOrName ||
75
- plugin.name === `Swup${pluginOrName}`
75
+ plugin.name === `Swup${String(pluginOrName)}`
76
76
  );
77
77
  }
@@ -47,14 +47,10 @@ export const renderPage = async function (this: Swup, requestedUrl: string, page
47
47
  });
48
48
 
49
49
  // scroll into view: either anchor or top of page
50
+ // @ts-ignore: not returning a promise is intentional to allow users to pause in handler
50
51
  await this.hooks.call('content:scroll', undefined, () => {
51
52
  return this.scrollToContent();
52
53
  });
53
54
 
54
55
  await this.hooks.call('page:view', { url: this.currentPageUrl, title: document.title });
55
-
56
- // empty cache if it's disabled (in case preload plugin filled it)
57
- if (!this.options.cache) {
58
- this.cache.clear();
59
- }
60
56
  };
@@ -1,4 +1,5 @@
1
1
  import Swup, { Options } from '../Swup.js';
2
+ import { query, queryAll } from '../utils.js';
2
3
  import { PageData } from './fetchPage.js';
3
4
 
4
5
  /**
@@ -20,6 +21,9 @@ export const replaceContent = function (
20
21
  const title = incomingDocument.querySelector('title')?.innerText || '';
21
22
  document.title = title;
22
23
 
24
+ // Save persisted elements
25
+ const persistedElements = queryAll('[data-swup-persist]:not([data-swup-persist=""])');
26
+
23
27
  // Update content containers
24
28
  const replaced = containers
25
29
  .map((selector) => {
@@ -39,5 +43,14 @@ export const replaceContent = function (
39
43
  })
40
44
  .filter(Boolean);
41
45
 
46
+ // Restore persisted elements
47
+ persistedElements.forEach((existing) => {
48
+ const key = existing.getAttribute('data-swup-persist');
49
+ const replacement = query(`[data-swup-persist="${key}"]`);
50
+ if (replacement && replacement !== existing) {
51
+ replacement.replaceWith(existing);
52
+ }
53
+ });
54
+
42
55
  return replaced.length === containers.length;
43
56
  };
@@ -7,7 +7,7 @@ import Swup from '../Swup.js';
7
7
  export const scrollToContent = function (this: Swup): boolean {
8
8
  const options: ScrollIntoViewOptions = { behavior: 'auto' };
9
9
  const { target, reset } = this.visit.scroll;
10
- const scrollTarget = target || this.visit.to.hash;
10
+ const scrollTarget = target ?? this.visit.to.hash;
11
11
 
12
12
  let scrolled = false;
13
13
 
@@ -23,18 +23,19 @@ export const nextTick = (): Promise<void> => {
23
23
  };
24
24
 
25
25
  /** Check if an object is a Promise or a Thenable */
26
- export function isPromise<T>(obj: any): obj is PromiseLike<T> {
26
+ export function isPromise<T>(obj: unknown): obj is PromiseLike<T> {
27
27
  return (
28
28
  !!obj &&
29
29
  (typeof obj === 'object' || typeof obj === 'function') &&
30
- typeof obj.then === 'function'
30
+ typeof (obj as Record<string, unknown>).then === 'function'
31
31
  );
32
32
  }
33
33
 
34
34
  /** Call a function as a Promise. Resolves with the returned Promsise or immediately. */
35
- export function runAsPromise(func: Function, args: any[] = []): Promise<any> {
35
+ // eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any
36
+ export function runAsPromise(func: Function, args: unknown[] = []): Promise<unknown> {
36
37
  return new Promise((resolve, reject) => {
37
- const result = func(...args);
38
+ const result: unknown = func(...args);
38
39
  if (isPromise(result)) {
39
40
  result.then(resolve, reject);
40
41
  } else {