UNPKG

react-native-reanimated

Version:

More powerful alternative to Animated library for React Native.

120 lines (110 loc) 3.46 kB
'use strict'; import { ReanimatedError } from '../../../../../common'; import type { ControlPoint, CSSTimingFunction } from '../../../../easings'; import { cubicBezier, linear, steps } from '../../../../easings'; import type { ConvertValuesToArraysWithUndefined, CSSTransitionProperties, } from '../../../../types'; import { camelizeKebabCase, isArrayOfLength, isPercentage, isPredefinedTimingFunction, isStepsModifier, parseSingleTransitionShorthand, splitByComma, splitByWhitespace, } from '../../../../utils'; export type ExpandedCSSTransitionConfigProperties = Required< ConvertValuesToArraysWithUndefined< Omit<CSSTransitionProperties, 'transition' | 'transitionProperty'> > > & { transitionProperty: string[]; }; export const createEmptyTransitionConfig = (): ExpandedCSSTransitionConfigProperties => ({ transitionProperty: [], transitionDuration: [], transitionTimingFunction: [], transitionDelay: [], transitionBehavior: [], }); export function parseTransitionShorthand(value: string) { return splitByComma(value).reduce<ExpandedCSSTransitionConfigProperties>( (acc, part) => { const result = parseSingleTransitionShorthand(part); acc.transitionProperty.push( camelizeKebabCase(result.transitionProperty ?? 'all') ); acc.transitionDuration.push(result.transitionDuration); acc.transitionTimingFunction.push( result.transitionTimingFunction ? parseTimingFunction(result.transitionTimingFunction) : undefined ); acc.transitionDelay.push(result.transitionDelay); acc.transitionBehavior.push(result.transitionBehavior); return acc; }, createEmptyTransitionConfig() ); } function asControlPoint(value: string[]): ControlPoint | null { const [first, ...rest] = value; if (!first || isNaN(Number(first)) || !rest.every(isPercentage)) { return null; } return [Number(first), ...rest]; } function parseTimingFunction(value: string): CSSTimingFunction { if (isPredefinedTimingFunction(value)) { return value; } // TODO: implement more strict check const regex = /^(.+)\((.+)\)$/; if (!regex.test(value)) { throw new ReanimatedError(`Unsupported timing function: ${value}`); } const [, name, args] = value.match(regex)!; const parsedArgs = splitByComma(args); switch (name) { case 'cubic-bezier': { const numberArgs = parsedArgs.map(Number); if ( isArrayOfLength(numberArgs, 4) && numberArgs.every((n) => !isNaN(n)) ) { return cubicBezier(...numberArgs); } break; } case 'linear': { const controlPoints = parsedArgs.map((arg) => { const parts = splitByWhitespace(arg); const controlPoint = asControlPoint(parts); if (!controlPoint) { throw new ReanimatedError( `Invalid control point: ${arg} in ${value} timing function` ); } return controlPoint; }); return linear(...controlPoints); } case 'steps': { const stepsNumber = Number(parsedArgs[0]); const stepsModifier = parsedArgs[1]; if ( !isNaN(stepsNumber) && stepsNumber > 0 && (stepsModifier === undefined || isStepsModifier(stepsModifier)) ) { return steps(stepsNumber, stepsModifier); } break; } } throw new ReanimatedError(`Invalid timing function: ${value}`); }