first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
"use strict";
/**
* Simple cross fade animation
*/
export function forFade({
current
}) {
return {
sceneStyle: {
opacity: current.progress.interpolate({
inputRange: [-1, 0, 1],
outputRange: [0, 1, 0]
})
}
};
}
/**
* Animation where the screens slightly shift to left/right
*/
export function forShift({
current
}) {
return {
sceneStyle: {
opacity: current.progress.interpolate({
inputRange: [-1, 0, 1],
outputRange: [0, 1, 0]
}),
transform: [{
translateX: current.progress.interpolate({
inputRange: [-1, 0, 1],
outputRange: [-50, 0, 50]
})
}]
}
};
}
//# sourceMappingURL=SceneStyleInterpolators.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["forFade","current","sceneStyle","opacity","progress","interpolate","inputRange","outputRange","forShift","transform","translateX"],"sourceRoot":"../../../src","sources":["TransitionConfigs/SceneStyleInterpolators.tsx"],"mappings":";;AAKA;AACA;AACA;AACA,OAAO,SAASA,OAAOA,CAAC;EACtBC;AACgC,CAAC,EAAmC;EACpE,OAAO;IACLC,UAAU,EAAE;MACVC,OAAO,EAAEF,OAAO,CAACG,QAAQ,CAACC,WAAW,CAAC;QACpCC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACtBC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;MACvB,CAAC;IACH;EACF,CAAC;AACH;;AAEA;AACA;AACA;AACA,OAAO,SAASC,QAAQA,CAAC;EACvBP;AACgC,CAAC,EAAmC;EACpE,OAAO;IACLC,UAAU,EAAE;MACVC,OAAO,EAAEF,OAAO,CAACG,QAAQ,CAACC,WAAW,CAAC;QACpCC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACtBC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;MACvB,CAAC,CAAC;MACFE,SAAS,EAAE,CACT;QACEC,UAAU,EAAET,OAAO,CAACG,QAAQ,CAACC,WAAW,CAAC;UACvCC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;UACtBC,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;QAC1B,CAAC;MACH,CAAC;IAEL;EACF,CAAC;AACH","ignoreList":[]}

View File

@@ -0,0 +1,13 @@
"use strict";
import { forFade, forShift } from "./SceneStyleInterpolators.js";
import { FadeSpec, ShiftSpec } from "./TransitionSpecs.js";
export const FadeTransition = {
transitionSpec: FadeSpec,
sceneStyleInterpolator: forFade
};
export const ShiftTransition = {
transitionSpec: ShiftSpec,
sceneStyleInterpolator: forShift
};
//# sourceMappingURL=TransitionPresets.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["forFade","forShift","FadeSpec","ShiftSpec","FadeTransition","transitionSpec","sceneStyleInterpolator","ShiftTransition"],"sourceRoot":"../../../src","sources":["TransitionConfigs/TransitionPresets.tsx"],"mappings":";;AACA,SAASA,OAAO,EAAEC,QAAQ,QAAQ,8BAA2B;AAC7D,SAASC,QAAQ,EAAEC,SAAS,QAAQ,sBAAmB;AAEvD,OAAO,MAAMC,cAAyC,GAAG;EACvDC,cAAc,EAAEH,QAAQ;EACxBI,sBAAsB,EAAEN;AAC1B,CAAC;AAED,OAAO,MAAMO,eAA0C,GAAG;EACxDF,cAAc,EAAEF,SAAS;EACzBG,sBAAsB,EAAEL;AAC1B,CAAC","ignoreList":[]}

View File

@@ -0,0 +1,18 @@
"use strict";
import { Easing } from 'react-native';
export const FadeSpec = {
animation: 'timing',
config: {
duration: 150,
easing: Easing.in(Easing.linear)
}
};
export const ShiftSpec = {
animation: 'timing',
config: {
duration: 150,
easing: Easing.inOut(Easing.ease)
}
};
//# sourceMappingURL=TransitionSpecs.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["Easing","FadeSpec","animation","config","duration","easing","in","linear","ShiftSpec","inOut","ease"],"sourceRoot":"../../../src","sources":["TransitionConfigs/TransitionSpecs.tsx"],"mappings":";;AAAA,SAASA,MAAM,QAAQ,cAAc;AAIrC,OAAO,MAAMC,QAAwB,GAAG;EACtCC,SAAS,EAAE,QAAQ;EACnBC,MAAM,EAAE;IACNC,QAAQ,EAAE,GAAG;IACbC,MAAM,EAAEL,MAAM,CAACM,EAAE,CAACN,MAAM,CAACO,MAAM;EACjC;AACF,CAAC;AAED,OAAO,MAAMC,SAAyB,GAAG;EACvCN,SAAS,EAAE,QAAQ;EACnBC,MAAM,EAAE;IACNC,QAAQ,EAAE,GAAG;IACbC,MAAM,EAAEL,MAAM,CAACS,KAAK,CAACT,MAAM,CAACU,IAAI;EAClC;AACF,CAAC","ignoreList":[]}

View File

