1
1
import _ from 'lodash' ;
2
- import React , { useRef , useCallback , useEffect , useState } from 'react' ;
2
+ import React , { useRef , useCallback , useEffect } from 'react' ;
3
3
import { StyleSheet , StyleProp , ViewStyle , TextStyle , LayoutChangeEvent } from 'react-native' ;
4
4
import {
5
5
Easing ,
@@ -97,6 +97,7 @@ export type SegmentedControlProps = {
97
97
} ;
98
98
99
99
const nonAreUndefined = < T , > ( array : Array < T | undefined > ) : array is Array < T > => {
100
+ 'worklet' ;
100
101
for ( const item of array ) {
101
102
if ( item === undefined ) {
102
103
return false ;
@@ -105,10 +106,6 @@ const nonAreUndefined = <T, >(array: Array<T | undefined>): array is Array<T> =>
105
106
return true ;
106
107
} ;
107
108
108
- function getInitialSegmentsDimensionsArray ( length : number ) {
109
- return Array < { x : number ; width : number } | undefined > ( length ) . fill ( undefined ) ;
110
- }
111
-
112
109
/**
113
110
* @description : SegmentedControl component for toggling two values or more
114
111
* @example : https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/SegmentedControlScreen.tsx
@@ -138,8 +135,8 @@ const SegmentedControl = (props: SegmentedControlProps) => {
138
135
const animatedSelectedIndex = useSharedValue ( initialIndex ) ;
139
136
const segmentsStyle = useSharedValue ( [ ] as { x : number ; width : number } [ ] ) ;
140
137
// const shouldResetOnDimensionsOnNextLayout = useRef(false); // use this flag if there bugs with onLayout being called more than once.
141
- const segmentsDimensions = useRef ( getInitialSegmentsDimensionsArray ( segments ?. length || 0 ) ) ;
142
- const [ containerHeight , setContainerHeight ] = useState ( 0 ) ;
138
+ const segmentsDimensions = useRef < { x : number ; width : number } [ ] > ( [ ] ) ;
139
+ const containerHeight = useSharedValue ( 0 ) ;
143
140
144
141
useEffect ( ( ) => {
145
142
animatedSelectedIndex . value = initialIndex ;
@@ -171,40 +168,42 @@ const SegmentedControl = (props: SegmentedControlProps) => {
171
168
const onLayout = useCallback ( ( index : number , event : LayoutChangeEvent ) => {
172
169
// if (shouldResetOnDimensionsOnNextLayout.current) {
173
170
// shouldResetOnDimensionsOnNextLayout.current = false;
174
- // // segmentsDimensions.current = getInitialSegmentsDimensionsArray(segments? .length || 0);
171
+ // segmentsDimensions.current = getInitialSegmentsDimensionsArray(segments.length || 0);
175
172
// }
176
173
const { x, width} = event . nativeEvent . layout ;
177
174
segmentsDimensions . current [ index ] = { x, width} ;
178
- if ( nonAreUndefined ( segmentsDimensions . current ) ) {
175
+ if ( segmentsDimensions . current . length === segments . length && nonAreUndefined ( segmentsDimensions . current ) ) {
179
176
segmentsStyle . value = [ ...segmentsDimensions . current ] ;
180
177
// shouldResetOnDimensionsOnNextLayout.current = true;// in case onLayout will be called again (orientation change etc.)
181
178
}
182
179
} ,
183
180
// eslint-disable-next-line react-hooks/exhaustive-deps
184
- [ initialIndex , segments ? .length ] ) ;
181
+ [ initialIndex , segments . length ] ) ;
185
182
186
183
const containerOnLayout = useCallback ( ( { nativeEvent : { layout : { height} } } : LayoutChangeEvent ) => {
187
- setContainerHeight ( height ) ;
188
- } , [ ] ) ;
184
+ containerHeight . value = height ;
185
+ } , [ containerHeight ] ) ;
189
186
190
187
const animatedStyle = useAnimatedStyle ( ( ) => {
191
- if ( segmentsStyle . value . length !== 0 ) {
188
+ const { value} = segmentsStyle ;
189
+ const { value : height } = containerHeight ;
190
+ if ( height !== 0 && value . length === segments . length && nonAreUndefined ( value ) ) {
192
191
const isFirstElementSelected = animatedSelectedIndex . value === 0 ;
193
- const isLastElementSelected = animatedSelectedIndex . value === segmentsStyle . value . length - 1 ;
192
+ const isLastElementSelected = animatedSelectedIndex . value === value . length - 1 ;
194
193
const isMiddleSelected = ! isFirstElementSelected && ! isLastElementSelected ;
195
194
const insetFix = - CONTAINER_BORDER_WIDTH - ( ! isFirstElementSelected ? segmentDividerWidth : 1 ) ;
196
195
const widthFix = isMiddleSelected ? 2 * segmentDividerWidth : CONTAINER_BORDER_WIDTH + segmentDividerWidth ;
197
- const inset = withTiming ( segmentsStyle . value [ animatedSelectedIndex . value ] . x + insetFix , TIMING_CONFIG ) ;
198
- const width = withTiming ( segmentsStyle . value [ animatedSelectedIndex . value ] . width + widthFix , TIMING_CONFIG ) ;
199
- return Constants . isRTL ? { width, right : inset } : { width, left : inset } ;
196
+ const inset = withTiming ( value [ animatedSelectedIndex . value ] . x + insetFix , TIMING_CONFIG ) ;
197
+ const width = withTiming ( value [ animatedSelectedIndex . value ] . width + widthFix , TIMING_CONFIG ) ;
198
+ return Constants . isRTL ? { width, height , right : inset } : { width, height , left : inset } ;
200
199
}
201
200
return { } ;
202
201
} ) ;
203
202
const shouldRenderDividers = segmentDividerWidth !== 0 ;
204
203
205
204
const renderSegments = ( ) =>
206
205
_ . map ( segments , ( _value , index ) => {
207
- const isLastSegment = index + 1 === segments ? .length ;
206
+ const isLastSegment = index + 1 === segments . length ;
208
207
return (
209
208
< React . Fragment key = { `segment-fragment-${ index } ` } >
210
209
< Segment
@@ -218,7 +217,7 @@ const SegmentedControl = (props: SegmentedControlProps) => {
218
217
style = { [ segmentsStyleProp ] }
219
218
segmentLabelStyle = { segmentLabelStyle }
220
219
iconTintColor = { iconTintColor }
221
- { ...segments ?. [ index ] }
220
+ { ...segments [ index ] }
222
221
testID = { testID }
223
222
/>
224
223
{ ! isLastSegment && shouldRenderDividers && (
@@ -243,8 +242,7 @@ const SegmentedControl = (props: SegmentedControlProps) => {
243
242
borderRadius,
244
243
backgroundColor : activeBackgroundColor ,
245
244
borderWidth : shouldRenderDividers ? undefined : outlineWidth ,
246
- borderColor : shouldRenderDividers ? undefined : outlineColor ,
247
- height : containerHeight
245
+ borderColor : shouldRenderDividers ? undefined : outlineColor
248
246
} ,
249
247
animatedStyle
250
248
] }
@@ -258,8 +256,7 @@ const SegmentedControl = (props: SegmentedControlProps) => {
258
256
{
259
257
borderColor : outlineColor ,
260
258
borderRadius,
261
- borderWidth : outlineWidth ,
262
- height : containerHeight
259
+ borderWidth : outlineWidth
263
260
} ,
264
261
animatedStyle
265
262
] }
0 commit comments