Skip to content

Commit 0147b65

Browse files
committedSep 5, 2023
move functions in outside scope and update readme
1 parent 05acf9a commit 0147b65

File tree

3 files changed

+425
-192
lines changed

3 files changed

+425
-192
lines changed
 

‎.changeset/nervous-eels-visit.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'sveltekit-view-transition': patch
3+
---
4+
5+
move functions in outside scope and update readme

‎README.md

+225-4
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ The most easy and immediate setup is importing and adding `setupViewTransition`
6060

6161
You can target and modify the default animation with `::view-transition-old(root)` and `::view-transition-new(root)`. However it's ofter useful to have specific part of the page have different view transitions. For example the header might be fixed and we would like to animate it differently. To allow for this use case `setupViewTransition` return an object from which you can destructure `transition`.
6262

63-
## transition
63+
### transition
6464

6565
`transition` is an action that accept a string as input and assign that string as the `view-transition-name` of that element. Plain and simple.
6666

@@ -71,10 +71,231 @@ You can target and modify the default animation with `::view-transition-old(root
7171
const { transition } = setupViewTransition();
7272
</script>
7373
74-
<header use:transition="header" >
75-
<!-- links -->
74+
<header use:transition={'header'}>
75+
<!-- links -->
7676
</header>
7777
<slot />
7878
```
7979