@@ -0,0 +1,33 @@
"use strict";
import * as SceneStyleInterpolators from "./TransitionConfigs/SceneStyleInterpolators.js";
import * as TransitionPresets from "./TransitionConfigs/TransitionPresets.js";
import * as TransitionSpecs from "./TransitionConfigs/TransitionSpecs.js";
/**
* Transition Presets
*/
export { SceneStyleInterpolators, TransitionPresets, TransitionSpecs };
/**
* Navigators
*/
export { createBottomTabNavigator } from "./navigators/createBottomTabNavigator.js";
/**
* Views
*/
export { BottomTabBar } from "./views/BottomTabBar.js";
export { BottomTabView } from "./views/BottomTabView.js";
/**
* Utilities
*/
export { BottomTabBarHeightCallbackContext } from "./utils/BottomTabBarHeightCallbackContext.js";
export { BottomTabBarHeightContext } from "./utils/BottomTabBarHeightContext.js";
export { useBottomTabBarHeight } from "./utils/useBottomTabBarHeight.js";
/**
* Types
*/
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["SceneStyleInterpolators","TransitionPresets","TransitionSpecs","createBottomTabNavigator","BottomTabBar","BottomTabView","BottomTabBarHeightCallbackContext","BottomTabBarHeightContext","useBottomTabBarHeight"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAO,KAAKA,uBAAuB,MAAM,gDAA6C;AACtF,OAAO,KAAKC,iBAAiB,MAAM,0CAAuC;AAC1E,OAAO,KAAKC,eAAe,MAAM,wCAAqC;;AAEtE;AACA;AACA;AACA,SAASF,uBAAuB,EAAEC,iBAAiB,EAAEC,eAAe;;AAEpE;AACA;AACA;AACA,SAASC,wBAAwB,QAAQ,0CAAuC;;AAEhF;AACA;AACA;AACA,SAASC,YAAY,QAAQ,yBAAsB;AACnD,SAASC,aAAa,QAAQ,0BAAuB;;AAErD;AACA;AACA;AACA,SAASC,iCAAiC,QAAQ,8CAA2C;AAC7F,SAASC,yBAAyB,QAAQ,sCAAmC;AAC7E,SAASC,qBAAqB,QAAQ,kCAA+B;;AAErE;AACA;AACA","ignoreList":[]}

View File

@@ -0,0 +1,48 @@
"use strict";
import { createNavigatorFactory, TabRouter, useNavigationBuilder } from '@react-navigation/native';
import { BottomTabView } from "../views/BottomTabView.js";
import { jsx as _jsx } from "react/jsx-runtime";
function BottomTabNavigator({
id,
initialRouteName,
backBehavior,
UNSTABLE_routeNamesChangeBehavior,
children,
layout,
screenListeners,
screenOptions,
screenLayout,
UNSTABLE_router,
...rest
}) {
const {
state,
descriptors,
navigation,
NavigationContent
} = useNavigationBuilder(TabRouter, {
id,
initialRouteName,
backBehavior,
UNSTABLE_routeNamesChangeBehavior,
children,
layout,
screenListeners,
screenOptions,
screenLayout,
UNSTABLE_router
});
return /*#__PURE__*/_jsx(NavigationContent, {
children: /*#__PURE__*/_jsx(BottomTabView, {
...rest,
state: state,
navigation: navigation,
descriptors: descriptors
})
});
}
export function createBottomTabNavigator(config) {
return createNavigatorFactory(BottomTabNavigator)(config);
}
//# sourceMappingURL=createBottomTabNavigator.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["createNavigatorFactory","TabRouter","useNavigationBuilder","BottomTabView","jsx","_jsx","BottomTabNavigator","id","initialRouteName","backBehavior","UNSTABLE_routeNamesChangeBehavior","children","layout","screenListeners","screenOptions","screenLayout","UNSTABLE_router","rest","state","descriptors","navigation","NavigationContent","createBottomTabNavigator","config"],"sourceRoot":"../../../src","sources":["navigators/createBottomTabNavigator.tsx"],"mappings":";;AAAA,SACEA,sBAAsB,EAMtBC,SAAS,EAGTC,oBAAoB,QACf,0BAA0B;AAQjC,SAASC,aAAa,QAAQ,2BAAwB;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAEvD,SAASC,kBAAkBA,CAAC;EAC1BC,EAAE;EACFC,gBAAgB;EAChBC,YAAY;EACZC,iCAAiC;EACjCC,QAAQ;EACRC,MAAM;EACNC,eAAe;EACfC,aAAa;EACbC,YAAY;EACZC,eAAe;EACf,GAAGC;AACoB,CAAC,EAAE;EAC1B,MAAM;IAAEC,KAAK;IAAEC,WAAW;IAAEC,UAAU;IAAEC;EAAkB,CAAC,GACzDnB,oBAAoB,CAMlBD,SAAS,EAAE;IACXM,EAAE;IACFC,gBAAgB;IAChBC,YAAY;IACZC,iCAAiC;IACjCC,QAAQ;IACRC,MAAM;IACNC,eAAe;IACfC,aAAa;IACbC,YAAY;IACZC;EACF,CAAC,CAAC;EAEJ,oBACEX,IAAA,CAACgB,iBAAiB;IAAAV,QAAA,eAChBN,IAAA,CAACF,aAAa;MAAA,GACRc,IAAI;MACRC,KAAK,EAAEA,KAAM;MACbE,UAAU,EAAEA,UAAW;MACvBD,WAAW,EAAEA;IAAY,CAC1B;EAAC,CACe,CAAC;AAExB;AAEA,OAAO,SAASG,wBAAwBA,CAmBtCC,MAAe,EAAmC;EAClD,OAAOvB,sBAAsB,CAACM,kBAAkB,CAAC,CAACiB,MAAM,CAAC;AAC3D","ignoreList":[]}

View File

@@ -0,0 +1 @@
{"type":"module"}

View File

@@ -0,0 +1,4 @@
"use strict";
export {};
//# sourceMappingURL=types.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":[],"sourceRoot":"../../src","sources":["types.tsx"],"mappings":"","ignoreList":[]}

View File

@@ -0,0 +1,6 @@
"use strict";
export function NativeBottomTabView(_) {
throw new Error('Native Bottom Tabs are not supported on this platform.');
}
//# sourceMappingURL=NativeBottomTabView.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["NativeBottomTabView","_","Error"],"sourceRoot":"../../../src","sources":["unstable/NativeBottomTabView.tsx"],"mappings":";;AAiBA,OAAO,SAASA,mBAAmBA,CAACC,CAAQ,EAAE;EAC5C,MAAM,IAAIC,KAAK,CAAC,wDAAwD,CAAC;AAC3E","ignoreList":[]}

View File

@@ -0,0 +1,328 @@
"use strict";
import { getLabel, Lazy, SafeAreaProviderCompat, Screen as ScreenContent } from '@react-navigation/elements';
import { CommonActions, NavigationMetaContext, StackActions, useTheme } from '@react-navigation/native';
import Color from 'color';
import * as React from 'react';
import { Platform, PlatformColor } from 'react-native';
import { Tabs } from 'react-native-screens';
import { NativeScreen } from "./NativeScreen/NativeScreen.js";
import { jsx as _jsx } from "react/jsx-runtime";
const meta = {
type: 'native-tabs'
};
export function NativeBottomTabView({
state,
navigation,
descriptors
}) {
const {
dark,
colors,
fonts
} = useTheme();
const focusedRouteKey = state.routes[state.index].key;
const previousRouteKeyRef = React.useRef(focusedRouteKey);
React.useEffect(() => {
const previousRouteKey = previousRouteKeyRef.current;
if (previousRouteKey !== focusedRouteKey && descriptors[previousRouteKey]?.options.popToTopOnBlur) {
const prevRoute = state.routes.find(route => route.key === previousRouteKey);
if (prevRoute?.state?.type === 'stack' && prevRoute.state.key) {
const popToTopAction = {
...StackActions.popToTop(),
target: prevRoute.state.key
};
navigation.dispatch(popToTopAction);
}
}
previousRouteKeyRef.current = focusedRouteKey;
}, [descriptors, focusedRouteKey, navigation, state.index, state.routes]);
const currentOptions = descriptors[state.routes[state.index].key]?.options;
const {
fontFamily = Platform.select({
ios: fonts.medium.fontFamily,
default: fonts.regular.fontFamily
}),
fontWeight = Platform.select({
ios: fonts.medium.fontWeight,
default: fonts.regular.fontWeight
}),
fontSize,
fontStyle,
color: fontColor
} = currentOptions.tabBarLabelStyle || {};
const activeTintColor = currentOptions.tabBarActiveTintColor ?? colors.primary;
const inactiveTintColor = currentOptions.tabBarInactiveTintColor ?? Platform.select({
ios: PlatformColor('label'),
default: colors.text
});
const activeIndicatorColor = currentOptions?.tabBarActiveIndicatorColor ?? typeof activeTintColor === 'string' ? Color(activeTintColor)?.alpha(0.1).string() : undefined;
const onTransitionStart = ({
closing,
route
}) => {
navigation.emit({
type: 'transitionStart',
data: {
closing
},
target: route.key
});
};
const onTransitionEnd = ({
closing,
route
}) => {
navigation.emit({
type: 'transitionEnd',
data: {
closing
},
target: route.key
});
};
const tabBarControllerMode = currentOptions.tabBarControllerMode === 'auto' ? 'automatic' : currentOptions.tabBarControllerMode;
const tabBarMinimizeBehavior = currentOptions.tabBarMinimizeBehavior === 'auto' ? 'automatic' : currentOptions.tabBarMinimizeBehavior;
const shouldHideTabBar = currentOptions.tabBarStyle?.display === 'none';
const bottomAccessory = currentOptions.bottomAccessory;
return /*#__PURE__*/_jsx(SafeAreaProviderCompat, {
children: /*#__PURE__*/_jsx(Tabs.Host, {
bottomAccessory: bottomAccessory ? environment => bottomAccessory({
placement: environment
}) : undefined,
tabBarHidden: shouldHideTabBar,
tabBarItemLabelVisibilityMode: currentOptions?.tabBarLabelVisibilityMode,
tabBarControllerMode: tabBarControllerMode,
tabBarMinimizeBehavior: tabBarMinimizeBehavior,
tabBarTintColor: activeTintColor,
tabBarItemIconColor: inactiveTintColor,
tabBarItemIconColorActive: activeTintColor,
tabBarItemTitleFontColor: inactiveTintColor ?? fontColor,
tabBarItemTitleFontColorActive: activeTintColor,
tabBarItemTitleFontFamily: fontFamily,
tabBarItemTitleFontWeight: fontWeight,
tabBarItemTitleFontSize: fontSize,
tabBarItemTitleFontSizeActive: fontSize,
tabBarItemTitleFontStyle: fontStyle,
tabBarBackgroundColor: currentOptions.tabBarStyle?.backgroundColor ?? colors.card,
tabBarItemActiveIndicatorColor: activeIndicatorColor,
tabBarItemActiveIndicatorEnabled: currentOptions?.tabBarActiveIndicatorEnabled,
tabBarItemRippleColor: currentOptions?.tabBarRippleColor,
experimentalControlNavigationStateInJS: false,
onNativeFocusChange: e => {
const route = state.routes.find(route => route.key === e.nativeEvent.tabKey);
if (route) {
navigation.emit({
type: 'tabPress',
target: route.key
});
const isFocused = state.index === state.routes.findIndex(r => r.key === route.key);
if (!isFocused) {
navigation.dispatch({
...CommonActions.navigate(route.name, route.params),
target: state.key
});
}
}
},
children: state.routes.map((route, index) => {
const {
options,
render,
navigation
} = descriptors[route.key];
const isFocused = state.index === index;
const isPreloaded = state.preloadedRouteKeys.includes(route.key);
const {
title,
lazy = true,
tabBarLabel,
tabBarBadgeStyle,
tabBarIcon,
tabBarBadge,
tabBarSystemItem,
tabBarBlurEffect = dark ? 'systemMaterialDark' : 'systemMaterial',
tabBarStyle,
overrideScrollViewContentInsetAdjustmentBehavior
} = options;
const {
backgroundColor: tabBarBackgroundColor,
shadowColor: tabBarShadowColor
} = tabBarStyle || {};
const tabTitle =
// On iOS, `systemItem` already provides a localized label
// So we should only use `tabBarLabel` if explicitly provided
Platform.OS === 'ios' && tabBarSystemItem != null ? tabBarLabel : getLabel({
label: tabBarLabel,
title
}, route.name);
const badgeBackgroundColor = tabBarBadgeStyle?.backgroundColor ?? colors.notification;
const badgeTextColor = tabBarBadgeStyle?.color ?? (typeof badgeBackgroundColor === 'string' ? Color(badgeBackgroundColor).isLight() ? 'black' : 'white' : undefined);
const tabItemAppearance = {
tabBarItemTitleFontFamily: fontFamily,
tabBarItemTitleFontSize: fontSize,
tabBarItemTitleFontWeight: fontWeight,
tabBarItemTitleFontStyle: fontStyle,
tabBarItemTitleFontColor: inactiveTintColor ?? fontColor,
tabBarItemIconColor: inactiveTintColor,
tabBarItemBadgeBackgroundColor: badgeBackgroundColor
};
const icon = typeof tabBarIcon === 'function' ? getPlatformIcon(tabBarIcon({
focused: false
})) : tabBarIcon != null ? getPlatformIcon(tabBarIcon) : undefined;
const selectedIcon = typeof tabBarIcon === 'function' ? getPlatformIcon(tabBarIcon({
focused: true
})) : undefined;
return /*#__PURE__*/_jsx(Tabs.Screen, {
onWillDisappear: () => onTransitionStart({
closing: true,
route
}),
onWillAppear: () => onTransitionStart({
closing: false,
route
}),
onDidAppear: () => onTransitionEnd({
closing: false,
route
}),
onDidDisappear: () => onTransitionEnd({
closing: true,
route
}),
tabKey: route.key,
icon: icon,
selectedIcon: selectedIcon?.ios ?? selectedIcon?.shared,
tabBarItemBadgeBackgroundColor: badgeBackgroundColor,
tabBarItemBadgeTextColor: badgeTextColor,
badgeValue: tabBarBadge?.toString(),
systemItem: tabBarSystemItem,
isFocused: isFocused,
title: tabTitle,
scrollEdgeAppearance: {
tabBarBackgroundColor,
tabBarShadowColor,
tabBarBlurEffect,
stacked: {
normal: tabItemAppearance
},
inline: {
normal: tabItemAppearance
},
compactInline: {
normal: tabItemAppearance
}
},
standardAppearance: {
tabBarBackgroundColor,
tabBarShadowColor,
tabBarBlurEffect,
stacked: {
normal: tabItemAppearance
},
inline: {
normal: tabItemAppearance
},
compactInline: {
normal: tabItemAppearance
}
},
specialEffects: {
repeatedTabSelection: {
popToRoot: true,
scrollToTop: true
}
},
overrideScrollViewContentInsetAdjustmentBehavior: overrideScrollViewContentInsetAdjustmentBehavior,
experimental_userInterfaceStyle: dark ? 'dark' : 'light',
children: /*#__PURE__*/_jsx(Lazy, {
enabled: lazy,
visible: isFocused || isPreloaded,
children: /*#__PURE__*/_jsx(ScreenWithHeader, {
isFocused: isFocused,
route: route,
navigation: navigation,
options: options,
children: /*#__PURE__*/_jsx(NavigationMetaContext.Provider, {
value: meta,
children: render()
})
})
})
}, route.key);
})
})
});
}
function ScreenWithHeader({
isFocused,
route,
navigation,
options,
children
}) {
const {
headerTransparent,
header: renderCustomHeader,
headerShown = renderCustomHeader != null
} = options;
const hasNativeHeader = headerShown && renderCustomHeader == null;
const [wasNativeHeaderShown] = React.useState(hasNativeHeader);
React.useEffect(() => {
if (wasNativeHeaderShown !== hasNativeHeader) {
throw new Error(`Changing 'headerShown' or 'header' options dynamically is not supported when using native header.`);
}
}, [wasNativeHeaderShown, hasNativeHeader]);
if (hasNativeHeader) {
return /*#__PURE__*/_jsx(NativeScreen, {
route: route,
navigation: navigation,
options: options,
children: children
});
}
return /*#__PURE__*/_jsx(ScreenContent, {
focused: isFocused,
route: route,
navigation: navigation,
headerShown: headerShown,
headerTransparent: headerTransparent,
header: renderCustomHeader?.({
route,
navigation,
options
}),
children: children
});
}
function getPlatformIcon(icon) {
switch (icon.type) {
case 'sfSymbol':
return {
ios: icon,
android: undefined,
shared: undefined
};
case 'image':
return {
ios: icon.tinted === false ? {
type: 'imageSource',
imageSource: icon.source
} : {
type: 'templateSource',
templateSource: icon.source
},
android: undefined,
shared: {
type: 'imageSource',
imageSource: icon.source
}
};
default:
{
const _exhaustiveCheck = icon;
return _exhaustiveCheck;
}
}
}
//# sourceMappingURL=NativeBottomTabView.native.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,152 @@
"use strict";
import { getDefaultHeaderHeight, HeaderHeightContext, HeaderShownContext, useFrameSize } from '@react-navigation/elements';
import * as React from 'react';
import { Animated, Platform, StyleSheet, useAnimatedValue, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { ScreenStack, ScreenStackItem } from 'react-native-screens';
import { debounce } from "./debounce.js";
import { AnimatedHeaderHeightContext } from "./useAnimatedHeaderHeight.js";
import { useHeaderConfig } from "./useHeaderConfig.js";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const ANDROID_DEFAULT_HEADER_HEIGHT = 56;
export function NativeScreen({
route,
navigation,
options,
children
}) {
const {
header: renderCustomHeader,
headerShown = renderCustomHeader != null,
headerTransparent,
headerBackground
} = options;
const isModal = false;
const insets = useSafeAreaInsets();
// Modals are fullscreen in landscape only on iPhone
const isIPhone = Platform.OS === 'ios' && !(Platform.isPad || Platform.isTV);
const isParentHeaderShown = React.useContext(HeaderShownContext);
const parentHeaderHeight = React.useContext(HeaderHeightContext);
const isLandscape = useFrameSize(frame => frame.width > frame.height);
const topInset = isParentHeaderShown || Platform.OS === 'ios' && isModal || isIPhone && isLandscape ? 0 : insets.top;
const defaultHeaderHeight = useFrameSize(frame => Platform.select({
// FIXME: Currently screens isn't using Material 3
// So our `getDefaultHeaderHeight` doesn't return the correct value
// So we hardcode the value here for now until screens is updated
android: ANDROID_DEFAULT_HEADER_HEIGHT + topInset,
default: getDefaultHeaderHeight(frame, isModal, topInset)
}));
const [headerHeight, setHeaderHeight] = React.useState(defaultHeaderHeight);
// eslint-disable-next-line react-hooks/exhaustive-deps
const setHeaderHeightDebounced = React.useCallback(
// Debounce the header height updates to avoid excessive re-renders
debounce(setHeaderHeight, 100), []);
const hasCustomHeader = renderCustomHeader != null;
const animatedHeaderHeight = useAnimatedValue(defaultHeaderHeight);
const headerTopInsetEnabled = topInset !== 0;
const onHeaderHeightChange = Animated.event([{
nativeEvent: {
headerHeight: animatedHeaderHeight
}
}], {
useNativeDriver: true,
listener: e => {
if (hasCustomHeader) {
// If we have a custom header, don't use native header height
return;
}
if (e.nativeEvent && typeof e.nativeEvent === 'object' && 'headerHeight' in e.nativeEvent && typeof e.nativeEvent.headerHeight === 'number') {
const headerHeight = e.nativeEvent.headerHeight;
// Only debounce if header has large title or search bar
// As it's the only case where the header height can change frequently
const doesHeaderAnimate = Platform.OS === 'ios' && (options.headerLargeTitleEnabled || options.headerSearchBarOptions);
if (doesHeaderAnimate) {
setHeaderHeightDebounced(headerHeight);
} else {
setHeaderHeight(headerHeight);
}
}
}
});
const headerConfig = useHeaderConfig({
...options,
route,
headerHeight,
headerShown: hasCustomHeader ? false : headerShown === true,
headerTopInsetEnabled
});
return /*#__PURE__*/_jsx(ScreenStack, {
style: styles.container,
children: /*#__PURE__*/_jsx(ScreenStackItem, {
screenId: route.key
// Needed to show search bar in tab bar with systemItem=search
,
stackPresentation: "push",
headerConfig: headerConfig,
onHeaderHeightChange: onHeaderHeightChange,
children: /*#__PURE__*/_jsx(AnimatedHeaderHeightContext.Provider, {
value: animatedHeaderHeight,
children: /*#__PURE__*/_jsxs(HeaderHeightContext.Provider, {
value: headerShown ? headerHeight : parentHeaderHeight ?? 0,
children: [headerBackground != null ?
/*#__PURE__*/
/**
* To show a custom header background, we render it at the top of the screen below the header
* The header also needs to be positioned absolutely (with `translucent` style)
*/
_jsx(View, {
style: [styles.background, headerTransparent ? styles.translucent : null, {
height: headerHeight
}],
children: headerBackground()
}) : null, hasCustomHeader && headerShown ? /*#__PURE__*/_jsx(View, {
onLayout: e => {
const headerHeight = e.nativeEvent.layout.height;
setHeaderHeight(headerHeight);
animatedHeaderHeight.setValue(headerHeight);
},
style: [styles.header, headerTransparent ? styles.absolute : null],
children: renderCustomHeader?.({
route,
navigation,
options
})
}) : null, /*#__PURE__*/_jsx(HeaderShownContext.Provider, {
value: isParentHeaderShown || headerShown,
children: children
})]
})
})
})
});
}
const styles = StyleSheet.create({
container: {
flex: 1
},
header: {
zIndex: 1
},
absolute: {
position: 'absolute',
top: 0,
start: 0,
end: 0
},
translucent: {
position: 'absolute',
top: 0,
start: 0,
end: 0,
zIndex: 1,
elevation: 1
},
background: {
overflow: 'hidden'
}
});
//# sourceMappingURL=NativeScreen.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,12 @@
"use strict";
export function debounce(func, duration) {
let timeout;
return function (...args) {
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(this, args);
}, duration);
};
}
//# sourceMappingURL=debounce.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["debounce","func","duration","timeout","args","clearTimeout","setTimeout","apply"],"sourceRoot":"../../../../src","sources":["unstable/NativeScreen/debounce.tsx"],"mappings":";;AAAA,OAAO,SAASA,QAAQA,CACtBC,IAAO,EACPC,QAAgB,EACb;EACH,IAAIC,OAAsC;EAE1C,OAAO,UAAyB,GAAGC,IAAI,EAAE;IACvCC,YAAY,CAACF,OAAO,CAAC;IAErBA,OAAO,GAAGG,UAAU,CAAC,MAAM;MACzBL,IAAI,CAACM,KAAK,CAAC,IAAI,EAAEH,IAAI,CAAC;IACxB,CAAC,EAAEF,QAAQ,CAAC;EACd,CAAC;AACH","ignoreList":[]}

