UNPKG

react-native-collapsible-tab-view

Version:
186 lines (183 loc) 7.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TABBAR_HEIGHT = exports.MaterialTabBar = void 0; var _react = _interopRequireDefault(require("react")); var _reactNative = require("react-native"); var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated")); var _Indicator = require("./Indicator"); var _TabItem = require("./TabItem"); var _jsxRuntime = require("react/jsx-runtime"); 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; } function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const TABBAR_HEIGHT = exports.TABBAR_HEIGHT = 48; /** * Basic usage looks like this: * * ```tsx * <Tabs.Container * ... * TabBarComponent={(props) => ( * <MaterialTabBar * {...props} * activeColor="red" * inactiveColor="yellow" * inactiveOpacity={1} * labelStyle={{ fontSize: 14 }} * /> * )} * > * {...} * </Tabs.Container> * ``` */ const MaterialTabBar = ({ tabNames, indexDecimal, scrollEnabled = false, indicatorStyle, index, TabItemComponent = _TabItem.MaterialTabItem, getLabelText = name => String(name).toUpperCase(), onTabPress, style, tabProps, contentContainerStyle, labelStyle, inactiveColor, activeColor, tabStyle, width: customWidth, keepActiveTabCentered }) => { const tabBarRef = (0, _reactNativeReanimated.useAnimatedRef)(); const windowWidth = (0, _reactNative.useWindowDimensions)().width; const width = customWidth ?? windowWidth; const isFirstRender = _react.default.useRef(true); const itemLayoutGathering = _react.default.useRef(new Map()); const tabsOffset = (0, _reactNativeReanimated.useSharedValue)(0); const isScrolling = (0, _reactNativeReanimated.useSharedValue)(false); const nTabs = tabNames.length; const [itemsLayout, setItemsLayout] = _react.default.useState(scrollEnabled ? [] : tabNames.map((_, i) => { const tabWidth = width / nTabs; return { width: tabWidth, x: i * tabWidth }; })); _react.default.useEffect(() => { if (isFirstRender.current) { isFirstRender.current = false; } else if (!scrollEnabled) { // update items width on window resizing const tabWidth = width / nTabs; setItemsLayout(tabNames.map((_, i) => { return { width: tabWidth, x: i * tabWidth }; })); } }, [scrollEnabled, nTabs, tabNames, width]); const onTabItemLayout = _react.default.useCallback((event, name) => { if (scrollEnabled) { if (!event.nativeEvent?.layout) return; const { width, x } = event.nativeEvent.layout; itemLayoutGathering.current.set(name, { width, x }); // pick out the layouts for the tabs we know about (in case they changed dynamically) const layout = Array.from(itemLayoutGathering.current.entries()).filter(([tabName]) => tabNames.includes(tabName)).map(([, layout]) => layout).sort((a, b) => a.x - b.x); if (layout.length === tabNames.length) { setItemsLayout(layout); } } }, [scrollEnabled, tabNames]); const cancelNextScrollSync = (0, _reactNativeReanimated.useSharedValue)(index.value); const onScroll = (0, _reactNativeReanimated.useAnimatedScrollHandler)({ onScroll: event => { tabsOffset.value = event.contentOffset.x; }, onBeginDrag: () => { isScrolling.value = true; cancelNextScrollSync.value = index.value; }, onMomentumEnd: () => { isScrolling.value = false; } }, []); const currentIndexToSync = (0, _reactNativeReanimated.useSharedValue)(index.value); const targetIndexToSync = (0, _reactNativeReanimated.useSharedValue)(index.value); (0, _reactNativeReanimated.useAnimatedReaction)(() => { return index.value; }, nextIndex => { if (scrollEnabled) { (0, _reactNativeReanimated.cancelAnimation)(currentIndexToSync); targetIndexToSync.value = nextIndex; currentIndexToSync.value = (0, _reactNativeReanimated.withTiming)(nextIndex); } }, [scrollEnabled]); (0, _reactNativeReanimated.useAnimatedReaction)(() => { return currentIndexToSync.value === targetIndexToSync.value; }, canSync => { if (canSync && scrollEnabled && itemsLayout.length === nTabs && itemsLayout[index.value]) { const halfTab = itemsLayout[index.value].width / 2; const offset = itemsLayout[index.value].x; if (keepActiveTabCentered || offset < tabsOffset.value || offset > tabsOffset.value + width - 2 * halfTab) { (0, _reactNativeReanimated.scrollTo)(tabBarRef, offset - width / 2 + halfTab, 0, true); } } }, [scrollEnabled, itemsLayout, nTabs]); return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNativeReanimated.default.ScrollView, { ref: tabBarRef, horizontal: true, style: style, contentContainerStyle: [styles.contentContainer, !scrollEnabled && { width }, contentContainerStyle], keyboardShouldPersistTaps: "handled", bounces: false, alwaysBounceHorizontal: false, scrollsToTop: false, showsHorizontalScrollIndicator: false, automaticallyAdjustContentInsets: false, overScrollMode: "never", scrollEnabled: scrollEnabled, onScroll: scrollEnabled ? onScroll : undefined, scrollEventThrottle: 16, children: [tabNames.map((name, i) => { return /*#__PURE__*/(0, _jsxRuntime.jsx)(TabItemComponent, { index: i, name: name, label: tabProps.get(name)?.label || getLabelText(name), onPress: onTabPress, onLayout: scrollEnabled ? event => onTabItemLayout(event, name) : undefined, scrollEnabled: scrollEnabled, indexDecimal: indexDecimal, labelStyle: labelStyle, activeColor: activeColor, inactiveColor: inactiveColor, style: tabStyle }, name); }), itemsLayout.length === nTabs && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Indicator.Indicator, { indexDecimal: indexDecimal, itemsLayout: itemsLayout, fadeIn: scrollEnabled, style: indicatorStyle })] }); }; const MemoizedTabBar = exports.MaterialTabBar = /*#__PURE__*/_react.default.memo(MaterialTabBar); const styles = _reactNative.StyleSheet.create({ contentContainer: { flexDirection: 'row', flexWrap: 'nowrap' } }); //# sourceMappingURL=TabBar.js.map