@momo-kits/slider 0.77.5 → 0.77.6
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/Label.tsx +4 -13
- package/hooks.tsx +30 -10
- package/index.tsx +108 -15
- package/package.json +1 -1
- package/styles.ts +7 -0
package/Label.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, {PureComponent} from 'react';
|
|
2
2
|
import {View} from 'react-native';
|
|
3
|
-
import {Shadow, Text
|
|
3
|
+
import {Shadow, Text} from '@momo-kits/foundation';
|
|
4
|
+
import styles from './styles';
|
|
4
5
|
|
|
5
6
|
class Label extends PureComponent {
|
|
6
7
|
state = {
|
|
@@ -16,18 +17,8 @@ class Label extends PureComponent {
|
|
|
16
17
|
const {value} = this.state;
|
|
17
18
|
|
|
18
19
|
return (
|
|
19
|
-
<View
|
|
20
|
-
{
|
|
21
|
-
style={[
|
|
22
|
-
{
|
|
23
|
-
backgroundColor: Colors.black_01,
|
|
24
|
-
paddingVertical: Spacing.XS,
|
|
25
|
-
paddingHorizontal: Spacing.S,
|
|
26
|
-
borderRadius: Radius.XS,
|
|
27
|
-
},
|
|
28
|
-
Shadow.Light,
|
|
29
|
-
]}>
|
|
30
|
-
<Text typography={'description_xs'}>{value}</Text>
|
|
20
|
+
<View {...props} style={[styles.label, Shadow.Light]}>
|
|
21
|
+
<Text typography={'label_s'}>{value}</Text>
|
|
31
22
|
</View>
|
|
32
23
|
);
|
|
33
24
|
}
|
package/hooks.tsx
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import React, {
|
|
2
|
+
MutableRefObject,
|
|
2
3
|
useCallback,
|
|
3
|
-
useState,
|
|
4
|
-
useRef,
|
|
5
4
|
useMemo,
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
8
7
|
} from 'react';
|
|
9
|
-
import {Animated, I18nManager
|
|
8
|
+
import {Animated, I18nManager} from 'react-native';
|
|
10
9
|
import {clamp} from './helpers';
|
|
11
10
|
import styles from './styles';
|
|
12
11
|
import FollowerContainer from './Label';
|
|
13
|
-
import {
|
|
12
|
+
import {Spacing} from '@momo-kits/foundation';
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* low and high state variables are fallbacks for props (props are not required).
|
|
@@ -95,13 +94,21 @@ export const useWidthLayout = (
|
|
|
95
94
|
* @param gestureStateRef
|
|
96
95
|
* @param isPressed
|
|
97
96
|
* @param allowOverflow
|
|
97
|
+
* @param disabledLow
|
|
98
|
+
* @param disabledHigh
|
|
98
99
|
* @returns {[JSX.Element, function(*, *=): void]|*[]}
|
|
99
100
|
*/
|
|
100
101
|
export const useThumbFollower = (
|
|
101
102
|
containerWidthRef: MutableRefObject<number>,
|
|
102
|
-
gestureStateRef: MutableRefObject<{
|
|
103
|
+
gestureStateRef: MutableRefObject<{
|
|
104
|
+
isLow: boolean;
|
|
105
|
+
lastValue: number;
|
|
106
|
+
lastPosition: number;
|
|
107
|
+
}>,
|
|
103
108
|
isPressed: boolean,
|
|
104
109
|
allowOverflow: boolean,
|
|
110
|
+
disabledLow: boolean,
|
|
111
|
+
disabledHigh: boolean,
|
|
105
112
|
) => {
|
|
106
113
|
const xRef = useRef(new Animated.Value(0));
|
|
107
114
|
const widthRef = useRef(0);
|
|
@@ -111,6 +118,13 @@ export const useThumbFollower = (
|
|
|
111
118
|
|
|
112
119
|
const update = useCallback(
|
|
113
120
|
(thumbPositionInView, value) => {
|
|
121
|
+
if (
|
|
122
|
+
(gestureStateRef.current.isLow && disabledLow) ||
|
|
123
|
+
(!gestureStateRef.current.isLow && disabledHigh)
|
|
124
|
+
) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
114
128
|
const {current: width} = widthRef;
|
|
115
129
|
const {current: containerWidth} = containerWidthRef;
|
|
116
130
|
const position = thumbPositionInView - width / 2;
|
|
@@ -119,7 +133,7 @@ export const useThumbFollower = (
|
|
|
119
133
|
);
|
|
120
134
|
contentContainerRef.current?.setValue(value);
|
|
121
135
|
},
|
|
122
|
-
[widthRef, containerWidthRef, allowOverflow],
|
|
136
|
+
[widthRef, containerWidthRef, allowOverflow, disabledLow, disabledHigh], // Include dependencies here.
|
|
123
137
|
);
|
|
124
138
|
|
|
125
139
|
const handleLayout = useWidthLayout(widthRef, () => {
|
|
@@ -130,8 +144,14 @@ export const useThumbFollower = (
|
|
|
130
144
|
});
|
|
131
145
|
|
|
132
146
|
const transform = {transform: [{translateX: x}]};
|
|
147
|
+
|
|
148
|
+
const shouldDisplayLabel =
|
|
149
|
+
isPressed &&
|
|
150
|
+
((gestureStateRef.current.isLow && !disabledLow) ||
|
|
151
|
+
(!gestureStateRef.current.isLow && !disabledHigh));
|
|
152
|
+
|
|
133
153
|
const follower = (
|
|
134
|
-
<Animated.View style={[transform, {opacity:
|
|
154
|
+
<Animated.View style={[transform, {opacity: shouldDisplayLabel ? 1 : 0}]}>
|
|
135
155
|
<FollowerContainer onLayout={handleLayout} ref={contentContainerRef} />
|
|
136
156
|
</Animated.View>
|
|
137
157
|
);
|
|
@@ -189,7 +209,7 @@ export const useLabelContainerProps = (floating: boolean) => {
|
|
|
189
209
|
setLabelContainerHeight(height);
|
|
190
210
|
}, []);
|
|
191
211
|
|
|
192
|
-
const top = floating ? -labelContainerHeight :
|
|
212
|
+
const top = floating ? -(labelContainerHeight + Spacing.XS) : Spacing.XS;
|
|
193
213
|
const style = [
|
|
194
214
|
floating ? styles.labelFloatingContainer : styles.labelFixedContainer,
|
|
195
215
|
{top},
|
package/index.tsx
CHANGED
|
@@ -32,20 +32,86 @@ const trueFunc = () => true;
|
|
|
32
32
|
const falseFunc = () => false;
|
|
33
33
|
|
|
34
34
|
export interface SliderProps extends ViewProps {
|
|
35
|
+
/**
|
|
36
|
+
* Specifies the minimum value permitted for selection in the slider. This value sets the lower
|
|
37
|
+
* bound for the component.
|
|
38
|
+
*/
|
|
35
39
|
min: number;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Specifies the maximum value allowed for selection. This value sets the upper bound for the component.
|
|
43
|
+
*/
|
|
36
44
|
max: number;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Optional. Defines the minimum permitted range between the low and high values of the slider.
|
|
48
|
+
* Particularly useful when 'low' and 'high' values both exist, ensuring a certain spread between them.
|
|
49
|
+
*/
|
|
37
50
|
minRange?: number;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Specifies the interval between individual step values. The slider's handle will move only in these increments.
|
|
54
|
+
*/
|
|
38
55
|
step: number;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Optional. Represents the initial lower value of the range when the component is used as a range slider.
|
|
59
|
+
* This value is part of the selected range, between 'min' and 'high'.
|
|
60
|
+
*/
|
|
39
61
|
low?: number;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Optional. Represents the initial upper value of the range when used as a range slider.
|
|
65
|
+
* This value is part of the selected range, between 'low' and 'max'.
|
|
66
|
+
*/
|
|
40
67
|
high?: number;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Optional. If `true`, allows the label to extend beyond the width of the Slider component itself,
|
|
71
|
+
* rather than being clipped at the component boundaries. Defaults to `false` if not provided.
|
|
72
|
+
*/
|
|
41
73
|
allowLabelOverflow?: boolean;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Optional. If `true`, disables the range functionality of the slider, turning it into a regular
|
|
77
|
+
* single-value slider. Defaults to `false` if not provided.
|
|
78
|
+
*/
|
|
42
79
|
disableRange?: boolean;
|
|
43
|
-
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Optional. If `true`, the 'high' handle of the slider will be disabled and cannot be moved.
|
|
83
|
+
* Useful for setting a maximum limit that users cannot increase. Defaults to `false` if not provided.
|
|
84
|
+
*/
|
|
85
|
+
disabledHigh?: boolean;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Optional. If `true`, the 'low' handle of the slider will be disabled and cannot be moved.
|
|
89
|
+
* Useful for setting a minimum limit that users cannot decrease. Defaults to `false` if not provided.
|
|
90
|
+
*/
|
|
91
|
+
disabledLow?: boolean;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Optional. If `true`, labels will be displayed in a floating manner above the slider handles,
|
|
95
|
+
* typically used to display the current value. Defaults to `false` if not provided.
|
|
96
|
+
*/
|
|
44
97
|
floatingLabel?: boolean;
|
|
45
|
-
|
|
46
|
-
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Optional. A callback function triggered when the slider value changes, either by the user or programmatically.
|
|
101
|
+
* It receives the new low and high values of the slider, as well as a boolean indicating if the change was made by the user.
|
|
102
|
+
*/
|
|
47
103
|
onValueChanged?: (low: number, high: number, byUser: boolean) => void;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Optional. A callback function triggered when the user starts touching the slider's draggable area.
|
|
107
|
+
* It receives the current low and high values of the slider.
|
|
108
|
+
*/
|
|
48
109
|
onSliderTouchStart?: (low: number, high: number) => void;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Optional. A callback function triggered when the user releases the slider's draggable area.
|
|
113
|
+
* It receives the current low and high values of the slider.
|
|
114
|
+
*/
|
|
49
115
|
onSliderTouchEnd?: (low: number, high: number) => void;
|
|
50
116
|
}
|
|
51
117
|
|
|
@@ -59,12 +125,11 @@ const Slider: React.FC<SliderProps> = ({
|
|
|
59
125
|
floatingLabel = false,
|
|
60
126
|
allowLabelOverflow = false,
|
|
61
127
|
disableRange = false,
|
|
62
|
-
|
|
128
|
+
disabledHigh = false,
|
|
129
|
+
disabledLow = false,
|
|
63
130
|
onValueChanged,
|
|
64
131
|
onSliderTouchStart,
|
|
65
132
|
onSliderTouchEnd,
|
|
66
|
-
renderRail,
|
|
67
|
-
renderRailSelected,
|
|
68
133
|
...restProps
|
|
69
134
|
}) => {
|
|
70
135
|
const {theme} = useContext(ApplicationContext);
|
|
@@ -169,9 +234,18 @@ const Slider: React.FC<SliderProps> = ({
|
|
|
169
234
|
gestureStateRef,
|
|
170
235
|
isPressed,
|
|
171
236
|
allowLabelOverflow,
|
|
237
|
+
disabledLow,
|
|
238
|
+
disabledHigh,
|
|
172
239
|
);
|
|
173
240
|
|
|
174
241
|
const renderThumb = (name: string) => {
|
|
242
|
+
const isDisabled =
|
|
243
|
+
(name === 'low' && disabledLow) || (name === 'high' && disabledHigh);
|
|
244
|
+
|
|
245
|
+
const thumbColor = isDisabled
|
|
246
|
+
? theme.colors.text.disable
|
|
247
|
+
: theme.colors.primary;
|
|
248
|
+
|
|
175
249
|
return (
|
|
176
250
|
<View
|
|
177
251
|
style={[
|
|
@@ -182,7 +256,7 @@ const Slider: React.FC<SliderProps> = ({
|
|
|
182
256
|
borderRadius: Radius.M,
|
|
183
257
|
borderWidth: 4,
|
|
184
258
|
borderColor: theme.colors.background.surface,
|
|
185
|
-
backgroundColor:
|
|
259
|
+
backgroundColor: thumbColor,
|
|
186
260
|
},
|
|
187
261
|
]}
|
|
188
262
|
/>
|
|
@@ -209,9 +283,6 @@ const Slider: React.FC<SliderProps> = ({
|
|
|
209
283
|
) => Math.abs(gestureState.dx) > 2 * Math.abs(gestureState.dy),
|
|
210
284
|
|
|
211
285
|
onPanResponderGrant: ({nativeEvent}, gestureState) => {
|
|
212
|
-
if (disabled) {
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
286
|
const {numberActiveTouches} = gestureState;
|
|
216
287
|
if (numberActiveTouches > 1) {
|
|
217
288
|
return;
|
|
@@ -237,6 +308,10 @@ const Slider: React.FC<SliderProps> = ({
|
|
|
237
308
|
disableRange || isLowCloser(downX, lowPosition, highPosition);
|
|
238
309
|
gestureStateRef.current.isLow = isLow;
|
|
239
310
|
|
|
311
|
+
if ((isLow && disabledLow) || (!isLow && disabledHigh)) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
240
315
|
const handlePositionChange = (positionInView: number) => {
|
|
241
316
|
const {low, high, min, max, step} = inPropsRef.current;
|
|
242
317
|
const minValue = isLow ? min : low + minRange;
|
|
@@ -278,13 +353,25 @@ const Slider: React.FC<SliderProps> = ({
|
|
|
278
353
|
});
|
|
279
354
|
},
|
|
280
355
|
|
|
281
|
-
onPanResponderMove:
|
|
282
|
-
?
|
|
283
|
-
|
|
356
|
+
onPanResponderMove: (evt, gestureState) => {
|
|
357
|
+
if (gestureStateRef.current.isLow ? disabledLow : disabledHigh) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
Animated.event([null, {moveX: pointerX}], {
|
|
362
|
+
useNativeDriver: false,
|
|
363
|
+
})(evt, gestureState);
|
|
364
|
+
},
|
|
284
365
|
|
|
285
366
|
onPanResponderRelease: () => {
|
|
286
367
|
setPressed(false);
|
|
287
368
|
const {low, high} = inPropsRef.current;
|
|
369
|
+
if (
|
|
370
|
+
(gestureStateRef.current.isLow && disabledLow) ||
|
|
371
|
+
(!gestureStateRef.current.isLow && disabledHigh)
|
|
372
|
+
) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
288
375
|
onSliderTouchEnd?.(low, high);
|
|
289
376
|
},
|
|
290
377
|
}),
|
|
@@ -293,8 +380,9 @@ const Slider: React.FC<SliderProps> = ({
|
|
|
293
380
|
inPropsRef,
|
|
294
381
|
thumbWidth,
|
|
295
382
|
disableRange,
|
|
296
|
-
disabled,
|
|
297
383
|
onValueChanged,
|
|
384
|
+
disabledHigh,
|
|
385
|
+
disabledLow,
|
|
298
386
|
setLow,
|
|
299
387
|
setHigh,
|
|
300
388
|
labelUpdate,
|
|
@@ -315,6 +403,11 @@ const Slider: React.FC<SliderProps> = ({
|
|
|
315
403
|
);
|
|
316
404
|
};
|
|
317
405
|
|
|
406
|
+
const trackColor =
|
|
407
|
+
disabledHigh && disabledLow
|
|
408
|
+
? theme.colors.text.disable
|
|
409
|
+
: theme.colors.primary;
|
|
410
|
+
|
|
318
411
|
return (
|
|
319
412
|
<View {...restProps}>
|
|
320
413
|
<View {...labelContainerProps}>{labelView}</View>
|
|
@@ -322,7 +415,7 @@ const Slider: React.FC<SliderProps> = ({
|
|
|
322
415
|
<View style={railContainerStyles}>
|
|
323
416
|
{renderTrack(theme.colors.background.default)}
|
|
324
417
|
<Animated.View style={selectedRailStyle}>
|
|
325
|
-
{renderTrack(
|
|
418
|
+
{renderTrack(trackColor)}
|
|
326
419
|
</Animated.View>
|
|
327
420
|
</View>
|
|
328
421
|
<Animated.View style={lowStyles} onLayout={handleThumbLayout}>
|
package/package.json
CHANGED
package/styles.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {I18nManager, StyleSheet} from 'react-native';
|
|
2
|
+
import {Colors, Radius, Spacing} from '@momo-kits/foundation';
|
|
2
3
|
|
|
3
4
|
export default StyleSheet.create({
|
|
4
5
|
controlsContainer: {
|
|
@@ -26,4 +27,10 @@ export default StyleSheet.create({
|
|
|
26
27
|
touchableArea: {
|
|
27
28
|
...StyleSheet.absoluteFillObject,
|
|
28
29
|
},
|
|
30
|
+
label: {
|
|
31
|
+
backgroundColor: Colors.black_01,
|
|
32
|
+
paddingVertical: Spacing.XXS,
|
|
33
|
+
paddingHorizontal: Spacing.XS,
|
|
34
|
+
borderRadius: Radius.XS,
|
|
35
|
+
},
|
|
29
36
|
});
|