Skip to content

Commit b51cf37

Browse files
build: 0.2.0
1 parent 9ebc6b9 commit b51cf37

File tree

5 files changed

+115
-82
lines changed

5 files changed

+115
-82
lines changed

.github/workflows/ci.yml

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -60,39 +60,19 @@ jobs:
6060
- name: Build package
6161
run: bun prepare
6262

63-
build-web:
64-
runs-on: ubuntu-latest
65-
66-
steps:
67-
- name: Checkout
68-
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
69-
70-
- name: Setup
71-
uses: ./.github/actions/setup
72-
73-
- name: Build library
74-
run: bun prepare
75-
76-
- name: Build example for Web
77-
run: |
78-
bun example expo export --platform web
63+
# build-web:
64+
# runs-on: ubuntu-latest
7965

80-
publish:
81-
runs-on: ubuntu-latest
82-
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
83-
needs: [lint, test, build-library]
84-
85-
steps:
86-
- name: Checkout
87-
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
66+
# steps:
67+
# - name: Checkout
68+
# uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
8869

89-
- name: Setup
90-
uses: ./.github/actions/setup
70+
# - name: Setup
71+
# uses: ./.github/actions/setup
9172

92-
- name: Build package
93-
run: bunx bob build
73+
# - name: Build library
74+
# run: bun prepare
9475

95-
- name: Publish to npm
96-
run: npm publish --access public
97-
env:
98-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
76+
# - name: Build example for Web
77+
# run: |
78+
# bun example expo export --platform web

README.md

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,75 @@
1-
# react-native-reanimated-slider
1+
# @jellify-music/react-native-reanimated-slider
22

3-
A reusable slider component for React Native, powered by React Native Gesture Handler and Reanimated.
3+
A performant, customizable slider component for React Native, powered by React Native Gesture Handler and Reanimated.
44

55
## Installation
66

7-
87
```sh
9-
npm install react-native-reanimated-slider
8+
npm install @jellify-music/react-native-reanimated-slider
9+
# or
10+
yarn add @jellify-music/react-native-reanimated-slider
11+
# or
12+
bun add @jellify-music/react-native-reanimated-slider
1013
```
1114

15+
### Peer Dependencies
16+
17+
This library requires the following peer dependencies:
18+
19+
- `react-native-reanimated` >= 3.0.0
20+
- `react-native-gesture-handler` >= 2.0.0
1221

1322
## Usage
1423

24+
```tsx
25+
import Slider from '@jellify-music/react-native-reanimated-slider';
26+
import { useSharedValue } from 'react-native-reanimated';
27+
28+
function MyComponent() {
29+
const progress = useSharedValue(0);
30+
31+
return (
32+
<Slider
33+
value={progress}
34+
onValueChange={(value) => {
35+
console.log('Slider value:', value);
36+
}}
37+
maxValue={100}
38+
thumbWidth={24}
39+
trackHeight={8}
40+
backgroundColor="#e0e0e0"
41+
color="#6200ee"
42+
thumbShadowColor="#000"
43+
/>
44+
);
45+
}
46+
```
1547

16-
```js
17-
import { multiply } from 'react-native-reanimated-slider';
48+
## Props
1849

19-
// ...
50+
| Prop | Type | Required | Description |
51+
|------|------|----------|-------------|
52+
| `value` | `SharedValue<number>` || A Reanimated shared value that controls the slider position |
53+
| `onValueChange` | `(value: number) => void` || Callback fired when the user releases the slider |
54+
| `maxValue` | `number` || The maximum value of the slider |
55+
| `thumbWidth` | `number` || The width and height of the thumb (circular) |
56+
| `trackHeight` | `number` || The height of the track |
57+
| `backgroundColor` | `string` || The color of the background track |
58+
| `color` | `string` || The color of the progress track and thumb |
59+
| `thumbShadowColor` | `string` | | The shadow color of the thumb |
60+
| `gestureActiveRef` | `RefObject<boolean>` | | A `ref` indicating whether the slider is being used |
2061

21-
const result = await multiply(3, 7);
22-
```
62+
## Features
2363

64+
- Smooth gesture handling with tap and pan support
65+
- Powered by Reanimated for 60fps animations
66+
- Fully customizable colors
67+
- Works on iOS and Android
2468

2569
## Contributing
2670

