Skip to content

Commit e6d1b8d

Browse files
committed
add ViewTransition component
1 parent d9db1c7 commit e6d1b8d

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<script lang="ts" module>
2+
import type { Snippet } from "svelte";
3+
4+
import { onNavigate } from "$app/navigation";
5+
6+
type Props = {
7+
children?: Snippet;
8+
fixedElements?: Snippet;
9+
fixedElementsPosition?: "beforeContent" | "afterContent";
10+
};
11+
</script>
12+
13+
<script lang="ts">
14+
let {
15+
children,
16+
fixedElements,
17+
fixedElementsPosition = "beforeContent",
18+
}: Props = $props();
19+
20+
onNavigate((navigation) => {
21+
if (!document.startViewTransition) {
22+
return;
23+
}
24+
25+
return new Promise((resolve) => {
26+
document.startViewTransition(async () => {
27+
resolve();
28+
29+
await navigation.complete;
30+
});
31+
});
32+
});
33+
</script>
34+
35+
{#snippet fixedSnippet()}
36+
<div class="fixed-elements-wrapper">
37+
{@render fixedElements?.()}
38+
</div>
39+
{/snippet}
40+
41+
{#if fixedElements && fixedElementsPosition === "beforeContent"}
42+
{@render fixedSnippet()}
43+
{/if}
44+
45+
{@render children?.()}
46+
47+
{#if fixedElements && fixedElementsPosition === "afterContent"}
48+
{@render fixedSnippet()}
49+
{/if}
50+
51+
<style>
52+
@keyframes fade-in {
53+
from {
54+
opacity: 0;
55+
}
56+
}
57+
58+
@keyframes fade-out {
59+
to {
60+
opacity: 0;
61+
}
62+
}
63+
64+
@keyframes slide-from-right {
65+
from {
66+
transform: translateX(30px);
67+
}
68+
}
69+
70+
@keyframes slide-to-left {
71+
to {
72+
transform: translateX(-30px);
73+
}
74+
}
75+
76+
@media (prefers-reduced-motion: no-preference) {
77+
:root::view-transition-old(root) {
78+
animation:
79+
90ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
80+
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
81+
}
82+
83+
:root::view-transition-new(root) {
84+
animation:
85+
210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,
86+
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
87+
}
88+
}
89+
90+
.fixed-elements-wrapper {
91+
view-transition-name: fixed-elements;
92+
}
93+
</style>

src/lib/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@ export { default as Tooltip } from "$components/Tooltip.svelte";
1313
// Ago
1414
export type { Props as AgoProps } from "$components/Ago.svelte";
1515
export { default as Ago } from "$components/Ago.svelte";
16+
// ViewTransition
17+
export type { Props as ViewTransitionProps } from "$components/ViewTransition.svelte";
18+
export { default as ViewTransition } from "$components/ViewTransition.svelte";

0 commit comments

Comments
 (0)