UNPKG

@audira/carbon-react-native

Version:

Build React Native apps with component and shared patterns using Carbon

148 lines (147 loc) 5.34 kB
"use strict"; import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react'; import { Animated, Easing, View } from 'react-native'; import { Motion } from '@audira/carbon-react-native-elements'; import { CommonStyleSheet, FlexStyleSheet } from "../../_internal/style-sheets/index.js"; import { jsx as _jsx } from "react/jsx-runtime"; export const Collapsible = /*#__PURE__*/forwardRef(function ({ defaultOpen, open: openProp, motion = { toOpen: { duration: Motion.Duration.fast_02, easing: Easing.bezier(Motion.Easing.entrance.productive.x1, Motion.Easing.entrance.productive.y1, Motion.Easing.entrance.productive.x2, Motion.Easing.entrance.productive.y2) }, toClose: { duration: Motion.Duration.fast_02, easing: Easing.bezier(Motion.Easing.exit.productive.x1, Motion.Easing.exit.productive.y1, Motion.Easing.exit.productive.x2, Motion.Easing.exit.productive.y2) } }, children, style, contentContainerStyle, onToggle, onOpened, onClosed, ...props }, forwardedRef) { const viewRef = useRef(null), ref = useRef({ positionView: defaultOpen ?? openProp ? 'relative' : 'absolute', contentHeight: 0, openSelf: !!defaultOpen }), [openSelf, setOpenSelf] = useState(ref.current.openSelf), /** * Absolute position is required to keep content being rendered as it is when the container is not open (zero height) * * We need 'relative' position when the collapsible is initially opened due to heightAnimated initial value is zero and only will be calculated after content is rendered * * This state will be changed once only from 'relative' to 'absolute' */ [positionView, setPositionView] = useState(ref.current.positionView), heightAnimated = useRef(new Animated.Value(0)), /** * - 0 -> Closed * - 1 -> Opened */ contentContainerAnimated = useRef(new Animated.Value(0)), controlled = typeof openProp === 'boolean', open = controlled ? !!openProp : openSelf, setPositionViewToAbsolute = useCallback(() => { if (ref.current.positionView === 'relative') { ref.current.positionView = 'absolute'; setPositionView('absolute'); } }, []), onLayoutContent = useCallback(({ nativeEvent }) => { if (ref.current.contentHeight !== nativeEvent.layout.height) { ref.current.contentHeight = nativeEvent.layout.height; if (open) { Animated.timing(heightAnimated.current, { toValue: ref.current.contentHeight, duration: 0, useNativeDriver: false }).start(setPositionViewToAbsolute); } } }, [heightAnimated, open, setPositionViewToAbsolute]); useEffect(() => { if (ref.current.contentHeight) { if (open) { Animated.timing(heightAnimated.current, { toValue: ref.current.contentHeight, useNativeDriver: false, duration: motion.toOpen.duration, easing: motion.toOpen.easing }).start(onOpened); Animated.timing(contentContainerAnimated.current, { toValue: 1, duration: motion.toOpen.duration, easing: motion.toOpen.easing, useNativeDriver: false }).start(); } else { Animated.timing(heightAnimated.current, { toValue: 0, duration: motion.toClose.duration, easing: motion.toClose.easing, useNativeDriver: false }).start(onClosed); Animated.timing(contentContainerAnimated.current, { toValue: 0, duration: motion.toClose.duration, easing: motion.toClose.easing, useNativeDriver: false }).start(); } onToggle?.(open); } }, [open, heightAnimated, contentContainerAnimated, motion, onToggle, onOpened, onClosed]); useImperativeHandle(forwardedRef, () => { return Object.assign(viewRef.current, { setOpen(value) { if (!controlled) { if (typeof value === 'boolean') { ref.current.openSelf = value; } else { ref.current.openSelf = value(ref.current.openSelf); } setOpenSelf(ref.current.openSelf); } } }); }, [controlled]); return /*#__PURE__*/_jsx(Animated.View, { ...props, style: [CommonStyleSheet.overflow_hidden, positionView === 'absolute' ? { height: heightAnimated.current } : null, style], ref: viewRef, children: /*#__PURE__*/_jsx(View, { style: [CommonStyleSheet.w_full, { position: positionView }], children: /*#__PURE__*/_jsx(Animated.View, { style: [FlexStyleSheet.flex_initial, { opacity: contentContainerAnimated.current.interpolate({ inputRange: contentContainerInterpolationRange, outputRange: [0, 1] }), transform: [{ translateY: contentContainerAnimated.current.interpolate({ inputRange: contentContainerInterpolationRange, outputRange: [-12, 0] }) }] }, contentContainerStyle], onLayout: onLayoutContent, children: children }) }) }); }); const contentContainerInterpolationRange = [0, 1]; //# sourceMappingURL=Collapsible.js.map