2771
- [Development workflow](CONTRIBUTING.md#development-workflow)
2872
- [Sending a pull request](CONTRIBUTING.md#sending-a-pull-request)
29-
- [Code of conduct](CODE_OF_CONDUCT.md)
3073

3174
## License
3275

example/src/App.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ export default function App() {
1313
console.log('Slider value:', val);
1414
}}
1515
maxValue={100}
16-
thumbWidth={40}
16+
thumbWidth={20}
17+
trackHeight={10}
1718
backgroundColor="#ccc"
1819
color="#bb00ffe0"
20+
thumbShadowColor="#000"
1921
/>
2022
</View>
2123
);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@jellify-music/react-native-reanimated-slider",
3-
"version": "0.1.3",
3+
"version": "0.2.1",
44
"description": "A reusable slider component for React Native, powered by React Native Gesture Handler and Reanimated.",
55
"main": "./lib/module/index.js",
66
"types": "./lib/typescript/src/index.d.ts",

src/index.tsx

Lines changed: 46 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,36 @@ import Animated, {
33
Extrapolation,
44
interpolate,
55
useAnimatedStyle,
6+
useSharedValue,
67
type SharedValue,
78
} from 'react-native-reanimated';
89
import { GestureDetector, Gesture } from 'react-native-gesture-handler';
910
import { HIT_SLOP } from './config';
10-
import { useRef } from 'react';
1111

1212
interface SliderProps {
1313
onValueChange: (value: number) => void;
1414
maxValue: number;
1515
value: SharedValue<number>;
1616
thumbWidth: number;
17+
thumbShadowColor?: string;
18+
trackHeight: number;
1719
backgroundColor: string;
1820
color: string;
21+
gestureActiveRef?: React.RefObject<boolean>;
1922
}
2023

