UNPKG

24.4 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7
8var React = _interopRequireWildcard(require("react"));
9
10var _reactNative = require("react-native");
11
12var _reactNativeIphoneXHelper = require("react-native-iphone-x-helper");
13
14var _color = _interopRequireDefault(require("color"));
15
16var _overlay = _interopRequireDefault(require("../styles/overlay"));
17
18var _Icon = _interopRequireDefault(require("./Icon"));
19
20var _Surface = _interopRequireDefault(require("./Surface"));
21
22var _Badge = _interopRequireDefault(require("./Badge"));
23
24var _TouchableRipple = _interopRequireDefault(require("./TouchableRipple/TouchableRipple"));
25
26var _Text = _interopRequireDefault(require("./Typography/Text"));
27
28var _colors = require("../styles/colors");
29
30var _theming = require("../core/theming");
31
32var _useAnimatedValue = _interopRequireDefault(require("../utils/useAnimatedValue"));
33
34var _useAnimatedValueArray = _interopRequireDefault(require("../utils/useAnimatedValueArray"));
35
36var _useLayout = _interopRequireDefault(require("../utils/useLayout"));
37
38function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
39
40function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
41
42function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
43
44function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
45
46const MIN_RIPPLE_SCALE = 0.001; // Minimum scale is not 0 due to bug with animation
47
48const MIN_TAB_WIDTH = 96;
49const MAX_TAB_WIDTH = 168;
50const BAR_HEIGHT = 56;
51const BOTTOM_INSET = (0, _reactNativeIphoneXHelper.getBottomSpace)();
52const FAR_FAR_AWAY = _reactNative.Platform.OS === 'web' ? 0 : 9999;
53
54const Touchable = ({
55 route: _0,
56 style,
57 children,
58 borderless,
59 centered,
60 rippleColor,
61 ...rest
62}) => _TouchableRipple.default.supported ? /*#__PURE__*/React.createElement(_TouchableRipple.default, _extends({}, rest, {
63 disabled: rest.disabled || undefined,
64 borderless: borderless,
65 centered: centered,
66 rippleColor: rippleColor,
67 style: style
68}), children) : /*#__PURE__*/React.createElement(_reactNative.TouchableWithoutFeedback, rest, /*#__PURE__*/React.createElement(_reactNative.View, {
69 style: style
70}, children));
71
72const SceneComponent = /*#__PURE__*/React.memo(({
73 component,
74 ...rest
75}) => /*#__PURE__*/React.createElement(component, rest));
76/**
77 * Bottom navigation provides quick navigation between top-level views of an app with a bottom navigation bar.
78 * It is primarily designed for use on mobile.
79 *
80 * For integration with React Navigation, you can use [react-navigation-material-bottom-tabs](https://github.com/react-navigation/react-navigation/tree/main/packages/material-bottom-tabs) and consult [createMaterialBottomTabNavigator](https://reactnavigation.org/docs/material-bottom-tab-navigator/) documentation.
81 *
82 * By default Bottom navigation uses primary color as a background, in dark theme with `adaptive` mode it will use surface colour instead.
83 * See [Dark Theme](https://callstack.github.io/react-native-paper/theming.html#dark-theme) for more information.
84 *
85 * <div class="screenshots">
86 * <img class="medium" src="screenshots/bottom-navigation.gif" />
87 * </div>
88 *
89 * ## Usage
90 * ```js
91 * import * as React from 'react';
92 * import { BottomNavigation, Text } from 'react-native-paper';
93 *
94 * const MusicRoute = () => <Text>Music</Text>;
95 *
96 * const AlbumsRoute = () => <Text>Albums</Text>;
97 *
98 * const RecentsRoute = () => <Text>Recents</Text>;
99 *
100 * const MyComponent = () => {
101 * const [index, setIndex] = React.useState(0);
102 * const [routes] = React.useState([
103 * { key: 'music', title: 'Music', icon: 'queue-music' },
104 * { key: 'albums', title: 'Albums', icon: 'album' },
105 * { key: 'recents', title: 'Recents', icon: 'history' },
106 * ]);
107 *
108 * const renderScene = BottomNavigation.SceneMap({
109 * music: MusicRoute,
110 * albums: AlbumsRoute,
111 * recents: RecentsRoute,
112 * });
113 *
114 * return (
115 * <BottomNavigation
116 * navigationState={{ index, routes }}
117 * onIndexChange={setIndex}
118 * renderScene={renderScene}
119 * />
120 * );
121 * };
122 *
123 * export default MyComponent;
124 * ```
125 */
126
127const BottomNavigation = ({
128 navigationState,
129 renderScene,
130 renderIcon,
131 renderLabel,
132 renderTouchable = props => /*#__PURE__*/React.createElement(Touchable, props),
133 getLabelText = ({
134 route
135 }) => route.title,
136 getBadge = ({
137 route
138 }) => route.badge,
139 getColor = ({
140 route
141 }) => route.color,
142 getAccessibilityLabel = ({
143 route
144 }) => route.accessibilityLabel,
145 getTestID = ({
146 route
147 }) => route.testID,
148 activeColor,
149 inactiveColor,
150 keyboardHidesNavigationBar = true,
151 barStyle,
152 labeled = true,
153 style,
154 theme,
155 sceneAnimationEnabled = false,
156 onTabPress,
157 onIndexChange,
158 shifting = navigationState.routes.length > 3,
159 safeAreaInsets
160}) => {
161 var _safeAreaInsets$left, _safeAreaInsets$right, _safeAreaInsets$botto;
162
163 const {
164 scale
165 } = theme.animation;
166 const focusedKey = navigationState.routes[navigationState.index].key;
167 /**
168 * Visibility of the navigation bar, visible state is 1 and invisible is 0.
169 */
170
171 const visibleAnim = (0, _useAnimatedValue.default)(1);
172 /**
173 * Active state of individual tab items, active state is 1 and inactive state is 0.
174 */
175
176 const tabsAnims = (0, _useAnimatedValueArray.default)(navigationState.routes.map( // focused === 1, unfocused === 0
177 (_, i) => i === navigationState.index ? 1 : 0));
178 /**
179 * The top offset for each tab item to position it offscreen.
180 * Placing items offscreen helps to save memory usage for inactive screens with removeClippedSubviews.
181 * We use animated values for this to prevent unnecessary re-renders.
182 */
183
184 const offsetsAnims = (0, _useAnimatedValueArray.default)(navigationState.routes.map( // offscreen === 1, normal === 0
185 (_, i) => i === navigationState.index ? 0 : 1));
186 /**
187 * Index of the currently active tab. Used for setting the background color.
188 * We don't use the color as an animated value directly, because `setValue` seems to be buggy with colors.
189 */
190
191 const indexAnim = (0, _useAnimatedValue.default)(navigationState.index);
192 /**
193 * Animation for the background color ripple, used to determine it's scale and opacity.
194 */
195
196 const rippleAnim = (0, _useAnimatedValue.default)(MIN_RIPPLE_SCALE);
197 /**
198 * Layout of the navigation bar. The width is used to determine the size and position of the ripple.
199 */
200
201 const [layout, onLayout] = (0, _useLayout.default)();
202 /**
203 * List of loaded tabs, tabs will be loaded when navigated to.
204 */
205
206 const [loaded, setLoaded] = React.useState([focusedKey]);
207
208 if (!loaded.includes(focusedKey)) {
209 // Set the current tab to be loaded if it was not loaded before
210 setLoaded(loaded => [...loaded, focusedKey]);
211 }
212 /**
213 * Track whether the keyboard is visible to show and hide the navigation bar.
214 */
215
216
217 const [keyboardVisible, setKeyboardVisible] = React.useState(false);
218 const handleKeyboardShow = React.useCallback(() => {
219 setKeyboardVisible(true);
220
221 _reactNative.Animated.timing(visibleAnim, {
222 toValue: 0,
223 duration: 150 * scale,
224 useNativeDriver: true
225 }).start();
226 }, [scale, visibleAnim]);
227 const handleKeyboardHide = React.useCallback(() => {
228 _reactNative.Animated.timing(visibleAnim, {
229 toValue: 1,
230 duration: 100 * scale,
231 useNativeDriver: true
232 }).start(() => {
233 setKeyboardVisible(false);
234 });
235 }, [scale, visibleAnim]);
236 const animateToIndex = React.useCallback(index => {
237 // Reset the ripple to avoid glitch if it's currently animating
238 rippleAnim.setValue(MIN_RIPPLE_SCALE);
239
240 _reactNative.Animated.parallel([_reactNative.Animated.timing(rippleAnim, {
241 toValue: 1,
242 duration: shifting ? 400 * scale : 0,
243 useNativeDriver: true
244 }), ...navigationState.routes.map((_, i) => _reactNative.Animated.timing(tabsAnims[i], {
245 toValue: i === index ? 1 : 0,
246 duration: shifting ? 150 * scale : 0,
247 useNativeDriver: true
248 }))]).start(({
249 finished
250 }) => {
251 // Workaround a bug in native animations where this is reset after first animation
252 tabsAnims.map((tab, i) => tab.setValue(i === index ? 1 : 0)); // Update the index to change bar's background color and then hide the ripple
253
254 indexAnim.setValue(index);
255 rippleAnim.setValue(MIN_RIPPLE_SCALE);
256
257 if (finished) {
258 // Position all inactive screens offscreen to save memory usage
259 // Only do it when animation has finished to avoid glitches mid-transition if switching fast
260 offsetsAnims.forEach((offset, i) => {
261 if (i === index) {
262 offset.setValue(0);
263 } else {
264 offset.setValue(1);
265 }
266 });
267 }
268 });
269 }, [indexAnim, shifting, navigationState.routes, offsetsAnims, rippleAnim, scale, tabsAnims]);
270 React.useEffect(() => {
271 // Workaround for native animated bug in react-native@^0.57
272 // Context: https://github.com/callstack/react-native-paper/pull/637
273 animateToIndex(navigationState.index); // eslint-disable-next-line react-hooks/exhaustive-deps
274 }, []);
275 React.useEffect(() => {
276 if (_reactNative.Platform.OS === 'ios') {
277 _reactNative.Keyboard.addListener('keyboardWillShow', handleKeyboardShow);
278
279 _reactNative.Keyboard.addListener('keyboardWillHide', handleKeyboardHide);
280 } else {
281 _reactNative.Keyboard.addListener('keyboardDidShow', handleKeyboardShow);
282
283 _reactNative.Keyboard.addListener('keyboardDidHide', handleKeyboardHide);
284 }
285
286 return () => {
287 if (_reactNative.Platform.OS === 'ios') {
288 _reactNative.Keyboard.removeListener('keyboardWillShow', handleKeyboardShow);
289
290 _reactNative.Keyboard.removeListener('keyboardWillHide', handleKeyboardHide);
291 } else {
292 _reactNative.Keyboard.removeListener('keyboardDidShow', handleKeyboardShow);
293
294 _reactNative.Keyboard.removeListener('keyboardDidHide', handleKeyboardHide);
295 }
296 };
297 }, [handleKeyboardHide, handleKeyboardShow]);
298 const prevNavigationState = React.useRef();
299 React.useEffect(() => {
300 // Reset offsets of previous and current tabs before animation
301 offsetsAnims.forEach((offset, i) => {
302 var _prevNavigationState$;
303
304 if (i === navigationState.index || i === ((_prevNavigationState$ = prevNavigationState.current) === null || _prevNavigationState$ === void 0 ? void 0 : _prevNavigationState$.index)) {
305 offset.setValue(0);
306 }
307 });
308 animateToIndex(navigationState.index);
309 }, [navigationState.index, animateToIndex, offsetsAnims]);
310
311 const handleTabPress = index => {
312 const event = {
313 route: navigationState.routes[index],
314 defaultPrevented: false,
315 preventDefault: () => {
316 event.defaultPrevented = true;
317 }
318 };
319 onTabPress === null || onTabPress === void 0 ? void 0 : onTabPress(event);
320
321 if (event.defaultPrevented) {
322 return;
323 }
324
325 if (index !== navigationState.index) {
326 onIndexChange(index);
327 }
328 };
329
330 const jumpTo = React.useCallback(key => {
331 const index = navigationState.routes.findIndex(route => route.key === key);
332 onIndexChange(index);
333 }, [navigationState.routes, onIndexChange]);
334 const {
335 routes
336 } = navigationState;
337 const {
338 colors,
339 dark: isDarkTheme,
340 mode
341 } = theme;
342 const {
343 backgroundColor: customBackground,
344 elevation = 4
345 } = _reactNative.StyleSheet.flatten(barStyle) || {};
346 const approxBackgroundColor = customBackground ? customBackground : isDarkTheme && mode === 'adaptive' ? (0, _overlay.default)(elevation, colors.surface) : colors.primary;
347 const backgroundColor = shifting ? indexAnim.interpolate({
348 inputRange: routes.map((_, i) => i),
349 // FIXME: does outputRange support ColorValue or just strings?
350 // @ts-expect-error
351 outputRange: routes.map(route => getColor({
352 route
353 }) || approxBackgroundColor)
354 }) : approxBackgroundColor;
355 const isDark = typeof approxBackgroundColor === 'string' ? !(0, _color.default)(approxBackgroundColor).isLight() : true;
356 const textColor = isDark ? _colors.white : _colors.black;
357 const activeTintColor = typeof activeColor !== 'undefined' ? activeColor : textColor;
358 const inactiveTintColor = typeof inactiveColor !== 'undefined' ? inactiveColor : (0, _color.default)(textColor).alpha(0.5).rgb().string();
359 const touchColor = (0, _color.default)(activeColor || activeTintColor).alpha(0.12).rgb().string();
360 const maxTabWidth = routes.length > 3 ? MIN_TAB_WIDTH : MAX_TAB_WIDTH;
361 const maxTabBarWidth = maxTabWidth * routes.length;
362 const tabBarWidth = Math.min(layout.width, maxTabBarWidth);
363 const tabWidth = tabBarWidth / routes.length;
364 const rippleSize = layout.width / 4;
365 const insets = {
366 left: (_safeAreaInsets$left = safeAreaInsets === null || safeAreaInsets === void 0 ? void 0 : safeAreaInsets.left) !== null && _safeAreaInsets$left !== void 0 ? _safeAreaInsets$left : 0,
367 right: (_safeAreaInsets$right = safeAreaInsets === null || safeAreaInsets === void 0 ? void 0 : safeAreaInsets.right) !== null && _safeAreaInsets$right !== void 0 ? _safeAreaInsets$right : 0,
368 bottom: (_safeAreaInsets$botto = safeAreaInsets === null || safeAreaInsets === void 0 ? void 0 : safeAreaInsets.bottom) !== null && _safeAreaInsets$botto !== void 0 ? _safeAreaInsets$botto : BOTTOM_INSET
369 };
370 return /*#__PURE__*/React.createElement(_reactNative.View, {
371 style: [styles.container, style]
372 }, /*#__PURE__*/React.createElement(_reactNative.View, {
373 style: [styles.content, {
374 backgroundColor: colors.background
375 }]
376 }, routes.map((route, index) => {
377 if (!loaded.includes(route.key)) {
378 // Don't render a screen if we've never navigated to it
379 return null;
380 }
381
382 const focused = navigationState.index === index;
383 const opacity = sceneAnimationEnabled ? tabsAnims[index] : focused ? 1 : 0;
384 const top = sceneAnimationEnabled ? offsetsAnims[index].interpolate({
385 inputRange: [0, 1],
386 outputRange: [0, FAR_FAR_AWAY]
387 }) : focused ? 0 : FAR_FAR_AWAY;
388 return /*#__PURE__*/React.createElement(_reactNative.Animated.View, {
389 key: route.key,
390 pointerEvents: focused ? 'auto' : 'none',
391 accessibilityElementsHidden: !focused,
392 importantForAccessibility: focused ? 'auto' : 'no-hide-descendants',
393 style: [_reactNative.StyleSheet.absoluteFill, {
394 opacity
395 }],
396 collapsable: false,
397 removeClippedSubviews: // On iOS, set removeClippedSubviews to true only when not focused
398 // This is an workaround for a bug where the clipped view never re-appears
399 _reactNative.Platform.OS === 'ios' ? navigationState.index !== index : true
400 }, /*#__PURE__*/React.createElement(_reactNative.Animated.View, {
401 style: [styles.content, {
402 top
403 }]
404 }, renderScene({
405 route,
406 jumpTo
407 })));
408 })), /*#__PURE__*/React.createElement(_Surface.default, {
409 style: [styles.bar, keyboardHidesNavigationBar ? {
410 // When the keyboard is shown, slide down the navigation bar
411 transform: [{
412 translateY: visibleAnim.interpolate({
413 inputRange: [0, 1],
414 outputRange: [layout.height, 0]
415 })
416 }],
417 // Absolutely position the navigation bar so that the content is below it
418 // This is needed to avoid gap at bottom when the navigation bar is hidden
419 position: keyboardVisible ? 'absolute' : null
420 } : null, barStyle],
421 pointerEvents: layout.measured ? keyboardHidesNavigationBar && keyboardVisible ? 'none' : 'auto' : 'none',
422 onLayout: onLayout
423 }, /*#__PURE__*/React.createElement(_reactNative.Animated.View, {
424 style: [styles.barContent, {
425 backgroundColor
426 }]
427 }, /*#__PURE__*/React.createElement(_reactNative.View, {
428 style: [styles.items, {
429 marginBottom: insets.bottom,
430 marginHorizontal: Math.max(insets.left, insets.right),
431 maxWidth: maxTabBarWidth
432 }],
433 accessibilityRole: 'tablist'
434 }, shifting ? /*#__PURE__*/React.createElement(_reactNative.Animated.View, {
435 pointerEvents: "none",
436 style: [styles.ripple, {
437 // Since we have a single ripple, we have to reposition it so that it appears to expand from active tab.
438 // We need to move it from the top to center of the navigation bar and from the left to the active tab.
439 top: (BAR_HEIGHT - rippleSize) / 2,
440 left: tabWidth * (navigationState.index + 0.5) - rippleSize / 2,
441 height: rippleSize,
442 width: rippleSize,
443 borderRadius: rippleSize / 2,
444 backgroundColor: getColor({
445 route: routes[navigationState.index]
446 }),
447 transform: [{
448 // Scale to twice the size to ensure it covers the whole navigation bar
449 scale: rippleAnim.interpolate({
450 inputRange: [0, 1],
451 outputRange: [0, 8]
452 })
453 }],
454 opacity: rippleAnim.interpolate({
455 inputRange: [0, MIN_RIPPLE_SCALE, 0.3, 1],
456 outputRange: [0, 0, 1, 1]
457 })
458 }]
459 }) : null, routes.map((route, index) => {
460 const focused = navigationState.index === index;
461 const active = tabsAnims[index]; // Scale the label up
462
463 const scale = labeled && shifting ? active.interpolate({
464 inputRange: [0, 1],
465 outputRange: [0.5, 1]
466 }) : 1; // Move down the icon to account for no-label in shifting and smaller label in non-shifting.
467
468 const translateY = labeled ? shifting ? active.interpolate({
469 inputRange: [0, 1],
470 outputRange: [7, 0]
471 }) : 0 : 7; // We render the active icon and label on top of inactive ones and cross-fade them on change.
472 // This trick gives the illusion that we are animating between active and inactive colors.
473 // This is to ensure that we can use native driver, as colors cannot be animated with native driver.
474
475 const activeOpacity = active;
476 const inactiveOpacity = active.interpolate({
477 inputRange: [0, 1],
478 outputRange: [1, 0]
479 });
480 const badge = getBadge({
481 route
482 });
483 return renderTouchable({
484 key: route.key,
485 route,
486 borderless: true,
487 centered: true,
488 rippleColor: touchColor,
489 onPress: () => handleTabPress(index),
490 testID: getTestID({
491 route
492 }),
493 accessibilityLabel: getAccessibilityLabel({
494 route
495 }),
496 // @ts-expect-error We keep old a11y props for backwards compat with old RN versions
497 accessibilityTraits: focused ? ['button', 'selected'] : 'button',
498 accessibilityComponentType: 'button',
499 accessibilityRole: _reactNative.Platform.OS === 'ios' ? 'button' : 'tab',
500 accessibilityState: {
501 selected: focused
502 },
503 style: styles.item,
504 children: /*#__PURE__*/React.createElement(_reactNative.View, {
505 pointerEvents: "none"
506 }, /*#__PURE__*/React.createElement(_reactNative.Animated.View, {
507 style: [styles.iconContainer, {
508 transform: [{
509 translateY
510 }]
511 }]
512 }, /*#__PURE__*/React.createElement(_reactNative.Animated.View, {
513 style: [styles.iconWrapper, {
514 opacity: activeOpacity
515 }]
516 }, renderIcon ? renderIcon({
517 route,
518 focused: true,
519 color: activeTintColor
520 }) : /*#__PURE__*/React.createElement(_Icon.default, {
521 source: route.icon,
522 color: activeTintColor,
523 size: 24
524 })), /*#__PURE__*/React.createElement(_reactNative.Animated.View, {
525 style: [styles.iconWrapper, {
526 opacity: inactiveOpacity
527 }]
528 }, renderIcon ? renderIcon({
529 route,
530 focused: false,
531 color: inactiveTintColor
532 }) : /*#__PURE__*/React.createElement(_Icon.default, {
533 source: route.icon,
534 color: inactiveTintColor,
535 size: 24
536 })), /*#__PURE__*/React.createElement(_reactNative.View, {
537 style: [styles.badgeContainer, {
538 right: (badge != null && typeof badge !== 'boolean' ? String(badge).length * -2 : 0) - 2
539 }]
540 }, typeof badge === 'boolean' ? /*#__PURE__*/React.createElement(_Badge.default, {
541 visible: badge,
542 size: 8
543 }) : /*#__PURE__*/React.createElement(_Badge.default, {
544 visible: badge != null,
545 size: 16
546 }, badge))), labeled ? /*#__PURE__*/React.createElement(_reactNative.Animated.View, {
547 style: [styles.labelContainer, {
548 transform: [{
549 scale
550 }]
551 }]
552 }, /*#__PURE__*/React.createElement(_reactNative.Animated.View, {
553 style: [styles.labelWrapper, {
554 opacity: activeOpacity
555 }]
556 }, renderLabel ? renderLabel({
557 route,
558 focused: true,
559 color: activeTintColor
560 }) : /*#__PURE__*/React.createElement(_Text.default, {
561 style: [styles.label, {
562 color: activeTintColor
563 }]
564 }, getLabelText({
565 route
566 }))), shifting ? null : /*#__PURE__*/React.createElement(_reactNative.Animated.View, {
567 style: [styles.labelWrapper, {
568 opacity: inactiveOpacity
569 }]
570 }, renderLabel ? renderLabel({
571 route,
572 focused: false,
573 color: inactiveTintColor
574 }) : /*#__PURE__*/React.createElement(_Text.default, {
575 selectable: false,
576 style: [styles.label, {
577 color: inactiveTintColor
578 }]
579 }, getLabelText({
580 route
581 })))) : /*#__PURE__*/React.createElement(_reactNative.View, {
582 style: styles.labelContainer
583 }))
584 });
585 })))));
586};
587/**
588 * Function which takes a map of route keys to components.
589 * Pure components are used to minimize re-rendering of the pages.
590 * This drastically improves the animation performance.
591 */
592
593
594BottomNavigation.SceneMap = scenes => {
595 return ({
596 route,
597 jumpTo
598 }) => /*#__PURE__*/React.createElement(SceneComponent, {
599 key: route.key,
600 component: scenes[route.key ? route.key : ''],
601 route: route,
602 jumpTo: jumpTo
603 });
604};
605
606var _default = (0, _theming.withTheme)(BottomNavigation);
607
608exports.default = _default;
609
610const styles = _reactNative.StyleSheet.create({
611 container: {
612 flex: 1,
613 overflow: 'hidden'
614 },
615 content: {
616 flex: 1
617 },
618 bar: {
619 left: 0,
620 right: 0,
621 bottom: 0,
622 elevation: 4
623 },
624 barContent: {
625 alignItems: 'center',
626 overflow: 'hidden'
627 },
628 items: {
629 flexDirection: 'row',
630 ...(_reactNative.Platform.OS === 'web' ? {
631 width: '100%'
632 } : null)
633 },
634 item: {
635 flex: 1,
636 // Top padding is 6 and bottom padding is 10
637 // The extra 4dp bottom padding is offset by label's height
638 paddingVertical: 6
639 },
640 ripple: {
641 position: 'absolute'
642 },
643 iconContainer: {
644 height: 24,
645 width: 24,
646 marginTop: 2,
647 marginHorizontal: 12,
648 alignSelf: 'center'
649 },
650 iconWrapper: { ..._reactNative.StyleSheet.absoluteFillObject,
651 alignItems: 'center'
652 },
653 labelContainer: {
654 height: 16,
655 paddingBottom: 2
656 },
657 labelWrapper: { ..._reactNative.StyleSheet.absoluteFillObject
658 },
659 // eslint-disable-next-line react-native/no-color-literals
660 label: {
661 fontSize: 12,
662 textAlign: 'center',
663 backgroundColor: 'transparent',
664 ...(_reactNative.Platform.OS === 'web' ? {
665 whiteSpace: 'nowrap',
666 alignSelf: 'center'
667 } : null)
668 },
669 badgeContainer: {
670 position: 'absolute',
671 left: 0,
672 top: -2
673 }
674});
675//# sourceMappingURL=BottomNavigation.js.map
\No newline at end of file