react-native-ui-lib 8.4.0-snapshot.7827 → 8.4.0-snapshot.7835
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/components/slider/Thumb.d.ts +5 -1
- package/src/components/slider/Thumb.js +2 -1
- package/src/components/slider/index.js +14 -2
- package/src/incubator/slider/Thumb.d.ts +1 -0
- package/src/incubator/slider/Thumb.js +9 -6
- package/src/incubator/slider/index.d.ts +5 -0
- package/src/incubator/slider/index.js +47 -4
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ViewStyle, ViewProps, View as RNView } from 'react-native';
|
|
2
|
+
import { ViewStyle, ViewProps, View as RNView, Animated } from 'react-native';
|
|
3
3
|
export interface ThumbProps extends ViewProps {
|
|
4
4
|
/**
|
|
5
5
|
* The thumb style
|
|
@@ -27,6 +27,10 @@ export interface ThumbProps extends ViewProps {
|
|
|
27
27
|
disabled?: boolean;
|
|
28
28
|
/** ref to thumb component */
|
|
29
29
|
ref?: React.RefObject<RNView>;
|
|
30
|
+
/**
|
|
31
|
+
* External scale animation value (used by useRelativeDrag)
|
|
32
|
+
*/
|
|
33
|
+
scaleAnimation?: Animated.Value;
|
|
30
34
|
}
|
|
31
35
|
declare const Thumb: React.ForwardRefExoticComponent<Omit<ThumbProps, "ref"> & React.RefAttributes<unknown>>;
|
|
32
36
|
export default Thumb;
|
|
@@ -18,6 +18,7 @@ const Thumb = forwardRef((props, ref) => {
|
|
|
18
18
|
thumbHitSlop,
|
|
19
19
|
onTouchStart,
|
|
20
20
|
onTouchEnd,
|
|
21
|
+
scaleAnimation,
|
|
21
22
|
...others
|
|
22
23
|
} = props;
|
|
23
24
|
const thumbRef = useCombinedRefs(ref);
|
|
@@ -82,7 +83,7 @@ const Thumb = forwardRef((props, ref) => {
|
|
|
82
83
|
backgroundColor: disabled ? DEFAULT_COLOR : thumbTintColor || ACTIVE_COLOR
|
|
83
84
|
}, {
|
|
84
85
|
transform: [{
|
|
85
|
-
scale: thumbScaleAnimation.current
|
|
86
|
+
scale: scaleAnimation ?? thumbScaleAnimation.current
|
|
86
87
|
}]
|
|
87
88
|
}]} />;
|
|
88
89
|
});
|
|
@@ -57,6 +57,7 @@ class Slider extends PureComponent {
|
|
|
57
57
|
height: THUMB_SIZE
|
|
58
58
|
};
|
|
59
59
|
_containerDragInitialValue = 0;
|
|
60
|
+
_containerThumbScale = new Animated.Value(1);
|
|
60
61
|
constructor(props) {
|
|
61
62
|
super(props);
|
|
62
63
|
this.activeThumbRef = this.thumb;
|
|
@@ -216,6 +217,7 @@ class Slider extends PureComponent {
|
|
|
216
217
|
};
|
|
217
218
|
handleContainerGrant = () => {
|
|
218
219
|
this._containerDragInitialValue = this.getValueForX(this._x);
|
|
220
|
+
this.animateContainerThumbScale(1.5);
|
|
219
221
|
this.onSeekStart();
|
|
220
222
|
};
|
|
221
223
|
handleContainerMove = (_e, gestureState) => {
|
|
@@ -238,8 +240,16 @@ class Slider extends PureComponent {
|
|
|
238
240
|
};
|
|
239
241
|
handleContainerEnd = () => {
|
|
240
242
|
this.bounceToStep();
|
|
243
|
+
this.animateContainerThumbScale(1);
|
|
241
244
|
this.onSeekEnd();
|
|
242
245
|
};
|
|
246
|
+
animateContainerThumbScale = toValue => {
|
|
247
|
+
Animated.timing(this._containerThumbScale, {
|
|
248
|
+
toValue,
|
|
249
|
+
duration: 100,
|
|
250
|
+
useNativeDriver: true
|
|
251
|
+
}).start();
|
|
252
|
+
};
|
|
243
253
|
|
|
244
254
|
/* Actions */
|
|
245
255
|
|
|
@@ -576,7 +586,8 @@ class Slider extends PureComponent {
|
|
|
576
586
|
disableActiveStyling,
|
|
577
587
|
disabled,
|
|
578
588
|
thumbTintColor,
|
|
579
|
-
thumbHitSlop
|
|
589
|
+
thumbHitSlop,
|
|
590
|
+
useRelativeDrag
|
|
580
591
|
} = this.props;
|
|
581
592
|
const {
|
|
582
593
|
thumbSize
|
|
@@ -596,7 +607,8 @@ class Slider extends PureComponent {
|
|
|
596
607
|
activeThumbStyle,
|
|
597
608
|
disableActiveStyling,
|
|
598
609
|
thumbHitSlop: thumbHitSlop ?? calculatedHitSlop,
|
|
599
|
-
onLayout: this.onThumbLayout
|
|
610
|
+
onLayout: this.onThumbLayout,
|
|
611
|
+
scaleAnimation: useRelativeDrag ? this._containerThumbScale : undefined
|
|
600
612
|
};
|
|
601
613
|
};
|
|
602
614
|
|
|
@@ -31,7 +31,9 @@ const Thumb = props => {
|
|
|
31
31
|
stepInterpolatedValue,
|
|
32
32
|
gap = 0,
|
|
33
33
|
secondary,
|
|
34
|
-
enableShadow
|
|
34
|
+
enableShadow,
|
|
35
|
+
pointerEvents,
|
|
36
|
+
isActive
|
|
35
37
|
} = props;
|
|
36
38
|
const rtlFix = Constants.isRTL ? -1 : 1;
|
|
37
39
|
const isPressed = useSharedValue(false);
|
|
@@ -40,7 +42,7 @@ const Thumb = props => {
|
|
|
40
42
|
height: THUMB_SIZE
|
|
41
43
|
});
|
|
42
44
|
const lastOffset = useSharedValue(0);
|
|
43
|
-
const gesture = Gesture.Pan().onBegin(() => {
|
|
45
|
+
const gesture = Gesture.Pan().hitSlop(hitSlop ?? DEFAULT_THUMB_HIT_SLOP).onBegin(() => {
|
|
44
46
|
onSeekStart?.();
|
|
45
47
|
isPressed.value = true;
|
|
46
48
|
lastOffset.value = offset.value;
|
|
@@ -64,15 +66,16 @@ const Thumb = props => {
|
|
|
64
66
|
offset.value = Math.round(offset.value / stepInterpolatedValue.value) * stepInterpolatedValue.value;
|
|
65
67
|
}
|
|
66
68
|
});
|
|
67
|
-
gesture.enabled(!disabled);
|
|
69
|
+
gesture.enabled(!disabled && pointerEvents !== 'none');
|
|
68
70
|
const animatedStyle = useAnimatedStyle(() => {
|
|
69
|
-
const
|
|
71
|
+
const active = isPressed.value || isActive?.value;
|
|
72
|
+
const customStyle = active ? activeStyle?.value : defaultStyle?.value;
|
|
70
73
|
return {
|
|
71
74
|
...customStyle,
|
|
72
75
|
transform: [{
|
|
73
76
|
translateX: (offset.value - thumbSize.value.width / 2) * rtlFix
|
|
74
77
|
}, {
|
|
75
|
-
scale: withSpring(!disableActiveStyling &&
|
|
78
|
+
scale: withSpring(!disableActiveStyling && active ? 1.3 : 1)
|
|
76
79
|
}]
|
|
77
80
|
};
|
|
78
81
|
});
|
|
@@ -86,7 +89,7 @@ const Thumb = props => {
|
|
|
86
89
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
87
90
|
}, []);
|
|
88
91
|
return <GestureDetector gesture={gesture}>
|
|
89
|
-
<View reanimated style={[styles.thumbPosition, enableShadow && styles.thumbShadow, animatedStyle]} hitSlop={hitSlop} onLayout={onThumbLayout} />
|
|
92
|
+
<View reanimated pointerEvents={pointerEvents} style={[styles.thumbPosition, enableShadow && styles.thumbShadow, animatedStyle]} hitSlop={hitSlop} onLayout={onThumbLayout} />
|
|
90
93
|
</GestureDetector>;
|
|
91
94
|
};
|
|
92
95
|
const styles = StyleSheet.create({
|
|
@@ -126,6 +126,11 @@ export interface SliderProps extends AccessibilityProps {
|
|
|
126
126
|
* Whether to use the new Slider implementation using Reanimated
|
|
127
127
|
*/
|
|
128
128
|
migrate?: boolean;
|
|
129
|
+
/**
|
|
130
|
+
* If true, dragging anywhere on the slider moves the thumb relative to its current position
|
|
131
|
+
* instead of snapping to the touch point. Designed for single-thumb mode.
|
|
132
|
+
*/
|
|
133
|
+
useRelativeDrag?: boolean;
|
|
129
134
|
/**
|
|
130
135
|
* Control the throttle time of the onValueChange and onRangeChange callbacks
|
|
131
136
|
*/
|
|
@@ -2,13 +2,14 @@ import _throttle from "lodash/throttle";
|
|
|
2
2
|
import React, { useImperativeHandle, useCallback, useMemo, useEffect, useRef } from 'react';
|
|
3
3
|
import { StyleSheet } from 'react-native';
|
|
4
4
|
import { useSharedValue, useAnimatedStyle, runOnJS, useAnimatedReaction, withTiming } from 'react-native-reanimated';
|
|
5
|
-
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
5
|
+
import { GestureHandlerRootView, GestureDetector, Gesture } from 'react-native-gesture-handler';
|
|
6
6
|
import { forwardRef, Constants } from "../../commons/new";
|
|
7
7
|
import { extractAccessibilityProps } from "../../commons/modifiers";
|
|
8
8
|
import { Colors, Spacings } from "../../style";
|
|
9
9
|
import { StyleUtils } from "../../utils";
|
|
10
10
|
import { useThemeProps, useDidUpdate } from "../../hooks";
|
|
11
11
|
import { validateValues, getOffsetForValue, getValueForOffset, getStepInterpolated } from "./SliderPresenter";
|
|
12
|
+
import View from "../../components/view";
|
|
12
13
|
import Thumb from "./Thumb";
|
|
13
14
|
import Track from "./Track";
|
|
14
15
|
var ThumbType = /*#__PURE__*/function (ThumbType) {
|
|
@@ -54,6 +55,7 @@ const Slider = React.memo(props => {
|
|
|
54
55
|
accessible = true,
|
|
55
56
|
testID,
|
|
56
57
|
enableThumbShadow = true,
|
|
58
|
+
useRelativeDrag,
|
|
57
59
|
throttleTime = 200
|
|
58
60
|
} = themeProps;
|
|
59
61
|
const accessibilityProps = useMemo(() => {
|
|
@@ -215,6 +217,36 @@ const Slider = React.memo(props => {
|
|
|
215
217
|
runOnJS(onSeekEnd)();
|
|
216
218
|
}
|
|
217
219
|
};
|
|
220
|
+
const containerDragStartOffset = useSharedValue(0);
|
|
221
|
+
const isContainerDragging = useSharedValue(false);
|
|
222
|
+
const clampOffset = offset => {
|
|
223
|
+
'worklet';
|
|
224
|
+
|
|
225
|
+
return Math.max(0, Math.min(trackSize.value.width, offset));
|
|
226
|
+
};
|
|
227
|
+
const snapToStep = () => {
|
|
228
|
+
'worklet';
|
|
229
|
+
|
|
230
|
+
if (shouldBounceToStep) {
|
|
231
|
+
const step = stepInterpolatedValue.value;
|
|
232
|
+
defaultThumbOffset.value = Math.round(defaultThumbOffset.value / step) * step;
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
const containerGesture = Gesture.Pan().onBegin(() => {
|
|
236
|
+
containerDragStartOffset.value = defaultThumbOffset.value;
|
|
237
|
+
isContainerDragging.value = true;
|
|
238
|
+
_onSeekStart();
|
|
239
|
+
}).onUpdate(e => {
|
|
240
|
+
if (trackSize.value.width === 0) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const dx = e.translationX * (shouldDisableRTL ? 1 : rtlFix);
|
|
244
|
+
defaultThumbOffset.value = clampOffset(containerDragStartOffset.value + dx);
|
|
245
|
+
}).onEnd(() => _onSeekEnd()).onFinalize(() => {
|
|
246
|
+
isContainerDragging.value = false;
|
|
247
|
+
snapToStep();
|
|
248
|
+
});
|
|
249
|
+
containerGesture.enabled(!disabled && !!useRelativeDrag);
|
|
218
250
|
const trackAnimatedStyles = useAnimatedStyle(() => {
|
|
219
251
|
if (useRange) {
|
|
220
252
|
return {
|
|
@@ -236,15 +268,22 @@ const Slider = React.memo(props => {
|
|
|
236
268
|
|
|
237
269
|
/** renders */
|
|
238
270
|
const renderThumb = type => {
|
|
239
|
-
return <Thumb start={type === ThumbType.DEFAULT ? start : defaultThumbOffset} end={type === ThumbType.DEFAULT ? rangeThumbOffset : end} offset={type === ThumbType.DEFAULT ? defaultThumbOffset : rangeThumbOffset} gap={rangeGap} secondary={type !== ThumbType.DEFAULT} onSeekStart={_onSeekStart} onSeekEnd={_onSeekEnd} shouldDisableRTL={shouldDisableRTL} disabled={disabled} disableActiveStyling={disableActiveStyling} defaultStyle={_thumbStyle} activeStyle={_activeThumbStyle} hitSlop={thumbHitSlop} shouldBounceToStep={shouldBounceToStep} stepInterpolatedValue={stepInterpolatedValue} enableShadow={enableThumbShadow} />;
|
|
271
|
+
return <Thumb start={type === ThumbType.DEFAULT ? start : defaultThumbOffset} end={type === ThumbType.DEFAULT ? rangeThumbOffset : end} offset={type === ThumbType.DEFAULT ? defaultThumbOffset : rangeThumbOffset} gap={rangeGap} secondary={type !== ThumbType.DEFAULT} onSeekStart={_onSeekStart} onSeekEnd={_onSeekEnd} shouldDisableRTL={shouldDisableRTL} disabled={disabled} pointerEvents={useRelativeDrag ? 'none' : undefined} isActive={useRelativeDrag ? isContainerDragging : undefined} disableActiveStyling={disableActiveStyling} defaultStyle={_thumbStyle} activeStyle={_activeThumbStyle} hitSlop={thumbHitSlop} shouldBounceToStep={shouldBounceToStep} stepInterpolatedValue={stepInterpolatedValue} enableShadow={enableThumbShadow} />;
|
|
240
272
|
};
|
|
241
273
|
const _renderTrack = () => {
|
|
242
|
-
return <Track renderTrack={renderTrack} onLayout={onTrackLayout} onPress={onTrackPress} animatedStyle={trackAnimatedStyles} disabled={disabled} maximumTrackTintColor={maximumTrackTintColor} minimumTrackTintColor={minimumTrackTintColor} trackStyle={trackStyle} />;
|
|
274
|
+
return <Track renderTrack={renderTrack} onLayout={onTrackLayout} onPress={useRelativeDrag ? undefined : onTrackPress} animatedStyle={trackAnimatedStyles} disabled={disabled} maximumTrackTintColor={maximumTrackTintColor} minimumTrackTintColor={minimumTrackTintColor} trackStyle={trackStyle} />;
|
|
243
275
|
};
|
|
244
|
-
|
|
276
|
+
const renderSliderContent = () => <>
|
|
245
277
|
{_renderTrack()}
|
|
246
278
|
{renderThumb(ThumbType.DEFAULT)}
|
|
247
279
|
{useRange && renderThumb(ThumbType.RANGE)}
|
|
280
|
+
</>;
|
|
281
|
+
return <GestureHandlerRootView style={[styles.container, containerStyle, shouldDisableRTL && styles.disableRTL]} testID={testID} {...accessibilityProps}>
|
|
282
|
+
{useRelativeDrag ? <GestureDetector gesture={containerGesture}>
|
|
283
|
+
<View style={styles.gestureContainer}>
|
|
284
|
+
{renderSliderContent()}
|
|
285
|
+
</View>
|
|
286
|
+
</GestureDetector> : renderSliderContent()}
|
|
248
287
|
</GestureHandlerRootView>;
|
|
249
288
|
});
|
|
250
289
|
Slider.displayName = 'Incubator.Slider';
|
|
@@ -254,6 +293,10 @@ const styles = StyleSheet.create({
|
|
|
254
293
|
height: THUMB_SIZE + SHADOW_RADIUS,
|
|
255
294
|
justifyContent: 'center'
|
|
256
295
|
},
|
|
296
|
+
gestureContainer: {
|
|
297
|
+
flex: 1,
|
|
298
|
+
justifyContent: 'center'
|
|
299
|
+
},
|
|
257
300
|
disableRTL: {
|
|
258
301
|
transform: [{
|
|
259
302
|
scaleX: -1
|