Skip to content

Commit 203865c

Browse files
committed
feat: RLT support
1 parent 6181479 commit 203865c

File tree

9 files changed

+77
-41
lines changed

9 files changed

+77
-41
lines changed

example/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22

3-
# @generated expo-cli sync-b5df6a44d8735348b729920a7406b633cfb74d4c
3+
# @generated expo-cli sync-8d4afeec25ea8a192358fae2f8e2fc766bdce4ec
44
# The following patterns were generated by expo-cli
55

66
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
@@ -12,6 +12,7 @@ node_modules/
1212
.expo/
1313
dist/
1414
web-build/
15+
expo-env.d.ts
1516

1617
# Native
1718
*.orig.*

example/app.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
},
2929
"web": {
3030
"favicon": "./assets/favicon.png"
31-
}
31+
},
32+
"extra": {
33+
"supportsRTL": true
34+
},
35+
"plugins": ["expo-localization"]
3236
}
3337
}

example/assets/favicon.png

4.86 KB
Loading

example/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"@expo/webpack-config": "~19.0.1",
1212
"expo": "^52.0.20",
1313
"expo-haptics": "~14.0.0",
14+
"expo-localization": "~16.0.0",
1415
"expo-splash-screen": "~0.29.18",
1516
"expo-status-bar": "~2.0.0",
1617
"lottie-react-native": "7.1.0",