View File

@@ -0,0 +1,4 @@
"use strict";
export {};
//# sourceMappingURL=types.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":[],"sourceRoot":"../../../../src","sources":["unstable/NativeScreen/types.ts"],"mappings":"","ignoreList":[]}

View File

@@ -0,0 +1,12 @@
"use strict";
import * as React from 'react';
export const AnimatedHeaderHeightContext = /*#__PURE__*/React.createContext(undefined);
export function useAnimatedHeaderHeight() {
const animatedValue = React.useContext(AnimatedHeaderHeightContext);
if (animatedValue === undefined) {
throw new Error("Couldn't find the header height. Are you inside a screen in a native stack navigator?");
}
return animatedValue;
}
//# sourceMappingURL=useAnimatedHeaderHeight.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","AnimatedHeaderHeightContext","createContext","undefined","useAnimatedHeaderHeight","animatedValue","useContext","Error"],"sourceRoot":"../../../../src","sources":["unstable/NativeScreen/useAnimatedHeaderHeight.tsx"],"mappings":";;AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAG9B,OAAO,MAAMC,2BAA2B,gBAAGD,KAAK,CAACE,aAAa,CAE5DC,SAAS,CAAC;AAEZ,OAAO,SAASC,uBAAuBA,CAAA,EAAG;EACxC,MAAMC,aAAa,GAAGL,KAAK,CAACM,UAAU,CAACL,2BAA2B,CAAC;EAEnE,IAAII,aAAa,KAAKF,SAAS,EAAE;IAC/B,MAAM,IAAII,KAAK,CACb,uFACF,CAAC;EACH;EAEA,OAAOF,aAAa;AACtB","ignoreList":[]}

View File

@@ -0,0 +1,304 @@
"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') {
const {
multiselectable,
layout
} = item.menu;
processedItem = {
...processedItem,
menu: {
...processedItem.menu,
singleSelection: !multiselectable,
displayAsPalette: layout === 'palette',
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 => {
if (item.type === 'submenu') {
const {
label,
inline,
layout,
items,
multiselectable,
...rest
} = item;
return {
...rest,
title: label,
displayAsPalette: layout === 'palette',
displayInline: inline,
singleSelection: !multiselectable,
items: items.map(getMenuItem)
};
}
const {
label,
description,
...rest
} = item;
return {
...rest,
title: label,
subtitle: description
};
};
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,
dark
} = 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),
experimental_userInterfaceStyle: dark ? 'dark' : 'light'
};
}
//# sourceMappingURL=useHeaderConfig.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,6 @@
"use strict";
export const createNativeBottomTabNavigator = () => {
throw new Error('Native Bottom Tabs are not supported on this platform.');
};
//# sourceMappingURL=createNativeBottomTabNavigator.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["createNativeBottomTabNavigator","Error"],"sourceRoot":"../../../src","sources":["unstable/createNativeBottomTabNavigator.tsx"],"mappings":";;AAAA,OAAO,MAAMA,8BAAuH,GAClIA,CAAA,KAAM;EACJ,MAAM,IAAIC,KAAK,CAAC,wDAAwD,CAAC;AAC3E,CAAC","ignoreList":[]}

View File

