UNPKG

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