diff --git a/examples/blog/src/components/BaseHead.astro b/examples/blog/src/components/BaseHead.astro
index 39e1366d1745d..405871662ae82 100644
--- a/examples/blog/src/components/BaseHead.astro
+++ b/examples/blog/src/components/BaseHead.astro
@@ -2,7 +2,7 @@
// Import the global.css file here so that it is included on
// all pages through the use of the component.
import '../styles/global.css';
-import { ViewTransitions } from 'astro/components';
+import { ViewTransitions } from 'astro:transitions';
export interface Props {
title: string;
diff --git a/examples/blog/src/components/Header.astro b/examples/blog/src/components/Header.astro
index 92f0bfb98395f..bf0896366852a 100644
--- a/examples/blog/src/components/Header.astro
+++ b/examples/blog/src/components/Header.astro
@@ -1,4 +1,5 @@
---
+import { slide } from 'astro:transitions';
import HeaderLink from './HeaderLink.astro';
import { SITE_TITLE } from '../consts';
---
diff --git a/packages/astro/client-base.d.ts b/packages/astro/client-base.d.ts
index 37bae7b1c6ae8..c0203e0ef3358 100644
--- a/packages/astro/client-base.d.ts
+++ b/packages/astro/client-base.d.ts
@@ -70,6 +70,15 @@ declare module 'astro:assets' {
export const { getImage, getConfiguredImageService, Image }: AstroAssets;
}
+declare module 'astro:transitions' {
+ type TransitionModule = typeof import('./dist/transitions/index.js');
+ export const slide: TransitionModule['slide'];
+ export const fade: TransitionModule['fade'];
+
+ type ViewTransitionsModule = typeof import('./components/ViewTransitions.astro');
+ export const ViewTransitions: ViewTransitionsModule['default'];
+}
+
type MD = import('./dist/@types/astro').MarkdownInstance>;
interface ExportedMarkdownModuleEntities {
frontmatter: MD['frontmatter'];
diff --git a/packages/astro/package.json b/packages/astro/package.json
index b208b83d1f8df..4055a5aeb8b4a 100644
--- a/packages/astro/package.json
+++ b/packages/astro/package.json
@@ -70,7 +70,8 @@
"./middleware": {
"types": "./dist/core/middleware/index.d.ts",
"default": "./dist/core/middleware/index.js"
- }
+ },
+ "./transitions": "./dist/transitions/index.js"
},
"imports": {
"#astro/*": "./dist/*.js"
diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts
index 8e3311966cac8..79e73d470abab 100644
--- a/packages/astro/src/@types/astro.ts
+++ b/packages/astro/src/@types/astro.ts
@@ -55,6 +55,25 @@ export interface AstroBuiltinProps {
'client:only'?: boolean | string;
}
+export interface TransitionAnimation {
+ name: string; // The name of the keyframe
+ delay?: number | string;
+ duration?: number | string;
+ easing?: string;
+ fillMode?: string;
+ direction?: string;
+}
+
+export interface TransitionAnimationPair {
+ old: TransitionAnimation | TransitionAnimation[];
+ new: TransitionAnimation | TransitionAnimation[];
+}
+
+export interface TransitionDirectionalAnimations {
+ forwards: TransitionAnimationPair;
+ backwards: TransitionAnimationPair;
+}
+
// Allow users to extend this for astro-jsx.d.ts
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface AstroClientDirectives {}
@@ -69,7 +88,7 @@ export interface AstroBuiltinAttributes {
'set:html'?: any;
'set:text'?: any;
'is:raw'?: boolean;
- 'transition:animate'?: 'morph' | 'slide' | 'fade';
+ 'transition:animate'?: 'morph' | 'slide' | 'fade' | TransitionDirectionalAnimations;
'transition:name'?: string;
}
diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts
index 89dec9d4b3afe..e0ba8711d8c1d 100644
--- a/packages/astro/src/core/create-vite.ts
+++ b/packages/astro/src/core/create-vite.ts
@@ -27,6 +27,7 @@ import astroScannerPlugin from '../vite-plugin-scanner/index.js';
import astroScriptsPlugin from '../vite-plugin-scripts/index.js';
import astroScriptsPageSSRPlugin from '../vite-plugin-scripts/page-ssr.js';
import { vitePluginSSRManifest } from '../vite-plugin-ssr-manifest/index.js';
+import astroTransitions from '../transitions/vite-plugin-transitions.js';
import { joinPaths } from './path.js';
interface CreateViteOptions {
@@ -132,6 +133,7 @@ export async function createVite(
astroContentAssetPropagationPlugin({ mode, settings }),
vitePluginSSRManifest(),
settings.config.experimental.assets ? [astroAssetsPlugin({ settings, logging, mode })] : [],
+ astroTransitions(),
],
publicDir: fileURLToPath(settings.config.publicDir),
root: fileURLToPath(settings.config.root),
diff --git a/packages/astro/src/transitions/index.ts b/packages/astro/src/transitions/index.ts
new file mode 100644
index 0000000000000..a8d4d5aac860d
--- /dev/null
+++ b/packages/astro/src/transitions/index.ts
@@ -0,0 +1,65 @@
+import type { TransitionDirectionalAnimations, TransitionAnimationPair } from '../@types/astro';
+
+export function slide({
+ duration
+}: {
+ duration?: string | number;
+} = {}): TransitionDirectionalAnimations {
+ return {
+ forwards: {
+ old: [{
+ name: 'astroFadeOut',
+ duration: duration ?? '90ms',
+ easing: 'cubic-bezier(0.4, 0, 1, 1)',
+ fillMode: 'both'
+ }, {
+ name: 'astroSlideToLeft',
+ duration: duration ?? '300ms',
+ easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
+ fillMode: 'both'
+ }],
+ new: [{
+ name: 'astroFadeIn',
+ duration: duration ?? '210ms',
+ easing: 'cubic-bezier(0, 0, 0.2, 1)',
+ delay: '90ms',
+ fillMode: 'both'
+ }, {
+ name: 'astroSlideFromRight',
+ duration: duration ?? '300ms',
+ easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
+ fillMode: 'both'
+ }]
+ },
+ backwards: {
+ old: [{ name: 'astroFadeOut' }, { name: 'astroSlideToRight' }],
+ new: [{ name: 'astroFadeIn' }, { name: 'astroSlideFromLeft' }]
+ }
+ };
+}
+
+export function fade({
+ duration
+}: {
+ duration?: string | number;
+}): TransitionDirectionalAnimations {
+ const anim = {
+ old: {
+ name: 'astroFadeInOut',
+ duration: duration ?? '0.2s',
+ easing: 'linear',
+ direction: 'forwards',
+ },
+ new: {
+ name: 'astroFadeInOut',
+ duration: duration ?? '0.3s',
+ easing: 'linear',
+ direction: 'backwards',
+ }
+ } satisfies TransitionAnimationPair;
+
+ return {
+ forwards: anim,
+ backwards: anim,
+ };
+}
diff --git a/packages/astro/src/transitions/vite-plugin-transitions.ts b/packages/astro/src/transitions/vite-plugin-transitions.ts
new file mode 100644
index 0000000000000..54107ef75092f
--- /dev/null
+++ b/packages/astro/src/transitions/vite-plugin-transitions.ts
@@ -0,0 +1,25 @@
+import * as vite from 'vite';
+
+const virtualModuleId = 'astro:transitions';
+
+// The virtual module for the astro:transitions namespace
+export default function astroTransitions(): vite.Plugin {
+ const resolvedVirtualModuleId = '\0' + virtualModuleId;
+
+ return {
+ name: 'astro:transitions',
+ async resolveId(id) {
+ if (id === virtualModuleId) {
+ return resolvedVirtualModuleId;
+ }
+ },
+ load(id) {
+ if (id === resolvedVirtualModuleId) {
+ return `
+ export * from "astro/transitions";
+ export { default as ViewTransitions } from "astro/components/ViewTransitions.astro";
+ `;
+ }
+ },
+ };
+}
diff --git a/packages/astro/tsconfig.json b/packages/astro/tsconfig.json
index 23ac0c78b62b0..4d79cdcd3413c 100644
--- a/packages/astro/tsconfig.json
+++ b/packages/astro/tsconfig.json
@@ -6,6 +6,7 @@
"declarationDir": "./dist",
"module": "ES2022",
"outDir": "./dist",
- "target": "ES2021"
+ "target": "ES2021",
+ "jsx": "preserve"
}
}