@@ -0,0 +1,65 @@
"use strict";
import { createNavigatorFactory, StackActions, TabRouter, useNavigationBuilder } from '@react-navigation/native';
import * as React from 'react';
import { NativeBottomTabView } from "./NativeBottomTabView.native.js";
import { jsx as _jsx } from "react/jsx-runtime";
function NativeBottomTabNavigator({
id,
initialRouteName,
backBehavior,
children,
layout,
screenListeners,
screenOptions,
screenLayout,
UNSTABLE_router,
UNSTABLE_routeNamesChangeBehavior,
...rest
}) {
const {
state,
navigation,
descriptors,
NavigationContent
} = useNavigationBuilder(TabRouter, {
id,
initialRouteName,
backBehavior,
children,
layout,
screenListeners,
screenOptions,
screenLayout,
UNSTABLE_router,
UNSTABLE_routeNamesChangeBehavior
});
const focusedRouteKey = state.routes[state.index].key;
const previousRouteKeyRef = React.useRef(focusedRouteKey);
React.useEffect(() => {
const previousRouteKey = previousRouteKeyRef.current;
if (previousRouteKey !== focusedRouteKey && descriptors[previousRouteKey]?.options.popToTopOnBlur) {
const prevRoute = state.routes.find(route => route.key === previousRouteKey);
if (prevRoute?.state?.type === 'stack' && prevRoute.state.key) {
const popToTopAction = {
...StackActions.popToTop(),
target: prevRoute.state.key
};
navigation.dispatch(popToTopAction);
}
}
previousRouteKeyRef.current = focusedRouteKey;
}, [descriptors, focusedRouteKey, navigation, state.index, state.routes]);
return /*#__PURE__*/_jsx(NavigationContent, {
children: /*#__PURE__*/_jsx(NativeBottomTabView, {
...rest,
state: state,
navigation: navigation,
descriptors: descriptors
})
});
}
export function createNativeBottomTabNavigator(config) {
return createNavigatorFactory(NativeBottomTabNavigator)(config);
}
//# sourceMappingURL=createNativeBottomTabNavigator.native.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["createNavigatorFactory","StackActions","TabRouter","useNavigationBuilder","React","NativeBottomTabView","jsx","_jsx","NativeBottomTabNavigator","id","initialRouteName","backBehavior","children","layout","screenListeners","screenOptions","screenLayout","UNSTABLE_router","UNSTABLE_routeNamesChangeBehavior","rest","state","navigation","descriptors","NavigationContent","focusedRouteKey","routes","index","key","previousRouteKeyRef","useRef","useEffect","previousRouteKey","current","options","popToTopOnBlur","prevRoute","find","route","type","popToTopAction","popToTop","target","dispatch","createNativeBottomTabNavigator","config"],"sourceRoot":"../../../src","sources":["unstable/createNativeBottomTabNavigator.native.tsx"],"mappings":";;AAAA,SACEA,sBAAsB,EAGtBC,YAAY,EAIZC,SAAS,EAGTC,oBAAoB,QACf,0BAA0B;AACjC,OAAO,KAAKC,KAAK,MAAM,OAAO;AAE9B,SAASC,mBAAmB,QAAQ,iCAA8B;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAQnE,SAASC,wBAAwBA,CAAC;EAChCC,EAAE;EACFC,gBAAgB;EAChBC,YAAY;EACZC,QAAQ;EACRC,MAAM;EACNC,eAAe;EACfC,aAAa;EACbC,YAAY;EACZC,eAAe;EACfC,iCAAiC;EACjC,GAAGC;AAC0B,CAAC,EAAE;EAChC,MAAM;IAAEC,KAAK;IAAEC,UAAU;IAAEC,WAAW;IAAEC;EAAkB,CAAC,GACzDpB,oBAAoB,CAMlBD,SAAS,EAAE;IACXO,EAAE;IACFC,gBAAgB;IAChBC,YAAY;IACZC,QAAQ;IACRC,MAAM;IACNC,eAAe;IACfC,aAAa;IACbC,YAAY;IACZC,eAAe;IACfC;EACF,CAAC,CAAC;EAEJ,MAAMM,eAAe,GAAGJ,KAAK,CAACK,MAAM,CAACL,KAAK,CAACM,KAAK,CAAC,CAACC,GAAG;EACrD,MAAMC,mBAAmB,GAAGxB,KAAK,CAACyB,MAAM,CAACL,eAAe,CAAC;EAEzDpB,KAAK,CAAC0B,SAAS,CAAC,MAAM;IACpB,MAAMC,gBAAgB,GAAGH,mBAAmB,CAACI,OAAO;IAEpD,IACED,gBAAgB,KAAKP,eAAe,IACpCF,WAAW,CAACS,gBAAgB,CAAC,EAAEE,OAAO,CAACC,cAAc,EACrD;MACA,MAAMC,SAAS,GAAGf,KAAK,CAACK,MAAM,CAACW,IAAI,CAChCC,KAAK,IAAKA,KAAK,CAACV,GAAG,KAAKI,gBAC3B,CAAC;MAED,IAAII,SAAS,EAAEf,KAAK,EAAEkB,IAAI,KAAK,OAAO,IAAIH,SAAS,CAACf,KAAK,CAACO,GAAG,EAAE;QAC7D,MAAMY,cAAc,GAAG;UACrB,GAAGtC,YAAY,CAACuC,QAAQ,CAAC,CAAC;UAC1BC,MAAM,EAAEN,SAAS,CAACf,KAAK,CAACO;QAC1B,CAAC;QACDN,UAAU,CAACqB,QAAQ,CAACH,cAAc,CAAC;MACrC;IACF;IAEAX,mBAAmB,CAACI,OAAO,GAAGR,eAAe;EAC/C,CAAC,EAAE,CAACF,WAAW,EAAEE,eAAe,EAAEH,UAAU,EAAED,KAAK,CAACM,KAAK,EAAEN,KAAK,CAACK,MAAM,CAAC,CAAC;EAEzE,oBACElB,IAAA,CAACgB,iBAAiB;IAAAX,QAAA,eAChBL,IAAA,CAACF,mBAAmB;MAAA,GACdc,IAAI;MACRC,KAAK,EAAEA,KAAM;MACbC,UAAU,EAAEA,UAAW;MACvBC,WAAW,EAAEA;IAAY,CAC1B;EAAC,CACe,CAAC;AAExB;AAEA,OAAO,SAASqB,8BAA8BA,CAmB5CC,MAAe,EAAmC;EAClD,OAAO5C,sBAAsB,CAACQ,wBAAwB,CAAC,CAACoC,MAAM,CAAC;AACjE","ignoreList":[]}

View File

@@ -0,0 +1,16 @@
"use strict";
/**
* Navigators
*/
export { createNativeBottomTabNavigator } from './createNativeBottomTabNavigator';
/**
* Views
*/
export { NativeBottomTabView } from './NativeBottomTabView';
/**
* Types
*/
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["createNativeBottomTabNavigator","NativeBottomTabView"],"sourceRoot":"../../../src","sources":["unstable/index.tsx"],"mappings":";;AAAA;AACA;AACA;AACA,SAASA,8BAA8B,QAAQ,kCAAkC;;AAEjF;AACA;AACA;AACA,SAASC,mBAAmB,QAAQ,uBAAuB;;AAE3D;AACA;AACA","ignoreList":[]}

View File

@@ -0,0 +1,4 @@
"use strict";
export {};
//# sourceMappingURL=types.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":[],"sourceRoot":"../../../src","sources":["unstable/types.tsx"],"mappings":"","ignoreList":[]}

View File

@@ -0,0 +1,5 @@
"use strict";
import * as React from 'react';
export const BottomTabBarHeightCallbackContext = /*#__PURE__*/React.createContext(undefined);
//# sourceMappingURL=BottomTabBarHeightCallbackContext.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","BottomTabBarHeightCallbackContext","createContext","undefined"],"sourceRoot":"../../../src","sources":["utils/BottomTabBarHeightCallbackContext.tsx"],"mappings":";;AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAE9B,OAAO,MAAMC,iCAAiC,gBAAGD,KAAK,CAACE,aAAa,CAElEC,SAAS,CAAC","ignoreList":[]}

View File

@@ -0,0 +1,5 @@
"use strict";
import * as React from 'react';
export const BottomTabBarHeightContext = /*#__PURE__*/React.createContext(undefined);
//# sourceMappingURL=BottomTabBarHeightContext.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","BottomTabBarHeightContext","createContext","undefined"],"sourceRoot":"../../../src","sources":["utils/BottomTabBarHeightContext.tsx"],"mappings":";;AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAE9B,OAAO,MAAMC,yBAAyB,gBAAGD,KAAK,CAACE,aAAa,CAE1DC,SAAS,CAAC","ignoreList":[]}

View File

@@ -0,0 +1,23 @@
"use strict";
import * as React from 'react';
import { Animated } from 'react-native';
export function useAnimatedHashMap({
routes,
index
}) {
const refs = React.useRef({});
const previous = refs.current;
const routeKeys = Object.keys(previous);
if (routes.length === routeKeys.length && routes.every(route => routeKeys.includes(route.key))) {
return previous;
}
refs.current = {};
routes.forEach(({
key
}, i) => {
refs.current[key] = previous[key] ?? new Animated.Value(i === index ? 0 : i >= index ? 1 : -1);
});
return refs.current;
}
//# sourceMappingURL=useAnimatedHashMap.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","Animated","useAnimatedHashMap","routes","index","refs","useRef","previous","current","routeKeys","Object","keys","length","every","route","includes","key","forEach","i","Value"],"sourceRoot":"../../../src","sources":["utils/useAnimatedHashMap.tsx"],"mappings":";;AACA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SAASC,QAAQ,QAAQ,cAAc;AAEvC,OAAO,SAASC,kBAAkBA,CAAC;EAAEC,MAAM;EAAEC;AAAuB,CAAC,EAAE;EACrE,MAAMC,IAAI,GAAGL,KAAK,CAACM,MAAM,CAAiC,CAAC,CAAC,CAAC;EAC7D,MAAMC,QAAQ,GAAGF,IAAI,CAACG,OAAO;EAC7B,MAAMC,SAAS,GAAGC,MAAM,CAACC,IAAI,CAACJ,QAAQ,CAAC;EAEvC,IACEJ,MAAM,CAACS,MAAM,KAAKH,SAAS,CAACG,MAAM,IAClCT,MAAM,CAACU,KAAK,CAAEC,KAAK,IAAKL,SAAS,CAACM,QAAQ,CAACD,KAAK,CAACE,GAAG,CAAC,CAAC,EACtD;IACA,OAAOT,QAAQ;EACjB;EACAF,IAAI,CAACG,OAAO,GAAG,CAAC,CAAC;EAEjBL,MAAM,CAACc,OAAO,CAAC,CAAC;IAAED;EAAI,CAAC,EAAEE,CAAC,KAAK;IAC7Bb,IAAI,CAACG,OAAO,CAACQ,GAAG,CAAC,GACfT,QAAQ,CAACS,GAAG,CAAC,IACb,IAAIf,QAAQ,CAACkB,KAAK,CAACD,CAAC,KAAKd,KAAK,GAAG,CAAC,GAAGc,CAAC,IAAId,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;EAC7D,CAAC,CAAC;EAEF,OAAOC,IAAI,CAACG,OAAO;AACrB","ignoreList":[]}

View File

@@ -0,0 +1,12 @@
"use strict";
import * as React from 'react';
import { BottomTabBarHeightContext } from "./BottomTabBarHeightContext.js";
export function useBottomTabBarHeight() {
const height = React.useContext(BottomTabBarHeightContext);
if (height === undefined) {
throw new Error("Couldn't find the bottom tab bar height. Are you inside a screen in Bottom Tab Navigator?");
}
return height;
}
//# sourceMappingURL=useBottomTabBarHeight.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","BottomTabBarHeightContext","useBottomTabBarHeight","height","useContext","undefined","Error"],"sourceRoot":"../../../src","sources":["utils/useBottomTabBarHeight.tsx"],"mappings":";;AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAE9B,SAASC,yBAAyB,QAAQ,gCAA6B;AAEvE,OAAO,SAASC,qBAAqBA,CAAA,EAAG;EACtC,MAAMC,MAAM,GAAGH,KAAK,CAACI,UAAU,CAACH,yBAAyB,CAAC;EAE1D,IAAIE,MAAM,KAAKE,SAAS,EAAE;IACxB,MAAM,IAAIC,KAAK,CACb,2FACF,CAAC;EACH;EAEA,OAAOH,MAAM;AACf","ignoreList":[]}

