UNPKG

react-native-reanimated

Version:

More powerful alternative to Animated library for React Native.

146 lines (130 loc) 4.49 kB
'use strict'; import { ReanimatedError } from '../errors'; const INDEX_X = 0; const INDEX_Y = 1; const INDEX_Z = 2; // Implementation based on https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/StyleSheet/processTransformOrigin.js function validateTransformOrigin(transformOrigin: Array<string | number>) { 'worklet'; if (transformOrigin.length !== 3) { throw new ReanimatedError('Transform origin must have exactly 3 values.'); } const [x, y, z] = transformOrigin; if (!(typeof x === 'number' || (typeof x === 'string' && x.endsWith('%')))) { throw new ReanimatedError( `Transform origin x-position must be a number or a percentage string. Passed value: ${x}.` ); } if (!(typeof y === 'number' || (typeof y === 'string' && y.endsWith('%')))) { throw new ReanimatedError( `Transform origin y-position must be a number or a percentage string. Passed value: ${y}.` ); } if (typeof z !== 'number') { throw new ReanimatedError( `Transform origin z-position must be a number. Passed value: ${z}.` ); } } export function processTransformOrigin( transformOriginIn: Array<string | number> | string | undefined ): Array<string | number> { 'worklet'; let transformOrigin: Array<string | number> = Array.isArray(transformOriginIn) ? transformOriginIn : ['50%', '50%', 0]; if (typeof transformOriginIn === 'string') { const transformOriginString = transformOriginIn; const regex = /(top|bottom|left|right|center|\d+(?:%|px)|0)/gi; const transformOriginArray: Array<string | number> = ['50%', '50%', 0]; let index = INDEX_X; let matches; while ((matches = regex.exec(transformOriginString))) { let nextIndex = index + 1; const value = matches[0]; const valueLower = value.toLowerCase(); switch (valueLower) { case 'left': case 'right': { if (index !== INDEX_X) { throw new ReanimatedError( `Transform-origin ${value} can only be used for x-position` ); } transformOriginArray[INDEX_X] = valueLower === 'left' ? 0 : '100%'; break; } case 'top': case 'bottom': { if (index === INDEX_Z) { throw new ReanimatedError( `Transform-origin ${value} can only be used for y-position` ); } transformOriginArray[INDEX_Y] = valueLower === 'top' ? 0 : '100%'; // Handle [[ center | left | right ] && [ center | top | bottom ]] <length>? if (index === INDEX_X) { const horizontal = regex.exec(transformOriginString); if (horizontal == null) { break; } switch (horizontal?.[0].toLowerCase()) { case 'left': transformOriginArray[INDEX_X] = 0; break; case 'right': transformOriginArray[INDEX_X] = '100%'; break; case 'center': transformOriginArray[INDEX_X] = '50%'; break; default: throw new ReanimatedError( `Could not parse transform-origin: ${transformOriginString}` ); } nextIndex = INDEX_Z; } break; } case 'center': { if (index === INDEX_Z) { throw new ReanimatedError( `Transform-origin value ${value} cannot be used for z-position` ); } transformOriginArray[index] = '50%'; break; } default: { if (value.endsWith('%')) { transformOriginArray[index] = value; } else { const numericValue = parseFloat(value); if (isNaN(numericValue)) { throw new ReanimatedError( `Invalid numeric value in transform-origin: ${value}` ); } transformOriginArray[index] = numericValue; } break; } } index = nextIndex; } transformOrigin = transformOriginArray; } if ( typeof transformOriginIn !== 'string' && !Array.isArray(transformOriginIn) ) { throw new ReanimatedError( `Invalid transformOrigin type: ${typeof transformOriginIn}` ); } if (__DEV__) { validateTransformOrigin(transformOrigin); } return transformOrigin; }