UNPKG

@react-navigation/bottom-tabs

Version:

Bottom tab navigator following iOS design guidelines

283 lines (282 loc) 10.5 kB
"use strict"; import { getHeaderTitle, HeaderTitle } from '@react-navigation/elements'; import { useLocale, useTheme } from '@react-navigation/native'; import Color from 'color'; import { Platform, StyleSheet, View } from 'react-native'; import { isSearchBarAvailableForCurrentPlatform, ScreenStackHeaderCenterView, ScreenStackHeaderLeftView, ScreenStackHeaderRightView, ScreenStackHeaderSearchBarView, SearchBar } from 'react-native-screens'; import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; const processBarButtonItems = (items, colors, fonts) => { return items?.map((item, index) => { if (item.type === 'custom') { // Handled with `ScreenStackHeaderLeftView` or `ScreenStackHeaderRightView` return null; } if (item.type === 'spacing') { if (item.spacing == null) { throw new Error(`Spacing item must have a 'spacing' property defined: ${JSON.stringify(item)}`); } return item; } if (item.type === 'button' || item.type === 'menu') { if (item.type === 'menu' && item.menu == null) { throw new Error(`Menu item must have a 'menu' property defined: ${JSON.stringify(item)}`); } const { badge, label, labelStyle, icon, ...rest } = item; let processedItem = { ...rest, index, title: label, titleStyle: { ...fonts.regular, ...labelStyle }, icon: icon?.type === 'image' ? icon.tinted === false ? { type: 'imageSource', imageSource: icon.source } : { type: 'templateSource', templateSource: icon.source } : icon }; if (processedItem.type === 'menu' && item.type === 'menu') { processedItem = { ...processedItem, menu: { ...processedItem.menu, items: item.menu.items.map(getMenuItem) } }; } if (badge) { const badgeBackgroundColor = badge.style?.backgroundColor ?? colors.notification; const badgeTextColor = typeof badgeBackgroundColor === 'string' && Color(badgeBackgroundColor)?.isLight() ? 'black' : 'white'; processedItem = { ...processedItem, badge: { ...badge, value: String(badge.value), style: { backgroundColor: badgeBackgroundColor, color: badgeTextColor, ...fonts.regular, ...badge.style } } }; } return processedItem; } throw new Error(`Invalid item type: ${JSON.stringify(item)}. Valid types are 'button', 'menu', 'custom' and 'spacing'.`); }).filter(item => item != null); }; const getMenuItem = item => { const { label, ...rest } = item; if (rest.type === 'submenu') { return { ...rest, title: label, items: rest.items.map(getMenuItem) }; } return { ...rest, title: label }; }; export function useHeaderConfig({ headerShadowVisible, headerLargeStyle, headerLargeTitleEnabled, headerLargeTitleShadowVisible, headerLargeTitleStyle, headerBackground, headerLeft, headerRight, headerShown, headerStyle, headerBlurEffect, headerTintColor, headerTitle, headerTitleAlign, headerTitleStyle, headerTransparent, headerSearchBarOptions, headerTopInsetEnabled, route, title, unstable_headerLeftItems: headerLeftItems, unstable_headerRightItems: headerRightItems }) { const { direction } = useLocale(); const { colors, fonts } = useTheme(); const tintColor = headerTintColor ?? (Platform.OS === 'ios' ? colors.primary : colors.text); const headerLargeTitleStyleFlattened = StyleSheet.flatten([Platform.select({ ios: fonts.heavy, default: fonts.medium }), headerLargeTitleStyle]) || {}; const headerTitleStyleFlattened = StyleSheet.flatten([Platform.select({ ios: fonts.bold, default: fonts.medium }), headerTitleStyle]) || {}; const headerStyleFlattened = StyleSheet.flatten(headerStyle) || {}; const headerLargeStyleFlattened = StyleSheet.flatten(headerLargeStyle) || {}; const titleText = getHeaderTitle({ title, headerTitle }, route.name); const titleColor = 'color' in headerTitleStyleFlattened ? headerTitleStyleFlattened.color : headerTintColor ?? colors.text; const titleFontSize = 'fontSize' in headerTitleStyleFlattened ? headerTitleStyleFlattened.fontSize : undefined; const titleFontFamily = headerTitleStyleFlattened.fontFamily; const titleFontWeight = headerTitleStyleFlattened.fontWeight; const largeTitleFontFamily = headerLargeTitleStyleFlattened.fontFamily; const largeTitleBackgroundColor = headerLargeStyleFlattened.backgroundColor; const largeTitleColor = 'color' in headerLargeTitleStyleFlattened ? headerLargeTitleStyleFlattened.color : undefined; const largeTitleFontSize = 'fontSize' in headerLargeTitleStyleFlattened ? headerLargeTitleStyleFlattened.fontSize : undefined; const largeTitleFontWeight = headerLargeTitleStyleFlattened.fontWeight; const headerTitleStyleSupported = { color: titleColor }; if (headerTitleStyleFlattened.fontFamily != null) { headerTitleStyleSupported.fontFamily = headerTitleStyleFlattened.fontFamily; } if (titleFontSize != null) { headerTitleStyleSupported.fontSize = titleFontSize; } if (titleFontWeight != null) { headerTitleStyleSupported.fontWeight = titleFontWeight; } const headerBackgroundColor = headerStyleFlattened.backgroundColor ?? (headerBackground != null || headerTransparent ? 'transparent' : colors.card); const headerLeftElement = headerLeft?.({ tintColor }); const headerRightElement = headerRight?.({ tintColor }); const headerTitleElement = typeof headerTitle === 'function' ? headerTitle({ tintColor, children: titleText }) : null; const hasHeaderSearchBar = isSearchBarAvailableForCurrentPlatform && headerSearchBarOptions != null; const translucent = headerBackground != null || headerTransparent || // When using a SearchBar or large title, the header needs to be translucent for it to work on iOS (hasHeaderSearchBar || headerLargeTitleEnabled) && Platform.OS === 'ios' && headerTransparent !== false; const isCenterViewRenderedAndroid = headerTitleAlign === 'center'; const leftItems = headerLeftItems?.({ tintColor }); let rightItems = headerRightItems?.({ tintColor }); if (rightItems) { // iOS renders right items in reverse order // So we need to reverse them here to match the order rightItems = [...rightItems].reverse(); } const children = /*#__PURE__*/_jsxs(_Fragment, { children: [Platform.OS === 'ios' ? /*#__PURE__*/_jsxs(_Fragment, { children: [leftItems ? leftItems.map((item, index) => { if (item.type === 'custom') { return /*#__PURE__*/_jsx(ScreenStackHeaderLeftView // eslint-disable-next-line @eslint-react/no-array-index-key , { hidesSharedBackground: item.hidesSharedBackground, children: item.element }, index); } return null; }) : headerLeftElement != null ? /*#__PURE__*/_jsx(ScreenStackHeaderLeftView, { children: headerLeftElement }) : null, headerTitleElement != null ? /*#__PURE__*/_jsx(ScreenStackHeaderCenterView, { children: headerTitleElement }) : null] }) : /*#__PURE__*/_jsxs(_Fragment, { children: [headerLeftElement != null || typeof headerTitle === 'function' ? /*#__PURE__*/ // The style passed to header left, together with title element being wrapped // in flex view is reqruied for proper header layout, in particular, // for the text truncation to work. _jsxs(ScreenStackHeaderLeftView, { style: !isCenterViewRenderedAndroid ? { flex: 1 } : null, children: [headerLeftElement, headerTitleAlign !== 'center' ? typeof headerTitle === 'function' ? /*#__PURE__*/_jsx(View, { style: { flex: 1 }, children: headerTitleElement }) : /*#__PURE__*/_jsx(View, { style: { flex: 1 }, children: /*#__PURE__*/_jsx(HeaderTitle, { tintColor: tintColor, style: headerTitleStyleSupported, children: titleText }) }) : null] }) : null, isCenterViewRenderedAndroid ? /*#__PURE__*/_jsx(ScreenStackHeaderCenterView, { children: typeof headerTitle === 'function' ? headerTitleElement : /*#__PURE__*/_jsx(HeaderTitle, { tintColor: tintColor, style: headerTitleStyleSupported, children: titleText }) }) : null] }), Platform.OS === 'ios' && rightItems ? rightItems.map((item, index) => { if (item.type === 'custom') { return /*#__PURE__*/_jsx(ScreenStackHeaderRightView // eslint-disable-next-line @eslint-react/no-array-index-key , { hidesSharedBackground: item.hidesSharedBackground, children: item.element }, index); } return null; }) : headerRightElement != null ? /*#__PURE__*/_jsx(ScreenStackHeaderRightView, { children: headerRightElement }) : null, hasHeaderSearchBar ? /*#__PURE__*/_jsx(ScreenStackHeaderSearchBarView, { children: /*#__PURE__*/_jsx(SearchBar, { ...headerSearchBarOptions }) }) : null] }); return { backgroundColor: headerBackgroundColor, blurEffect: headerBlurEffect, color: tintColor, direction, hidden: headerShown === false, hideShadow: headerShadowVisible === false || headerBackground != null || headerTransparent && headerShadowVisible !== true, largeTitle: headerLargeTitleEnabled, largeTitleBackgroundColor, largeTitleColor, largeTitleFontFamily, largeTitleFontSize, largeTitleFontWeight, largeTitleHideShadow: headerLargeTitleShadowVisible === false, title: titleText, titleColor, titleFontFamily, titleFontSize, titleFontWeight: String(titleFontWeight), topInsetEnabled: headerTopInsetEnabled, translucent: translucent === true, children, headerLeftBarButtonItems: processBarButtonItems(leftItems, colors, fonts), headerRightBarButtonItems: processBarButtonItems(rightItems, colors, fonts) }; } //# sourceMappingURL=useHeaderConfig.js.map