View File

@@ -0,0 +1,22 @@
"use strict";
import * as React from 'react';
import { Keyboard, Platform } from 'react-native';
export function useIsKeyboardShown() {
const [isKeyboardShown, setIsKeyboardShown] = React.useState(false);
React.useEffect(() => {
const handleKeyboardShow = () => setIsKeyboardShown(true);
const handleKeyboardHide = () => setIsKeyboardShown(false);
let subscriptions;
if (Platform.OS === 'ios') {
subscriptions = [Keyboard.addListener('keyboardWillShow', handleKeyboardShow), Keyboard.addListener('keyboardWillHide', handleKeyboardHide)];
} else {
subscriptions = [Keyboard.addListener('keyboardDidShow', handleKeyboardShow), Keyboard.addListener('keyboardDidHide', handleKeyboardHide)];
}
return () => {
subscriptions.forEach(s => s.remove());
};
}, []);
return isKeyboardShown;
}
//# sourceMappingURL=useIsKeyboardShown.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","Keyboard","Platform","useIsKeyboardShown","isKeyboardShown","setIsKeyboardShown","useState","useEffect","handleKeyboardShow","handleKeyboardHide","subscriptions","OS","addListener","forEach","s","remove"],"sourceRoot":"../../../src","sources":["utils/useIsKeyboardShown.tsx"],"mappings":";;AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SAAmCC,QAAQ,EAAEC,QAAQ,QAAQ,cAAc;AAE3E,OAAO,SAASC,kBAAkBA,CAAA,EAAG;EACnC,MAAM,CAACC,eAAe,EAAEC,kBAAkB,CAAC,GAAGL,KAAK,CAACM,QAAQ,CAAC,KAAK,CAAC;EAEnEN,KAAK,CAACO,SAAS,CAAC,MAAM;IACpB,MAAMC,kBAAkB,GAAGA,CAAA,KAAMH,kBAAkB,CAAC,IAAI,CAAC;IACzD,MAAMI,kBAAkB,GAAGA,CAAA,KAAMJ,kBAAkB,CAAC,KAAK,CAAC;IAE1D,IAAIK,aAAoC;IAExC,IAAIR,QAAQ,CAACS,EAAE,KAAK,KAAK,EAAE;MACzBD,aAAa,GAAG,CACdT,QAAQ,CAACW,WAAW,CAAC,kBAAkB,EAAEJ,kBAAkB,CAAC,EAC5DP,QAAQ,CAACW,WAAW,CAAC,kBAAkB,EAAEH,kBAAkB,CAAC,CAC7D;IACH,CAAC,MAAM;MACLC,aAAa,GAAG,CACdT,QAAQ,CAACW,WAAW,CAAC,iBAAiB,EAAEJ,kBAAkB,CAAC,EAC3DP,QAAQ,CAACW,WAAW,CAAC,iBAAiB,EAAEH,kBAAkB,CAAC,CAC5D;IACH;IAEA,OAAO,MAAM;MACXC,aAAa,CAACG,OAAO,CAAEC,CAAC,IAAKA,CAAC,CAACC,MAAM,CAAC,CAAC,CAAC;IAC1C,CAAC;EACH,CAAC,EAAE,EAAE,CAAC;EAEN,OAAOX,eAAe;AACxB","ignoreList":[]}

View File

