Repository: swup/swup
Pull request #734 (2023-07-20 21:06:41)

Visit context
**Description**

- Rename object `this.context` to `this.visit`
- Rename method `swup.visit()` to `swup.navigate()`

**Checks**

- [x] The PR is submitted to the `next` branch
- [x] The code was linted before pushing (`npm run lint`)
- [x] All tests are passing (`npm run test`)
- [ ] ~~New or updated tests are included~~
- [ ] The documentation was updated as required



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 086192a..65cfb78 100755
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,7 +18,7 @@ See the [release notes](https://swup.js.org/announcements/swup-4/) and
 - New hook system: `swup.hooks.on('page:view', () => {})`
 - Container selectors now only match a single element per selector
 - Custom animation attribute renamed to `data-swup-animation`
-- Navigation method renamed: `swup.visit(url)`
+- Navigation method renamed: `swup.navigate(url)`
 - Swup no longer adds `data-swup` attributes to containers
 - Use the global context instead of the `swup.transition` object
 - Simplified cache API: `cache.set(url, {})` and `cache.get(url)`
diff --git a/cypress/fixtures/plugins/body-class-plugin-1.html b/cypress/fixtures/plugins/body-class-plugin-1.html
index 1b175b6..66c38e1 100644
--- a/cypress/fixtures/plugins/body-class-plugin-1.html
+++ b/cypress/fixtures/plugins/body-class-plugin-1.html
@@ -29,7 +29,7 @@
             name = 'CustomBodyClassPlugin';
             isSwupPlugin = true;
             mount() {
-                this.swup.hooks.on('content:replace', (context, { page: { html } }) => {
+                this.swup.hooks.on('content:replace', (visit, { page: { html } }) => {
                     const doc = new DOMParser().parseFromString(html, 'text/html');
                     const body = doc.querySelector('body');
                     if (body) {
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
index 33d4102..43c6384 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.js
@@ -119,7 +119,7 @@ Cypress.Commands.add('shouldAnimateWithDuration', function (durationInMs, url =
 		this.swup.hooks.on('animation:skip', () => (durationIn = 0));
 		this.swup.hooks.on('animation:skip', () => (durationOut = 0));
 		url = url || window.location.href;
-		this.swup.visit(url);
+		this.swup.navigate(url);
 	});
 
 	cy.window().should(() => {
diff --git a/src/Swup.ts b/src/Swup.ts
index 0f4e030..55ca199 100644
--- a/src/Swup.ts
+++ b/src/Swup.ts
@@ -7,11 +7,11 @@ import { DelegateEventUnsubscribe } from './helpers/delegateEvent.js';
 
 import { Cache } from './modules/Cache.js';
 import { Classes } from './modules/Classes.js';
-import { Context, createContext } from './modules/Context.js';
+import { Visit, createVisit } from './modules/Visit.js';
 import { Hooks } from './modules/Hooks.js';
 import { getAnchorElement } from './modules/getAnchorElement.js';
 import { awaitAnimations } from './modules/awaitAnimations.js';
-import { visit, performVisit, HistoryAction } from './modules/visit.js';
+import { navigate, performNavigation } from './modules/navigate.js';
 import { fetchPage } from './modules/fetchPage.js';
 import { animatePageOut } from './modules/animatePageOut.js';
 import { replaceContent } from './modules/replaceContent.js';
@@ -52,8 +52,8 @@ export default class Swup {
 	options: Options;
 	/** Registered plugin instances */
 	plugins: Plugin[] = [];
-	/** Global context of the current visit */
-	context: Context;
+	/** Data about the current visit */
+	visit: Visit;
 	/** Cache instance */
 	cache: Cache;
 	/** Hook registry */
@@ -67,8 +67,8 @@ export default class Swup {
 	/** Delegated event subscription handle */
 	private clickDelegate?: DelegateEventUnsubscribe;
 
-	visit = visit;
-	performVisit = performVisit;
+	navigate = navigate;
+	performNavigation = performNavigation;
 	animatePageOut = animatePageOut;
 	renderPage = renderPage;
 	replaceContent = replaceContent;
@@ -81,7 +81,7 @@ export default class Swup {
 	unuse = unuse;
 	findPlugin = findPlugin;
 	getCurrentUrl = getCurrentUrl;
-	createContext = createContext;
+	createVisit = createVisit;
 	log: (message: string, context?: any) => void = () => {}; // here so it can be used by plugins
 
 	/** Default options before merging user options */
@@ -112,7 +112,7 @@ export default class Swup {
 		this.cache = new Cache(this);
 		this.classes = new Classes(this);
 		this.hooks = new Hooks(this);
-		this.context = this.createContext({ to: undefined });
+		this.visit = this.createVisit({ to: undefined });
 
 		if (!this.checkRequirements()) {
 			return;
@@ -215,7 +215,7 @@ export default class Swup {
 			return;
 		}
 
-		this.context = this.createContext({ to: url, hash, el, event });
+		this.visit = this.createVisit({ to: url, hash, el, event });
 
 		// Exit early if control key pressed
 		if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
@@ -229,7 +229,7 @@ export default class Swup {
 		}
 
 		this.hooks.callSync('link:click', { el, event }, () => {
-			const from = this.context.from.url ?? '';
+			const from = this.visit.from.url ?? '';
 
 			event.preventDefault();
 
@@ -240,7 +240,7 @@ export default class Swup {
 					this.hooks.callSync(
 						'link:anchor',
 						{ hash, options: { behavior: 'auto' } },
-						(context, { hash, options }) => {
+						(visit, { hash, options }) => {
 							const target = this.getAnchorElement(hash);
 							if (target) {
 								target.scrollIntoView(options);
@@ -248,8 +248,8 @@ export default class Swup {
 						}
 					);
 				} else {
-					this.hooks.callSync('link:self', undefined, (context) => {
-						if (!context.scroll.reset) return;
+					this.hooks.callSync('link:self', undefined, (visit) => {
+						if (!visit.scroll.reset) return;
 						window.scroll({ top: 0, left: 0, behavior: 'auto' });
 					});
 				}
@@ -262,7 +262,7 @@ export default class Swup {
 			}
 
 			// Finally, proceed with loading the page
-			this.performVisit(url);
+			this.performNavigation(url);
 		});
 	}
 
@@ -295,7 +295,7 @@ export default class Swup {
 		const animate = this.options.animateHistoryBrowsing;
 		const resetScroll = this.options.animateHistoryBrowsing;
 
-		this.context = this.createContext({
+		this.visit = this.createVisit({
 			to: url,
 			hash,
 			event,
@@ -304,13 +304,13 @@ export default class Swup {
 		});
 
 		// Mark as popstate visit
-		this.context.history.popstate = true;
+		this.visit.history.popstate = true;
 
 		// Determine direction of history visit
 		const index = Number(event.state?.index);
 		if (index) {
 			const direction = index - this.currentHistoryIndex > 0 ? 'forwards' : 'backwards';
-			this.context.history.direction = direction;
+			this.visit.history.direction = direction;
 		}
 
 		// Does this even do anything?
@@ -319,7 +319,7 @@ export default class Swup {
 		// }
 
 		this.hooks.callSync('history:popstate', { event }, () => {
-			this.performVisit(url);
+			this.performNavigation(url);
 		});
 	}
 
diff --git a/src/index.ts b/src/index.ts
index 0cea7fa..b63eb86 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -3,13 +3,13 @@ import type { Path } from 'path-to-regexp';
 import Swup, { type Options } from './Swup.js';
 import type { CacheData } from './modules/Cache.js';
 import type {
-	Context,
-	FromContext,
-	ToContext,
-	AnimationContext,
-	ScrollContext,
-	HistoryContext
-} from './modules/Context.js';
+	Visit,
+	VisitFrom,
+	VisitTo,
+	VisitAnimation,
+	VisitScroll,
+	VisitHistory
+} from './modules/Visit.js';
 import type {
 	HookDefinitions,
 	HookName,
@@ -28,12 +28,12 @@ export type {
 	Options,
 	Plugin,
 	CacheData,
-	Context,
-	FromContext,
-	ToContext,
-	AnimationContext,
-	ScrollContext,
-	HistoryContext,
+	Visit,
+	VisitFrom,
+	VisitTo,
+	VisitAnimation,
+	VisitScroll,
+	VisitHistory,
 	HookDefinitions,
 	HookName,
 	HookOptions,
diff --git a/src/modules/Classes.ts b/src/modules/Classes.ts
index 9158eac..11b780d 100644
--- a/src/modules/Classes.ts
+++ b/src/modules/Classes.ts
@@ -11,8 +11,8 @@ export class Classes {
 	}
 
 	get selectors(): string[] {
-		const { scope } = this.swup.context.animation;
-		if (scope === 'containers') return this.swup.context.containers;
+		const { scope } = this.swup.visit.animation;
+		if (scope === 'containers') return this.swup.visit.containers;
 		if (scope === 'html') return ['html'];
 		if (Array.isArray(scope)) return scope;
 		return [];
diff --git a/src/modules/Hooks.ts b/src/modules/Hooks.ts
index 41a7b57..c7622cd 100644
--- a/src/modules/Hooks.ts
+++ b/src/modules/Hooks.ts
@@ -2,7 +2,7 @@ import { DelegateEvent } from 'delegate-it';
 
 import Swup from '../Swup.js';
 import { isPromise, runAsPromise } from '../utils.js';
-import { Context } from './Context.js';
+import { Visit } from './Visit.js';
 import { FetchOptions, PageData } from './fetchPage.js';
 
 export interface HookDefinitions {
@@ -38,11 +38,11 @@ export type HookArguments<T extends HookName> = HookDefinitions[T];
 export type HookName = keyof HookDefinitions;
 
 export type Handler<T extends HookName> = (
-	/** The global context object for the current visit */
-	context: Context,
-	/** The local arguments passed into the handler */
+	/** Context about the current visit */
+	visit: Visit,
+	/** Local arguments passed into the handler */
 	args: HookArguments<T>,
-	/** The default handler to be executed, available if replacing an internal hook handler */
+	/** Default handler to be executed, available if replacing an internal hook handler */
 	defaultHandler?: Handler<T>
 ) => Promise<any> | void;
 
@@ -324,7 +324,7 @@ export class Hooks {
 	): Promise<any> {
 		const results = [];
 		for (const { hook, handler, defaultHandler, once } of registrations) {
-			const result = await runAsPromise(handler, [this.swup.context, args, defaultHandler]);
+			const result = await runAsPromise(handler, [this.swup.visit, args, defaultHandler]);
 			results.push(result);
 			if (once) {
 				this.off(hook, handler);
@@ -344,7 +344,7 @@ export class Hooks {
 	): any[] {
 		const results = [];
 		for (const { hook, handler, defaultHandler, once } of registrations) {
-			const result = handler(this.swup.context, args as HookArguments<T>, defaultHandler);
+			const result = handler(this.swup.visit, args as HookArguments<T>, defaultHandler);
 			results.push(result);
 			if (isPromise(result)) {
 				console.warn(
@@ -392,8 +392,8 @@ export class Hooks {
 				const createDefaultHandler = (index: number): Handler<T> | undefined => {
 					const next = replace[index - 1];
 					if (next) {
-						return (context, args) =>
-							next.handler(context, args, createDefaultHandler(index - 1));
+						return (visit, args) =>
+							next.handler(visit, args, createDefaultHandler(index - 1));
 					} else {
 						return defaultHandler;
 					}
@@ -428,7 +428,7 @@ export class Hooks {
 	 * @param hook Name of the hook.
 	 */
 	private dispatchDomEvent<T extends HookName>(hook: T, args?: HookArguments<T>): void {
-		const detail = { hook, args, context: this.swup.context };
+		const detail = { hook, args, visit: this.swup.visit };
 		document.dispatchEvent(new CustomEvent(`swup:${hook}`, { detail }));
 	}
 }
diff --git a/src/modules/Context.ts b/src/modules/Visit.ts
similarity index 82%
rename from src/modules/Context.ts
rename to src/modules/Visit.ts
index 65775b8..37e91c8 100644
--- a/src/modules/Context.ts
+++ b/src/modules/Visit.ts
@@ -1,36 +1,36 @@
 import Swup, { Options } from '../Swup.js';
-import { HistoryAction, HistoryDirection } from './visit.js';
+import { HistoryAction, HistoryDirection } from './navigate.js';
 
-export interface Context {
+export interface Visit {
 	/** The previous page, about to leave */
-	from: FromContext;
+	from: VisitFrom;
 	/** The next page, about to enter */
-	to: ToContext;
+	to: VisitTo;
 	/** The content containers, about to be replaced */
 	containers: Options['containers'];
 	/** Information about animated page transitions */
-	animation: AnimationContext;
+	animation: VisitAnimation;
 	/** What triggered this visit */
-	trigger: TriggerContext;
+	trigger: VisitTrigger;
 	/** Browser history behavior on this visit */
-	history: HistoryContext;
+	history: VisitHistory;
 	/** Scroll behavior on this visit */
-	scroll: ScrollContext;
+	scroll: VisitScroll;
 }
 
-export interface FromContext {
+export interface VisitFrom {
 	/** The URL of the previous page */
 	url: string;
 }
 
-export interface ToContext {
+export interface VisitTo {
 	/** The URL of the next page */
 	url?: string;
 	/** The HTML content of the next page */
 	html?: string;
 }
 
-export interface AnimationContext {
+export interface VisitAnimation {
 	/** Whether this visit is animated. Default: `true` */
 	animate: boolean;
 	/** Whether to wait for the next page to load before starting the animation. Default: `false` */
@@ -43,21 +43,21 @@ export interface AnimationContext {
 	selector: Options['animationSelector'];
 }
 
-export interface ScrollContext {
+export interface VisitScroll {
 	/** Whether to reset the scroll position after the visit. Default: `true` */
 	reset: boolean;
 	/** Anchor element to scroll to on the next page. */
 	target?: string;
 }
 
-export interface TriggerContext {
+export interface VisitTrigger {
 	/** DOM element that triggered this visit. */
 	el?: Element;
 	/** DOM event that triggered this visit. */
 	event?: Event;
 }
 
-export interface HistoryContext {
+export interface VisitHistory {
 	/** History action to perform: `push` for creating a new history entry, `replace` for replacing the current entry. Default: `push` */
 	action: HistoryAction;
 	/** Whether this visit was triggered by a browser history navigation. */
@@ -66,7 +66,7 @@ export interface HistoryContext {
 	direction: HistoryDirection | undefined;
 }
 
-export interface ContextInitOptions {
+export interface VisitInitOptions {
 	to: string | undefined;
 	from?: string;
 	hash?: string;
@@ -79,7 +79,7 @@ export interface ContextInitOptions {
 	resetScroll?: boolean;
 }
 
-export function createContext(
+export function createVisit(
 	this: Swup,
 	{
 		to,
@@ -91,8 +91,8 @@ export function createContext(
 		event,
 		action = 'push',
 		resetScroll: reset = true
-	}: ContextInitOptions
-): Context {
+	}: VisitInitOptions
+): Visit {
 	return {
 		from: { url: from },
 		to: { url: to },
diff --git a/src/modules/animatePageIn.ts b/src/modules/animatePageIn.ts
index a5e4e84..5ebe6cb 100755
--- a/src/modules/animatePageIn.ts
+++ b/src/modules/animatePageIn.ts
@@ -6,16 +6,16 @@ import { nextTick } from '../utils.js';
  * @returns Promise<void>
  */
 export const animatePageIn = async function (this: Swup) {
-	if (!this.context.animation.animate) {
+	if (!this.visit.animation.animate) {
 		return;
 	}
 
 	const animation = this.hooks.call(
 		'animation:in:await',
 		{ skip: false },
-		async (context, { skip }) => {
+		async (visit, { skip }) => {
 			if (skip) return;
-			await this.awaitAnimations({ selector: context.animation.selector });
+			await this.awaitAnimations({ selector: visit.animation.selector });
 		}
 	);
 
diff --git a/src/modules/animatePageOut.ts b/src/modules/animatePageOut.ts
index df94976..af96f0e 100755
--- a/src/modules/animatePageOut.ts
+++ b/src/modules/animatePageOut.ts
@@ -6,24 +6,24 @@ import { classify } from '../helpers.js';
  * @returns Promise<void>
  */
 export const animatePageOut = async function (this: Swup) {
-	if (!this.context.animation.animate) {
+	if (!this.visit.animation.animate) {
 		await this.hooks.call('animation:skip');
 		return;
 	}
 
-	await this.hooks.call('animation:out:start', undefined, () => {
+	await this.hooks.call('animation:out:start', undefined, (visit) => {
 		this.classes.add('is-changing', 'is-leaving', 'is-animating');
-		if (this.context.history.popstate) {
+		if (visit.history.popstate) {
 			this.classes.add('is-popstate');
 		}
-		if (this.context.animation.name) {
-			this.classes.add(`to-${classify(this.context.animation.name)}`);
+		if (visit.animation.name) {
+			this.classes.add(`to-${classify(visit.animation.name)}`);
 		}
 	});
 
-	await this.hooks.call('animation:out:await', { skip: false }, async (context, { skip }) => {
+	await this.hooks.call('animation:out:await', { skip: false }, async (visit, { skip }) => {
 		if (skip) return;
-		await this.awaitAnimations({ selector: context.animation.selector });
+		await this.awaitAnimations({ selector: visit.animation.selector });
 	});
 
 	await this.hooks.call('animation:out:end');
diff --git a/src/modules/fetchPage.ts b/src/modules/fetchPage.ts
index 3872bb4..bba30b7 100644
--- a/src/modules/fetchPage.ts
+++ b/src/modules/fetchPage.ts
@@ -48,7 +48,7 @@ export async function fetchPage(
 	const response: Response = await this.hooks.call(
 		'fetch:request',
 		{ url, options },
-		(context, { url, options }) => fetch(url, options)
+		(visit, { url, options }) => fetch(url, options)
 	);
 
 	const { status, url: responseUrl } = response;
diff --git a/src/modules/visit.ts b/src/modules/navigate.ts
similarity index 68%
rename from src/modules/visit.ts
rename to src/modules/navigate.ts
index 932b164..e004f59 100755
--- a/src/modules/visit.ts
+++ b/src/modules/navigate.ts
@@ -1,12 +1,12 @@
 import Swup from '../Swup.js';
 import { createHistoryRecord, updateHistoryRecord, getCurrentUrl, Location } from '../helpers.js';
 import { FetchOptions } from './fetchPage.js';
-import { ContextInitOptions } from './Context.js';
+import { VisitInitOptions } from './Visit.js';
 
 export type HistoryAction = 'push' | 'replace';
 export type HistoryDirection = 'forwards' | 'backwards';
 
-type VisitOptions = {
+type NavigationOptions = {
 	/** Whether this visit is animated. Default: `true` */
 	animate?: boolean;
 	/** Name of a custom animation to run. */
@@ -21,11 +21,11 @@ type VisitOptions = {
  * @param options Options for how to perform this visit.
  * @returns Promise<void>
  */
-export function visit(
+export function navigate(
 	this: Swup,
 	url: string,
-	options: VisitOptions & FetchOptions = {},
-	context: Omit<ContextInitOptions, 'to'> = {}
+	options: NavigationOptions & FetchOptions = {},
+	init: Omit<VisitInitOptions, 'to'> = {}
 ) {
 	// Check if the visit should be ignored
 	if (this.shouldIgnoreVisit(url)) {
@@ -34,53 +34,53 @@ export function visit(
 	}
 
 	const { url: to, hash } = Location.fromUrl(url);
-	this.context = this.createContext({ ...context, to, hash });
-	this.performVisit(to, options);
+	this.visit = this.createVisit({ ...init, to, hash });
+	this.performNavigation(to, options);
 }
 
 /**
  * Start a visit to a new URL.
  *
- * Internal method that assumes the global context has already been set up.
+ * Internal method that assumes the visit context has already been created.
  *
- * As a user, you should call `swup.visit(url)` instead.
+ * As a user, you should call `swup.navigate(url)` instead.
  *
  * @param url The URL to navigate to.
  * @param options Options for how to perform this visit.
  * @returns Promise<void>
  */
-export async function performVisit(
+export async function performNavigation(
 	this: Swup,
 	url: string,
-	options: VisitOptions & FetchOptions = {}
+	options: NavigationOptions & FetchOptions = {}
 ) {
 	if (typeof url !== 'string') {
-		throw new Error(`swup.visit() requires a URL parameter`);
+		throw new Error(`swup.navigate() requires a URL parameter`);
 	}
 
-	const { el } = this.context.trigger;
-	this.context.to.url = Location.fromUrl(url).url;
+	const { el } = this.visit.trigger;
+	this.visit.to.url = Location.fromUrl(url).url;
 	options.referrer = options.referrer || this.currentPageUrl;
 
 	if (options.animate === false) {
-		this.context.animation.animate = false;
+		this.visit.animation.animate = false;
 	}
 
 	// Clean up old animation classes
-	if (!this.context.animation.animate) {
+	if (!this.visit.animation.animate) {
 		this.classes.clear();
 	}
 
 	// Get history action from option or attribute on trigger element
 	const history = options.history || el?.getAttribute('data-swup-history') || undefined;
 	if (history && ['push', 'replace'].includes(history)) {
-		this.context.history.action = history as HistoryAction;
+		this.visit.history.action = history as HistoryAction;
 	}
 
 	// Get custom animation name from option or attribute on trigger element
 	const animation = options.animation || el?.getAttribute('data-swup-animation') || undefined;
 	if (animation) {
-		this.context.animation.name = animation;
+		this.visit.animation.name = animation;
 	}
 
 	try {
@@ -89,14 +89,14 @@ export async function performVisit(
 		// Begin fetching page
 		const pagePromise = this.hooks.call(
 			'page:request',
-			{ url: this.context.to.url, options },
-			async (context, { options }) => await this.fetchPage(context.to.url as string, options)
+			{ url: this.visit.to.url, options },
+			async (visit, { options }) => await this.fetchPage(visit.to.url as string, options)
 		);
 
 		// Create history record if this is not a popstate call (with or without anchor)
-		if (!this.context.history.popstate) {
-			const newUrl = url + (this.context.scroll.target || '');
-			if (this.context.history.action === 'replace') {
+		if (!this.visit.history.popstate) {
+			const newUrl = url + (this.visit.scroll.target || '');
+			if (this.visit.history.action === 'replace') {
 				updateHistoryRecord(newUrl);
 			} else {
 				const index = this.currentHistoryIndex + 1;
@@ -107,9 +107,9 @@ export async function performVisit(
 		this.currentPageUrl = getCurrentUrl();
 
 		// Wait for page before starting to animate out?
-		if (this.context.animation.wait) {
+		if (this.visit.animation.wait) {
 			const { html } = await pagePromise;
-			this.context.to.html = html;
+			this.visit.to.html = html;
 		}
 
 		// Wait for page to load and leave animation to finish
@@ -117,7 +117,7 @@ export async function performVisit(
 		const [page] = await Promise.all([pagePromise, animationPromise]);
 
 		// Render page: replace content and scroll to top/fragment
-		await this.renderPage(this.context.to.url, page);
+		await this.renderPage(this.visit.to.url, page);
 
 		// Wait for enter animation
 		await this.animatePageIn();
@@ -125,9 +125,9 @@ export async function performVisit(
 		// Finalize visit
 		await this.hooks.call('visit:end', undefined, () => this.classes.clear());
 
-		// Reset context after visit?
-		// if (this.context.to && this.isSameResolvedUrl(this.context.to.url, requestedUrl)) {
-		// 	this.createContext({ to: undefined });
+		// Reset visit info after finish?
+		// if (this.visit.to && this.isSameResolvedUrl(this.visit.to.url, requestedUrl)) {
+		// 	this.createVisit({ to: undefined });
 		// }
 	} catch (error: unknown) {
 		// Return early if error is undefined (probably aborted preload request)
@@ -140,7 +140,7 @@ export async function performVisit(
 
 		// Rewrite `skipPopStateHandling` to redirect manually when `history.go` is processed
 		this.options.skipPopStateHandling = () => {
-			window.location.href = this.context.to.url as string;
+			window.location.href = this.visit.to.url as string;
 			return true;
 		};
 
diff --git a/src/modules/renderPage.ts b/src/modules/renderPage.ts
index 39e4cd4..48ed3b4 100755
--- a/src/modules/renderPage.ts
+++ b/src/modules/renderPage.ts
@@ -20,28 +20,28 @@ export const renderPage = async function (this: Swup, requestedUrl: string, page
 	if (!this.isSameResolvedUrl(getCurrentUrl(), url)) {
 		updateHistoryRecord(url);
 		this.currentPageUrl = getCurrentUrl();
-		this.context.to.url = this.currentPageUrl;
+		this.visit.to.url = this.currentPageUrl;
 	}
 
 	// only add for animated page loads
-	if (this.context.animation.animate) {
+	if (this.visit.animation.animate) {
 		this.classes.add('is-rendering');
 	}
 
-	// save html into context for easier retrieval
-	this.context.to.html = html;
+	// save html into visit context for easier retrieval
+	this.visit.to.html = html;
 
 	// replace content: allow handlers and plugins to overwrite paga data and containers
-	await this.hooks.call('content:replace', { page }, (context, { page }) => {
-		const success = this.replaceContent(page, { containers: context.containers });
+	await this.hooks.call('content:replace', { page }, (visit, { page }) => {
+		const success = this.replaceContent(page, { containers: visit.containers });
 		if (!success) {
 			throw new Error('[swup] Container mismatch, aborting');
 		}
-		if (this.context.animation.animate) {
+		if (visit.animation.animate) {
 			// Make sure to add these classes to new containers as well
 			this.classes.add('is-animating', 'is-changing', 'is-rendering');
-			if (this.context.animation.name) {
-				this.classes.add(`to-${classify(this.context.animation.name)}`);
+			if (visit.animation.name) {
+				this.classes.add(`to-${classify(visit.animation.name)}`);
 			}
 		}
 	});
@@ -49,15 +49,15 @@ export const renderPage = async function (this: Swup, requestedUrl: string, page
 	await this.hooks.call(
 		'content:scroll',
 		{ options: { behavior: 'auto' } },
-		(context, { options }) => {
-			if (this.context.scroll.target) {
-				const target = this.getAnchorElement(this.context.scroll.target);
+		(visit, { options }) => {
+			if (visit.scroll.target) {
+				const target = this.getAnchorElement(visit.scroll.target);
 				if (target) {
 					target.scrollIntoView(options);
 					return;
 				}
 			}
-			if (this.context.scroll.reset) {
+			if (visit.scroll.reset) {
 				window.scrollTo(0, 0);
 			}
 		}


Test patch:
diff --git a/cypress/e2e/_plugins.spec.js b/cypress/e2e/_plugins.spec.js
index f473bd8..8a325a3 100644
--- a/cypress/e2e/_plugins.spec.js
+++ b/cypress/e2e/_plugins.spec.js
@@ -70,7 +70,7 @@ describe('Body Class Plugin', function () {
 
 	it('should update the body class', function () {
 		cy.get('body').should('have.class', 'body-1');
-		this.swup.visit('/plugins/body-class-plugin-2.html');
+		this.swup.navigate('/plugins/body-class-plugin-2.html');
 		cy.get('body').should('have.class', 'body-2');
 		cy.get('body').should('not.have.class', 'body-1');
 	});
diff --git a/cypress/e2e/main.spec.js b/cypress/e2e/main.spec.js
index e8d995a..3387275 100644
--- a/cypress/e2e/main.spec.js
+++ b/cypress/e2e/main.spec.js
@@ -33,7 +33,7 @@ describe('Request', function () {
 	it('should force-load on server error', function () {
 		cy.intercept('/error-500.html', { statusCode: 500, times: 1 });
 		cy.shouldHaveReloadedAfterAction(() => {
-			this.swup.visit('/error-500.html');
+			this.swup.navigate('/error-500.html');
 		});
 		cy.shouldBeAtPage('/error-500.html');
 	});
@@ -41,7 +41,7 @@ describe('Request', function () {
 	it('should force-load on network error', function () {
 		cy.intercept('/error-network.html', { times: 1 }, { forceNetworkError: true });
 		cy.shouldHaveReloadedAfterAction(() => {
-			this.swup.visit('/error-network.html');
+			this.swup.navigate('/error-network.html');
 		});
 		cy.shouldBeAtPage('/error-network.html');
 	});
@@ -54,10 +54,10 @@ describe('Fetch', function () {
 	});
 
 	it('should allow calling original page:request handler', function () {
-		this.swup.hooks.replace('page:request', (context, args, defaultHandler) => {
-			return defaultHandler(context, args);
+		this.swup.hooks.replace('page:request', (visit, args, defaultHandler) => {
+			return defaultHandler(visit, args);
 		});
-		this.swup.visit('/page-2.html');
+		this.swup.navigate('/page-2.html');
 
 		cy.shouldBeAtPage('/page-2.html');
 		cy.shouldHaveH1('Page 2');
@@ -75,7 +75,7 @@ describe('Fetch', function () {
 				html: '<html><body><div id="swup"><h1>Page 3</h1></div></body></html>'
 			};
 		});
-		this.swup.visit('/page-2.html');
+		this.swup.navigate('/page-2.html');
 
 		cy.shouldBeAtPage('/page-3.html');
 		cy.shouldHaveH1('Page 3');
@@ -88,7 +88,7 @@ describe('Fetch', function () {
 		this.swup.hooks.replace('page:request', () => {
 			return this.swup.fetchPage('page-3.html');
 		});
-		this.swup.visit('/page-2.html');
+		this.swup.navigate('/page-2.html');
 
 		cy.shouldBeAtPage('/page-3.html');
 		cy.shouldHaveH1('Page 3');
@@ -102,13 +102,13 @@ describe('Cache', function () {
 	});
 
 	it('should cache pages', function () {
-		this.swup.visit('/page-2.html');
+		this.swup.navigate('/page-2.html');
 		cy.shouldBeAtPage('/page-2.html');
 		cy.shouldHaveCacheEntry('/page-2.html');
 	});
 
 	it('should cache pages from absolute URLs', function () {
-		this.swup.visit(`${baseUrl}/page-2.html`);
+		this.swup.navigate(`${baseUrl}/page-2.html`);
 		cy.shouldBeAtPage('/page-2.html');
 		cy.shouldHaveCacheEntry('/page-2.html');
 	});
@@ -379,10 +379,10 @@ describe('Ignoring visits', function () {
 		cy.shouldBeAtPage('/page-2.html#hash');
 	});
 
-	it('should ignore visits in swup.visit', function () {
+	it('should ignore visits in swup.navigate', function () {
 		this.swup.options.ignoreVisit = (url) => true;
 		cy.shouldHaveReloadedAfterAction(() => {
-			this.swup.visit('/page-2.html');
+			this.swup.navigate('/page-2.html');
 		});
 		cy.shouldBeAtPage('/page-2.html');
 	});
@@ -488,11 +488,11 @@ describe('History', function () {
 
 	it('should replace the current history state via API', function () {
 		cy.window().then(() => {
-			this.swup.visit('/page-2.html');
+			this.swup.navigate('/page-2.html');
 		});
 		cy.shouldBeAtPage('/page-2.html');
 		cy.window().then(() => {
-			this.swup.visit('/page-3.html', { history: 'replace' });
+			this.swup.navigate('/page-3.html', { history: 'replace' });
 		});
 		cy.shouldBeAtPage('/page-3.html');
 		cy.window().then((window) => {
@@ -543,8 +543,8 @@ describe('History', function () {
 
 	it('should calculate the travel direction of history visits', function () {
 		let direction = null;
-		this.swup.hooks.on('history:popstate', (context) => {
-			direction = context.history.direction;
+		this.swup.hooks.on('history:popstate', (visit) => {
+			direction = visit.history.direction;
 		});
 
 		cy.triggerClickOnLink('/page-2.html');
@@ -612,13 +612,13 @@ describe('API', function () {
 	});
 
 	it('should navigate to pages using swup API', function () {
-		this.swup.visit('/page-2.html');
+		this.swup.navigate('/page-2.html');
 		cy.shouldBeAtPage('/page-2.html');
 		cy.shouldHaveH1('Page 2');
 	});
 });
 
-describe('Context', function () {
+describe('Visit context', function () {
 	beforeEach(() => {
 		cy.visit('/page-1.html');
 		cy.wrapSwupInstance();
@@ -627,9 +627,9 @@ describe('Context', function () {
 	it('has the current and next url', function () {
 		let from = '';
 		let to = '';
-		this.swup.hooks.before('visit:start', (ctx) => {
-			from = ctx.from.url;
-			to = ctx.to.url;
+		this.swup.hooks.before('visit:start', (visit) => {
+			from = visit.from.url;
+			to = visit.to.url;
 		});
 		cy.triggerClickOnLink('/page-2.html');
 		cy.window().should(() => {
@@ -641,9 +641,9 @@ describe('Context', function () {
 	it('has the correct current url on history visits', function () {
 		let from = '';
 		let to = '';
-		this.swup.hooks.before('visit:start', (ctx) => {
-			from = ctx.from.url;
-			to = ctx.to.url;
+		this.swup.hooks.before('visit:start', (visit) => {
+			from = visit.from.url;
+			to = visit.to.url;
 		});
 		cy.triggerClickOnLink('/page-2.html');
 		cy.shouldBeAtPage('/page-2.html');
@@ -662,9 +662,9 @@ describe('Context', function () {
 	it('passes along the click trigger and event', function () {
 		let el = null;
 		let event = null;
-		this.swup.hooks.before('visit:start', (context) => {
-			el = context.trigger.el;
-			event = context.trigger.event;
+		this.swup.hooks.before('visit:start', (visit) => {
+			el = visit.trigger.el;
+			event = visit.trigger.event;
 		});
 		cy.triggerClickOnLink('/page-2.html');
 		cy.window().should((win) => {
@@ -676,12 +676,12 @@ describe('Context', function () {
 	it('passes along the popstate status and event', function () {
 		let event = null;
 		let historyVisit = null;
-		this.swup.hooks.before('visit:start', (context) => {
-			event = context.trigger.event;
-			historyVisit = context.history.popstate;
+		this.swup.hooks.before('visit:start', (visit) => {
+			event = visit.trigger.event;
+			historyVisit = visit.history.popstate;
 		});
 		cy.window().then(() => {
-			this.swup.visit('/page-2.html');
+			this.swup.navigate('/page-2.html');
 		});
 		cy.shouldBeAtPage('/page-2.html');
 		cy.window().then((window) => {
@@ -697,8 +697,8 @@ describe('Context', function () {
 	it('passes along the custom animation', function () {
 		let name = null;
 		let expectedName = null;
-		this.swup.hooks.before('visit:start', (context) => {
-			name = context.animation.name;
+		this.swup.hooks.before('visit:start', (visit) => {
+			name = visit.animation.name;
 		});
 		cy.get('a[data-swup-animation]').should(($el) => {
 			expect($el.length).to.be.at.least(1);
@@ -712,8 +712,8 @@ describe('Context', function () {
 	});
 
 	it('should allow disabling animations', function () {
-		this.swup.hooks.before('visit:start', (context) => {
-			context.animation.animate = false;
+		this.swup.hooks.before('visit:start', (visit) => {
+			visit.animation.animate = false;
 		});
 		cy.shouldAnimateWithDuration(0, '/page-2.html');
 	});
@@ -726,26 +726,26 @@ describe('Containers', function () {
 	});
 
 	it('should be customizable from context', function () {
-		this.swup.hooks.before('visit:start', (context) => {
-			context.containers = ['#aside'];
+		this.swup.hooks.before('visit:start', (visit) => {
+			visit.containers = ['#aside'];
 		});
-		this.swup.visit('/containers-2.html', { animate: false });
+		this.swup.navigate('/containers-2.html', { animate: false });
 		cy.get('h1').should('contain', 'Containers 1');
 		cy.get('h2').should('contain', 'Heading 2');
 	});
 
 	it('should be customizable from hook context', function () {
-		this.swup.hooks.before('content:replace', (context) => {
-			context.containers = ['#main'];
+		this.swup.hooks.before('content:replace', (visit) => {
+			visit.containers = ['#main'];
 		});
-		this.swup.visit('/containers-2.html', { animate: false });
+		this.swup.navigate('/containers-2.html', { animate: false });
 		cy.get('h1').should('contain', 'Containers 2');
 		cy.get('h2').should('contain', 'Heading 1');
 	});
 
 	it('should force-load on container mismatch', function () {
 		cy.shouldHaveReloadedAfterAction(() => {
-			this.swup.visit('/containers-missing.html');
+			this.swup.navigate('/containers-missing.html');
 		});
 		cy.shouldBeAtPage('/containers-missing.html');
 	});
diff --git a/src/__test__/index.test.ts b/src/__test__/index.test.ts
index 4104b2e..4a1c7c5 100644
--- a/src/__test__/index.test.ts
+++ b/src/__test__/index.test.ts
@@ -87,7 +87,7 @@ describe('ignoreVisit', () => {
 	it('should be called from visit method', () => {
 		const ignoreVisit = vi.fn(() => true);
 		const swup = new Swup({ ignoreVisit });
-		swup.visit('/path/');
+		swup.navigate('/path/');
 
 		expect(ignoreVisit.mock.calls).toHaveLength(1);
 	});
diff --git a/src/modules/__test__/cache.test.ts b/src/modules/__test__/cache.test.ts
index 19c9b1b..58f3552 100644
--- a/src/modules/__test__/cache.test.ts
+++ b/src/modules/__test__/cache.test.ts
@@ -1,7 +1,7 @@
 import { beforeEach, describe, expect, it, vi } from 'vitest';
 import Swup from '../../Swup.js';
 import { Cache, CacheData } from '../Cache.js';
-import { Context } from '../Context.js';
+import { Visit } from '../Visit.js';
 
 interface CacheTtlData {
 	ttl: number;
@@ -15,7 +15,7 @@ interface CacheIndexData {
 interface AugmentedCacheData extends CacheData, CacheTtlData, CacheIndexData {}
 
 const swup = new Swup();
-const ctx = swup.context;
+const visit = swup.visit;
 const cache = new Cache(swup);
 
 const page1 = { url: '/page-1', html: '1' };
@@ -82,7 +82,7 @@ describe('Cache', () => {
 		cache.set(page1.url, page1);
 
 		expect(handler).toBeCalledTimes(1);
-		expect(handler).toBeCalledWith(ctx, { page: page1 }, undefined);
+		expect(handler).toBeCalledWith(visit, { page: page1 }, undefined);
 	});
 
 	it('should allow augmenting cache entries on save', () => {
@@ -124,7 +124,7 @@ describe('Types', () => {
 		const cache = new Cache(swup);
 
 		// @ts-expect-no-error
-		swup.hooks.on('history:popstate', (ctx: Context, { event: PopStateEvent }) => {});
+		swup.hooks.on('history:popstate', (visit: Visit, { event: PopStateEvent }) => {});
 		// @ts-expect-no-error
 		await swup.hooks.call('history:popstate', { event: new PopStateEvent('') });
 
diff --git a/src/modules/__test__/hooks.test.ts b/src/modules/__test__/hooks.test.ts
index 4a77ea4..167d2d4 100644
--- a/src/modules/__test__/hooks.test.ts
+++ b/src/modules/__test__/hooks.test.ts
@@ -1,7 +1,7 @@
 import { describe, expect, it, vi } from 'vitest';
 import Swup from '../../Swup.js';
 import { Handler, Hooks } from '../Hooks.js';
-import { Context } from '../Context.js';
+import { Visit } from '../Visit.js';
 
 describe('Hook registry', () => {
 	it('should add handlers', () => {
@@ -226,14 +226,14 @@ describe('Hook registry', () => {
 		const args = { foo: 'bar' };
 		const customHandler = vi.fn((c, a, handler) => handler(c, args));
 		const defaultHandler = vi.fn();
-		const ctx = swup.context;
+		const visit = swup.visit;
 
 		swup.hooks.on('enable', customHandler, { replace: true });
 
 		await swup.hooks.call('enable', undefined, defaultHandler);
 
-		expect(customHandler).toBeCalledWith(ctx, undefined, defaultHandler);
-		expect(defaultHandler).toBeCalledWith(ctx, args);
+		expect(customHandler).toBeCalledWith(visit, undefined, defaultHandler);
+		expect(defaultHandler).toBeCalledWith(visit, args);
 	});
 
 	it('should return result of replacing handler', async () => {
@@ -257,7 +257,7 @@ describe('Hook registry', () => {
 		const firstHandler = vi.fn((c, a, handler) => handler(c, args1));
 		const secondHandler = vi.fn((c, a, handler) => handler(c, args2));
 		const thirdHandler = vi.fn((c, a, handler) => handler(c, args3, handler));
-		const ctx = swup.context;
+		const visit = swup.visit;
 
 		swup.hooks.on('enable', firstHandler, { replace: true });
 		swup.hooks.on('enable', secondHandler, { replace: true });
@@ -265,36 +265,36 @@ describe('Hook registry', () => {
 
 		await swup.hooks.call('enable', undefined, defaultHandler);
 
-		expect(defaultHandler).toBeCalledWith(ctx, args1);
-		expect(thirdHandler).toBeCalledWith(ctx, undefined, expect.any(Function));
-		expect(secondHandler).toBeCalledWith(ctx, args3, expect.any(Function));
-		expect(firstHandler).toBeCalledWith(ctx, args2, expect.any(Function));
+		expect(defaultHandler).toBeCalledWith(visit, args1);
+		expect(thirdHandler).toBeCalledWith(visit, undefined, expect.any(Function));
+		expect(secondHandler).toBeCalledWith(visit, args3, expect.any(Function));
+		expect(firstHandler).toBeCalledWith(visit, args2, expect.any(Function));
 	});
 
 	it('should not pass original handler into normal handlers', async () => {
 		const swup = new Swup();
 		const listener = vi.fn();
 		const handler = vi.fn();
-		const ctx = swup.context;
+		const visit = swup.visit;
 
 		swup.hooks.on('enable', listener);
 
 		await swup.hooks.call('enable', undefined, handler);
 
-		expect(listener).toBeCalledWith(ctx, undefined, undefined);
+		expect(listener).toBeCalledWith(visit, undefined, undefined);
 	});
 
-	it('should trigger event handler with context and args', async () => {
+	it('should trigger event handler with visit and args', async () => {
 		const swup = new Swup();
 		const handler: Handler<'history:popstate'> = vi.fn();
-		const ctx = swup.context;
+		const visit = swup.visit;
 		const args = { event: new PopStateEvent('') };
 
 		swup.hooks.on('history:popstate', handler);
 		await swup.hooks.call('history:popstate', args);
 
 		expect(handler).toBeCalledTimes(1);
-		expect(handler).toBeCalledWith(ctx, args, undefined);
+		expect(handler).toBeCalledWith(visit, args, undefined);
 	});
 });
 
@@ -305,7 +305,7 @@ describe('Types', () => {
 		// @ts-expect-no-error
 		swup.hooks.on(
 			'history:popstate',
-			(ctx: Context, { event }: { event: PopStateEvent }) => {}
+			(visit: Visit, { event }: { event: PopStateEvent }) => {}
 		);
 		// @ts-expect-no-error
 		await swup.hooks.call('history:popstate', { event: new PopStateEvent('') });
@@ -313,7 +313,7 @@ describe('Types', () => {
 		// @ts-expect-error
 		swup.hooks.on('history:popstate', ({ event: MouseEvent }) => {});
 		// @ts-expect-error
-		swup.hooks.on('history:popstate', (ctx: Context, { event }: { event: MouseEvent }) => {});
+		swup.hooks.on('history:popstate', (visit: Visit, { event }: { event: MouseEvent }) => {});
 		// @ts-expect-error
 		await swup.hooks.call('history:popstate', { event: new MouseEvent('') });
 	});