nandorojo / moti

šŸ¼ The React Native (+ Web) animation library, powered by Reanimated 3.
https://moti.fyi
MIT License
3.9k stars 120 forks source link

WEB - Accordion does not open automatically on initial render. #245

Closed Puneet56 closed 1 year ago

Puneet56 commented 1 year ago

Hi, I Have been using the example code for accordion in the docs and if hide is false in props then the accordion does not open automatically only on web. Works fine on mobile app.

Also the snack embed is broken. image

nandorojo commented 1 year ago

yeah expo snack broke reanimated.

thatā€™s odd for the accordion. it never shows at all?

Puneet56 commented 1 year ago

Yeah if I set hide to false. It still has 0 height on first render. When I click the header and click it again i.e change it from false to true then true to false,, then it shows.

https://user-images.githubusercontent.com/26213419/204336610-de1e8b40-1d28-4081-aeab-3636ff850d2e.mp4

nandorojo commented 1 year ago

Certainly odd. I wonder why this doesn't happen to me.

nandorojo commented 1 year ago

Here is an AnimateHeight component built directly with Reanimated. Can you try swapping this in?

import { StyleSheet } from 'react-native'
import Animated, {
  useAnimatedStyle,
  useSharedValue,
  withTiming,
  runOnJS,
} from 'react-native-reanimated' 

export type AnimateHeightProps = {
  children?: React.ReactNode
  /**
   * If `true`, the height will automatically animate to 0. Default: `false`.
   */
  hide?: boolean
  onHeightDidAnimate?: (height: number) => void
  initialHeight?: number
}

const transition = { duration: 200 } as const

function AnimateHeight({
  children,
  hide = false,
  style,
  onHeightDidAnimate,
  initialHeight = 0,
}: AnimateHeightProps) {
  const measuredHeight = useSharedValue(initialHeight)
  const childStyle = useAnimatedStyle(
    () => ({
      opacity: withTiming(!measuredHeight.value || hide ? 0 : 1, transition),
    }),
    [hide, measuredHeight]
  )

  const containerStyle = useAnimatedStyle(() => {
    return {
      height: withTiming(hide ? 0 : measuredHeight.value, transition, () => {
        if (onHeightDidAnimate) {
          runOnJS(onHeightDidAnimate)(measuredHeight.value)
        }
      }),
    }
  }, [hide, measuredHeight])

  return (
    <Animated.View style={[styles.hidden, style, containerStyle]}>
      <Animated.View
        style={[StyleSheet.absoluteFill, styles.autoBottom, childStyle]}
        onLayout={({ nativeEvent }) => {
          measuredHeight.value = Math.ceil(nativeEvent.layout.height)
        }}
      >
        {children}
      </Animated.View>
    </Animated.View>
  )
}

const styles = StyleSheet.create({
  autoBottom: {
    bottom: 'auto',
  },
  hidden: {
    overflow: 'hidden',
  },
})

export { AnimateHeight }
nandorojo commented 1 year ago

I was able to reproduce this in Safari, while it works fine on Chrome. Very weird...

gianpaj commented 1 year ago

i think is still an issue on Chrome

image
n.g.__reanimatedWorkletInit is not a function
  Evaluating @motify/core.js
  Evaluating animate-height.tsx.js
  Evaluating App.tsx.js
  Loading App.tsx

https://snack.expo.dev/@nandorojo/moti-animate-height