@@ -0,0 +1,366 @@
"use strict";
import { getDefaultSidebarWidth, getLabel, MissingIcon, useFrameSize } from '@react-navigation/elements';
import { CommonActions, NavigationProvider, useLinkBuilder, useLocale, useTheme } from '@react-navigation/native';
import React from 'react';
import { Animated, Platform, StyleSheet, View } from 'react-native';
import { BottomTabBarHeightCallbackContext } from "../utils/BottomTabBarHeightCallbackContext.js";
import { useIsKeyboardShown } from "../utils/useIsKeyboardShown.js";
import { BottomTabItem } from "./BottomTabItem.js";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const TABBAR_HEIGHT_UIKIT = 49;
const TABBAR_HEIGHT_UIKIT_COMPACT = 32;
const SPACING_UIKIT = 15;
const SPACING_MATERIAL = 12;
const DEFAULT_MAX_TAB_ITEM_WIDTH = 125;
const useNativeDriver = Platform.OS !== 'web';
const shouldUseHorizontalLabels = ({
state,
descriptors,
dimensions
}) => {
const {
tabBarLabelPosition
} = descriptors[state.routes[state.index].key].options;
if (tabBarLabelPosition) {
switch (tabBarLabelPosition) {
case 'beside-icon':
return true;
case 'below-icon':
return false;
}
}
if (dimensions.width >= 768) {
// Screen size matches a tablet
const maxTabWidth = state.routes.reduce((acc, route) => {
const {
tabBarItemStyle
} = descriptors[route.key].options;
const flattenedStyle = StyleSheet.flatten(tabBarItemStyle);
if (flattenedStyle) {
if (typeof flattenedStyle.width === 'number') {
return acc + flattenedStyle.width;
} else if (typeof flattenedStyle.maxWidth === 'number') {
return acc + flattenedStyle.maxWidth;
}
}
return acc + DEFAULT_MAX_TAB_ITEM_WIDTH;
}, 0);
return maxTabWidth <= dimensions.width;
} else {
return dimensions.width > dimensions.height;
}
};
const isCompact = ({
state,
descriptors,
dimensions
}) => {
const {
tabBarPosition,
tabBarVariant
} = descriptors[state.routes[state.index].key].options;
if (tabBarPosition === 'left' || tabBarPosition === 'right' || tabBarVariant === 'material') {
return false;
}
const isLandscape = dimensions.width > dimensions.height;
const horizontalLabels = shouldUseHorizontalLabels({
state,
descriptors,
dimensions
});
if (Platform.OS === 'ios' && !Platform.isPad && isLandscape && horizontalLabels) {
return true;
}
return false;
};
export const getTabBarHeight = ({
state,
descriptors,
dimensions,
insets,
style
}) => {
const {
tabBarPosition
} = descriptors[state.routes[state.index].key].options;
const flattenedStyle = StyleSheet.flatten(style);
const customHeight = flattenedStyle && 'height' in flattenedStyle ? flattenedStyle.height : undefined;
if (typeof customHeight === 'number') {
return customHeight;
}
const inset = insets[tabBarPosition === 'top' ? 'top' : 'bottom'];
if (isCompact({
state,
descriptors,
dimensions
})) {
return TABBAR_HEIGHT_UIKIT_COMPACT + inset;
}
return TABBAR_HEIGHT_UIKIT + inset;
};
export function BottomTabBar({
state,
navigation,
descriptors,
insets,
style
}) {
const {
colors
} = useTheme();
const {
direction
} = useLocale();
const {
buildHref
} = useLinkBuilder();
const focusedRoute = state.routes[state.index];
const focusedDescriptor = descriptors[focusedRoute.key];
const focusedOptions = focusedDescriptor.options;
const {
tabBarPosition = 'bottom',
tabBarShowLabel,
tabBarLabelPosition,
tabBarHideOnKeyboard = false,
tabBarVisibilityAnimationConfig,
tabBarVariant = 'uikit',
tabBarStyle,
tabBarBackground,
tabBarActiveTintColor,
tabBarInactiveTintColor,
tabBarActiveBackgroundColor,
tabBarInactiveBackgroundColor
} = focusedOptions;
if (tabBarVariant === 'material' && tabBarPosition !== 'left' && tabBarPosition !== 'right') {
throw new Error("The 'material' variant for tab bar is only supported when 'tabBarPosition' is set to 'left' or 'right'.");
}
if (tabBarLabelPosition === 'below-icon' && tabBarVariant === 'uikit' && (tabBarPosition === 'left' || tabBarPosition === 'right')) {
throw new Error("The 'below-icon' label position for tab bar is only supported when 'tabBarPosition' is set to 'top' or 'bottom' when using the 'uikit' variant.");
}
const isKeyboardShown = useIsKeyboardShown();
const onHeightChange = React.useContext(BottomTabBarHeightCallbackContext);
const shouldShowTabBar = !(tabBarHideOnKeyboard && isKeyboardShown);
const visibilityAnimationConfigRef = React.useRef(tabBarVisibilityAnimationConfig);
React.useEffect(() => {
visibilityAnimationConfigRef.current = tabBarVisibilityAnimationConfig;
});
const [isTabBarHidden, setIsTabBarHidden] = React.useState(!shouldShowTabBar);
const [visible] = React.useState(() => new Animated.Value(shouldShowTabBar ? 1 : 0));
React.useEffect(() => {
const visibilityAnimationConfig = visibilityAnimationConfigRef.current;
if (shouldShowTabBar) {
const animation = visibilityAnimationConfig?.show?.animation === 'spring' ? Animated.spring : Animated.timing;
animation(visible, {
toValue: 1,
useNativeDriver,
duration: 250,
...visibilityAnimationConfig?.show?.config
}).start(({
finished
}) => {
if (finished) {
setIsTabBarHidden(false);
}
});
} else {
// eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
setIsTabBarHidden(true);
const animation = visibilityAnimationConfig?.hide?.animation === 'spring' ? Animated.spring : Animated.timing;
animation(visible, {
toValue: 0,
useNativeDriver,
duration: 200,
...visibilityAnimationConfig?.hide?.config
}).start();
}
return () => visible.stopAnimation();
}, [visible, shouldShowTabBar]);
const [layout, setLayout] = React.useState({
height: 0
});
const handleLayout = e => {
const {
height
} = e.nativeEvent.layout;
onHeightChange?.(height);
setLayout(layout => {
if (height === layout.height) {
return layout;
} else {
return {
height
};
}
});
};
const {
routes
} = state;
const tabBarHeight = useFrameSize(dimensions => getTabBarHeight({
state,
descriptors,
insets,
dimensions,
style: [tabBarStyle, style]
}));
const hasHorizontalLabels = useFrameSize(dimensions => shouldUseHorizontalLabels({
state,
descriptors,
dimensions
}));
const compact = useFrameSize(dimensions => isCompact({
state,
descriptors,
dimensions
}));
const sidebar = tabBarPosition === 'left' || tabBarPosition === 'right';
const spacing = tabBarVariant === 'material' ? SPACING_MATERIAL : SPACING_UIKIT;
const minSidebarWidth = useFrameSize(size => sidebar && hasHorizontalLabels ? getDefaultSidebarWidth(size) : 0);
const tabBarBackgroundElement = tabBarBackground?.();
return /*#__PURE__*/_jsxs(Animated.View, {
style: [tabBarPosition === 'left' ? styles.start : tabBarPosition === 'right' ? styles.end : styles.bottom, (Platform.OS === 'web' ? tabBarPosition === 'right' : direction === 'rtl' && tabBarPosition === 'left' || direction !== 'rtl' && tabBarPosition === 'right') ? {
borderLeftWidth: StyleSheet.hairlineWidth
} : (Platform.OS === 'web' ? tabBarPosition === 'left' : direction === 'rtl' && tabBarPosition === 'right' || direction !== 'rtl' && tabBarPosition === 'left') ? {
borderRightWidth: StyleSheet.hairlineWidth
} : tabBarPosition === 'top' ? {
borderBottomWidth: StyleSheet.hairlineWidth
} : {
borderTopWidth: StyleSheet.hairlineWidth
}, {
backgroundColor: tabBarBackgroundElement != null ? 'transparent' : colors.card,
borderColor: colors.border
}, sidebar ? {
paddingTop: (hasHorizontalLabels ? spacing : spacing / 2) + insets.top,
paddingBottom: (hasHorizontalLabels ? spacing : spacing / 2) + insets.bottom,
paddingStart: spacing + (tabBarPosition === 'left' ? insets.left : 0),
paddingEnd: spacing + (tabBarPosition === 'right' ? insets.right : 0),
minWidth: minSidebarWidth
} : [{
transform: [{
translateY: visible.interpolate({
inputRange: [0, 1],
outputRange: [layout.height + insets[tabBarPosition === 'top' ? 'top' : 'bottom'] + StyleSheet.hairlineWidth, 0]
})
}],
// Absolutely position the tab bar so that the content is below it
// This is needed to avoid gap at bottom when the tab bar is hidden
position: isTabBarHidden ? 'absolute' : undefined
}, {
height: tabBarHeight,
paddingBottom: tabBarPosition === 'bottom' ? insets.bottom : 0,
paddingTop: tabBarPosition === 'top' ? insets.top : 0,
paddingHorizontal: Math.max(insets.left, insets.right)
}], tabBarStyle],
pointerEvents: isTabBarHidden ? 'none' : 'auto',
onLayout: sidebar ? undefined : handleLayout,
children: [/*#__PURE__*/_jsx(View, {
pointerEvents: "none",
style: StyleSheet.absoluteFill,
children: tabBarBackgroundElement
}), /*#__PURE__*/_jsx(View, {
role: "tablist",
style: sidebar ? styles.sideContent : styles.bottomContent,
children: routes.map((route, index) => {
const focused = index === state.index;
const {
options
} = descriptors[route.key];
const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true
});
if (!focused && !event.defaultPrevented) {
navigation.dispatch({
...CommonActions.navigate(route),
target: state.key
});
}
};
const onLongPress = () => {
navigation.emit({
type: 'tabLongPress',
target: route.key
});
};
const label = typeof options.tabBarLabel === 'function' ? options.tabBarLabel : getLabel({
label: options.tabBarLabel,
title: options.title
}, route.name);
const accessibilityLabel = options.tabBarAccessibilityLabel !== undefined ? options.tabBarAccessibilityLabel : typeof label === 'string' && Platform.OS === 'ios' ? `${label}, tab, ${index + 1} of ${routes.length}` : undefined;
return /*#__PURE__*/_jsx(NavigationProvider, {
route: route,
navigation: descriptors[route.key].navigation,
children: /*#__PURE__*/_jsx(BottomTabItem, {
href: buildHref(route.name, route.params),
route: route,
descriptor: descriptors[route.key],
focused: focused,
horizontal: hasHorizontalLabels,
compact: compact,
sidebar: sidebar,
variant: tabBarVariant,
onPress: onPress,
onLongPress: onLongPress,
accessibilityLabel: accessibilityLabel,
testID: options.tabBarButtonTestID,
allowFontScaling: options.tabBarAllowFontScaling,
activeTintColor: tabBarActiveTintColor,
inactiveTintColor: tabBarInactiveTintColor,
activeBackgroundColor: tabBarActiveBackgroundColor,
inactiveBackgroundColor: tabBarInactiveBackgroundColor,
button: options.tabBarButton,
icon: options.tabBarIcon ?? (({
color,
size
}) => /*#__PURE__*/_jsx(MissingIcon, {
color: color,
size: size
})),
badge: options.tabBarBadge,
badgeStyle: options.tabBarBadgeStyle,
label: label,
showLabel: tabBarShowLabel,
labelStyle: options.tabBarLabelStyle,
iconStyle: options.tabBarIconStyle,
style: [sidebar ? {
marginVertical: hasHorizontalLabels ? tabBarVariant === 'material' ? 0 : 1 : spacing / 2
} : styles.bottomItem, options.tabBarItemStyle]
})
}, route.key);
})
})]
});
}
const styles = StyleSheet.create({
start: {
top: 0,
bottom: 0,
start: 0
},
end: {
top: 0,
bottom: 0,
end: 0
},
bottom: {
start: 0,
end: 0,
bottom: 0,
elevation: 8
},
bottomContent: {
flex: 1,
flexDirection: 'row'
},
sideContent: {
flex: 1,
flexDirection: 'column'
},
bottomItem: {
flex: 1
}
});
//# sourceMappingURL=BottomTabBar.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,219 @@
"use strict";
import { getLabel, Label, PlatformPressable } from '@react-navigation/elements';
import { useTheme } from '@react-navigation/native';
import Color from 'color';
import React from 'react';
import { Platform, StyleSheet, View } from 'react-native';
import { TabBarIcon } from "./TabBarIcon.js";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const renderButtonDefault = props => /*#__PURE__*/_jsx(PlatformPressable, {
...props
});
const SUPPORTS_LARGE_CONTENT_VIEWER = Platform.OS === 'ios' && parseInt(Platform.Version, 10) >= 13;
export function BottomTabItem({
route,
href,
focused,
descriptor,
label,
icon,
badge,
badgeStyle,
button = renderButtonDefault,
accessibilityLabel,
testID,
onPress,
onLongPress,
horizontal,
compact,
sidebar,
variant,
activeTintColor: customActiveTintColor,
inactiveTintColor: customInactiveTintColor,
activeBackgroundColor: customActiveBackgroundColor,
inactiveBackgroundColor = 'transparent',
showLabel = true,
// On iOS 13+, we use `largeContentTitle` for accessibility
// So we don't need the font to scale up
// https://developer.apple.com/documentation/uikit/uiview/3183939-largecontenttitle
allowFontScaling = SUPPORTS_LARGE_CONTENT_VIEWER ? false : undefined,
labelStyle,
iconStyle,
style
}) {
const {
colors,
fonts
} = useTheme();
const activeTintColor = customActiveTintColor ?? (variant === 'uikit' && sidebar && horizontal ? Color(colors.primary).isDark() ? 'white' : Color(colors.primary).darken(0.71).string() : colors.primary);
const inactiveTintColor = customInactiveTintColor === undefined ? variant === 'material' ? Color(colors.text).alpha(0.68).rgb().string() : Color(colors.text).mix(Color(colors.card), 0.5).hex() : customInactiveTintColor;
const activeBackgroundColor = customActiveBackgroundColor ?? (variant === 'material' ? Color(activeTintColor).alpha(0.12).rgb().string() : sidebar && horizontal ? colors.primary : 'transparent');
const {
options
} = descriptor;
const labelString = getLabel({
label: typeof options.tabBarLabel === 'string' ? options.tabBarLabel : undefined,
title: options.title
}, route.name);
let labelInactiveTintColor = inactiveTintColor;
let iconInactiveTintColor = inactiveTintColor;
if (variant === 'uikit' && sidebar && horizontal && customInactiveTintColor === undefined) {
iconInactiveTintColor = colors.primary;
labelInactiveTintColor = colors.text;
}
const renderLabel = ({
focused
}) => {
if (showLabel === false) {
return null;
}
const color = focused ? activeTintColor : labelInactiveTintColor;
if (typeof label !== 'string') {
return label({
focused,
color,
position: horizontal ? 'beside-icon' : 'below-icon',
children: labelString
});
}
return /*#__PURE__*/_jsx(Label, {
style: [horizontal ? [styles.labelBeside, variant === 'material' ? styles.labelSidebarMaterial : sidebar ? styles.labelSidebarUiKit : compact ? styles.labelBesideUikitCompact : styles.labelBesideUikit, icon == null && {
marginStart: 0
}] : styles.labelBeneath, compact || variant === 'uikit' && sidebar && horizontal ? fonts.regular : fonts.medium, labelStyle],
allowFontScaling: allowFontScaling,
tintColor: color,
children: label
});
};
const renderIcon = ({
focused
}) => {
if (icon === undefined) {
return null;
}
const activeOpacity = focused ? 1 : 0;
const inactiveOpacity = focused ? 0 : 1;
return /*#__PURE__*/_jsx(TabBarIcon, {
route: route,
variant: variant,
size: compact ? 'compact' : 'regular',
badge: badge,
badgeStyle: badgeStyle,
activeOpacity: activeOpacity,
allowFontScaling: allowFontScaling,
inactiveOpacity: inactiveOpacity,
activeTintColor: activeTintColor,
inactiveTintColor: iconInactiveTintColor,
renderIcon: icon,
style: iconStyle
});
};
const scene = {
route,
focused
};
const backgroundColor = focused ? activeBackgroundColor : inactiveBackgroundColor;
const {
flex
} = StyleSheet.flatten(style || {});
const borderRadius = variant === 'material' ? horizontal ? 56 : 16 : sidebar && horizontal ? 10 : 0;
return /*#__PURE__*/_jsx(View, {
style: [
// Clip ripple effect on Android
{
borderRadius,
overflow: variant === 'material' ? 'hidden' : 'visible'
}, style],
children: button({
href,
onPress,
onLongPress,
testID,
'aria-label': accessibilityLabel,
'accessibilityLargeContentTitle': labelString,
'accessibilityShowsLargeContentViewer': true,
// FIXME: role: 'tab' doesn't seem to work as expected on iOS
'role': Platform.select({
ios: 'button',
default: 'tab'
}),
'aria-selected': focused,
'android_ripple': {
borderless: true
},
'hoverEffect': variant === 'material' || sidebar && horizontal ? {
color: colors.text
} : undefined,
'pressOpacity': 1,
'style': [styles.tab, {
flex,
backgroundColor,
borderRadius
}, sidebar ? variant === 'material' ? horizontal ? styles.tabBarSidebarMaterial : styles.tabVerticalMaterial : horizontal ? styles.tabBarSidebarUiKit : styles.tabVerticalUiKit : variant === 'material' ? styles.tabVerticalMaterial : horizontal ? styles.tabHorizontalUiKit : styles.tabVerticalUiKit],
'children': /*#__PURE__*/_jsxs(React.Fragment, {
children: [renderIcon(scene), renderLabel(scene)]
})
})
});
}
const styles = StyleSheet.create({
tab: {
alignItems: 'center',
// Roundness for iPad hover effect
borderRadius: 10,
borderCurve: 'continuous'
},
tabVerticalUiKit: {
justifyContent: 'flex-start',
flexDirection: 'column',
padding: 5
},
tabVerticalMaterial: {
padding: 10
},
tabHorizontalUiKit: {
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'row',
padding: 5
},
tabBarSidebarUiKit: {
justifyContent: 'flex-start',
alignItems: 'center',
flexDirection: 'row',
paddingVertical: 7,
paddingHorizontal: 5
},
tabBarSidebarMaterial: {
justifyContent: 'flex-start',
alignItems: 'center',
flexDirection: 'row',
paddingVertical: 15,
paddingStart: 16,
paddingEnd: 24
},
labelSidebarMaterial: {
marginStart: 12
},
labelSidebarUiKit: {
fontSize: 17,
marginStart: 10
},
labelBeneath: {
fontSize: 10
},
labelBeside: {
marginEnd: 12,
lineHeight: 24
},
labelBesideUikit: {
fontSize: 13,
marginStart: 5
},
labelBesideUikitCompact: {
fontSize: 12,
marginStart: 5
}
});
//# sourceMappingURL=BottomTabItem.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,255 @@
"use strict";
import { getHeaderTitle, Header, SafeAreaProviderCompat, Screen } from '@react-navigation/elements';
import { StackActions } from '@react-navigation/native';
import * as React from 'react';
import { Animated, Platform, StyleSheet } from 'react-native';
import { SafeAreaInsetsContext } from 'react-native-safe-area-context';
import { FadeTransition, ShiftTransition } from "../TransitionConfigs/TransitionPresets.js";
import { BottomTabBarHeightCallbackContext } from "../utils/BottomTabBarHeightCallbackContext.js";
import { BottomTabBarHeightContext } from "../utils/BottomTabBarHeightContext.js";
import { useAnimatedHashMap } from "../utils/useAnimatedHashMap.js";
import { BottomTabBar, getTabBarHeight } from "./BottomTabBar.js";
import { MaybeScreen, MaybeScreenContainer } from "./ScreenFallback.js";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const EPSILON = 1e-5;
const STATE_INACTIVE = 0;
const STATE_TRANSITIONING_OR_BELOW_TOP = 1;
const STATE_ON_TOP = 2;
const NAMED_TRANSITIONS_PRESETS = {
fade: FadeTransition,
shift: ShiftTransition,
none: {
sceneStyleInterpolator: undefined,
transitionSpec: {
animation: 'timing',
config: {
duration: 0
}
}
}
};
const useNativeDriver = Platform.OS !== 'web';
const hasAnimation = options => {
const {
animation,
transitionSpec
} = options;
if (animation) {
return animation !== 'none';
}
return Boolean(transitionSpec);
};
const renderTabBarDefault = props => /*#__PURE__*/_jsx(BottomTabBar, {
...props
});
export function BottomTabView(props) {
const {
tabBar = renderTabBarDefault,
state,
navigation,
descriptors,
safeAreaInsets,
detachInactiveScreens = Platform.OS === 'web' || Platform.OS === 'android' || Platform.OS === 'ios'
} = props;
const focusedRouteKey = state.routes[state.index].key;
/**
* List of loaded tabs, tabs will be loaded when navigated to.
*/
const [loaded, setLoaded] = React.useState([focusedRouteKey]);
if (!loaded.includes(focusedRouteKey)) {
// Set the current tab to be loaded if it was not loaded before
setLoaded([...loaded, focusedRouteKey]);
}
const previousRouteKeyRef = React.useRef(focusedRouteKey);
const tabAnims = useAnimatedHashMap(state);
React.useEffect(() => {
const previousRouteKey = previousRouteKeyRef.current;
let popToTopAction;
if (previousRouteKey !== focusedRouteKey && descriptors[previousRouteKey]?.options.popToTopOnBlur) {
const prevRoute = state.routes.find(route => route.key === previousRouteKey);
if (prevRoute?.state?.type === 'stack' && prevRoute.state.key) {
popToTopAction = {
...StackActions.popToTop(),
target: prevRoute.state.key
};
}
}
const animateToIndex = () => {
if (previousRouteKey !== focusedRouteKey) {
navigation.emit({
type: 'transitionStart',
target: focusedRouteKey
});
}
Animated.parallel(state.routes.map((route, index) => {
const {
options
} = descriptors[route.key];
const {
animation = 'none',
transitionSpec = NAMED_TRANSITIONS_PRESETS[animation].transitionSpec
} = options;
let spec = transitionSpec;
if (route.key !== previousRouteKey && route.key !== focusedRouteKey) {
// Don't animate if the screen is not previous one or new one
// This will avoid flicker for screens not involved in the transition
spec = NAMED_TRANSITIONS_PRESETS.none.transitionSpec;
}
spec = spec ?? NAMED_TRANSITIONS_PRESETS.none.transitionSpec;
const toValue = index === state.index ? 0 : index >= state.index ? 1 : -1;
return Animated[spec.animation](tabAnims[route.key], {
...spec.config,
toValue,
useNativeDriver
});
}).filter(Boolean)).start(({
finished
}) => {
if (finished && popToTopAction) {
navigation.dispatch(popToTopAction);
}
if (previousRouteKey !== focusedRouteKey) {
navigation.emit({
type: 'transitionEnd',
target: focusedRouteKey
});
}
});
};
animateToIndex();
previousRouteKeyRef.current = focusedRouteKey;
}, [descriptors, focusedRouteKey, navigation, state.index, state.routes, tabAnims]);
const dimensions = SafeAreaProviderCompat.initialMetrics.frame;
const [tabBarHeight, setTabBarHeight] = React.useState(() => getTabBarHeight({
state,
descriptors,
dimensions,
insets: {
...SafeAreaProviderCompat.initialMetrics.insets,
...props.safeAreaInsets
},
style: descriptors[state.routes[state.index].key].options.tabBarStyle
}));
const renderTabBar = () => {
return /*#__PURE__*/_jsx(SafeAreaInsetsContext.Consumer, {
children: insets => tabBar({
state: state,
descriptors: descriptors,
navigation: navigation,
insets: {
top: safeAreaInsets?.top ?? insets?.top ?? 0,
right: safeAreaInsets?.right ?? insets?.right ?? 0,
bottom: safeAreaInsets?.bottom ?? insets?.bottom ?? 0,
left: safeAreaInsets?.left ?? insets?.left ?? 0
}
})
});
};
const {
routes
} = state;
// If there is no animation, we only have 2 states: visible and invisible
const hasTwoStates = !routes.some(route => hasAnimation(descriptors[route.key].options));
const {
tabBarPosition = 'bottom'
} = descriptors[focusedRouteKey].options;
const tabBarElement = /*#__PURE__*/_jsx(BottomTabBarHeightCallbackContext.Provider, {
value: setTabBarHeight,
children: renderTabBar()
}, "tabbar");
return /*#__PURE__*/_jsxs(SafeAreaProviderCompat, {
style: {
flexDirection: tabBarPosition === 'left' || tabBarPosition === 'right' ? 'row' : 'column'
},
children: [tabBarPosition === 'top' || tabBarPosition === 'left' ? tabBarElement : null, /*#__PURE__*/_jsx(MaybeScreenContainer, {
enabled: detachInactiveScreens,
hasTwoStates: hasTwoStates,
style: styles.screens,
children: routes.map((route, index) => {
const descriptor = descriptors[route.key];
const {
lazy = true,
animation = 'none',
sceneStyleInterpolator = NAMED_TRANSITIONS_PRESETS[animation].sceneStyleInterpolator
} = descriptor.options;
const isFocused = state.index === index;
const isPreloaded = state.preloadedRouteKeys.includes(route.key);
if (lazy && !loaded.includes(route.key) && !isFocused && !isPreloaded) {
// Don't render a lazy screen if we've never navigated to it or it wasn't preloaded
return null;
}
const {
freezeOnBlur,
header = ({
layout,
options
}) => /*#__PURE__*/_jsx(Header, {
...options,
layout: layout,
title: getHeaderTitle(options, route.name)
}),
headerShown,
headerStatusBarHeight,
headerTransparent,
sceneStyle: customSceneStyle
} = descriptor.options;
const {
sceneStyle
} = sceneStyleInterpolator?.({
current: {
progress: tabAnims[route.key]
}
}) ?? {};
const animationEnabled = hasAnimation(descriptor.options);
const activityState = isFocused ? STATE_ON_TOP // the screen is on top after the transition
: animationEnabled // is animation is not enabled, immediately move to inactive state
? tabAnims[route.key].interpolate({
inputRange: [0, 1 - EPSILON, 1],
outputRange: [STATE_TRANSITIONING_OR_BELOW_TOP,
// screen visible during transition
STATE_TRANSITIONING_OR_BELOW_TOP, STATE_INACTIVE // the screen is detached after transition
],
extrapolate: 'extend'
}) : STATE_INACTIVE;
return /*#__PURE__*/_jsx(MaybeScreen, {
style: [StyleSheet.absoluteFill, {
zIndex: isFocused ? 0 : -1
}],
active: activityState,
enabled: detachInactiveScreens,
freezeOnBlur: freezeOnBlur,
shouldFreeze: activityState === STATE_INACTIVE && !isPreloaded,
children: /*#__PURE__*/_jsx(BottomTabBarHeightContext.Provider, {
value: tabBarPosition === 'bottom' ? tabBarHeight : 0,
children: /*#__PURE__*/_jsx(Screen, {
focused: isFocused,
route: descriptor.route,
navigation: descriptor.navigation,
headerShown: headerShown,
headerStatusBarHeight: headerStatusBarHeight,
headerTransparent: headerTransparent,
header: header({
layout: dimensions,
route: descriptor.route,
navigation: descriptor.navigation,
options: descriptor.options
}),
style: [customSceneStyle, animationEnabled && sceneStyle],
children: descriptor.render()
})
})
}, route.key);
})
}, "screens"), tabBarPosition === 'bottom' || tabBarPosition === 'right' ? tabBarElement : null]
});
}
const styles = StyleSheet.create({
screens: {
flex: 1,
overflow: 'hidden'
}
});
//# sourceMappingURL=BottomTabView.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,42 @@
"use strict";
import * as React from 'react';
import { View } from 'react-native';
import { jsx as _jsx } from "react/jsx-runtime";
let Screens;
try {
Screens = require('react-native-screens');
} catch (e) {
// Ignore
}
export const MaybeScreenContainer = ({
enabled,
...rest
}) => {
if (Screens?.screensEnabled?.()) {
return /*#__PURE__*/_jsx(Screens.ScreenContainer, {
enabled: enabled,
...rest
});
}
return /*#__PURE__*/_jsx(View, {
...rest
});
};
export function MaybeScreen({
enabled,
active,
...rest
}) {
if (Screens?.screensEnabled?.()) {
return /*#__PURE__*/_jsx(Screens.Screen, {
enabled: enabled,
activityState: active,
...rest
});
}
return /*#__PURE__*/_jsx(View, {
...rest
});
}
//# sourceMappingURL=ScreenFallback.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","View","jsx","_jsx","Screens","require","e","MaybeScreenContainer","enabled","rest","screensEnabled","ScreenContainer","MaybeScreen","active","Screen","activityState"],"sourceRoot":"../../../src","sources":["views/ScreenFallback.tsx"],"mappings":";;AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SAGEC,IAAI,QAGC,cAAc;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAWtB,IAAIC,OAA0D;AAE9D,IAAI;EACFA,OAAO,GAAGC,OAAO,CAAC,sBAAsB,CAAC;AAC3C,CAAC,CAAC,OAAOC,CAAC,EAAE;EACV;AAAA;AAGF,OAAO,MAAMC,oBAAoB,GAAGA,CAAC;EACnCC,OAAO;EACP,GAAGC;AAKL,CAAC,KAAK;EACJ,IAAIL,OAAO,EAAEM,cAAc,GAAG,CAAC,EAAE;IAC/B,oBAAOP,IAAA,CAACC,OAAO,CAACO,eAAe;MAACH,OAAO,EAAEA,OAAQ;MAAA,GAAKC;IAAI,CAAG,CAAC;EAChE;EAEA,oBAAON,IAAA,CAACF,IAAI;IAAA,GAAKQ;EAAI,CAAG,CAAC;AAC3B,CAAC;AAED,OAAO,SAASG,WAAWA,CAAC;EAAEJ,OAAO;EAAEK,MAAM;EAAE,GAAGJ;AAAwB,CAAC,EAAE;EAC3E,IAAIL,OAAO,EAAEM,cAAc,GAAG,CAAC,EAAE;IAC/B,oBACEP,IAAA,CAACC,OAAO,CAACU,MAAM;MAACN,OAAO,EAAEA,OAAQ;MAACO,aAAa,EAAEF,MAAO;MAAA,GAAKJ;IAAI,CAAG,CAAC;EAEzE;EAEA,oBAAON,IAAA,CAACF,IAAI;IAAA,GAAKQ;EAAI,CAAG,CAAC;AAC3B","ignoreList":[]}