example/src/sample/src/with-custom-bubble.tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,12 @@ export function WithCustomBubble() {
2020
minimumValue={min}
2121
maximumValue={max}
2222
bubbleWidth={bubbleWidth}
23+
bubbleMaxWidth={bubbleWidth}
2324
bubbleTranslateY={-50}
2425
bubbleOffsetX={5}
2526
thumbWidth={thumbWidth}
2627
renderThumb={() => <View style={styles.customThumb} />}
27-
renderBubble={() => (
28-
<View style={styles.customBubble}>
29-
<Image
30-
source={require('../../../assets/preview.png')}
31-
style={styles.bubbleImg}
32-
/>
33-
</View>
34-
)}
28+
renderBubble={() => <View style={styles.customBubble} />}
3529
theme={COLORS.sliderTheme}
3630
/>
3731
</SliderCard>
@@ -53,6 +47,9 @@ const styles = StyleSheet.create({
5347
customBubble: {
5448
alignItems: 'center',
5549
width: bubbleWidth,
50+
height: 60,
51+
backgroundColor: '#fff',
52+
borderRadius: 4,
5653
},
5754
bubbleImg: {
5855
width: 90,

example/src/sample/src/with-disable-track.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ export function WithDisableTrack() {
1717
minimumValue={min}
1818
maximumValue={max}
1919
theme={COLORS.sliderTheme}
20-
renderBubble={() => null}
2120
disableTapEvent
2221
disableTrackFollow
2322
hapticMode={HapticModeEnum.BOTH}

example/src/sample/src/with-haptic.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export function WithHaptic() {
4949
onSlidingComplete={(e) => {
5050
console.log(e);
5151
}}
52-
thumbWidth={24}
52+
thumbWidth={12}
5353
hapticMode={HapticModeEnum.STEP}
5454
theme={COLORS.sliderTheme}
5555
/>

src/slider.tsx

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
TextStyle,
88
View,
99
ViewStyle,
10+
I18nManager,
1011
} from 'react-native';
1112
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
1213
import type { WithTimingConfig } from 'react-native-reanimated';
@@ -42,6 +43,7 @@ export enum PanDirectionEnum {
4243
RIGHT = 2,
4344
END = 3,
4445
}
46+
4547
export type SliderThemeType =
4648
| {
4749
/**
@@ -301,6 +303,11 @@ export type AwesomeSliderProps = {
301303
* When 'heartbeat' is set to true, the progress bar color will animate back and forth between its current color and the color specified for the heartbeat.
302304
*/
303305
heartbeat?: boolean;
306+
/**
307+
* Whether the slider is in RTL mode.
308+
* @default true
309+
*/
310+
isRTL?: boolean;
304311
};
305312
const defaultTheme: SliderThemeType = {
306313
minimumTrackTintColor: palette.Main,
@@ -362,6 +369,7 @@ export const Slider: FC<AwesomeSliderProps> = memo(function Slider({
362369
heartbeat = false,
363370
snapThreshold = 0,
364371
snapThresholdMode = 'absolute',
372+
isRTL = I18nManager.isRTL,
365373
}) {
366374
const step = propsStep || steps;
367375

@@ -408,7 +416,6 @@ export const Slider: FC<AwesomeSliderProps> = memo(function Slider({
408416
} else {
409417
seekWidth = progressToValue(progress.value) + thumbWidth / 2;
410418
}
411-
sliderTotalValue.value; // hack: force recompute styles when 'sliderTotalValue' changes
412419

413420
return {
414421
width:
@@ -428,7 +435,7 @@ export const Slider: FC<AwesomeSliderProps> = memo(function Slider({
428435
const animatedThumbStyle = useAnimatedStyle(() => {
429436
let translateX = 0;
430437
// when you set step
431-
438+
const subtractedWidth = width.value - thumbWidth;
432439
if (snappingEnabled && markLeftArr.value.length >= step) {
433440
translateX = stepTimingOptions
434441
? withTiming(markLeftArr.value[thumbIndex.value]!, stepTimingOptions)
@@ -437,21 +444,19 @@ export const Slider: FC<AwesomeSliderProps> = memo(function Slider({
437444
translateX = clamp(
438445
thumbValue.value,
439446
0,
440-
width.value ? width.value - thumbWidth : 0
447+
width.value ? subtractedWidth : 0
441448
);
442449
} else {
443450
translateX = clamp(
444451
progressToValue(progress.value),
445452
0,
446-
width.value ? width.value - thumbWidth : 0
453+
width.value ? subtractedWidth : 0
447454
);
448455
}
449-
450-
sliderTotalValue.value; // hack: force recompute styles when 'sliderTotalValue' change
451456
return {
452457
transform: [
453458
{
454-
translateX,
459+
translateX: isRTL ? subtractedWidth - translateX : translateX,
455460
},
456461
{
457462
scale: withTiming(thumbScaleValue ? thumbScaleValue.value : 1, {
@@ -460,7 +465,7 @@ export const Slider: FC<AwesomeSliderProps> = memo(function Slider({
460465
},
461466
],
462467
};
463-
}, [progress, minimumValue, maximumValue, width, snappingEnabled]);
468+
}, [progress, minimumValue, maximumValue, width, snappingEnabled, isRTL]);
464469

465470
const animatedBubbleStyle = useAnimatedStyle(() => {
466471
let translateX = 0;
@@ -470,6 +475,11 @@ export const Slider: FC<AwesomeSliderProps> = memo(function Slider({
470475
} else {
471476
translateX = thumbValue.value + thumbWidth / 2;
472477
}
478+
translateX = isRTL ? width.value - translateX : translateX;
479+
480+
const minX = bubbleWidth / 2 - thumbWidth / 2;
481+
const maxX = width.value - bubbleWidth / 2;
482+
473483
return {
474484
opacity: bubbleOpacity.value,
475485
transform: [
@@ -479,26 +489,15 @@ export const Slider: FC<AwesomeSliderProps> = memo(function Slider({
479489
{
480490
translateX:
481491
snappingEnabled && stepTimingOptions
482-
? withTiming(
483-
clamp(
484-
translateX,
485-
bubbleWidth / 2,
486-
width.value - bubbleWidth / 2
487-
),
488-
stepTimingOptions
489-
)
490-
: clamp(
491-
translateX,
492-
bubbleWidth / 2,
493-
width.value - bubbleWidth / 2
494-
),
492+
? withTiming(clamp(translateX, minX, maxX), stepTimingOptions)
493+
: clamp(translateX, minX, maxX),
495494
},
496495
{
497496
scale: bubbleOpacity.value,
498497
},
499498
],
500499
};
501-
}, [bubbleTranslateY, bubbleWidth, width, snappingEnabled]);
500+
}, [bubbleTranslateY, bubbleWidth, width, snappingEnabled, isRTL]);
502501

503502
const animatedCacheXStyle = useAnimatedStyle(() => {
504503
const cacheX =
@@ -738,7 +737,8 @@ export const Slider: FC<AwesomeSliderProps> = memo(function Slider({
738737
const onGestureEvent = useMemo(() => {
739738
const gesture = Gesture.Pan()
740739
.hitSlop(panHitSlop)
741-
.onBegin(({ x }) => {
740+
.onBegin(({ x: xValue }) => {
741+
const x = isRTL ? width.value - xValue : xValue;
742742
if (disableTrackPress) {
743743
isTouchInThumbRange.value =
744744
Math.abs(x - thumbPosition.value) <= thumbTouchSize;
@@ -762,7 +762,8 @@ export const Slider: FC<AwesomeSliderProps> = memo(function Slider({
762762
runOnJS(onSlidingStart)();
763763
}
764764
})
765-
.onUpdate(({ x }) => {
765+
.onUpdate(({ x: xValue }) => {
766+
const x = isRTL ? width.value - xValue : xValue;
766767
if (disable || (!isTouchInThumbRange.value && disableTrackPress)) {
767768
return;
768769
}
@@ -777,7 +778,8 @@ export const Slider: FC<AwesomeSliderProps> = memo(function Slider({
777778

778779
onActiveSlider(x);
779780
})
780-
.onEnd(({ x }) => {
781+
.onEnd(({ x: xValue }) => {
782+
const x = isRTL ? width.value - xValue : xValue;
781783
isScrubbingInner.value = false;
782784
if (disable) {
783785
return;
@@ -850,12 +852,15 @@ export const Slider: FC<AwesomeSliderProps> = memo(function Slider({
850852
xToProgress,
851853
shareValueToSeconds,
852854
disableTrackPress,
855+
isRTL,
856+
width,
853857
]);
854858
const onSingleTapEvent = useMemo(
855859
() =>
856860
Gesture.Tap()
857861
.hitSlop(panHitSlop)
858-
.onEnd(({ x }, isFinished) => {
862+
.onEnd(({ x: xValue }, isFinished) => {
863+
const x = isRTL ? width.value - xValue : xValue;
859864
if (onTap) {
860865
runOnJS(onTap)();
861866
}
@@ -890,6 +895,8 @@ export const Slider: FC<AwesomeSliderProps> = memo(function Slider({
890895
onTap,
891896
panHitSlop,
892897
shareValueToSeconds,
898+
isRTL,
899+
width,
893900
]
894901
);
895902

@@ -1095,7 +1102,13 @@ export const Slider: FC<AwesomeSliderProps> = memo(function Slider({
10951102
);
10961103
})
10971104
: null}
1098-
<Animated.View style={[styles.thumb, animatedThumbStyle]}>
1105+
<Animated.View
1106+
style={[
1107+
styles.thumb,
1108+
animatedThumbStyle,
1109+
isRTL ? { right: 0 } : { left: 0 },
1110+
]}
1111+
>
10991112
{renderThumb ? (
11001113
renderThumb()
11011114
) : (
@@ -1113,9 +1126,11 @@ export const Slider: FC<AwesomeSliderProps> = memo(function Slider({
11131126
style={[
11141127
styles.bubble,
11151128
{
1116-
left: -bubbleMaxWidth / 2 + bubbleOffsetX,
11171129
width: bubbleMaxWidth,
11181130
},
1131+
isRTL
1132+
? { right: -bubbleMaxWidth / 2 + bubbleOffsetX }
1133+
: { left: -bubbleMaxWidth / 2 + bubbleOffsetX },
11191134
animatedBubbleStyle,
11201135
]}
11211136
>
@@ -1173,7 +1188,6 @@ const styles = StyleSheet.create({
11731188
},
11741189
thumb: {
11751190
position: 'absolute',
1176-
left: 0,
11771191
},
11781192
bubble: {
11791193
position: 'absolute',

yarn.lock

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5671,6 +5671,7 @@ __metadata:
56715671
babel-plugin-module-resolver: "npm:^5.0.0"
56725672
expo: "npm:^52.0.20"
56735673
expo-haptics: "npm:~14.0.0"
5674+
expo-localization: "npm:~16.0.0"
56745675
expo-splash-screen: "npm:~0.29.18"
56755676
expo-status-bar: "npm:~2.0.0"
56765677
lottie-react-native: "npm:7.1.0"
@@ -8924,6 +8925,18 @@ __metadata:
89248925
languageName: node
89258926
linkType: hard
89268927

8928+
"expo-localization@npm:~16.0.0":
8929+
version: 16.0.0
8930+
resolution: "expo-localization@npm:16.0.0"
8931+
dependencies:
8932+
rtl-detect: "npm:^1.0.2"
8933+
peerDependencies:
8934+
expo: "*"
8935+
react: "*"
8936+
checksum: 10/29c2fe136f8601aa1e4de07f02eac001bf75112946694fedf85fc6737f5806fc11dcdf00fb0b72902d8d364bc6bbfb0a7160cd4d970e4baf0be53d8c87cff670
8937+
languageName: node
8938+
linkType: hard
8939+
89278940
"expo-modules-autolinking@npm:2.0.4":
89288941
version: 2.0.4
89298942
resolution: "expo-modules-autolinking@npm:2.0.4"
@@ -16189,6 +16202,13 @@ __metadata:
1618916202
languageName: node
1619016203
linkType: hard
1619116204

16205+
"rtl-detect@npm:^1.0.2":
16206+
version: 1.1.2
16207+
resolution: "rtl-detect@npm:1.1.2"
16208+
checksum: 10/d19089c3b5f7a6fbabfa2c4724fcdf8694f313d196d44c8eee3625ba2e46418afe65b4da38e3e92822985291efd0656d85daa4b2ef296a46a65a702d0b156876
16209+
languageName: node
16210+
linkType: hard
16211+
1619216212
"run-applescript@npm:^5.0.0":
1619316213
version: 5.0.0
1619416214
resolution: "run-applescript@npm:5.0.0"

0 commit comments

Comments
 (0)