Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 19 additions & 18 deletions example-web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
// @ts-ignore
} from 'react-native';

import {examples, Props as ExamplesTabProperties} from './Examples';
import {ControlledSliderExample, examples, Props as ExamplesTabProperties} from './Examples';
import {propsExamples, Props as PropsTabProperties} from './Props';

function App() {
Expand All @@ -18,21 +18,17 @@ function App() {
) => {
return (
<View>
<ScrollView
style={styles.scrollView}
contentContainerStyle={styles.container}>
{(filtered
? (sliders as ExamplesTabProperties[]).filter(
e => !e.platform || e.platform === Platform.OS,
)
: sliders
).map((e, i) => (
<View key={`slider${i}`} style={styles.sliderWidget}>
<Text style={styles.instructions}>{e.title}</Text>
{e.render()}
</View>
))}
</ScrollView>
{(filtered
? (sliders as ExamplesTabProperties[]).filter(
e => !e.platform || e.platform === Platform.OS,
)
: sliders
).map((e, i) => (
<View key={`slider${i}`} style={styles.sliderWidget}>
<Text style={styles.instructions}>{e.title}</Text>
{e.render()}
</View>
))}
</View>
);
};
Expand All @@ -41,8 +37,13 @@ function App() {
<div className="App">
<header className="App-header">
<View style={{ width: '100%', margin: 'auto' }}>
{renderExampleTab(examples, true)}
{renderExampleTab(propsExamples)}
<ScrollView
style={styles.scrollView}
contentContainerStyle={styles.container}>
{renderExampleTab(examples, true)}
{renderExampleTab(propsExamples)}
<ControlledSliderExample />
</ScrollView>
</View>
</header>
</div>
Expand Down
41 changes: 38 additions & 3 deletions example-web/src/Examples.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, {useState} from 'react';
import React, {useRef, useState} from 'react';
// @ts-ignore
import {Text, View, StyleSheet, ScrollView} from 'react-native';
import {Text, View, StyleSheet, ScrollView, Button} from 'react-native';
// @ts-ignore
import Slider, {SliderProps} from '@react-native-community/slider';
import Slider, {SliderProps, SliderRef} from '@react-native-community/slider';

export interface Props {
title: string;
Expand Down Expand Up @@ -65,6 +65,31 @@ const SlidingCompleteExample = (props: SliderProps) => {

export default SliderExample;


export function ControlledSliderExample() {
const ref = useRef<SliderRef>(null);
const [value, setValue] = useState(50);
return (
<View>
<Text style={styles.instructions}>Controlled Slider</Text>
<Text style={styles.text}>{value && +value.toFixed(3)}</Text>
<Slider
style={styles.slider}
onValueChange={setValue}
value={value}
minimumValue={0}
maximumValue={100}
step={1}
ref={ref}
/>
<View style={styles.actions}>
<Button title="-10" onPress={() => ref.current?.updateValue(value - 10)} />
<Button title="+10" onPress={() => ref.current?.updateValue(value + 10)} />
</View>
</View>
)
}

const styles = StyleSheet.create({
slider: {
width: 300,
Expand All @@ -78,6 +103,16 @@ const styles = StyleSheet.create({
fontWeight: '500',
margin: 0,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
fontSize: 20,
},
actions: {
flexDirection: 'row',
justifyContent: 'space-around',
},
});

export const examples: Props[] = [
Expand Down
18 changes: 8 additions & 10 deletions package/src/RNCSliderNativeComponent.web.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {RefObject, useCallback} from 'react';
import React, {useCallback, useRef} from 'react';
import {
Animated,
View,
Expand Down Expand Up @@ -76,7 +76,7 @@ const RCTSliderWebComponent = React.forwardRef(
) => {
const containerSize = React.useRef({width: 0, height: 0});
const containerPositionX = React.useRef(0);
const containerRef = forwardedRef || React.createRef();
const containerRef = useRef<HTMLElement>(null);
const containerPositionInvalidated = React.useRef(false);
const [value, setValue] = React.useState(initialValue || minimumValue);
const lastInitialValue = React.useRef<number>();
Expand Down Expand Up @@ -136,7 +136,7 @@ const RCTSliderWebComponent = React.forwardRef(
// Add a ref to track user interaction
const isUserInteracting = React.useRef(false);
const updateValue = useCallback(
(newValue: number) => {
(newValue: number, forceUpdate = false) => {
// Ensure that the value is correctly rounded
const hardRounded =
decimalPrecision.current < 20
Expand All @@ -150,7 +150,7 @@ const RCTSliderWebComponent = React.forwardRef(
);
if (value !== withinBounds) {
setValue(withinBounds);
if (isUserInteracting.current) {
if (isUserInteracting.current || forceUpdate) {
onValueChange(withinBounds);
}
return withinBounds;
Expand Down Expand Up @@ -257,9 +257,7 @@ const RCTSliderWebComponent = React.forwardRef(
}, [maximumValue, minimumValue, step]);

const updateContainerPositionX = () => {
const positionX = (
containerRef as RefObject<HTMLElement | undefined>
).current?.getBoundingClientRect().x;
const positionX = containerRef.current?.getBoundingClientRect().x;
containerPositionX.current = positionX ?? 0;
};

Expand Down Expand Up @@ -328,19 +326,19 @@ const RCTSliderWebComponent = React.forwardRef(
forwardedRef,
() => ({
updateValue: (val: number) => {
updateValue(val);
updateValue(val, true);
},
}),
[updateValue],
);

return (
<View
ref={containerRef}
ref={containerRef as any}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Ref Typing Issue Breaks DOM Access

The forwardedRef no longer provides access to the component's DOM element, instead only exposing the updateValue imperative handle. This breaks consumers expecting DOM access (e.g., getBoundingClientRect). The internal containerRef is typed as HTMLElement but requires as any when assigned to the View component, indicating a type mismatch and bypassing type safety.

Fix in Cursor Fix in Web

onLayout={({nativeEvent: {layout}}: LayoutChangeEvent) => {
containerSize.current.height = layout.height;
containerSize.current.width = layout.width;
if ((containerRef as RefObject<View>).current) {
if (containerRef.current) {
updateContainerPositionX();
}
}}
Expand Down