diff --git a/CHANGELOG.md b/CHANGELOG.md index 02c2975..fe740e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ +## [0.3.0] - 2023-11-22 + +- Add hooks for inserting and removing containers + ## [0.2.0] - 2023-08-24 - Allow keeping the previous container indefinitely diff --git a/README.md b/README.md index b563169..b9a95ad 100755 --- a/README.md +++ b/README.md @@ -292,3 +292,48 @@ swup.hooks.on('visit:start', (visit) => { } }); ``` + +## Hooks + +The plugin adds two new hooks to swup. Both hooks receive a `ContainerSet` instance as their +only argument: + +```ts +type ContainerSet = { + /** Selector to match this container */ + selector: string; + /** Incoming container element */ + next: HTMLElement; + /** Outgoing container element */ + previous: HTMLElement; + /** Container elements to keep around after the animation */ + keep: HTMLElement[]; + /** Container elements to remove after the animation */ + remove: HTMLElement[]; +}; +``` + +### `content:insert` + +Triggered when the new content containers are inserted. Hook before this to manipulate the +elements before they are inserted into the DOM. + +```js +swup.hooks.before('content:insert', (visit, { containers }) => { + for (const { next } of containers) { + console.log('About to insert container', next); + } +}); +``` + +### `content:remove` + +Triggered when the previous containers are removed, after the animation has finished. + +```js +swup.hooks.before('content:remove', (visit, { containers }) => { + for (const { remove } of containers) { + console.log('About to remove containers', remove); + } +}); +``` diff --git a/package-lock.json b/package-lock.json index 244efe4..facb69f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@swup/parallel-plugin", - "version": "0.2.0", + "version": "0.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@swup/parallel-plugin", - "version": "0.2.0", + "version": "0.3.0", "license": "MIT", "dependencies": { "@swup/plugin": "^3.0.0" diff --git a/package.json b/package.json index b6a40d9..e3b5cfc 100755 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@swup/parallel-plugin", "amdName": "SwupParallelPlugin", "description": "A swup plugin for animating the previous and next page in parallel", - "version": "0.2.0", + "version": "0.3.0", "type": "module", "source": "src/index.ts", "main": "./dist/index.cjs", diff --git a/src/index.ts b/src/index.ts index 3d59b70..86342e0 100755 --- a/src/index.ts +++ b/src/index.ts @@ -3,6 +3,10 @@ import { forceReflow } from 'swup'; import Plugin from '@swup/plugin'; declare module 'swup' { + export interface HookDefinitions { + 'content:insert': { containers: ContainerSet[] }; + 'content:remove': { containers: ContainerSet[] }; + } export interface VisitAnimation { /** Parallel visit: run in and out animation at the same time */ parallel?: boolean; @@ -13,7 +17,7 @@ type PluginOptions = { /** Containers to animate in parallel */ containers: string[]; /** Number of previous containers to keep around after the animation */ - keep: number | { [ container: string ]: number }; + keep: number | { [container: string]: number }; }; type ContainerSet = { @@ -57,6 +61,10 @@ export default class SwupParallelPlugin extends Plugin { this.options.containers = this.swup.options.containers; } + // Create new hooks + this.swup.hooks.create('content:insert'); + this.swup.hooks.create('content:remove'); + // On visit: check for containers and mark as parallel visit // Run after user hooks to allow disabling parallel animations beforehand this.on('visit:start', this.startVisit, { priority: 1 }); @@ -98,25 +106,28 @@ export default class SwupParallelPlugin extends Plugin { return; } - // Get info about parallel containers - this.parallelContainers = this.getParallelContainersForVisit(visit, page); + // Get info about parallel containers and save for later cleanup + const containers = this.getParallelContainersForVisit(visit, page); + this.parallelContainers = containers; // Replace parallel containers ourselves - for (const { all, next, previous, keep, remove } of this.parallelContainers) { - all.forEach((el, i) => el.style.setProperty('--swup-parallel-container', `${i}`)); - previous.setAttribute('aria-hidden', 'true'); - previous.before(next); - - if (visit.animation.animate) { - next.classList.add('is-next-container'); - forceReflow(next); - next.classList.remove('is-next-container'); + this.swup.hooks.call('content:insert', { containers }, () => { + for (const { all, next, previous, keep, remove } of containers) { + all.forEach((el, i) => el.style.setProperty('--swup-parallel-container', `${i}`)); + previous.setAttribute('aria-hidden', 'true'); + previous.before(next); + + if (visit.animation.animate) { + next.classList.add('is-next-container'); + forceReflow(next); + next.classList.remove('is-next-container'); + } + + previous.classList.add('is-previous-container'); + keep.forEach((el) => el.classList.add('is-kept-container')); + remove.forEach((el) => el.classList.add('is-removing-container')); } - - previous.classList.add('is-previous-container'); - keep.forEach((el) => el.classList.add('is-kept-container')); - remove.forEach((el) => el.classList.add('is-removing-container')); - } + }); // Modify visit containers so swup will only replace non-parallel containers this.originalContainers = visit.containers; @@ -133,10 +144,13 @@ export default class SwupParallelPlugin extends Plugin { /** After each visit: remove previous containers */ protected cleanupContainers = () => { - for (const { remove, next } of this.parallelContainers) { - remove.forEach((el) => el.remove()); - next.classList.remove('is-next-container'); - } + const containers = this.parallelContainers; + this.swup.hooks.call('content:remove', { containers }, () => { + for (const { remove, next } of containers) { + remove.forEach((el) => el.remove()); + next.classList.remove('is-next-container'); + } + }); this.parallelContainers = []; }; @@ -188,10 +202,7 @@ export default class SwupParallelPlugin extends Plugin { protected visitHasPotentialParallelAnimation(visit: Visit) { // Checking for visit.animation.parallel !== false here allows explicitly // disabling parallel animations in user hooks before this plugin executes - return ( - visit.animation.parallel !== false && - this.visitHasParallelContainers(visit) - ); + return visit.animation.parallel !== false && this.visitHasParallelContainers(visit); } /** Check if any of a visit's containers are animated in parallel */