Skip to content
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ The context provider that must wrap your carousel components. **All carousel con
| `disableInfiniteScroll` | `boolean` | `false` | Disable infinite scrolling (shows first/last slide boundaries) |
| `autoScrollAnimation` | `(to: number, duration: number) => number` | `withTiming` | Custom animation function for auto-scroll transitions |
| `renderWindow` | `number` | all slides | Slides kept mounted on each side of the current one; for long carousels |
| `centerSlide` | `boolean` | `false` | Centre the current slide when `slideWidth` is narrower, so neighbours peek in |
| `children` | `React.ReactNode` | Required | Carousel content (should contain HeroCarousel component) |

#### `HeroCarousel`
Expand Down Expand Up @@ -355,6 +356,18 @@ Different carousel configurations using the compound pattern:
>
<HeroCarousel>{slides}</HeroCarousel>
</HeroCarousel.Provider>

// Centred slides with the neighbours peeking in on both sides.
// Put the gap between slides inside each slide (half on each side), so the content stays centred.
<HeroCarousel.Provider slideWidth={300} centerSlide disableInfiniteScroll disableAutoScroll>
<HeroCarousel>
{slides.map((slide) => (
<View key={slide.id} style={{ paddingHorizontal: 6 }}>
<Slide {...slide} />
</View>
))}
</HeroCarousel>
</HeroCarousel.Provider>
```

### Using HeroCarousel.AnimatedView
Expand Down
11 changes: 7 additions & 4 deletions src/components/AnimatedPagedView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ export const AnimatedPagedView = forwardRef<AnimatedPagedScrollViewRef, Animated
(props, ref) => {
const translateX = useSharedValue(0)
const context = useSharedValue({ x: 0 })
const { slideWidth } = useCarouselContext()
const { slideWidth, centerSlide } = useCarouselContext()
// Starts the row at the carousel's middle, less half a slide. Layout resolves the 50% against the
// carousel's own width, so the current slide is centred from the first frame.
const centerStyle = centerSlide ? { left: '50%' as const, marginLeft: -slideWidth / 2 } : null
const childrenArray = React.Children.toArray(props.children)
// Worklets must not capture `props`: it holds React elements, which can't be copied to the UI thread.
const { onScroll, onScrollBeginDrag } = props
Expand Down Expand Up @@ -70,7 +73,7 @@ export const AnimatedPagedView = forwardRef<AnimatedPagedScrollViewRef, Animated
return {
transform: [{ translateX: -clampedTranslateX }],
}
}, [])
}, [clampValue])

useAnimatedReaction(
() => translateX.value,
Expand All @@ -93,8 +96,8 @@ export const AnimatedPagedView = forwardRef<AnimatedPagedScrollViewRef, Animated

return (
<GestureDetector gesture={gesture}>
<Animated.View style={[styles.container]}>
<Animated.View style={[styles.contentContainer, animatedStyle]}>
<Animated.View style={styles.container}>
<Animated.View style={[styles.contentContainer, centerStyle, animatedStyle]}>
{props.children}
</Animated.View>
</Animated.View>
Expand Down
2 changes: 1 addition & 1 deletion src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { HeroCarousel, HeroCarouselProps } from './HeroCarousel'
export { HeroCarousel, type HeroCarouselProps } from './HeroCarousel'
5 changes: 5 additions & 0 deletions src/context/CarouselContext/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ type ContextProps = {
autoScrollAnimation?: (to: number, duration: number) => number
/** Slides kept mounted on each side of the current one. Mounts every slide when omitted. */
renderWindow?: number
/** Centres the current slide when `slideWidth` is narrower than the carousel, so its neighbours peek in on both sides. */
centerSlide?: boolean
}

export const CarouselContextProvider = ({
Expand All @@ -51,6 +53,7 @@ export const CarouselContextProvider = ({
disableAutoScroll = false,
autoScrollAnimation = DEFAULT_ANIMATION,
renderWindow,
centerSlide = false,
...rest
}: ContextProps) => {
const userInteracted = useUserInteracted()
Expand All @@ -73,6 +76,7 @@ export const CarouselContextProvider = ({
disableAutoScroll,
autoScrollAnimation,
renderWindow,
centerSlide,
}),
[
manualScroll,
Expand All @@ -83,6 +87,7 @@ export const CarouselContextProvider = ({
disableAutoScroll,
autoScrollAnimation,
renderWindow,
centerSlide,
],
)}
>
Expand Down
Loading