11import * as React from 'react' ;
2- import { FlatList , View } from 'react-native' ;
3- import { animated , useSpring } from 'react-spring/native.cjs' ;
2+ import { View } from 'react-native' ;
43import { DeepPartial } from 'ts-essentials' ;
54
6- import { springDefaultConfig } from '../../constants/Animation' ;
7- import { initialMeasurements , Measurements } from '../../hooks' ;
5+ import { Measurements } from '../../hooks' ;
86import { useTheme } from '../../theme' ;
97import { mergeStyles , ReplaceReturnType } from '../../utils/mergeStyles' ;
10- import { Box } from '../Box' ;
118import { TabProps } from './Tab' ;
129import { GetTabsStyles , getTabsStyles , TabsStyles } from './Tabs.styles' ;
1310
1411export type TabsDistribution = 'scrollable' | 'fit' ;
1512
16- const AnimatedView = animated ( View ) ;
17-
1813export interface TabsProps {
19- /** The indicator of active tab. Currently works only when distribution="fit" */
20- ActiveBar ?: React . ComponentType < ActiveBarProps > ;
2114 activeTabIndex ?: number ;
2215 children : Array < React . ReactElement < TabProps > > ;
2316 defaultActiveTabIndex ?: number ;
2417 getStyles ?: ReplaceReturnType < GetTabsStyles , DeepPartial < TabsStyles > > ;
25- distribution ?: TabsDistribution ;
18+ shouldFit ?: boolean ;
2619
2720 onPress : ( index : number ) => void ;
2821}
@@ -36,130 +29,46 @@ export interface ActiveBarProps {
3629 measurements : Measurements ;
3730}
3831
39- const DefaultActiveBar = ( props : ActiveBarProps ) => {
40- const { index, measurements } = props ;
41- const theme = useTheme ( ) ;
42-
43- const { x, width } = useSpring ( {
44- config : springDefaultConfig ,
45-
46- width : measurements . width ,
47- x : index * measurements . width ,
48- } ) ;
49-
50- return (
51- < AnimatedView
52- // @ts -ignore
53- style = { {
54- backgroundColor : theme . colors . background . primaryDefault ,
55- height : 3 ,
56- left : x ,
57- position : 'absolute' ,
58- top : measurements . height ,
59- width,
60- } }
61- />
62- ) ;
63- } ;
64-
6532export const Tabs = ( props : TabsProps ) => {
6633 const {
67- ActiveBar = DefaultActiveBar ,
6834 children,
6935 activeTabIndex,
7036 defaultActiveTabIndex = 0 ,
7137 onPress,
7238 getStyles,
73- distribution = 'fit' ,
39+ shouldFit = false ,
7440 } = props ;
7541 const [ localActiveTabIndex , setLocalActiveTabIndex ] = React . useState (
7642 defaultActiveTabIndex ,
7743 ) ;
7844 const theme = useTheme ( ) ;
7945 const isControlled = ! ! ( activeTabIndex || onPress ) ;
80- const listRef = React . useRef < FlatList < TabProps > > ( null ) ;
81- const [ activeBarProps , setActiveBarProps ] = React . useState ( {
82- index : ( isControlled ? activeTabIndex : localActiveTabIndex ) || - 1 ,
83- measurements : initialMeasurements ,
84- } ) ;
85-
86- React . useEffect ( ( ) => {
87- if ( listRef . current && distribution === 'scrollable' ) {
88- if ( isControlled && activeTabIndex ) {
89- listRef . current . scrollToIndex ( {
90- animated : true ,
91- index : Math . max ( activeTabIndex - 2 , 0 ) ,
92- } ) ;
93- } else if ( localActiveTabIndex ) {
94- listRef . current . scrollToIndex ( {
95- animated : true ,
96- index : Math . max ( localActiveTabIndex - 2 , 0 ) ,
97- } ) ;
98- }
99- }
100- } ) ;
10146
102- const {
103- containerStyle,
104- tabContainerStyle,
105- textStyle,
106- buttonStyle,
107- dividerStyle,
108- } = mergeStyles ( getTabsStyles , getStyles ) ( { distribution } , theme ) ;
47+ const { containerStyle } = mergeStyles ( getTabsStyles , getStyles ) ( { } , theme ) ;
10948
11049 const data = React . Children . map ( children , ( child , index ) => {
11150 if ( ! child ) return null ;
11251
113- const tabCommonProps : Partial < TabProps > = {
114- getStyles : ( ) => ( {
115- buttonStyle,
116- containerStyle : tabContainerStyle ,
117- dividerStyle,
118- textStyle,
119- } ) ,
120- index,
121- onActive : ( i , measurements ) => {
122- setActiveBarProps ( { index, measurements } ) ;
123- } ,
124- } ;
125-
12652 return isControlled
12753 ? {
128- ... tabCommonProps ,
54+ index ,
12955 isActive : index === activeTabIndex ,
13056 onPress : i => onPress ( i ) ,
57+ shouldFit,
13158 }
13259 : {
133- ... tabCommonProps ,
60+ index ,
13461 isActive : index === localActiveTabIndex ,
13562 onPress : i => setLocalActiveTabIndex ( i ) ,
63+ shouldFit,
13664 } ;
13765 } ) as TabProps [ ] ;
13866
13967 const tabs = React . Children . toArray ( children ) ;
14068
141- if ( distribution === 'fit' ) {
142- return (
143- < View style = { containerStyle } >
144- { data . map ( ( tabProps , index ) =>
145- React . cloneElement ( tabs [ index ] , tabProps ) ,
146- ) }
147- < ActiveBar { ...activeBarProps } />
148- </ View >
149- ) ;
150- }
151-
15269 return (
153- < >
154- < FlatList
155- ref = { listRef }
156- horizontal
157- keyExtractor = { item => `${ item . index } ` }
158- data = { data }
159- renderItem = { ( { item, index } ) => React . cloneElement ( tabs [ index ] , item ) }
160- showsHorizontalScrollIndicator = { false }
161- ListFooterComponent = { ( ) => < Box width = "100%" testID = "zxcv" /> }
162- />
163- </ >
70+ < View style = { containerStyle } >
71+ { data . map ( ( tabProps , index ) => React . cloneElement ( tabs [ index ] , tabProps ) ) }
72+ </ View >
16473 ) ;
16574} ;
0 commit comments