From 32b1367877e29413819fe6401ecef3d9985d4e49 Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Sat, 24 Jan 2026 15:16:04 +0300 Subject: [PATCH] feat(springySliderFade): add custom transition function for slide+fade --- src/shared/lib/index.ts | 2 + src/shared/lib/transitions/index.ts | 1 + .../springySlideFade/springySlideFade.ts | 60 +++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 src/shared/lib/transitions/index.ts create mode 100644 src/shared/lib/transitions/springySlideFade/springySlideFade.ts diff --git a/src/shared/lib/index.ts b/src/shared/lib/index.ts index a431e86..a57a6ee 100644 --- a/src/shared/lib/index.ts +++ b/src/shared/lib/index.ts @@ -20,3 +20,5 @@ export { } from './helpers'; export { splitArray } from './utils'; + +export { springySlideFade } from './transitions'; diff --git a/src/shared/lib/transitions/index.ts b/src/shared/lib/transitions/index.ts new file mode 100644 index 0000000..2264a9d --- /dev/null +++ b/src/shared/lib/transitions/index.ts @@ -0,0 +1 @@ +export { springySlideFade } from './springySlideFade/springySlideFade'; diff --git a/src/shared/lib/transitions/springySlideFade/springySlideFade.ts b/src/shared/lib/transitions/springySlideFade/springySlideFade.ts new file mode 100644 index 0000000..a32d8a0 --- /dev/null +++ b/src/shared/lib/transitions/springySlideFade/springySlideFade.ts @@ -0,0 +1,60 @@ +import type { + SlideParams, + TransitionConfig, +} from 'svelte/transition'; + +function elasticOut(t: number) { + return Math.pow(2, -10 * t) * Math.sin((t - 0.075) * (2 * Math.PI) / 0.3) + 1; +} + +function gentleSpring(t: number) { + return 1 - Math.pow(1 - t, 3) * Math.cos(t * Math.PI * 2); +} + +/** + * Svelte slide transition function for custom slide+fade + * @param node - The element to apply the transition to + * @param params - Transition parameters + * @returns Transition configuration + */ +export function springySlideFade( + node: HTMLElement, + params: SlideParams = {}, +): TransitionConfig { + const { duration = 400 } = params; + const height = node.scrollHeight; + + // Check if the browser is Firefox to work around specific rendering issues + const isFirefox = navigator.userAgent.toLowerCase().includes('firefox'); + + return { + duration, + // We use 'tick' for the most precise control over the + // coordination with the elements below. + css: t => { + // Use elastic easing + const eased = gentleSpring(t); + + return ` + height: ${eased * height}px; + opacity: ${t}; + transform: translateY(${(1 - t) * -10}px); + transform-origin: top; + overflow: hidden; + contain: size layout style; + will-change: max-height, opacity, transform; + backface-visibility: hidden; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + ${ + isFirefox + ? ` + perspective: 1000px; + isolation: isolate; + ` + : '' + } + `; + }, + }; +}