You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
6.5 KiB

var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import React from 'react';
import { View, Animated, StyleSheet, ScrollView, } from 'react-native';
import { defaultTheme } from '../helpers';
export const TabBase = (_a) => {
var _b, _c;
var { theme = defaultTheme, children, value = 0, scrollable = false, onChange = () => { }, indicatorStyle, disableIndicator, variant = 'default', style, dense, iconPosition, buttonStyle, titleStyle, containerStyle } = _a, rest = __rest(_a, ["theme", "children", "value", "scrollable", "onChange", "indicatorStyle", "disableIndicator", "variant", "style", "dense", "iconPosition", "buttonStyle", "titleStyle", "containerStyle"]);
const animationRef = React.useRef(new Animated.Value(0));
const scrollViewRef = React.useRef(null);
const scrollViewPosition = React.useRef(0);
const validChildren = React.useMemo(() => React.Children.toArray(children), [children]);
const tabItemPositions = React.useRef([]);
const [tabContainerWidth, setTabContainerWidth] = React.useState(0);
const scrollHandler = React.useCallback((currValue) => {
if (tabItemPositions.current.length > currValue) {
let itemStartPosition = currValue === 0
? 0
: tabItemPositions.current[currValue - 1].position;
let itemEndPosition = tabItemPositions.current[currValue].position;
const scrollCurrentPosition = scrollViewPosition.current;
const tabContainerCurrentWidth = tabContainerWidth;
let scrollX = scrollCurrentPosition;
if (itemStartPosition < scrollCurrentPosition) {
scrollX += itemStartPosition - scrollCurrentPosition;
}
else if (scrollCurrentPosition + tabContainerCurrentWidth <
itemEndPosition) {
scrollX +=
itemEndPosition -
(scrollCurrentPosition + tabContainerCurrentWidth);
}
scrollViewRef.current.scrollTo({
x: scrollX,
y: 0,
animated: true,
});
}
}, [tabContainerWidth]);
React.useEffect(() => {
Animated.timing(animationRef.current, {
toValue: value,
useNativeDriver: true,
duration: 170,
}).start();
scrollable && requestAnimationFrame(() => scrollHandler(value));
}, [animationRef, scrollHandler, value, scrollable]);
const onScrollHandler = React.useCallback((event) => {
scrollViewPosition.current = event.nativeEvent.contentOffset.x;
}, []);
const indicatorTransitionInterpolate = React.useMemo(() => {
const countItems = validChildren.length;
if (countItems < 2 || !tabItemPositions.current.length) {
return 0;
}
const inputRange = Array.from(Array(countItems + 1).keys());
const outputRange = tabItemPositions.current.map(({ position }) => position);
if (inputRange.length - 1 !== outputRange.length) {
return 0;
}
return animationRef.current.interpolate({
inputRange,
outputRange: [0, ...outputRange],
});
}, [animationRef, validChildren, tabItemPositions.current.length]);
const WIDTH = React.useMemo(() => {
var _a;
return (_a = tabItemPositions.current[value]) === null || _a === void 0 ? void 0 : _a.width;
}, [value, tabItemPositions.current.length]);
return (React.createElement(View, Object.assign({}, rest, { accessibilityRole: "tablist", style: [
variant === 'primary' && {
backgroundColor: (_b = theme === null || theme === void 0 ? void 0 : theme.colors) === null || _b === void 0 ? void 0 : _b.primary,
},
styles.viewStyle,
style,
], onLayout: ({ nativeEvent: { layout } }) => {
setTabContainerWidth(layout.width);
} }), React.createElement(scrollable ? ScrollView : React.Fragment, Object.assign(Object.assign({}, (scrollable && {
horizontal: true,
ref: scrollViewRef,
onScroll: onScrollHandler,
showsHorizontalScrollIndicator: false,
})), { children: (React.createElement(React.Fragment, null,
validChildren.map((child, index) => {
return React.cloneElement(child, {
onPress: () => onChange(index),
onLayout: (event) => {
var _a;
const { width } = event.nativeEvent.layout;
const previousItemPosition = ((_a = tabItemPositions.current[index - 1]) === null || _a === void 0 ? void 0 : _a.position) || 0;
tabItemPositions.current[index] = {
position: previousItemPosition + width,
width,
};
},
active: index === value,
variant,
_parentProps: {
dense,
iconPosition,
buttonStyle,
containerStyle,
titleStyle,
},
});
}),
!disableIndicator && (React.createElement(Animated.View, { style: [
styles.indicator,
{
backgroundColor: (_c = theme === null || theme === void 0 ? void 0 : theme.colors) === null || _c === void 0 ? void 0 : _c.secondary,
transform: [
{
translateX: indicatorTransitionInterpolate,
},
],
width: WIDTH,
},
indicatorStyle,
] })))) }))));
};
const styles = StyleSheet.create({
viewStyle: {
flexDirection: 'row',
position: 'relative',
},
indicator: {
display: 'flex',
position: 'absolute',
height: 2,
bottom: 0,
},
});
TabBase.displayName = 'Tab';