/** * Resolve Slide Transition Settings * * Cascade: Page Transition Settings -> Element Override * * Unlike page transitions, slide transitions: * - Map 'video' type to 'fade' (no video between slides) * - Support fade through overlay for crossfade effect */ import type { ResolvedTransitionSettings, EasingFunction, SlideTransitionType, } from '../types/transition'; export interface SlideTransitionOverride { type?: SlideTransitionType | '' | undefined; durationMs?: number | '' | undefined; easing?: EasingFunction | '' | undefined; overlayColor?: string | undefined; } export interface ResolvedSlideTransition { type: SlideTransitionType; durationMs: number; easing: EasingFunction; overlayColor: string; } /** * Resolve slide transition settings with cascade: * Element override -> Page transition defaults -> Hardcoded fallback * * @param pageTransition - Resolved page transition (from useTransitionSettings) * @param elementOverride - Element-level override (optional) * @returns Final resolved settings for slide transition */ export function resolveSlideTransition( pageTransition: ResolvedTransitionSettings | null | undefined, elementOverride?: SlideTransitionOverride | null, ): ResolvedSlideTransition { // Fallback values if no page transition available const fallback: ResolvedSlideTransition = { type: 'fade', durationMs: 700, easing: 'ease-in-out', overlayColor: '#000000', }; // Helper to check if a value is a non-empty string const hasValue = ( val: T | '' | undefined, ): val is Exclude => Boolean(val); if (!pageTransition) { // No page transition settings - use element override or fallback return { type: hasValue(elementOverride?.type) ? elementOverride.type : fallback.type, durationMs: typeof elementOverride?.durationMs === 'number' && elementOverride.durationMs > 0 ? elementOverride.durationMs : fallback.durationMs, easing: hasValue(elementOverride?.easing) ? elementOverride.easing : fallback.easing, overlayColor: elementOverride?.overlayColor && elementOverride.overlayColor !== '' ? elementOverride.overlayColor : fallback.overlayColor, }; } // Cascade: Element override -> Page transition // Type: 'video' maps to 'fade' for slides let type: SlideTransitionType = 'fade'; if (hasValue(elementOverride?.type)) { type = elementOverride.type; } else if (pageTransition.type === 'none') { type = 'none'; } else { type = 'fade'; // 'fade' or 'video' -> 'fade' } // Duration: Element override -> Page transition const durationMs = typeof elementOverride?.durationMs === 'number' && elementOverride.durationMs > 0 ? elementOverride.durationMs : pageTransition.durationMs; // Easing: Element override -> Page transition const easing = hasValue(elementOverride?.easing) ? elementOverride.easing : pageTransition.easing; // Overlay color: Element override -> Page transition const overlayColor = elementOverride?.overlayColor && elementOverride.overlayColor !== '' ? elementOverride.overlayColor : pageTransition.overlayColor; return { type, durationMs, easing, overlayColor }; } /** * Extract slide transition override from carousel element */ export function extractCarouselSlideOverride( element: | { carouselSlideTransitionType?: SlideTransitionType | ''; carouselSlideTransitionDurationMs?: number | ''; carouselSlideTransitionEasing?: EasingFunction | ''; carouselSlideTransitionOverlayColor?: string; } | null | undefined, ): SlideTransitionOverride | null { if (!element) return null; return { type: element.carouselSlideTransitionType, durationMs: element.carouselSlideTransitionDurationMs, easing: element.carouselSlideTransitionEasing, overlayColor: element.carouselSlideTransitionOverlayColor, }; } /** * Extract slide transition override from gallery element */ export function extractGallerySlideOverride( element: | { gallerySlideTransitionType?: SlideTransitionType | ''; gallerySlideTransitionDurationMs?: number | ''; gallerySlideTransitionEasing?: EasingFunction | ''; gallerySlideTransitionOverlayColor?: string; } | null | undefined, ): SlideTransitionOverride | null { if (!element) return null; return { type: element.gallerySlideTransitionType, durationMs: element.gallerySlideTransitionDurationMs, easing: element.gallerySlideTransitionEasing, overlayColor: element.gallerySlideTransitionOverlayColor, }; }