1+ import React from 'react' ;
12import { View } from 'react-native' ;
2- import React , { useState } from 'react' ;
3- import { Gesture , GestureDetector } from 'react-native-gesture-handler' ;
3+ import { GestureDetector } from 'react-native-gesture-handler' ;
44import { type LayoutChangeEvent , type ViewProps , type StyleProp , type ViewStyle , type TextStyle } from 'react-native' ;
5- import { interpolate , runOnJS , useAnimatedReaction , useAnimatedStyle , useSharedValue , withSpring , withTiming } from 'react-native-reanimated' ;
65
76import { styles } from './slider.styles' ;
7+ import { useSlider } from './useSlider.hook' ;
88import { useTheme } from '../../theme/useTheme.hook' ;
9- import { SliderTrack } from './slider-track/SliderTrack.component' ;
10- import { SliderIndicator } from './slider-indicator/SliderIndicator.component' ;
11- import { SliderTrackPoint } from './slider-track-point/SliderTrackPoint.component' ;
9+ import { useSliderTrackPoints } from './useSliderTrackPoints.hook' ;
10+ import { SliderTrack } from '../ui/slider-track/SliderTrack.component' ;
11+ import { SliderIndicator } from '../ui/slider-indicator/SliderIndicator.component' ;
12+ import { SliderTrackPoint } from '../ui/slider-track-point/SliderTrackPoint.component' ;
1213
1314export interface SliderProps extends ViewProps {
1415 max : number ;
@@ -25,7 +26,8 @@ export interface SliderProps extends ViewProps {
2526 trackPointsStyle ?: StyleProp < ViewStyle > ;
2627 filledTrackStyle ?: StyleProp < ViewStyle > ;
2728 remainingTrackStyle ?: StyleProp < ViewStyle > ;
28- valueContainerStyle ?: StyleProp < ViewStyle > ;
29+
30+ throttleDelay ?: number ;
2931
3032 onChangeValue ?: ( value : number ) => void ;
3133}
@@ -44,124 +46,70 @@ export const Slider: React.FC<SliderProps> = ({
4446 trackPointStyle,
4547 trackPointsStyle,
4648 filledTrackStyle,
47- valueContainerStyle,
4849 remainingTrackStyle,
4950
5051 onChangeValue,
5152 onLayout,
5253 style,
5354 ...props
5455} ) => {
55- const [ sliderWidth , setSliderWith ] = useState ( 0 ) ;
56- const [ selectedValue , setSelectedValue ] = useState ( value ) ;
57-
5856 const { primary, secondaryContainer} = useTheme ( ) ;
5957
60- const sliding = useSharedValue ( 0 ) ;
61- const thumbTranslationX = useSharedValue ( 0 ) ;
62- const thumbTranslationXContext = useSharedValue ( 0 ) ;
63-
64- const filledTrackAnimatedStyle = useAnimatedStyle ( ( ) => ( { flex : interpolate ( thumbTranslationX . value , [ 0 , sliderWidth ] , [ 0 , 1 ] ) } ) , [ sliderWidth ] ) ;
65- const remainingTrackAnimatedStyle = useAnimatedStyle ( ( ) => ( { flex : interpolate ( thumbTranslationX . value , [ 0 , sliderWidth ] , [ 1 , 0 ] ) } ) , [ sliderWidth ] ) ;
66-
67- const getDiscreteTrackPoints = ( discreteStep : number ) => {
68- const totalPoints = Math . ceil ( ( max - min ) / discreteStep ) + 1 ;
69-
70- return Array . from ( { length : totalPoints } , ( _ , index ) => Math . min ( min + index * discreteStep , max ) ) ;
71- } ;
72-
73- const trackPoints = step ? getDiscreteTrackPoints ( step ) : centered ? [ min , ( min + max ) / 2 , max ] : [ max ] ;
74-
75- const calcAndUpdateValueBasedOnThumbTranslationX = ( translationX : number , onChange : ( value : number ) => void ) => {
76- const currrentValue = Math . round ( interpolate ( translationX , [ 0 , sliderWidth ] , [ min , max ] ) ) ;
77-
78- onChange ( currrentValue ) ;
79- } ;
80-
81- useAnimatedReaction (
82- ( ) => thumbTranslationX . value ,
83- ( currentThumbValue ) => {
84- runOnJS ( calcAndUpdateValueBasedOnThumbTranslationX ) ( currentThumbValue , setSelectedValue ) ;
85- }
86- ) ;
58+ const trackPoints = useSliderTrackPoints ( { max, min, step, centered} ) ;
59+ const {
60+ gesture,
61+ sliding,
62+ selectedValue,
63+ animValueProps,
64+ filledTrackAnimatedStyle,
65+ remainingTrackAnimatedStyle,
66+ slideToTrackPoint,
67+ setUpSliderLayout,
68+ } = useSlider ( { max, min, step} , value , onChangeValue ) ;
8769
88- const gesture = Gesture . Pan ( )
89- . onStart ( ( ) => {
90- sliding . value = withTiming ( 1 ) ;
91- } )
92- . onUpdate ( ( e ) => {
93- thumbTranslationX . value = Math . max ( 0 , Math . min ( Math . round ( thumbTranslationXContext . value + e . translationX ) , sliderWidth ) ) ;
94-
95- runOnJS ( calcAndUpdateValueBasedOnThumbTranslationX ) ( thumbTranslationX . value , setSelectedValue ) ;
96- } )
97- . onEnd ( ( ) => {
98- thumbTranslationXContext . value = thumbTranslationX . value ;
99- sliding . value = withTiming ( 0 ) ;
100-
101- if ( onChangeValue ) {
102- runOnJS ( calcAndUpdateValueBasedOnThumbTranslationX ) ( thumbTranslationX . value , onChangeValue ) ;
103- }
104- } ) ;
70+ const trackPointsJustifyContent = trackPoints . length > 1 ? 'space-between' : 'flex-end' ;
10571
10672 const handleLayoutChange = ( e : LayoutChangeEvent ) => {
107- const width = e . nativeEvent . layout . width ;
108-
109- initializeThumbPosition ( width ) ;
110- setSliderWith ( width ) ;
73+ setUpSliderLayout ( e . nativeEvent . layout . width ) ;
11174
11275 if ( onLayout ) {
11376 onLayout ( e ) ;
11477 }
11578 } ;
11679
117- const initializeThumbPosition = ( width : number ) => {
118- const initialTthumbTranslationX = ( ( value - min ) / ( max - min ) ) * width ;
119-
120- thumbTranslationX . value = initialTthumbTranslationX ;
121- thumbTranslationXContext . value = initialTthumbTranslationX ;
122- } ;
123-
124- const slideToTrackPoint = ( pointValue : number ) => {
125- const thumbPointValueTranslationX = ( ( pointValue - min ) / ( max - min ) ) * sliderWidth ;
126-
127- sliding . value = withTiming ( 1 ) ;
128- thumbTranslationX . value = withSpring ( thumbPointValueTranslationX , { damping : 20 } , ( ) => {
129- sliding . value = withTiming ( 0 ) ;
130- thumbTranslationXContext . value = thumbPointValueTranslationX ;
131-
132- if ( onChangeValue ) {
133- runOnJS ( onChangeValue ) ( pointValue ) ;
134- }
135- } ) ;
136- } ;
137-
13880 const renderTrackPoint = ( pointValue : number ) => (
13981 < SliderTrackPoint
14082 key = { pointValue }
83+ selectedValue = { selectedValue }
14184 value = { pointValue }
14285 onPress = { slideToTrackPoint }
143- style = { [ { backgroundColor : selectedValue > pointValue ? secondaryContainer . background : secondaryContainer . text } , trackPointStyle ] }
86+ disableColorChange = { centered }
87+ style = { trackPointStyle }
14488 />
14589 ) ;
14690
14791 return (
14892 < GestureDetector gesture = { gesture } >
14993 < View style = { [ styles . container , style ] } onLayout = { handleLayoutChange } { ...props } >
150- < SliderTrack style = { [ { backgroundColor : primary . background } , styles . filledTrack , filledTrackAnimatedStyle , filledTrackStyle ] } />
94+ < SliderTrack
95+ style = { [
96+ { backgroundColor : centered ? secondaryContainer . background : primary . background } ,
97+ styles . filledTrack ,
98+ filledTrackAnimatedStyle ,
99+ filledTrackStyle ,
100+ ] }
101+ />
151102 < SliderIndicator
152- value = { selectedValue }
153103 sliding = { sliding }
104+ animValueProps = { animValueProps }
154105 style = { [ styles . thumb , indicatorStyle ] }
155106 thumbStyle = { thumbStyle }
156107 valueStyle = { valueStyle }
157- valueContainerStyle = { valueContainerStyle }
158108 />
159109 < SliderTrack
160110 style = { [ { backgroundColor : secondaryContainer . background } , styles . remainingTrack , remainingTrackAnimatedStyle , remainingTrackStyle ] }
161111 />
162- < View style = { [ styles . trackPoints , { justifyContent : trackPoints . length > 1 ? 'space-between' : 'flex-end' } , trackPointsStyle ] } >
163- { trackPoints . map ( renderTrackPoint ) }
164- </ View >
112+ < View style = { [ styles . trackPoints , { justifyContent : trackPointsJustifyContent } , trackPointsStyle ] } > { trackPoints . map ( renderTrackPoint ) } </ View >
165113 </ View >
166114 </ GestureDetector >
167115 ) ;
0 commit comments