View File

@@ -0,0 +1,97 @@
"use strict";
import { Badge } from '@react-navigation/elements';
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
* Icon sizes taken from Apple HIG
* https://developer.apple.com/design/human-interface-guidelines/tab-bars
*/
const ICON_SIZE_WIDE = 31;
const ICON_SIZE_WIDE_COMPACT = 23;
const ICON_SIZE_TALL = 28;
const ICON_SIZE_TALL_COMPACT = 20;
const ICON_SIZE_ROUND = 25;
const ICON_SIZE_ROUND_COMPACT = 18;
const ICON_SIZE_MATERIAL = 24;
export function TabBarIcon({
route: _,
variant,
size,
badge,
badgeStyle,
activeOpacity,
inactiveOpacity,
activeTintColor,
inactiveTintColor,
renderIcon,
allowFontScaling,
style
}) {
const iconSize = variant === 'material' ? ICON_SIZE_MATERIAL : size === 'compact' ? ICON_SIZE_ROUND_COMPACT : ICON_SIZE_ROUND;
// We render the icon twice at the same position on top of each other:
// active and inactive one, so we can fade between them.
return /*#__PURE__*/_jsxs(View, {
style: [variant === 'material' ? styles.wrapperMaterial : size === 'compact' ? styles.wrapperUikitCompact : styles.wrapperUikit, style],
children: [/*#__PURE__*/_jsx(View, {
style: [styles.icon, {
opacity: activeOpacity,
// Workaround for react-native >= 0.54 layout bug
minWidth: iconSize
}],
children: renderIcon({
focused: true,
size: iconSize,
color: activeTintColor
})
}), /*#__PURE__*/_jsx(View, {
style: [styles.icon, {
opacity: inactiveOpacity
}],
children: renderIcon({
focused: false,
size: iconSize,
color: inactiveTintColor
})
}), /*#__PURE__*/_jsx(Badge, {
visible: badge != null,
size: iconSize * 0.75,
allowFontScaling: allowFontScaling,
style: [styles.badge, badgeStyle],
children: badge
})]
});
}
const styles = StyleSheet.create({
icon: {
// We render the icon twice at the same position on top of each other:
// active and inactive one, so we can fade between them:
// Cover the whole iconContainer:
position: 'absolute',
alignSelf: 'center',
alignItems: 'center',
justifyContent: 'center',
height: '100%',
width: '100%'
},
wrapperUikit: {
width: ICON_SIZE_WIDE,
height: ICON_SIZE_TALL
},
wrapperUikitCompact: {
width: ICON_SIZE_WIDE_COMPACT,
height: ICON_SIZE_TALL_COMPACT
},
wrapperMaterial: {
width: ICON_SIZE_MATERIAL,
height: ICON_SIZE_MATERIAL
},
badge: {
position: 'absolute',
end: -3,
top: -3
}
});
//# sourceMappingURL=TabBarIcon.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["Badge","React","StyleSheet","View","jsx","_jsx","jsxs","_jsxs","ICON_SIZE_WIDE","ICON_SIZE_WIDE_COMPACT","ICON_SIZE_TALL","ICON_SIZE_TALL_COMPACT","ICON_SIZE_ROUND","ICON_SIZE_ROUND_COMPACT","ICON_SIZE_MATERIAL","TabBarIcon","route","_","variant","size","badge","badgeStyle","activeOpacity","inactiveOpacity","activeTintColor","inactiveTintColor","renderIcon","allowFontScaling","style","iconSize","styles","wrapperMaterial","wrapperUikitCompact","wrapperUikit","children","icon","opacity","minWidth","focused","color","visible","create","position","alignSelf","alignItems","justifyContent","height","width","end","top"],"sourceRoot":"../../../src","sources":["views/TabBarIcon.tsx"],"mappings":";;AAAA,SAASA,KAAK,QAAQ,4BAA4B;AAElD,OAAOC,KAAK,MAAM,OAAO;AACzB,SAEEC,UAAU,EAEVC,IAAI,QAEC,cAAc;AAAC,SAAAC,GAAA,IAAAC,IAAA,EAAAC,IAAA,IAAAC,KAAA;AAqBtB;AACA;AACA;AACA;AACA,MAAMC,cAAc,GAAG,EAAE;AACzB,MAAMC,sBAAsB,GAAG,EAAE;AACjC,MAAMC,cAAc,GAAG,EAAE;AACzB,MAAMC,sBAAsB,GAAG,EAAE;AACjC,MAAMC,eAAe,GAAG,EAAE;AAC1B,MAAMC,uBAAuB,GAAG,EAAE;AAClC,MAAMC,kBAAkB,GAAG,EAAE;AAE7B,OAAO,SAASC,UAAUA,CAAC;EACzBC,KAAK,EAAEC,CAAC;EACRC,OAAO;EACPC,IAAI;EACJC,KAAK;EACLC,UAAU;EACVC,aAAa;EACbC,eAAe;EACfC,eAAe;EACfC,iBAAiB;EACjBC,UAAU;EACVC,gBAAgB;EAChBC;AACK,CAAC,EAAE;EACR,MAAMC,QAAQ,GACZX,OAAO,KAAK,UAAU,GAClBJ,kBAAkB,GAClBK,IAAI,KAAK,SAAS,GAChBN,uBAAuB,GACvBD,eAAe;;EAEvB;EACA;EACA,oBACEL,KAAA,CAACJ,IAAI;IACHyB,KAAK,EAAE,CACLV,OAAO,KAAK,UAAU,GAClBY,MAAM,CAACC,eAAe,GACtBZ,IAAI,KAAK,SAAS,GAChBW,MAAM,CAACE,mBAAmB,GAC1BF,MAAM,CAACG,YAAY,EACzBL,KAAK,CACL;IAAAM,QAAA,gBAEF7B,IAAA,CAACF,IAAI;MACHyB,KAAK,EAAE,CACLE,MAAM,CAACK,IAAI,EACX;QACEC,OAAO,EAAEd,aAAa;QACtB;QACAe,QAAQ,EAAER;MACZ,CAAC,CACD;MAAAK,QAAA,EAEDR,UAAU,CAAC;QACVY,OAAO,EAAE,IAAI;QACbnB,IAAI,EAAEU,QAAQ;QACdU,KAAK,EAAEf;MACT,CAAC;IAAC,CACE,CAAC,eACPnB,IAAA,CAACF,IAAI;MAACyB,KAAK,EAAE,CAACE,MAAM,CAACK,IAAI,EAAE;QAAEC,OAAO,EAAEb;MAAgB,CAAC,CAAE;MAAAW,QAAA,EACtDR,UAAU,CAAC;QACVY,OAAO,EAAE,KAAK;QACdnB,IAAI,EAAEU,QAAQ;QACdU,KAAK,EAAEd;MACT,CAAC;IAAC,CACE,CAAC,eACPpB,IAAA,CAACL,KAAK;MACJwC,OAAO,EAAEpB,KAAK,IAAI,IAAK;MACvBD,IAAI,EAAEU,QAAQ,GAAG,IAAK;MACtBF,gBAAgB,EAAEA,gBAAiB;MACnCC,KAAK,EAAE,CAACE,MAAM,CAACV,KAAK,EAAEC,UAAU,CAAE;MAAAa,QAAA,EAEjCd;IAAK,CACD,CAAC;EAAA,CACJ,CAAC;AAEX;AAEA,MAAMU,MAAM,GAAG5B,UAAU,CAACuC,MAAM,CAAC;EAC/BN,IAAI,EAAE;IACJ;IACA;IACA;IACAO,QAAQ,EAAE,UAAU;IACpBC,SAAS,EAAE,QAAQ;IACnBC,UAAU,EAAE,QAAQ;IACpBC,cAAc,EAAE,QAAQ;IACxBC,MAAM,EAAE,MAAM;IACdC,KAAK,EAAE;EACT,CAAC;EACDd,YAAY,EAAE;IACZc,KAAK,EAAEvC,cAAc;IACrBsC,MAAM,EAAEpC;EACV,CAAC;EACDsB,mBAAmB,EAAE;IACnBe,KAAK,EAAEtC,sBAAsB;IAC7BqC,MAAM,EAAEnC;EACV,CAAC;EACDoB,eAAe,EAAE;IACfgB,KAAK,EAAEjC,kBAAkB;IACzBgC,MAAM,EAAEhC;EACV,CAAC;EACDM,KAAK,EAAE;IACLsB,QAAQ,EAAE,UAAU;IACpBM,GAAG,EAAE,CAAC,CAAC;IACPC,GAAG,EAAE,CAAC;EACR;AACF,CAAC,CAAC","ignoreList":[]}