Skip to content

Commit

Permalink
Mt/link types (#16)
Browse files Browse the repository at this point in the history
* new link-types script

* wording
  • Loading branch information
martrapp authored Dec 11, 2024
1 parent 48db12a commit 5feccc0
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 14 deletions.
5 changes: 5 additions & 0 deletions .changeset/gold-oranges-switch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@vtbag/turn-signal': minor
---

link-types: assign view transition types directly to the links that trigger navigation!
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,31 @@ The @vtbag website can be found at https://vtbag.dev/

## !!! News !!!

Transition types and direction attributes are now also determined on the old page!
The Turn-Signal learned a new trick! With the new `link-types` script, you can assign view transition types directly to the links that trigger navigation. This means you can create different view transition animations for the same page, based on the link that takes you there! Simply use `data-vtbag-link-types` attributes to set transition types and use them in you CSS to guard your animation rules.

But that's not all: `link-types` lets you specify different transition types for history back navigation too!

Check out the [image viewer tech demo](https://vtbag.dev/viewwe-demo/) for a hands-on example and the docs at [vtbag.dev/tools/turn-signal](https://vtbag.dev/tools/turn-signal#link-types).

Happy animating! 🎉


For details see the [CHANGELOG](https://github.com/vtbag/turn-signal/blob/main/CHANGELOG.md) and the [documentation](https://vtbag.dev/tools/turn-signal/).



### What happened before?

> Transition types and direction attributes are now also determined on the old page!
For details see the [CHANGELOG](https://github.com/vtbag/turn-signal/blob/main/CHANGELOG.md) and the [documentation](https://vtbag.dev/tools/turn-signal/).

## What is it?

Turn-Signal is a lightweight script that enhances cross-document view transitions by detecting the direction of browser navigation. It enables developers to create smooth, responsive transitions that adjust based on forward or backward navigation, delivering a more intuitive user experience.
Turn-Signal is a lightweight script that enhances *browser-native* *cross-document* **view transitions** by detecting the **direction** of browser **navigation**. It enables developers to create smooth, responsive transitions that adjust based on forward or backward navigation, delivering a more intuitive user experience.

When your pages slide to the left on forward navigation, let them slide to the right when the users goes back in the browser's history.

The script automatically detects the traversal direction and sets `backward`, `neither` or `forward` view transition types accordingly. You can also instruct the script to set data attributes on the `<html>` element.
The script automatically detects the traversal direction and sets `backward`, `same` or `forward` view transition types accordingly. You can also instruct the script to set data attributes on the `<html>` element.

If your site has the concept of a _previous_ and _next_ page, the Turn-Signal can automatically generate directional transitions for you.

Expand Down
2 changes: 1 addition & 1 deletion bin/bundle
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ else
OPTS="--minify"
(cd lib && rm *.js.map) >> /dev/null 2>&1
fi
npx esbuild src/index.ts src/forced-traversal.ts --bundle $OPTS --target=ESnext --outdir=lib
npx esbuild src/index.ts src/forced-traversal.ts src/link-types.ts --bundle $OPTS --target=ESnext --outdir=lib

tsc
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@
"lib/index.js",
"lib/index.d.ts",
"lib/forced-traversal.js",
"lib/forced-traversal.d.ts"
"lib/forced-traversal.d.ts",
"lib/link-types.js",
"lib/link-types.d.ts"
],
"exports": {
".": "./lib/index.js",
"./forced-traversal": "./lib/forced-traversal.js"
"./forced-traversal": "./lib/forced-traversal.js",
"./link-types": "./lib/link-types.js"
},
"scripts": {
"dev": "bin/bundle dev",
Expand Down
4 changes: 2 additions & 2 deletions src/dom-view-transisions-level2.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ declare global {
}

interface NavigationActivation {
entry: NavigationEntry;
from: NavigationEntry;
entry: NavigationHistoryEntry;
from: NavigationHistoryEntry;
navigationType: string;
}
interface AnimationEffect {
Expand Down
10 changes: 5 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const currentScript = document.currentScript;

function direction(e: PageSwapEvent | PageRevealEvent) {
const activation = e.type === 'pageswap' ? (e as PageSwapEvent).activation : navigation?.activation;
const activation =
e.type === 'pageswap' ? (e as PageSwapEvent).activation : navigation?.activation;
if (e.viewTransition && activation) {
const pages = allPages();
let hereIdx = 1,
Expand All @@ -11,9 +12,9 @@ function direction(e: PageSwapEvent | PageRevealEvent) {
fromIdx = activation.from?.index;
} else {
if (pages.length) {
const index = (url: string) => pages.indexOf(new URL(url).pathname);
hereIdx = index(activation.entry?.url);
fromIdx = index(activation.from?.url);
const index = (url: string) => pages.indexOf(new URL(url, location.href).pathname);
hereIdx = index(activation.entry?.url ?? '');
fromIdx = index(activation.from?.url ?? '');
if (hereIdx === -1 || fromIdx === -1) {
hereIdx = 1;
fromIdx = 0;
Expand Down Expand Up @@ -75,4 +76,3 @@ function allPages() {

'onpagereveal' in window && addEventListener('pagereveal', direction);
'onpageswap' in window && addEventListener('pageswap', direction);

45 changes: 45 additions & 0 deletions src/link-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { direction, activation } from './navigation';

let anchor: Element | null = null;

addEventListener('DOMContentLoaded', () => {
document.addEventListener('click', (event) => {
const target = event.composedPath()[0];
anchor = target instanceof Element ? target.closest('a, area') : null;
anchor = anchor?.hasAttribute('data-vtbag-link-types') ? anchor : null;
});
});

addEventListener('pageswap', (event) => {
if (!event.viewTransition) return;
const lastAnchor = anchor;
anchor = null;
let types = history.state?.vtbagTypes ?? '';
if (activation(event).navigationType === 'traverse' && direction(event) === 'backward') return;
if (lastAnchor) {
types = lastAnchor.getAttribute('data-vtbag-link-types') ?? '';
console.log('s-types :>> ', types);
setViewTransitionTypes(types);
}
sessionStorage?.setItem('vtbag-link-types', types.split(/\s*\/\s*/, 1)[0]);
sessionStorage
?.getItem('vtbag-link-types')
?.split(/\s+/)
.forEach((type) => event.viewTransition?.types?.add(type));
console.log('x', ...event.viewTransition?.types);
});

addEventListener('pagereveal', (event) => {
if (!event.viewTransition) return;
let types = sessionStorage?.getItem('vtbag-link-types') ?? '';
if (activation().navigationType === 'traverse' && direction() === 'backward') {
types = history.state?.vtbagTypes ?? '';
types.includes('/') && (types = types.split(/\s*\/\s*/, 2)[1]);
}
types.split(/\s+/).forEach((type) => event.viewTransition?.types?.add(type));
console.log('r-types :>> ', [...event.viewTransition?.types]);
});

export function setViewTransitionTypes(types: string) {
history.replaceState({ ...history.state, vtbagTypes: types }, '');
}
11 changes: 11 additions & 0 deletions src/navigation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const activation = (e?: PageSwapEvent | PageRevealEvent) =>
e && 'activation' in e ? (e as PageSwapEvent).activation : window.navigation.activation;

export function direction(e?: PageSwapEvent | PageRevealEvent) {
const act = activation(e);
return act?.from.index > act?.entry.index
? 'backward'
: act.entry.index === act.from.index
? 'same'
: 'forward';
}

0 comments on commit 5feccc0

Please sign in to comment.