Skip to content

Commit

Permalink
Merge pull request #841 from swup/develop
Browse files Browse the repository at this point in the history
Merge develop
  • Loading branch information
daun committed Dec 1, 2023
2 parents 80d3f33 + 8a65783 commit 749eb10
Show file tree
Hide file tree
Showing 41 changed files with 819 additions and 313 deletions.
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## [4.5.0] - 2023-12

- Support View Transitions API in new native mode
- Handle rapid link clicks to achieve smooth transitions
- Abort superseded visits with new `visit:abort` hook

## [4.4.4] - 2023-11-17

- Dispatch DOM event `swup:any` every time a hook is run
Expand All @@ -20,7 +26,7 @@

## [4.4.0] - 2023-09-19

- Enable experimental `ViewTransition` support
- Enable experimental View Transition support
- Extend test coverage to all major browsers
- Add request timeout option

Expand Down Expand Up @@ -189,6 +195,7 @@ See [upgrade instructions](https://swup.js.org/getting-started/upgrading-v3/) fo

- Fix bug where animateHistoryBrowsing option was ignored for OUT animations

[4.5.0]: https://github.com/swup/swup/releases/tag/4.5.0
[4.4.4]: https://github.com/swup/swup/releases/tag/4.4.4
[4.4.3]: https://github.com/swup/swup/releases/tag/4.4.3
[4.4.2]: https://github.com/swup/swup/releases/tag/4.4.3
Expand Down
11 changes: 9 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "swup",
"amdName": "Swup",
"version": "4.4.4",
"version": "4.5.0",
"description": "Versatile and extensible page transition library for server-rendered websites",
"type": "module",
"source": "./src/Swup.ts",
Expand Down Expand Up @@ -67,6 +67,7 @@
"@playwright/test": "^1.37.1",
"@swup/browserslist-config": "^1.0.0",
"@swup/prettier-config": "^1.0.0",
"@types/dom-view-transitions": "^1.0.2",
"@types/jsdom": "^21.1.1",
"@typescript-eslint/eslint-plugin": "^6.3.0",
"@typescript-eslint/parser": "^6.3.0",
Expand Down
77 changes: 40 additions & 37 deletions src/Swup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { renderPage } from './modules/renderPage.js';
import { use, unuse, findPlugin, type Plugin } from './modules/plugins.js';
import { isSameResolvedUrl, resolveUrl } from './modules/resolveUrl.js';
import { nextTick } from './utils.js';
import { type HistoryState } from './helpers/createHistoryRecord.js';
import { type HistoryState } from './helpers/history.js';

/** Options for customizing swup's behavior. */
export type Options = {
Expand All @@ -41,6 +41,8 @@ export type Options = {
linkSelector: string;
/** How swup handles links to the same page. Default: `scroll` */
linkToSelf: NavigationToSelfAction;
/** Enable native animations using the View Transitions API. */
native: boolean;
/** Plugins to register on startup. */
plugins: Plugin[];
/** Custom headers sent along with fetch requests. */
Expand All @@ -62,6 +64,7 @@ const defaults: Options = {
ignoreVisit: (url, { el } = {}) => !!el?.closest('[data-no-swup]'),
linkSelector: 'a[href]',
linkToSelf: 'scroll',
native: false,
plugins: [],
resolveUrl: (url) => url,
requestHeaders: {
Expand Down Expand Up @@ -98,6 +101,8 @@ export default class Swup {
protected clickDelegate?: DelegateEventUnsubscribe;
/** Navigation status */
protected navigating: boolean = false;
/** Run anytime a visit ends */
protected onVisitEnd?: () => Promise<unknown>;

/** Install a plugin */
use = use;
Expand Down Expand Up @@ -185,6 +190,9 @@ export default class Swup {
// https://github.com/swup/swup/issues/475
}

// Sanitize/check native option
this.options.native = this.options.native && !!document.startViewTransition;

// Mount plugins
this.options.plugins.forEach((plugin) => this.use(plugin));

Expand All @@ -197,9 +205,10 @@ export default class Swup {
await nextTick();

// Trigger enable hook
await this.hooks.call('enable', undefined, () => {
// Add swup-enabled class to html tag
document.documentElement.classList.add('swup-enabled');
await this.hooks.call('enable', undefined, undefined, () => {
const html = document.documentElement;
html.classList.add('swup-enabled');
html.classList.toggle('swup-native', this.options.native);
});
}

Expand All @@ -218,9 +227,10 @@ export default class Swup {
this.options.plugins.forEach((plugin) => this.unuse(plugin));

// trigger disable hook
await this.hooks.call('disable', undefined, () => {
// remove swup-enabled class from html tag
document.documentElement.classList.remove('swup-enabled');
await this.hooks.call('disable', undefined, undefined, () => {
const html = document.documentElement;
html.classList.remove('swup-enabled');
html.classList.remove('swup-native');
});

// remove handlers
Expand Down Expand Up @@ -265,11 +275,11 @@ export default class Swup {
return;
}

this.visit = this.createVisit({ to: url, hash, el, event });
const visit = this.createVisit({ to: url, hash, el, event });

// Exit early if control key pressed
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
this.hooks.call('link:newtab', { href });
this.hooks.callSync('link:newtab', visit, { href });
return;
}

Expand All @@ -278,29 +288,27 @@ export default class Swup {
return;
}

this.hooks.callSync('link:click', { el, event }, () => {
const from = this.visit.from.url ?? '';
this.hooks.callSync('link:click', visit, { el, event }, () => {
const from = visit.from.url ?? '';

event.preventDefault();

// Handle links to the same page
if (!url || url === from) {
if (hash) {
// With hash: scroll to anchor
this.hooks.callSync('link:anchor', { hash }, () => {
this.hooks.callSync('link:anchor', visit, { hash }, () => {
updateHistoryRecord(url + hash);
this.scrollToContent();
this.scrollToContent(visit);
});
} else {
// Without hash: scroll to top or load/reload page
this.hooks.callSync('link:self', undefined, () => {
switch (this.options.linkToSelf) {
case 'navigate':
return this.performNavigation();
case 'scroll':
default:
updateHistoryRecord(url);
return this.scrollToContent();
this.hooks.callSync('link:self', visit, undefined, () => {
if (this.options.linkToSelf === 'navigate') {
this.performNavigation(visit);
} else {
updateHistoryRecord(url);
this.scrollToContent(visit);
}
});
}
Expand All @@ -313,7 +321,7 @@ export default class Swup {
}

// Finally, proceed with loading the page
this.performNavigation();
this.performNavigation(visit);
});
}

Expand All @@ -332,37 +340,32 @@ export default class Swup {

const { url, hash } = Location.fromUrl(href);

this.visit = this.createVisit({ to: url, hash, event });
const visit = this.createVisit({ to: url, hash, event });

// Mark as history visit
this.visit.history.popstate = true;
visit.history.popstate = true;

// Determine direction of history visit
const index = (event.state as HistoryState)?.index ?? 0;
if (index && index !== this.currentHistoryIndex) {
const direction = index - this.currentHistoryIndex > 0 ? 'forwards' : 'backwards';
this.visit.history.direction = direction;
visit.history.direction = direction;
this.currentHistoryIndex = index;
}

// Disable animation & scrolling for history visits
this.visit.animation.animate = false;
this.visit.scroll.reset = false;
this.visit.scroll.target = false;
visit.animation.animate = false;
visit.scroll.reset = false;
visit.scroll.target = false;

// Animated history visit: re-enable animation & scroll reset
if (this.options.animateHistoryBrowsing) {
this.visit.animation.animate = true;
this.visit.scroll.reset = true;
visit.animation.animate = true;
visit.scroll.reset = true;
}

// Does this even do anything?
// if (!hash) {
// event.preventDefault();
// }

this.hooks.callSync('history:popstate', { event }, () => {
this.performNavigation();
this.hooks.callSync('history:popstate', visit, { event }, () => {
this.performNavigation(visit);
});
}

Expand Down
3 changes: 1 addition & 2 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
// e.g. import { updateHistoryRecord } from 'swup'

export { classify } from './helpers/classify.js';
export { createHistoryRecord } from './helpers/createHistoryRecord.js';
export { updateHistoryRecord } from './helpers/updateHistoryRecord.js';
export { createHistoryRecord, updateHistoryRecord } from './helpers/history.js';
export { delegateEvent } from './helpers/delegateEvent.js';
export { getCurrentUrl } from './helpers/getCurrentUrl.js';
export { Location } from './helpers/Location.js';
Expand Down
1 change: 1 addition & 0 deletions src/helpers/Location.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
export class Location extends URL {
constructor(url: URL | string, base: string = document.baseURI) {
super(url.toString(), base);
// Fix Safari bug with extending native classes
Object.setPrototypeOf(this, Location.prototype);
}

Expand Down
24 changes: 0 additions & 24 deletions src/helpers/createHistoryRecord.ts

This file was deleted.

37 changes: 37 additions & 0 deletions src/helpers/history.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { getCurrentUrl } from './getCurrentUrl.js';

export interface HistoryState {
url: string;
source: 'swup';
random: number;
index?: number;
[key: string]: unknown;
}

type HistoryData = Record<string, unknown>;

/** Create a new history record with a custom swup identifier. */
export const createHistoryRecord = (url: string, data: HistoryData = {}): void => {
url = url || getCurrentUrl({ hash: true });
const state: HistoryState = {
url,
random: Math.random(),
source: 'swup',
...data
};
history.pushState(state, '', url);
};

/** Update the current history record with a custom swup identifier. */
export const updateHistoryRecord = (url: string | null = null, data: HistoryData = {}): void => {
url = url || getCurrentUrl({ hash: true });
const currentState = (history.state as HistoryState) || {};
const state: HistoryState = {
...currentState,
url,
random: Math.random(),
source: 'swup',
...data
};
history.replaceState(state, '', url);
};
19 changes: 0 additions & 19 deletions src/helpers/updateHistoryRecord.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/modules/Cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class Cache {
url = this.resolve(url);
page = { ...page, url };
this.pages.set(url, page);
this.swup.hooks.callSync('cache:set', { page });
this.swup.hooks.callSync('cache:set', undefined, { page });
}

/** Update a cache record, overwriting or adding custom data. */
Expand All @@ -67,7 +67,7 @@ export class Cache {
/** Empty the cache. */
clear(): void {
this.pages.clear();
this.swup.hooks.callSync('cache:clear', undefined);
this.swup.hooks.callSync('cache:clear', undefined, undefined);
}

/** Remove all cache entries that return true for a given predicate function. */
Expand Down

0 comments on commit 749eb10

Please sign in to comment.