80-
This will allow you to target the header with `::view-transition-old(header)` and `::view-transition-new(header)`
80+
This will allow you to target the header with `::view-transition-old(header)` and `::view-transition-new(header)`.
81+
82+
Now while this may seem enough sometimes you might want to be a bit more creative with the transition names and that's why instead of a string you can also pass an object to the transition action.
83+
84+
#### name
85+
86+
This is the name of the transition, much like the string that you would've passed before it's what will end up as the `view-transition-name`. It's the only required field.
87+
88+
#### classes
89+
90+
Either an array of strings or a function that returns an array of string that will be applied during the transition. This allows you to target specific classnames in your css. For example let's say that you are clicking on a back button and when going back on an old page you want to apply a different navigation, how would you do it? Simply pass the array `["back"]` and target the classes in your css `.back::view-transition-old(yourname)` and `.back::view-transition-new(yourname)`. The function will take a `OnNavigate` object as input which is the same object that sveltekit will pass to the `onNavigate` function. It looks like this
91+
92+
```ts
93+
interface Navigation {
94+
/**
95+
* Where navigation was triggered from
96+
*/
97+
from: {
98+
/**
99+
* Parameters of the target page - e.g. for a route like `/blog/[slug]`, a `{ slug: string }` object.
100+
* Is `null` if the target is not part of the SvelteKit app (could not be resolved to a route).
101+
*/
102+
params: Record<string, string> | null;
103+
/**
104+
* Info about the target route
105+
*/
106+
route: { id: string | null };
107+
/**
108+
* The URL that is navigated to
109+
*/
110+
url: URL;
111+
} | null;
112+
/**
113+
* Where navigation is going to/has gone to
114+
*/
115+
to: {
116+
/**
117+
* Parameters of the target page - e.g. for a route like `/blog/[slug]`, a `{ slug: string }` object.
118+
* Is `null` if the target is not part of the SvelteKit app (could not be resolved to a route).
119+
*/
120+
params: Record<string, string> | null;
121+
/**
122+
* Info about the target route
123+
*/
124+
route: { id: string | null };
125+
/**
126+
* The URL that is navigated to
127+
*/
128+
url: URL;
129+
} | null;
130+
/**
131+
* The type of navigation:
132+
* - `form`: The user submitted a `<form>`
133+
* - `leave`: The user is leaving the app by closing the tab or using the back/forward buttons to go to a different document
134+
* - `link`: Navigation was triggered by a link click
135+
* - `goto`: Navigation was triggered by a `goto(...)` call or a redirect
136+
* - `popstate`: Navigation was triggered by back/forward navigation
137+
*/
138+
type: 'form' | 'leave' | 'link' | 'goto' | 'popstate';
139+
/**
140+
* Whether or not the navigation will result in the page being unloaded (i.e. not a client-side navigation)
141+
*/
142+
willUnload: false;
143+
/**
144+
* In case of a history back/forward navigation, the number of steps to go back/forward
145+
*/
146+
delta?: number;
147+
/**
148+
* A promise that resolves once the navigation is complete, and rejects if the navigation
149+
* fails or is aborted. In the case of a `willUnload` navigation, the promise will never resolve
150+
*/
151+
complete: Promise<void>;
152+
}
153+
```
154+
155+
as you can see it contains a lot of useful information to determine the page you are going to and conditionally apply classes based on the navigation.
156+
157+
An example could be this one
158+
159+
```svelte
160+
<script>
161+
import { setupViewTransition } from 'sveltekit-view-transition';
162+
163+
const { transition } = setupViewTransition();
164+
</script>
165+
166+
<header
167+
use:transition={{
168+
name: 'header',
169+
classes({ navigation }) {
170+
if (navigation.to?.route?.id === '/') {
171+
return ['back'];
172+
}
173+
},
174+
}}
175+
>
176+
<a href="/">Back</a>
177+
</header>
178+
179+
<!-- your component -->
180+
```
181+
182+
#### applyImmediately
183+
184+
By default when you specify a transition name it will only be applied when it's actually navigating following [the suggestion](https://twitter.com/jaffathecake/status/1697541871847748098) from Jake Archibald himself (the creator of the view transition api) that you should not add transition names to everything but only to the elements involved in the transition. Sometimes tho you want to add a transition name immediately (for example when you are coming back from a detail page and you want to animate back an image in the list).
185+
`applyImmediately` is either a boolean or a function that take the navigation object (please note that this is the navigation object) from the previous page so the `from` will be the page that is navigating to this page and the `to` will be this page) and returns a boolean.
186+
187+
Here's a simple example of this in action
188+
189+
```svelte
190+
<script>
191+
import { setupViewTransition } from 'sveltekit-view-transition';
192+
193+
const { transition } = setupViewTransition();
194+
195+
export let data;
196+
</script>
197+
198+
<ul>
199+
{#each data.posts as post (post.id)}
200+
<li
201+
use:transition={{
202+
/**
203+
* in the post/[id] page we have a matching title transition name
204+
*/
205+
name: 'title',
206+
applyImmediately(navigation) {
207+
// this will apply the title view transition to this element
208+
// only if it's the one that matches the id we are coming from
209+
// so for example if we were visiting /post/1 and this is the
210+
// post with id 1. Notice that i'm checking the `from` because
211+
// this will actually be called when the navigation is still happening
212+
// from post/1 to /
213+
return navigation?.from?.params?.id === post.id.toString();
214+
},
215+
}}
216+
>
217+
<a href="/post/{post.id}">{post.title}</a>
218+
</li>
219+
{/each}
220+
</ul>
221+
```
222+
223+
in this example when we navigate back from the `/post/1` page the title will slide in his right place in the list. Also important note: **the transition name will be added before the transition ends and removed immediately after to allow for a forward transition from another post to happen. If not removed the transition name would be duplicated**
224+
225+
#### shouldApply
226+
227+
As mentioned above this can be either a boolean or a function that takes a navigation object (this time the `from` is this page and the `to` is the page you are navigating to) and return a boolean. If the boolean is true the transition name will be applied. This is useful when you want to navigate from a list to a detail.
228+
229+
So completing the example above
230+
231+
```svelte
232+
<script>
233+
import { setupViewTransition } from 'sveltekit-view-transition';
234+
235+
const { transition } = setupViewTransition();
236+
237+
export let data;
238+
</script>
239+
240+
<ul>
241+
{#each data.posts as post (post.id)}
242+
<li
243+
use:transition={{
244+
/**
245+
* in the post/[id] page we have a matching title transition name. Note that
246+
* the transition name will only be applied moments before the actual transition
247+
* if and when the shouldApply function returns true
248+
*/
249+
name: 'title',
250+
applyImmediately(navigation) {
251+
return navigation?.from?.params?.id === post.id.toString();
252+
},
253+
shouldApply(navigation) {
254+
// if the params.id i'm navigating to is equal to the id of the post
255+
// we add the title transition name.
256+
return navigation?.to?.params?.id === post.id.toString();
257+
},
258+
}}
259+
>
260+
<a href="/post/{post.id}">{post.title}</a>
261+
</li>
262+
{/each}
263+
</ul>
264+
```
265+
266+
### on
267+
268+
This function is returned from setupViewTransition and allows you to add a listener to run code in an arbitrary moment of the "lifecycle" of the view transition. It takes three arguments, the name of the event, the function and a boolean that indicates wether the callback should be added immediately (even if there's a transition running) or not. This is because there are events that runs after the component has mounted and if you add the listeners on mount specifying true as the third argument this listeners will be called immediately. This might be useful sometimes if you want to modify the state of after an incoming transition.
269+
270+
There are 7 types of events you can subscribe to in order of calling
271+
272+
- 'before-start-view-transition': event called before the transition even start if you modify the DOM here it will be included in the "screenshot" of the `view-transition`
273+
- 'before-navigation': event called before SvelteKit start to handle the navigation the view transition has already been started
274+
- 'before-navigation-complete': event called after SvelteKit started to handle the navigation but before it completes. The `view-transition` is still happening.
275+
- 'after-navigation-complete': event called after the navigation from SvelteKit has completed. The `view-transition` is sill happening
276+
- 'transition-ready': event called when the `view-transition` is ready, the pseudo-elements are created.
277+
- 'update-callback-done': event called when the callback of the `view-transition` has finished running.
278+
- 'transition-finished': event called when the `view-transition` finish and the new view is in place
279+
280+
The `on` function also returns a function that unregister the callback when called.
281+
282+
### off
283+
284+
It's a function to unsubscribe a specific handle from a specific event. You will probably rarely use this given that the `on` function already returns the unsubscribe.
285+
286+
### classes
287+
288+
Much like the `classes` function on the action this function can be called immediately in the script tag of a component to add a specific class to the `:root` element during a navigation. It can either be a array of strings or a function that returns an array of strings. The function takes as a parameter a navigation object just like the one from the action.
289+
290+
```svelte
291+
<script>
292+
import { setupViewTransition } from 'sveltekit-view-transition';
293+
294+
const { classes } = setupViewTransition();
295+
classes(({ navigation }) => {
296+
if (navigation.to?.route.id === '/') {
297+
return ['back'];
298+
}
299+
});
300+
</script>
301+
```

‎src/lib/sveltekit-view-transition.ts

+195-188
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ export type TransitionAction = {
77
name: string;
88
classes?:
99
| string[]
10-
| ((props: SveltekitViewTransitionEventsMap['before-start-view-transition']) => string[]);
10+
| ((
11+
props: SveltekitViewTransitionEventsMap['before-start-view-transition'],
12+
) => string[] | undefined);
1113
shouldApply?:
1214
| boolean
1315
| ((props: SveltekitViewTransitionEventsMap['before-start-view-transition']) => boolean);
@@ -59,209 +61,214 @@ let is_transition_happening = false;
5961

6062
const listeners_during_transition_queue = new Set<() => void>();
6163

62-
export function setupViewTransition() {
63-
function run_all_events<T extends SveltekitViewTransitionEvents>(
64-
event: T,
65-
props: SveltekitViewTransitionEventsMap[T],
66-
) {
67-
const events = callbacks[event];
68-
if (events) {
69-
events.forEach((callback) => {
70-
try {
71-
callback(props);
72-
} catch (e) {
73-
console.error(`Error in callback for event "${event}": ${e}`);
74-
}
75-
});
76-
events.clear();
77-
}
64+
function run_all_events<T extends SveltekitViewTransitionEvents>(
65+
event: T,
66+
props: SveltekitViewTransitionEventsMap[T],
67+
) {
68+
const events = callbacks[event];
69+
if (events) {
70+
events.forEach((callback) => {
71+
try {
72+
callback(props);
73+
} catch (e) {
74+
console.error(`Error in callback for event "${event}": ${e}`);
75+
}
76+
});
77+
events.clear();
7878
}
79+
}
7980

80-
/**
81-
* This function is used to deregister from an event. A function that
82-
* deregister from an event is also returned from the on function.
83-
* @param event the event name you want to deregister from
84-
* @param callback the callback reference you want to deregister
85-
*/
86-
function off<T extends SveltekitViewTransitionEvents>(
87-
event: T,
88-
callback: (props: SveltekitViewTransitionEventsMap[T]) => void | Promise<void>,
89-
) {
90-
let events = callbacks[event];
91-
if (!events) {
92-
callbacks[event] = new SetOfCallback<SveltekitViewTransitionEventsMap[T]>() as ListenerMap[T];
93-
events = callbacks[event];
94-
}
95-
events?.delete(callback);
81+
/**
82+
* This function is used to deregister from an event. A function that
83+
* deregister from an event is also returned from the on function.
84+
* @param event the event name you want to deregister from
85+
* @param callback the callback reference you want to deregister
86+
*/
87+
function off<T extends SveltekitViewTransitionEvents>(
88+
event: T,
89+
callback: (props: SveltekitViewTransitionEventsMap[T]) => void | Promise<void>,
90+
) {
91+
let events = callbacks[event];
92+
if (!events) {
93+
callbacks[event] = new SetOfCallback<SveltekitViewTransitionEventsMap[T]>() as ListenerMap[T];
94+
events = callbacks[event];
9695
}
96+
events?.delete(callback);
97+
}
9798

98-
/**
99-
* Function used to register a callback run during the onNavigate
100-
* @param event the event name you want to register a callback for
101-
* @param callback The callback you want to run
102-
* @param registerDuringTransition if you want to register this callback even if a transition is running (if false
103-
* it will still be registered as soon as the transition finishes)
104-
* @returns A function to deregister the callback
105-
*/
106-
function on<T extends SveltekitViewTransitionEvents>(
107-
event: T,
108-
callback: (props: SveltekitViewTransitionEventsMap[T]) => void,
109-
registerDuringTransition = false,
110-
) {
111-
const return_value = () => off(event, callback);
112-
// if there's a transition happening we store a function to add the listener
113-
// in the queue and return the un-subscriber
114-
if (is_transition_happening && !registerDuringTransition) {
115-
listeners_during_transition_queue.add(() => {
116-
on(event, callback);
117-
});
118-
return return_value;
119-
}
120-
let events = callbacks[event];
121-
if (!events) {
122-
callbacks[event] = new SetOfCallback<SveltekitViewTransitionEventsMap[T]>() as ListenerMap[T];
123-
events = callbacks[event];
124-
}
125-
events?.add(callback);
99+
/**
100+
* Function used to register a callback run during the onNavigate
101+
* @param event the event name you want to register a callback for
102+
* @param callback The callback you want to run
103+
* @param registerDuringTransition if you want to register this callback even if a transition is running (if false
104+
* it will still be registered as soon as the transition finishes)
105+
* @returns A function to deregister the callback
106+
*/
107+
function on<T extends SveltekitViewTransitionEvents>(
108+
event: T,
109+
callback: (props: SveltekitViewTransitionEventsMap[T]) => void,
110+
registerDuringTransition = false,
111+
) {
112+
const return_value = () => off(event, callback);
113+
// if there's a transition happening we store a function to add the listener
114+
// in the queue and return the un-subscriber
115+
if (is_transition_happening && !registerDuringTransition) {
116+
listeners_during_transition_queue.add(() => {
117+
on(event, callback);
118+
});
126119
return return_value;
127120
}
128-
129-
/**
130-
* Function to call during component initialization to add a class or a series of classes
131-
* during the navigation. This is useful to run a different types of transition when you are going
132-
* back to a specific page.
133-
*
134-
* The classes will be automatically removed at the end of the transition.
135-
*
136-
* @param to_add either a list of class that will always be applied or a function that returns an array
137-
* of strings. The function will get a navigation props as input to allow you to check the to, from, route id etc.
138-
*/
139-
function classes(
140-
to_add:
141-
| string[]
142-
| ((
143-
props: SveltekitViewTransitionEventsMap['before-start-view-transition'],
144-
) => string[] | undefined),
145-
) {
146-
let classes: string[] | undefined;
147-
const off_finished = on('transition-finished', () => {
148-
if (classes && classes.length > 0) {
149-
document.documentElement.classList.remove(...classes);
150-
}
151-
});
152-
on('before-start-view-transition', (navigation) => {
153-
classes = Array.isArray(to_add) ? to_add : to_add(navigation);
154-
if (classes) {
155-
document.documentElement.classList.add(...classes);
156-
} else {
157-
off_finished();
158-
}
159-
});
121+
let events = callbacks[event];
122+
if (!events) {
123+
callbacks[event] = new SetOfCallback<SveltekitViewTransitionEventsMap[T]>() as ListenerMap[T];
124+
events = callbacks[event];
160125
}
126+
events?.add(callback);
127+
return return_value;
128+
}
161129

162-
/**
163-
* The action to specify a transition name on a specific element. You can use it on an element
164-
* passing a string to directly assign that specific string as view transition name.
165-
*
166-
* If you pass an object instead you can specify a series of options:
167-
*
168-
* - name: required, it's the transition name that will be applied
169-
* - classes: either an array of strings or a function that returns an array of string that will be applied
170-
* during the transition. The function will take a navigation object
171-
* - applyImmediately: by default when you specify a transition name it will only be applied when it's actually navigating
172-
* following the suggestion from Jake Archibald himself (the creator of the view transition api) https://twitter.com/jaffathecake/status/1697541871847748098?s=20
173-
* that you should not add transition names to everything but only to the elements involved in the transition. Sometimes tho you want to
174-
* add a transition name immediately (for example when you are coming back from a detail page and you want to animate back an image in the list).
175-
* applyImmediately is either a boolean or a function that take the navigation object (please note that this is the navigation object) from
176-
* the previous page so the `from` will be the page that is navigating to this page and the `to` will be this page) and returns a boolean.
177-
* - shouldApply: as mentioned above this can be either a boolean or a function that takes a navigation object (this time the `from` is
178-
* this page and the `to` is the page you are navigating to) and return a boolean. If the boolean is true the transition name will be applied.
179-
* This is useful when you want to navigate from a list to a detail.
180-
*
181-
* @param node The element to apply the action to
182-
* @param props either a string for a simple view transition name or a set of options
183-
*/
184-
function transition(node: HTMLElement, props: string | TransitionAction) {
185-
if (typeof props === 'string') {
186-
node.style.setProperty('view-transition-name', props);
187-
return;
130+
/**
131+
* Function to call during component initialization to add a class or a series of classes
132+
* during the navigation. This is useful to run a different types of transition when you are going
133+
* back to a specific page.
134+
*
135+
* The classes will be automatically removed at the end of the transition.
136+
*
137+
* @param to_add either a list of class that will always be applied or a function that returns an array
138+
* of strings. The function will get a navigation props as input to allow you to check the to, from, route id etc.
139+
*/
140+
function classes(
141+
to_add:
142+
| string[]
143+
| ((
144+
props: SveltekitViewTransitionEventsMap['before-start-view-transition'],
145+
) => string[] | undefined),
146+
) {
147+
let classes: string[] | undefined;
148+
const off_finished = on('transition-finished', () => {
149+
if (classes && classes.length > 0) {
150+
document.documentElement.classList.remove(...classes);
188151
}
189-
function setup_listeners_for_props(props: TransitionAction) {
190-
let classes_to_add: string[] = [];
191-
on(
192-
'after-navigation-complete',
193-
(callback_props) => {
194-
let apply_immediately = false;
195-
if (props.applyImmediately != null) {
196-
apply_immediately =
197-
typeof props.applyImmediately === 'boolean'
198-
? props.applyImmediately
199-
: props.applyImmediately(callback_props);
200-
}
201-
if (apply_immediately) {
202-
node.style.setProperty('view-transition-name', props.name);
203-
on(
204-
'transition-finished',
205-
() => {
206-
node.style.setProperty('view-transition-name', null);
207-
},
208-
true,
209-
);
210-
}
211-
},
212-
true,
213-
);
214-
const off_before = on('before-start-view-transition', (callback_props) => {
215-
let should_apply = true;
216-
if (props.shouldApply != null) {
217-
should_apply =
218-
typeof props.shouldApply === 'boolean'
219-
? props.shouldApply
220-
: props.shouldApply(callback_props);
152+
});
153+
on('before-start-view-transition', (navigation) => {
154+
classes = Array.isArray(to_add) ? to_add : to_add(navigation);
155+
if (classes) {
156+
document.documentElement.classList.add(...classes);
157+
} else {
158+
off_finished();
159+
}
160+
});
161+
}
162+
163+
/**
164+
* The action to specify a transition name on a specific element. You can use it on an element
165+
* passing a string to directly assign that specific string as view transition name.
166+
*
167+
* If you pass an object instead you can specify a series of options:
168+
*
169+
* - name: required, it's the transition name that will be applied
170+
* - classes: either an array of strings or a function that returns an array of string that will be applied
171+
* during the transition. The function will take a navigation object
172+
* - applyImmediately: by default when you specify a transition name it will only be applied when it's actually navigating
173+
* following the suggestion from Jake Archibald himself (the creator of the view transition api) https://twitter.com/jaffathecake/status/1697541871847748098?s=20
174+
* that you should not add transition names to everything but only to the elements involved in the transition. Sometimes tho you want to
175+
* add a transition name immediately (for example when you are coming back from a detail page and you want to animate back an image in the list).
176+
* applyImmediately is either a boolean or a function that take the navigation object (please note that this is the navigation object) from
177+
* the previous page so the `from` will be the page that is navigating to this page and the `to` will be this page) and returns a boolean.
178+
* - shouldApply: as mentioned above this can be either a boolean or a function that takes a navigation object (this time the `from` is
179+
* this page and the `to` is the page you are navigating to) and return a boolean. If the boolean is true the transition name will be applied.
180+
* This is useful when you want to navigate from a list to a detail.
181+
*
182+
* @param node The element to apply the action to
183+
* @param props either a string for a simple view transition name or a set of options
184+
*/
185+
function transition(node: HTMLElement, props: string | TransitionAction) {
186+
if (typeof props === 'string') {
187+
node.style.setProperty('view-transition-name', props);
188+
return;
189+
}
190+
function setup_listeners_for_props(props: TransitionAction) {
191+
let classes_to_add: string[] | undefined;
192+
on(
193+
'after-navigation-complete',
194+
(callback_props) => {
195+
let apply_immediately = false;
196+
if (props.applyImmediately != null) {
197+
apply_immediately =
198+
typeof props.applyImmediately === 'boolean'
199+
? props.applyImmediately
200+
: props.applyImmediately(callback_props);
221201
}
222-
if (should_apply) {
202+
if (apply_immediately) {
223203
node.style.setProperty('view-transition-name', props.name);
224-
if (props.classes) {
225-
classes_to_add = Array.isArray(props.classes)
226-
? props.classes
227-
: props.classes(callback_props);
228-
}
229-
document.documentElement.classList.add(...classes_to_add);
204+
on(
205+
'transition-finished',
206+
() => {
207+
node.style.setProperty('view-transition-name', null);
208+
},
209+
true,
210+
);
230211
}
231-
});
232-
// eslint-disable-next-line @typescript-eslint/no-empty-function
233-
let off_finished = () => {};
234-
if (classes_to_add.length > 0) {
235-
off_finished = on('transition-finished', () => {
236-
document.documentElement.classList.remove(...classes_to_add);
237-
});
212+
},
213+
true,
214+
);
215+
const off_before = on('before-start-view-transition', (callback_props) => {
216+
let should_apply = true;
217+
if (props.shouldApply != null) {
218+
should_apply =
219+
typeof props.shouldApply === 'boolean'
220+
? props.shouldApply
221+
: props.shouldApply(callback_props);
238222
}
239-
return () => {
240-
off_before();
241-
off_finished?.();
242-
};
243-
}
244-
let cleanup: ReturnType<typeof setup_listeners_for_props> | undefined =
245-
setup_listeners_for_props(props);
246-
return {
247-
update(new_props: string | TransitionAction) {
248-
// on update remove the previous listeners
249-
cleanup?.();
250-
cleanup = undefined;
251-
// if it's a string just set the view transition name
252-
if (typeof new_props === 'string') {
253-
node.style.setProperty('view-transition-name', new_props);
254-
return;
223+
if (should_apply) {
224+
node.style.setProperty('view-transition-name', props.name);
225+
if (props.classes) {
226+
classes_to_add = Array.isArray(props.classes)
227+
? props.classes
228+
: props.classes(callback_props);
255229
}
256-
// otherwise run the setup listeners function and store the new cleanup
257-
cleanup = setup_listeners_for_props(new_props);
258-
},
259-
destroy() {
260-
// clean everything
261-
cleanup?.();
262-
},
230+
if (classes_to_add) {
231+
document.documentElement.classList.add(...classes_to_add);
232+
} else {
233+
off_finished?.();
234+
}
235+
}
236+
});
237+
// eslint-disable-next-line @typescript-eslint/no-empty-function
238+
let off_finished = () => {};
239+
off_finished = on('transition-finished', () => {
240+
if (classes_to_add && classes_to_add.length > 0) {
241+
document.documentElement.classList.remove(...classes_to_add);
242+
}
243+
});
244+
return () => {
245+
off_before();
246+
off_finished?.();
263247
};
264248
}
249+
let cleanup: ReturnType<typeof setup_listeners_for_props> | undefined =
250+
setup_listeners_for_props(props);
251+
return {
252+
update(new_props: string | TransitionAction) {
253+
// on update remove the previous listeners
254+
cleanup?.();
255+
cleanup = undefined;
256+
// if it's a string just set the view transition name
257+
if (typeof new_props === 'string') {
258+
node.style.setProperty('view-transition-name', new_props);
259+
return;
260+
}
261+
// otherwise run the setup listeners function and store the new cleanup
262+
cleanup = setup_listeners_for_props(new_props);
263+
},
264+
destroy() {
265+
// clean everything
266+
cleanup?.();
267+
},
268+
};
269+
}
270+
271+
export function setupViewTransition() {
265272
// only register once the onNavigate
266273
if (on_navigate_registered === 0) {
267274
on_navigate_registered++;

0 commit comments

Comments
 (0)
Please sign in to comment.