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" } }