UNPKG

@mindinventory/react-native-tab-bar-interaction

Version:
219 lines (217 loc) 9.18 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getPathXCenterByIndex = exports.getPathXCenter = exports.TabBar = void 0; var _react = require("react"); var _reactNative = require("react-native"); var _d3Shape = require("d3-shape"); var _reactNativeRedash = require("react-native-redash"); var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated")); var _reactNativeSvg = _interopRequireWildcard(require("react-native-svg")); var _TabItem = require("./TabItem.js"); var _AnimatedCircle = _interopRequireDefault(require("./AnimatedCircle.js")); var _jsxRuntime = require("react/jsx-runtime"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } const AnimatedPath = _reactNativeReanimated.default.createAnimatedComponent(_reactNativeSvg.Path); const TRANSITION_SPEED = 300; const FIX_WIDTH = 380; const TAB_BAR_HEIGHT = 64; const generateTabShapePath = (position, adjustedHeight, tabContainerWidth, numOfTabs) => { const adjustedWidth = tabContainerWidth / numOfTabs; const tabX = adjustedWidth * position; const scaleGen = tabContainerWidth / FIX_WIDTH * 1; const SCALE = Number(scaleGen.toFixed(2)); const radius = adjustedHeight / 1.6 * SCALE; // Increase radius slightly const lineGenerator = (0, _d3Shape.line)().curve(_d3Shape.curveBasis); const halfCircle = lineGenerator([[tabX - radius, 0], // Start of left side of half-circle [tabX - radius, radius / 1.2], // Control point for smoother, deeper transition [tabX, radius * 1.4], // Higher point at the top for more depth [tabX + radius, radius / 1.2], // Control point for smoother, deeper transition [tabX + radius, 0] // End of right side of half-circle ]); return `${halfCircle}`; }; const getPathXCenter = currentPath => { const curves = (0, _reactNativeRedash.parse)(currentPath).curves; const startPoint = curves[0].to; const endPoint = curves[curves.length - 1].to; const centerX = (startPoint.x + endPoint.x) / 2; return centerX; }; exports.getPathXCenter = getPathXCenter; const getPathXCenterByIndex = (tabPaths, index) => { const curves = tabPaths[index].curves; const startPoint = curves[0].to; const endPoint = curves[curves.length - 1].to; const centerX = (startPoint.x + endPoint.x) / 2; return centerX; }; exports.getPathXCenterByIndex = getPathXCenterByIndex; const TabBar = props => { const { tabs, onTabChange, containerWidth, tabBarContainerBackground, circleFillColor, containerBottomSpace, containerTopRightRadius = 10, containerTopLeftRadius = 10, containerBottomLeftRadius = 25, containerBottomRightRadius = 25, defaultActiveTabIndex, transitionSpeed } = props; const [currentIndex, setCurrentIndex] = (0, _react.useState)(0); const numOfTabs = (0, _react.useMemo)(() => tabs.length > 2 ? tabs.length : 3, [tabs.length]); const containerPath = (0, _react.useMemo)(() => { // return `M0,0L${containerWidth},0L${containerWidth},0L${containerWidth},${TAB_BAR_HEIGHT}L0,${TAB_BAR_HEIGHT}L0,0`; return `M${containerTopLeftRadius},0 H${containerWidth - containerTopRightRadius} A${containerTopRightRadius},${containerTopRightRadius} 0 0 1 ${containerWidth},${containerTopRightRadius} V${TAB_BAR_HEIGHT - containerBottomRightRadius} A${containerBottomRightRadius},${containerBottomRightRadius} 0 0 1 ${containerWidth - containerBottomRightRadius},${TAB_BAR_HEIGHT} H${containerBottomLeftRadius} A${containerBottomLeftRadius},${containerBottomLeftRadius} 0 0 1 0,${TAB_BAR_HEIGHT - containerBottomLeftRadius} V${containerTopLeftRadius} A${containerTopLeftRadius},${containerTopLeftRadius} 0 0 1 ${containerTopLeftRadius},0 Z`; }, [containerBottomLeftRadius, containerBottomRightRadius, containerTopLeftRadius, containerTopRightRadius, containerWidth]); const curvedPaths = (0, _react.useMemo)(() => { return Array.from({ length: numOfTabs }, (_, index) => { const tabShapePath = generateTabShapePath(index + 0.5, TAB_BAR_HEIGHT, containerWidth, numOfTabs); return (0, _reactNativeRedash.parse)(`${tabShapePath}`); }); }, [containerWidth, numOfTabs]); const circleXCoordinate = (0, _reactNativeReanimated.useSharedValue)(0); const progress = (0, _reactNativeReanimated.useSharedValue)(1); const handleMoveCircle = currentPath => { circleXCoordinate.value = getPathXCenter(currentPath); }; const animatedProps = (0, _reactNativeReanimated.useAnimatedProps)(() => { const currentPath = (0, _reactNativeRedash.interpolatePath)(progress.value, Array.from({ length: curvedPaths.length }, (_, index) => index + 1), curvedPaths); (0, _reactNativeReanimated.runOnJS)(handleMoveCircle)(currentPath); return { d: `${containerPath} ${currentPath}` }; }); const handleTabPress = index => { progress.value = (0, _reactNativeReanimated.withTiming)(index + 1, { duration: transitionSpeed ? transitionSpeed : TRANSITION_SPEED, easing: _reactNativeReanimated.Easing.linear }); setCurrentIndex(index); }; (0, _react.useEffect)(() => { if (defaultActiveTabIndex !== undefined) { progress.value = (0, _reactNativeReanimated.withTiming)(defaultActiveTabIndex + 1, { duration: transitionSpeed ? transitionSpeed : TRANSITION_SPEED }); setCurrentIndex(defaultActiveTabIndex); } }, [defaultActiveTabIndex, progress, transitionSpeed]); const tabBarContainerStyle = (0, _react.useMemo)(() => { return { bottom: containerBottomSpace ? containerBottomSpace : 0, borderBottomLeftRadius: 10, borderBottomRightRadius: 10 }; }, [containerBottomSpace]); if (tabs.length > 5) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.emptyContainer, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { children: "You can add maximum five tabs" }) }); } else if (tabs.length < 2) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: styles.emptyContainer, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { children: "Please add tab data" }) }); } return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: [styles.tabBarContainer, tabBarContainerStyle], children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.default, { width: containerWidth, height: TAB_BAR_HEIGHT, style: styles.shadowMd, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(AnimatedPath, { fill: tabBarContainerBackground ? tabBarContainerBackground : '#fff', animatedProps: animatedProps }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_AnimatedCircle.default, { circleX: circleXCoordinate, circleFillColor: circleFillColor }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: [styles.tabItemsContainer, { height: TAB_BAR_HEIGHT }], children: tabs.map((val, index) => { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_TabItem.TabItem, { label: val.name, activeIcon: val.activeIcon, inactiveIcon: val.inactiveIcon, activeIndex: defaultActiveTabIndex ? defaultActiveTabIndex : 1, index: index, onTabPress: () => { handleTabPress(index); if (val !== undefined) { onTabChange(val, index); } }, containerWidth: containerWidth, curvedPaths: curvedPaths, currentIndex: currentIndex, transitionSpeed: transitionSpeed }, index.toString()); }) })] }); }; exports.TabBar = TabBar; const styles = _reactNative.StyleSheet.create({ tabBarContainer: { position: 'absolute', zIndex: 2, marginHorizontal: 'auto', alignSelf: 'center', bottom: 0, borderBottomLeftRadius: 30 }, tabItemsContainer: { position: 'absolute', flexDirection: 'row', width: '100%', overflow: 'hidden' }, shadowMd: { elevation: 3, shadowColor: '#000', shadowOpacity: 0.2, shadowRadius: 3, shadowOffset: { width: 0, height: 3 } }, emptyContainer: { justifyContent: 'center', alignItems: 'center', height: TAB_BAR_HEIGHT } }); //# sourceMappingURL=TabBar.js.map