154 lines
4.6 KiB
TypeScript
154 lines
4.6 KiB
TypeScript
/**
|
|
* 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 = <T extends string>(
|
|
val: T | '' | undefined,
|
|
): val is Exclude<T, ''> => 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,
|
|
};
|
|
}
|