moti requires expo-linear-gradient when im using react native cli only without expo @nandorojo
Opened this issue · 12 comments
Is there an existing issue for this?
- I have searched the existing issues
Do you want this issue prioritized?
- Yes, I have sponsored
- Not urgent
Current Behavior
getting this weird error while trying to use moti with react native only
my package json contains these packages
"react-native-reanimated": "^3.6.1",
"react-native": "0.72.7",
"moti": "^0.27.2",
![Screenshot 2023-12-18 at 7 29 38 PM](https://private-user-images.githubusercontent.com/93282741/291348145-eaf2a620-96bd-4e84-964f-cf4e9a2c64f9.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MTk3NDU3MTAsIm5iZiI6MTcxOTc0NTQxMCwicGF0aCI6Ii85MzI4Mjc0MS8yOTEzNDgxNDUtZWFmMmE2MjAtOTZiZC00ZTg0LTk2NGYtY2Y0ZTlhMmM2NGY5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA2MzAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNjMwVDExMDMzMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWRkYjg0OWIxMDAyMjkzZTY1NDQ2OTgxYjFlZWQ4ZGFmOWQwYzQ3ODBkMTg1ZjNjNzk2NTQ1ODRlMjkzNTVkN2ImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.OOr44i_kW3qrgnmpwkKDG0RZP58751hx17tzfvfHlnM)
Expected Behavior
getting this weird error while trying to use moti with react native only
my package json contains these packages
"react-native-reanimated": "^3.6.1",
"react-native": "0.72.7",
"moti": "^0.27.2",
![Screenshot 2023-12-18 at 7 29 38 PM](https://private-user-images.githubusercontent.com/93282741/291348145-eaf2a620-96bd-4e84-964f-cf4e9a2c64f9.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MTk3NDU3MTAsIm5iZiI6MTcxOTc0NTQxMCwicGF0aCI6Ii85MzI4Mjc0MS8yOTEzNDgxNDUtZWFmMmE2MjAtOTZiZC00ZTg0LTk2NGYtY2Y0ZTlhMmM2NGY5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA2MzAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNjMwVDExMDMzMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWRkYjg0OWIxMDAyMjkzZTY1NDQ2OTgxYjFlZWQ4ZGFmOWQwYzQ3ODBkMTg1ZjNjNzk2NTQ1ODRlMjkzNTVkN2ImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.OOr44i_kW3qrgnmpwkKDG0RZP58751hx17tzfvfHlnM)
Steps To Reproduce
create new react native project with npx react-native init project
install moti package
instal reanimated package
use in in the code
Versions
"react-native-reanimated": "^3.6.1",
"react-native": "0.72.7",
"moti": "^0.27.2",
Screenshots
![Screenshot 2023-12-18 at 7 29 38 PM](https://private-user-images.githubusercontent.com/93282741/291348630-fbe382ca-c3c3-4436-8781-103410af7f00.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MTk3NDU3MTAsIm5iZiI6MTcxOTc0NTQxMCwicGF0aCI6Ii85MzI4Mjc0MS8yOTEzNDg2MzAtZmJlMzgyY2EtYzNjMy00NDM2LTg3ODEtMTAzNDEwYWY3ZjAwLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA2MzAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNjMwVDExMDMzMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWQ0ZDY1YTJiMjliZjI2M2ZjOTE3MzBhZmZlODJlMjYwYjNjY2Q1M2FjNjNmYTMxZWNiNWJiM2ZmNGQwZGM0Y2MmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.Zm9PwrZmN4ZUaI_ukuMgAZvnOe0OmCO3GJEvqR_e_Gs)
![Screenshot 2023-12-18 at 7 32 35 PM](https://private-user-images.githubusercontent.com/93282741/291348817-bb3f8299-d969-4b1f-9664-5217efc6cc00.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MTk3NDU3MTAsIm5iZiI6MTcxOTc0NTQxMCwicGF0aCI6Ii85MzI4Mjc0MS8yOTEzNDg4MTctYmIzZjgyOTktZDk2OS00YjFmLTk2NjQtNTIxN2VmYzZjYzAwLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA2MzAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNjMwVDExMDMzMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTk3NTdiYmM5ODM3ODEwYWNlYzg5OTBlN2EyZjk1M2E2MDMzZTBjYWYwMGI2MzQzMzIyZWY2ZDg2OGY4NTE0ZjYmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.WuYxdbm6jtfrRx2K8tPKduKHwZFLs9JE62yP7sKUu88)
Reproduction
npx create-react-native-app -t with-moti
@husam868maher @nandorojo same here any fix for this ?
Did you use the non-expo approach from the skeleton on docs?
Hey @nandorojo!
Recently I've also tried to use Skeleton component with react-native-cli & react-native-lineal-gradient but got the same error as @yamak-app
Seems like your Babel plugin isn't working
You added the module resolver one from the docs?
Hi @nandorojo !
Thanks again for such great package for animations. I've resolved
the problem for react-native cli by using this small patch changes:
Can you please send the code inline?
expo.tsx file:
import { LinearGradient } from 'react-native-linear-gradient'
import React from 'react'
import SkeletonNative from './skeleton-new'
import { MotiSkeletonProps } from './types'
export default function SkeletonExpo(
props: Omit<MotiSkeletonProps, 'Gradient'>
) {
return <SkeletonNative {...props} Gradient={LinearGradient as any} />
}
SkeletonExpo.Group = SkeletonNative.Group
skeleton.tsx:
import { LinearGradient } from 'react-native-linear-gradient'
import React, { useState, createContext, useContext } from 'react'
import { View, StyleSheet } from 'react-native'
import { View as MotiView } from '../components'
import { AnimatePresence, MotiTransitionProp } from '../core'
import {
DEFAULT_SKELETON_SIZE as DEFAULT_SIZE,
defaultDarkColors,
defaultLightColors,
baseColors,
} from './shared'
import { MotiSkeletonProps } from './types'
export default function Skeleton(props: MotiSkeletonProps) {
const skeletonGroupContext = useContext(SkeletonGroupContext)
const {
radius = 8,
children,
show = skeletonGroupContext ?? !children,
width,
height = children ? undefined : DEFAULT_SIZE,
boxHeight,
colorMode = 'dark',
colors = colorMode === 'dark' ? defaultDarkColors : defaultLightColors,
backgroundColor = colors[0] ??
colors[1] ??
baseColors[colorMode]?.secondary,
backgroundSize = 6,
disableExitAnimation,
transition,
} = props
const [measuredWidth, setMeasuredWidth] = useState(0)
const getBorderRadius = () => {
if (radius === 'square') {
return 0
}
if (radius === 'round') {
return 99999
}
return radius
}
const borderRadius = getBorderRadius()
const getOuterHeight = () => {
if (boxHeight != null) return boxHeight
if (show && !children) {
return height
}
return undefined
}
const outerHeight = getOuterHeight()
return (
<View
style={{
height: outerHeight,
minHeight: height,
minWidth: width ?? (children ? undefined : DEFAULT_SIZE),
}}
>
{children}
<AnimatePresence>
{show && (
<MotiView
style={{
position: 'absolute',
top: 0,
left: 0,
borderRadius,
width: width ?? (children ? '100%' : DEFAULT_SIZE),
height: height ?? '100%',
overflow: 'hidden',
}}
animate={{
backgroundColor,
opacity: 1,
}}
transition={{
type: 'timing',
}}
exit={
!disableExitAnimation && {
opacity: 0,
}
}
onLayout={({ nativeEvent }) => {
if (measuredWidth === nativeEvent.layout.width) return
setMeasuredWidth(nativeEvent.layout.width)
}}
pointerEvents="none"
>
<AnimatedGradient
// force a key change to make the loop animation re-mount
key={`${JSON.stringify(colors)}-${measuredWidth}-${JSON.stringify(
transition || null
)}`}
colors={colors}
backgroundSize={backgroundSize}
measuredWidth={measuredWidth}
transition={transition}
/>
</MotiView>
)}
</AnimatePresence>
</View>
)
}
const AnimatedGradient = React.memo(
function AnimatedGradient({
measuredWidth,
colors,
backgroundSize,
transition = {},
}: {
measuredWidth: number
colors: string[]
backgroundSize: number
transition?: MotiTransitionProp
}) {
return (
<MotiView
style={StyleSheet.absoluteFillObject}
from={{ opacity: 0 }}
transition={{
type: 'timing',
duration: 200,
}}
animate={
measuredWidth
? {
opacity: 1,
}
: undefined
}
>
<MotiView
style={[
StyleSheet.absoluteFillObject,
{
width: measuredWidth * backgroundSize,
},
]}
from={{
translateX: 0,
}}
animate={
measuredWidth
? {
translateX: -measuredWidth * (backgroundSize - 1),
}
: undefined
}
transition={{
loop: true,
delay: 200,
type: 'timing',
duration: 3000,
...(transition as any),
}}
>
<LinearGradient
colors={colors}
start={{
x: 0.1,
y: 1,
}}
end={{
x: 1,
y: 1,
}}
style={StyleSheet.absoluteFillObject}
/>
</MotiView>
</MotiView>
)
},
function propsAreEqual(prev, next) {
if (prev.measuredWidth !== next.measuredWidth) return false
if (prev.backgroundSize !== next.backgroundSize) return false
const didColorsChange = prev.colors.some((color, index) => {
return color !== next.colors[index]
})
if (didColorsChange) return false
// transition changes will not be respected, but it'll be in the key
return true
}
)
const SkeletonGroupContext = createContext<boolean | undefined>(undefined)
function SkeletonGroup({
children,
show,
}: {
children: React.ReactNode
/**
* If `true`, all `Skeleton` children components will be shown.
*
* If `false`, the `Skeleton` children will be hidden.
*/
show: boolean
}) {
return (
<SkeletonGroupContext.Provider value={show}>
{children}
</SkeletonGroupContext.Provider>
)
}
Skeleton.Group = SkeletonGroup
The only important change here is this new import { LinearGradient } from 'react-native-linear-gradient' instead of expo-linear-gradient.
babel.config.js:
module.exports = function (api) {
api.cache(true);
return {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
'react-native-reanimated/plugin',
[
'babel-plugin-module-resolver',
{
root: ['./src/'],
alias: [
{ 'moti/skeleton': 'moti/skeleton/react-native-linear-gradient' },
],
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
],
],
};
};
I didn't properly tested it with other RN versions. In my case it's working like a charm for both Android/iOS "react-native": "0.72.7"
@nandorojo Let me know if it's working on your side?
By the way, maybe it's better to override this react-native-linear-gradient/expo-linear-gradient dependency directly in json with "overrides" or something similar to it. What do you think?
Please send the patch file inline
What's wrong with the current docs for the skeleton using the Babel plugin? Doesn't it do this for you?
diff --git a/node_modules/moti/src/skeleton/expo.tsx b/node_modules/moti/src/skeleton/expo.tsx
index 1674b89..083824c 100644
--- a/node_modules/moti/src/skeleton/expo.tsx
+++ b/node_modules/moti/src/skeleton/expo.tsx
@@ -1,4 +1,4 @@
-import { LinearGradient } from 'expo-linear-gradient'
+import { LinearGradient } from 'react-native-linear-gradient'
import React from 'react'
import SkeletonNative from './skeleton-new'
diff --git a/node_modules/moti/src/skeleton/skeleton.tsx b/node_modules/moti/src/skeleton/skeleton.tsx
index 3ef5dd1..0e3bed3 100644
--- a/node_modules/moti/src/skeleton/skeleton.tsx
+++ b/node_modules/moti/src/skeleton/skeleton.tsx
@@ -1,4 +1,4 @@
-import { LinearGradient } from 'expo-linear-gradient'
+import { LinearGradient } from 'react-native-linear-gradient'
import React, { useState, createContext, useContext } from 'react'
import { View, StyleSheet } from 'react-native'
diff --git a/node_modules/moti/src/skeleton/types.ts b/node_modules/moti/src/skeleton/types.ts
index 7fa9d78..176f224 100644
--- a/node_modules/moti/src/skeleton/types.ts
+++ b/node_modules/moti/src/skeleton/types.ts
@@ -1,4 +1,4 @@
-import { LinearGradient } from 'expo-linear-gradient'
+import { LinearGradient } from 'react-native-linear-gradient'
import { MotiTransitionProp } from '../core'
import { baseColors } from './shared'
babel-plugin is working as expected now. Before, I had some troubles with changing babel.config.js.