2124
export default function Slider({
2225
onValueChange,
2326
value,
2427
thumbWidth,
28+
trackHeight,
2529
backgroundColor,
2630
color,
31+
thumbShadowColor,
2732
maxValue,
33+
gestureActiveRef,
2834
}: SliderProps) {
29-
const isInteractingRef = useRef(false);
30-
const sliderWidthRef = useRef(0);
31-
const sliderThumbWidthRef = useRef(0);
35+
const sliderWidth = useSharedValue(0);
3236

3337
const handleValueChange = async (position: number) => {
3438
const clampedValue = Math.max(0, Math.min(position, maxValue));
@@ -39,7 +43,9 @@ export default function Slider({
3943
console.error('Error updating Reanimated Slider value:', error);
4044
} finally {
4145
setTimeout(() => {
42-
isInteractingRef.current = false;
46+
if (gestureActiveRef) {
47+
gestureActiveRef.current = false;
48+
}
4349
}, 100);
4450
}
4551
};
@@ -48,34 +54,34 @@ export default function Slider({
4854
.runOnJS(true)
4955
.hitSlop(HIT_SLOP)
5056
.onStart((event) => {
51-
isInteractingRef.current = true;
57+
if (gestureActiveRef) {
58+
gestureActiveRef.current = true;
59+
}
5260

53-
const clampedX = Math.max(0, Math.min(event.x, sliderWidthRef.current));
61+
const clampedX = Math.max(0, Math.min(event.x, sliderWidth.value));
5462
const position = interpolate(
5563
clampedX,
56-
[0, sliderWidthRef.current],
64+
[0, sliderWidth.value],
5765
[0, maxValue],
5866
Extrapolation.CLAMP
5967
);
6068
value.set(position);
6169
})
6270
.onUpdate((event) => {
63-
if (isInteractingRef.current) {
64-
const clampedX = Math.max(0, Math.min(event.x, sliderWidthRef.current));
65-
const position = interpolate(
66-
clampedX,
67-
[0, sliderWidthRef.current],
68-
[0, maxValue],
69-
Extrapolation.CLAMP
70-
);
71-
value.set(position);
72-
}
71+
const clampedX = Math.max(0, Math.min(event.x, sliderWidth.value));
72+
const position = interpolate(
73+
clampedX,
74+
[0, sliderWidth.value],
75+
[0, maxValue],
76+
Extrapolation.CLAMP
77+
);
78+
value.set(position);
7379
})
7480
.onEnd(async (event) => {
75-
const clampedX = Math.max(0, Math.min(event.x, sliderWidthRef.current));
81+
const clampedX = Math.max(0, Math.min(event.x, sliderWidth.value));
7682
const position = interpolate(
7783
clampedX,
78-
[0, sliderWidthRef.current],
84+
[0, sliderWidth.value],
7985
[0, maxValue],
8086
Extrapolation.CLAMP
8187
);
@@ -89,13 +95,15 @@ export default function Slider({
8995
.runOnJS(true)
9096
.hitSlop(HIT_SLOP)
9197
.onBegin((event) => {
92-
isInteractingRef.current = true;
98+
if (gestureActiveRef) {
99+
gestureActiveRef.current = true;
100+
}
93101

94-
const clampedX = Math.max(0, Math.min(event.x, sliderWidthRef.current));
102+
const clampedX = Math.max(0, Math.min(event.x, sliderWidth.value));
95103

96104
const position = interpolate(
97105
clampedX,
98-
[0, sliderWidthRef.current],
106+
[0, sliderWidth.value],
99107
[0, maxValue],
100108
Extrapolation.CLAMP
101109
);
@@ -105,10 +113,10 @@ export default function Slider({
105113
.onFinalize(async (event, success) => {
106114
if (!success) return;
107115

108-
const clampedX = Math.max(0, Math.min(event.x, sliderWidthRef.current));
116+
const clampedX = Math.max(0, Math.min(event.x, sliderWidth.value));
109117
const position = interpolate(
110118
clampedX,
111-
[0, sliderWidthRef.current],
119+
[0, sliderWidth.value],
112120
[0, maxValue],
113121
Extrapolation.CLAMP
114122
);
@@ -130,7 +138,7 @@ export default function Slider({
130138
translateX: interpolate(
131139
value.value,
132140
[0, maxValue],
133-
[0, sliderWidthRef.current - sliderThumbWidthRef.current],
141+
[0, sliderWidth.value - thumbWidth],
134142
Extrapolation.CLAMP
135143
),
136144
},
@@ -141,15 +149,14 @@ export default function Slider({
141149
width: interpolate(
142150
value.value,
143151
[0, maxValue],
144-
[0, sliderWidthRef.current],
152+
[0, sliderWidth.value],
145153
Extrapolation.CLAMP
146154
),
147155
}));
148156

149-
const measureLayout = (event: LayoutChangeEvent) => {
150-
const { width } = event.nativeEvent.layout;
151-
sliderWidthRef.current = width;
152-
sliderThumbWidthRef.current = thumbWidth;
157+
const measure = (event: LayoutChangeEvent) => {
158+
sliderWidth.value = event.nativeEvent.layout.width;
159+
console.debug('Slider width:', sliderWidth.value);
153160
};
154161

155162
return (
@@ -158,20 +165,20 @@ export default function Slider({
158165
style={[
159166
styles.container,
160167
{
161-
height: thumbWidth,
168+
height: trackHeight,
162169
},
163170
]}
164-
onLayout={measureLayout}
171+
onLayout={measure}
165172
>
166173
{/* Background Track */}
167174
<View
168175
style={[
169176
styles.track,
170177
{
171-
height: thumbWidth,
178+
height: trackHeight,
172179
width: '100%',
173180
backgroundColor,
174-
borderRadius: thumbWidth / 2,
181+
borderRadius: trackHeight / 2,
175182
},
176183
]}
177184
/>
@@ -181,9 +188,9 @@ export default function Slider({
181188
style={[
182189
styles.track,
183190
{
184-
height: thumbWidth,
191+
height: trackHeight,
185192
backgroundColor: color,
186-
borderRadius: thumbWidth / 2,
193+
borderRadius: trackHeight / 2,
187194
},
188195
progressAnimatedStyle,
189196
]}
@@ -198,6 +205,7 @@ export default function Slider({
198205
height: thumbWidth,
199206
borderRadius: thumbWidth / 2,
200207
backgroundColor: color,
208+
shadowColor: thumbShadowColor,
201209
},
202210
thumbAnimatedStyle,
203211
]}
@@ -220,7 +228,7 @@ const styles = StyleSheet.create({
220228
},
221229
thumb: {
222230
position: 'absolute',
223-
shadowOpacity: 0.25,
231+
shadowOpacity: 0.75,
224232
shadowRadius: 3,
225233
shadowOffset: {
226234
width: 0,

0 commit comments

Comments
 (0)