@tamagui/animations-react-native 1.125.21 → 1.125.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tamagui/animations-react-native",
3
- "version": "1.125.21",
3
+ "version": "1.125.23",
4
4
  "source": "src/index.ts",
5
5
  "removeSideEffects": true,
6
6
  "sideEffects": [
@@ -29,12 +29,12 @@
29
29
  }
30
30
  },
31
31
  "dependencies": {
32
- "@tamagui/constants": "1.125.21",
33
- "@tamagui/use-presence": "1.125.21",
34
- "@tamagui/web": "1.125.21"
32
+ "@tamagui/constants": "1.125.23",
33
+ "@tamagui/use-presence": "1.125.23",
34
+ "@tamagui/web": "1.125.23"
35
35
  },
36
36
  "devDependencies": {
37
- "@tamagui/build": "1.125.21",
37
+ "@tamagui/build": "1.125.23",
38
38
  "react": "*",
39
39
  "react-native": "^0.76.5"
40
40
  },
@@ -0,0 +1,18 @@
1
+ {
2
+ "mappings": "AAEA,cAEE,iBAEA,yBACA,2BACA,8BACK,cAAc;AAGrB,SAAS,eAAe,WAAW,YAAY,cAAc;KAExD,iBAAiB,UAAU,mBAAmB,aAAa,KAAI;KAE/D,eAAe,EAAE,OAAO,SAAU,IAAG,QACxC,KACE,SAAS,uBACP,UACA,eACA,YACA,aACA,SACA,sBACA,UACA,cACA,YACA;KAID,eAAe,EAAE,MAAM,SAAU,IAAG,QAAQ,SAAS;KAErD,kBAAkB,eAAe;AAiCtC,OAAO,cAAMA,cAAc,SAAS,yBAAyB;AAC7D,OAAO,cAAMC,cAAc,SAAS,yBAAyB;AAE7D,OAAO,iBAAS,kBACdC,kBACC,wBAAwB,SAAS;KA2D/B,gBAAgB,wBAAwB,SAAS;AAEtD,OAAO,cAAMC,2BAA2B,0BAA0B;AAgBlE,OAAO,cAAMC,wBAAwB,uBAAuB;AAO5D,OAAO,iBAAS,iBAAiB,UAAU,kBACzCC,YAAY,IACX,gBAAgB",
3
+ "names": [
4
+ "AnimatedView: Animated.AnimatedComponent<typeof View>",
5
+ "AnimatedText: Animated.AnimatedComponent<typeof Text>",
6
+ "initial: number",
7
+ "useAnimatedNumberReaction: UseAnimatedNumberReaction<RNAnimatedNum>",
8
+ "useAnimatedNumberStyle: UseAnimatedNumberStyle<RNAnimatedNum>",
9
+ "animations: A"
10
+ ],
11
+ "sources": [
12
+ "src/createAnimations.tsx"
13
+ ],
14
+ "sourcesContent": [
15
+ "import { isWeb, useIsomorphicLayoutEffect } from '@tamagui/constants'\nimport { ResetPresence, usePresence } from '@tamagui/use-presence'\nimport type {\n AnimatedNumberStrategy,\n AnimationDriver,\n AnimationProp,\n UniversalAnimatedNumber,\n UseAnimatedNumberReaction,\n UseAnimatedNumberStyle,\n} from '@tamagui/web'\nimport { useEvent } from '@tamagui/web'\nimport React from 'react'\nimport { Animated, type Text, type View } from 'react-native'\n\ntype AnimationsConfig<A extends Object = any> = { [Key in keyof A]: AnimationConfig }\n\ntype SpringConfig = { type?: 'spring' } & Partial<\n Pick<\n Animated.SpringAnimationConfig,\n | 'delay'\n | 'bounciness'\n | 'damping'\n | 'friction'\n | 'mass'\n | 'overshootClamping'\n | 'speed'\n | 'stiffness'\n | 'tension'\n | 'velocity'\n >\n>\n\ntype TimingConfig = { type: 'timing' } & Partial<Animated.TimingAnimationConfig>\n\ntype AnimationConfig = SpringConfig | TimingConfig\n\nconst animatedStyleKey = {\n transform: true,\n opacity: true,\n}\n\nconst colorStyleKey = {\n backgroundColor: true,\n color: true,\n borderColor: true,\n borderLeftColor: true,\n borderRightColor: true,\n borderTopColor: true,\n borderBottomColor: true,\n}\n\n// these are the styles that are costly to animate because they don't support useNativeDriver and some of them are changing layout\nconst costlyToAnimateStyleKey = {\n borderRadius: true,\n borderTopLeftRadius: true,\n borderTopRightRadius: true,\n borderBottomLeftRadius: true,\n borderBottomRightRadius: true,\n borderWidth: true,\n borderLeftWidth: true,\n borderRightWidth: true,\n borderTopWidth: true,\n borderBottomWidth: true,\n ...colorStyleKey,\n // TODO for other keys like height or width, it's better to not add them here till layout animations are ready\n}\n\nexport const AnimatedView: Animated.AnimatedComponent<typeof View> = Animated.View\nexport const AnimatedText: Animated.AnimatedComponent<typeof Text> = Animated.Text\n\nexport function useAnimatedNumber(\n initial: number\n): UniversalAnimatedNumber<Animated.Value> {\n const state = React.useRef(\n null as any as {\n val: Animated.Value\n composite: Animated.CompositeAnimation | null\n strategy: AnimatedNumberStrategy\n }\n )\n if (!state.current) {\n state.current = {\n composite: null,\n val: new Animated.Value(initial),\n strategy: { type: 'spring' },\n }\n }\n\n return {\n getInstance() {\n return state.current.val\n },\n getValue() {\n return state.current.val['_value']\n },\n stop() {\n state.current.composite?.stop()\n state.current.composite = null\n },\n setValue(next: number, { type, ...config } = { type: 'spring' }, onFinish) {\n const val = state.current.val\n\n const handleFinish = onFinish\n ? ({ finished }) => (finished ? onFinish() : null)\n : undefined\n\n if (type === 'direct') {\n val.setValue(next)\n } else if (type === 'spring') {\n state.current.composite?.stop()\n const composite = Animated.spring(val, {\n ...config,\n toValue: next,\n useNativeDriver: !isWeb,\n })\n composite.start(handleFinish)\n state.current.composite = composite\n } else {\n state.current.composite?.stop()\n const composite = Animated.timing(val, {\n ...config,\n toValue: next,\n useNativeDriver: !isWeb,\n })\n composite.start(handleFinish)\n state.current.composite = composite\n }\n },\n }\n}\n\ntype RNAnimatedNum = UniversalAnimatedNumber<Animated.Value>\n\nexport const useAnimatedNumberReaction: UseAnimatedNumberReaction<RNAnimatedNum> = (\n { value },\n onValue\n) => {\n const onChange = useEvent((current) => {\n onValue(current.value)\n })\n\n React.useEffect(() => {\n const id = value.getInstance().addListener(onChange)\n return () => {\n value.getInstance().removeListener(id)\n }\n }, [value, onChange])\n}\n\nexport const useAnimatedNumberStyle: UseAnimatedNumberStyle<RNAnimatedNum> = (\n value,\n getStyle\n) => {\n return getStyle(value.getInstance())\n}\n\nexport function createAnimations<A extends AnimationsConfig>(\n animations: A\n): AnimationDriver<A> {\n return {\n isReactNative: true,\n animations,\n View: AnimatedView,\n Text: AnimatedText,\n useAnimatedNumber,\n useAnimatedNumberReaction,\n useAnimatedNumberStyle,\n usePresence,\n ResetPresence,\n useAnimations: ({ props, onDidAnimate, style, componentState, presence }) => {\n const isDisabled = isWeb && componentState.unmounted === true\n const isExiting = presence?.[0] === false\n const sendExitComplete = presence?.[1]\n\n /** store Animated value of each key e.g: color: AnimatedValue */\n const animateStyles = React.useRef<Record<string, Animated.Value>>({})\n const animatedTranforms = React.useRef<{ [key: string]: Animated.Value }[]>([])\n const animationsState = React.useRef(\n new WeakMap<\n Animated.Value,\n {\n interpolation: Animated.AnimatedInterpolation<any>\n current?: number | string | undefined\n // only for colors\n animateToValue?: number\n }\n >()\n )\n\n const animateOnly = (props.animateOnly as string[]) || []\n const hasAnimateOnly = !!props.animateOnly\n\n const args = [JSON.stringify(style), componentState, isExiting, !!onDidAnimate]\n\n // check if there is any style that is not supported by native driver\n const isThereNoNativeStyleKeys = React.useMemo(() => {\n if (isWeb) return true\n return Object.keys(style).some((key) => {\n if (animateOnly) {\n return !animatedStyleKey[key] && animateOnly.indexOf(key) === -1\n }\n return !animatedStyleKey[key]\n })\n }, args)\n\n const res = React.useMemo(() => {\n const runners: Function[] = []\n const completions: Promise<void>[] = []\n\n const nonAnimatedStyle = {}\n\n for (const key in style) {\n const val = style[key]\n\n if (isDisabled) {\n continue\n }\n\n if (animatedStyleKey[key] == null && !costlyToAnimateStyleKey[key]) {\n nonAnimatedStyle[key] = val\n continue\n }\n\n if (hasAnimateOnly && !animateOnly.includes(key)) {\n nonAnimatedStyle[key] = val\n continue\n }\n\n if (key !== 'transform') {\n animateStyles.current[key] = update(key, animateStyles.current[key], val)\n continue\n }\n // key: 'transform'\n // for now just support one transform key\n if (!val) continue\n if (typeof val === 'string') {\n console.warn(`Warning: Tamagui can't animate string transforms yet!`)\n continue\n }\n\n for (const [index, transform] of val.entries()) {\n if (!transform) continue\n // tkey: e.g: 'translateX'\n const tkey = Object.keys(transform)[0]\n const currentTransform = animatedTranforms.current[index]?.[tkey]\n animatedTranforms.current[index] = {\n [tkey]: update(tkey, currentTransform, transform[tkey]),\n }\n animatedTranforms.current = [...animatedTranforms.current]\n }\n }\n\n const animatedStyle = {\n ...Object.fromEntries(\n Object.entries(animateStyles.current).map(([k, v]) => [\n k,\n animationsState.current!.get(v)?.interpolation || v,\n ])\n ),\n transform: animatedTranforms.current.map((r) => {\n const key = Object.keys(r)[0]\n const val = animationsState.current!.get(r[key])?.interpolation || r[key]\n return { [key]: val }\n }),\n }\n\n return {\n runners,\n completions,\n style: [nonAnimatedStyle, animatedStyle],\n }\n\n function update(\n key: string,\n animated: Animated.Value | undefined,\n valIn: string | number\n ) {\n const isColorStyleKey = colorStyleKey[key]\n const [val, type] = isColorStyleKey ? [0, undefined] : getValue(valIn)\n let animateToValue = val\n const value = animated || new Animated.Value(val)\n const curInterpolation = animationsState.current.get(value)\n\n let interpolateArgs: any\n if (type) {\n interpolateArgs = getInterpolated(\n curInterpolation?.current ?? value['_value'],\n val,\n type\n )\n animationsState.current!.set(value, {\n interpolation: value.interpolate(interpolateArgs),\n current: val,\n })\n }\n\n if (isColorStyleKey) {\n animateToValue = curInterpolation?.animateToValue ? 0 : 1\n interpolateArgs = getColorInterpolated(\n curInterpolation?.current as string,\n // valIn is the next color\n valIn as string,\n animateToValue\n )\n animationsState.current!.set(value, {\n current: valIn,\n interpolation: value.interpolate(interpolateArgs),\n animateToValue: curInterpolation?.animateToValue ? 0 : 1,\n })\n }\n\n if (value) {\n const animationConfig = getAnimationConfig(key, animations, props.animation)\n\n let resolve\n const promise = new Promise<void>((res) => {\n resolve = res\n })\n completions.push(promise)\n\n runners.push(() => {\n value.stopAnimation()\n\n function getAnimation() {\n return Animated[animationConfig.type || 'spring'](value, {\n toValue: animateToValue,\n useNativeDriver: !isWeb && !isThereNoNativeStyleKeys,\n ...animationConfig,\n })\n }\n\n const animation = animationConfig.delay\n ? Animated.sequence([\n Animated.delay(animationConfig.delay),\n getAnimation(),\n ])\n : getAnimation()\n\n animation.start(({ finished }) => {\n if (finished) {\n resolve()\n }\n })\n })\n }\n\n if (process.env.NODE_ENV === 'development') {\n if (props['debug'] === 'verbose') {\n // prettier-ignore\n console.info(\n ' 💠 animate',\n key,\n `from (${value['_value']}) to`,\n valIn,\n `(${val})`,\n 'type',\n type,\n 'interpolate',\n interpolateArgs\n )\n }\n }\n return value\n }\n }, args)\n\n useIsomorphicLayoutEffect(() => {\n res.runners.forEach((r) => r())\n let cancel = false\n Promise.all(res.completions).then(() => {\n if (cancel) return\n onDidAnimate?.()\n if (isExiting) {\n sendExitComplete?.()\n }\n })\n return () => {\n cancel = true\n }\n }, args)\n\n if (process.env.NODE_ENV === 'development') {\n if (props['debug'] === 'verbose') {\n console.info(`Animated`, { response: res, inputStyle: style, isExiting })\n }\n }\n\n return res\n },\n }\n}\n\nfunction getColorInterpolated(\n currentColor: string | undefined,\n nextColor: string,\n animateToValue: number\n) {\n const inputRange = [0, 1]\n const outputRange = [currentColor ? currentColor : nextColor, nextColor]\n if (animateToValue === 0) {\n // because we are animating from value 1 to 0, we need to put target color at the beginning\n outputRange.reverse()\n }\n return {\n inputRange,\n outputRange,\n }\n}\n\nfunction getInterpolated(current: number, next: number, postfix = 'deg') {\n if (next === current) {\n current = next - 0.000000001\n }\n const inputRange = [current, next]\n const outputRange = [`${current}${postfix}`, `${next}${postfix}`]\n if (next < current) {\n inputRange.reverse()\n outputRange.reverse()\n }\n return {\n inputRange,\n outputRange,\n }\n}\n\nfunction getAnimationConfig(\n key: string,\n animations: AnimationsConfig,\n animation?: AnimationProp\n): AnimationConfig {\n if (typeof animation === 'string') {\n return animations[animation]\n }\n let type = ''\n let extraConf: any\n const shortKey = transformShorthands[key]\n if (Array.isArray(animation)) {\n type = animation[0] as string\n const conf = animation[1]?.[key] ?? animation[1]?.[shortKey]\n if (conf) {\n if (typeof conf === 'string') {\n type = conf\n } else {\n type = (conf as any).type || type\n extraConf = conf\n }\n }\n } else {\n const val = animation?.[key] ?? animation?.[shortKey]\n type = val?.type\n extraConf = val\n }\n const found = animations[type]\n return {\n ...found,\n ...extraConf,\n }\n}\n\n// try both combos\nconst transformShorthands = {\n x: 'translateX',\n y: 'translateY',\n translateX: 'x',\n translateY: 'y',\n}\n\nfunction getValue(input: number | string, isColor = false) {\n if (typeof input !== 'string') {\n return [input] as const\n }\n const [_, number, after] = input.match(/([-0-9]+)(deg|%|px)/) ?? []\n return [+number, after] as const\n}\n"
16
+ ],
17
+ "version": 3
18
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "mappings": "AAAA,OAAO,YAAY;AAEnB,cAAc",
3
+ "names": [],
4
+ "sources": [
5
+ "src/index.ts"
6
+ ],
7
+ "sourcesContent": [
8
+ "import './polyfill'\n\nexport * from './createAnimations'\n"
9
+ ],
10
+ "version": 3
11
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "mappings": "",
3
+ "names": [],
4
+ "sources": [
5
+ "src/polyfill.ts"
6
+ ],
7
+ "sourcesContent": [
8
+ "// for SSR\nif (typeof requestAnimationFrame === 'undefined') {\n globalThis['requestAnimationFrame'] =\n typeof setImmediate === 'undefined' ? setTimeout : setImmediate\n}\n"
9
+ ],
10
+ "version": 3
11
+ }