Skip to content

Commit c595958

Browse files
authored
feat!: Dynamic sizing with itemWidth/itemHeight props & modernized style API (#853)
* feat: update carousel examples and documentation for dynamic sizing support * chore: add changeset * fix: update deprecation messages for width and height props in TCarouselProps to clarify usage * feat: add itemWidth and itemHeight props for explicit snapping in carousels * chore: update git ignore file * test: add unit tests for itemWidth and itemHeight props in carousel component * test: simplify carousel component test rendering for better readability * test: add overscroll prevention test for small page size * test: add unit tests for Pagination component to validate size prop and rendering behavior
1 parent 5e6ec2a commit c595958

File tree

90 files changed

+2040
-795
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+2040
-795
lines changed

.changeset/blue-news-stare.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"react-native-reanimated-carousel": minor
3+
---
4+
5+
- add `itemWidth`/`itemHeight` props so horizontal and vertical carousels can define their snapping step explicitly (e.g. to show multiple cards per page)
6+
- default behaviour still falls back to the carousel container size or legacy `width`/`height` props

.changeset/odd-news-carry.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
"react-native-reanimated-carousel": minor
3+
---
4+
5+
## ✨ Style API refresh
6+
7+
- `style` now controls the outer carousel container (positioning, width/height, margins).
8+
- New `contentContainerStyle` replaces `containerStyle` for styling the scrollable content.
9+
- `width` and `height` props are deprecated; define size via `style` instead.
10+
11+
### Migration Example
12+
13+
```tsx
14+
// Before
15+
<Carousel
16+
width={300}
17+
height={200}
18+
containerStyle={{ paddingHorizontal: 16 }}
19+
/>
20+
21+
// After
22+
<Carousel
23+
style={{ width: 300, height: 200 }}
24+
contentContainerStyle={{ paddingHorizontal: 16 }}
25+
/>
26+
```
27+
28+
- Any layout logic still works; simply move `width`/`height` into `style` and container tweaks into `contentContainerStyle`.
29+
- `contentContainerStyle` runs on the JS thread—avoid adding `opacity` / `transform` there if you rely on built-in animations.

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,7 @@ coverage/
8181
.issue-tasks/
8282

8383
# Agents Docs
84-
*.local.md
84+
*.local.md
85+
86+
# Claude
87+
CLAUDE.md

CHANGELOG.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,37 @@
66

77
- [#850](https://github.com/dohooo/react-native-reanimated-carousel/pull/850) [`9b388e6`](https://github.com/dohooo/react-native-reanimated-carousel/commit/9b388e6f6237126c4ed25c2442c4b788aad7adf6) Thanks [@dohooo](https://github.com/dohooo)! - # 🎯 Support for Expo 54 & Dynamic Sizing
88

9+
- Style props refactoring:
10+
11+
- **BREAKING CHANGE**: The styling props have been refactored for clarity and consistency with React Native's `ScrollView`.
12+
- **DEPRECATED**: `width` and `height` props are now deprecated. Please use the `style` prop to define component size.
13+
- **NEW**: The `style` prop now controls the outer container's style and is the primary way to set `width` and `height`.
14+
- **NEW**: A new `contentContainerStyle` prop has been added to control the style of the inner scrollable content.
15+
16+
#### Migration Guide
17+
18+
**Before:**
19+
```jsx
20+
<Carousel
21+
width={300}
22+
height={200}
23+
style={{ backgroundColor: 'red' }} // Applied to inner container
24+
containerStyle={{ margin: 10 }} // Applied to outer container
25+
/>
26+
```
27+
28+
**After:**
29+
```jsx
30+
<Carousel
31+
style={{
32+
width: 300,
33+
height: 200,
34+
margin: 10
35+
}} // Applied to outer container
36+
contentContainerStyle={{ backgroundColor: 'red' }} // Applied to inner container
37+
/>
38+
```
39+
940
## ✨ Major Features
1041

1142
### Dynamic Sizing Support

example/app/app/demos/basic-layouts/left-align/demo.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,11 @@ function Index() {
1010
<View id="carousel-component" dataSet={{ kind: "basic-layouts", name: "left-align" }}>
1111
<Carousel
1212
loop={true}
13-
width={430}
14-
height={258}
1513
snapEnabled={true}
1614
pagingEnabled={true}
1715
autoPlayInterval={2000}
1816
data={defaultDataWith6Colors}
19-
style={{ width: "100%" }}
17+
style={{ width: 430, height: 258 }}
2018
onSnapToItem={(index) => console.log("current index:", index)}
2119
renderItem={renderItem({ rounded: true, style: { marginRight: 8 } })}
2220
/>

example/app/app/demos/basic-layouts/left-align/index.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import { CaptureWrapper } from "@/store/CaptureProvider";
66
import { renderItem } from "@/utils/render-item";
77
import * as React from "react";
88
import { View } from "react-native";
9-
import type { ICarouselInstance } from "react-native-reanimated-carousel";
9+
import type { StyleProp, ViewStyle } from "react-native";
10+
import type { ICarouselInstance, TCarouselProps } from "react-native-reanimated-carousel";
1011
import Carousel from "react-native-reanimated-carousel";
1112

1213
function Index() {
@@ -18,23 +19,31 @@ function Index() {
1819
autoPlayInterval: 2000,
1920
autoPlayReverse: false,
2021
data: defaultDataWith6Colors,
21-
height: 258,
2222
loop: true,
2323
pagingEnabled: true,
2424
snapEnabled: true,
2525
vertical: false,
26-
width: window.width,
2726
},
2827
});
2928

29+
const {
30+
width: _ignoredWidth,
31+
height: _ignoredHeight,
32+
...restSettings
33+
} = advancedSettings as TCarouselProps;
34+
3035
return (
3136
<View style={{ flex: 1 }}>
3237
<CaptureWrapper>
3338
<Carousel
34-
{...advancedSettings}
39+
{...restSettings}
3540
ref={ref}
36-
style={{ width: "100%" }}
37-
width={constants.PAGE_WIDTH * 0.75}
41+
style={{ width: window.width, height: 258 }}
42+
contentContainerStyle={{
43+
width: window.width / 2,
44+
height: 258,
45+
overflow: "visible",
46+
}}
3847
onSnapToItem={(index) => console.log("current index:", index)}
3948
renderItem={renderItem({ rounded: true, style: { marginRight: 8 } })}
4049
/>

example/app/app/demos/basic-layouts/normal/demo.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { View } from "react-native";
44
import { useSharedValue } from "react-native-reanimated";
55
import Carousel from "react-native-reanimated-carousel";
66

7+
import { window } from "@/constants/sizes";
8+
79
const defaultDataWith6Colors = ["#B0604D", "#899F9C", "#B3C680", "#5C6265", "#F5D399", "#F1F1F1"];
810

911
function Index() {
@@ -14,14 +16,12 @@ function Index() {
1416
<Carousel
1517
testID={"xxx"}
1618
loop={true}
17-
width={430}
18-
height={258}
1919
snapEnabled={true}
2020
pagingEnabled={true}
2121
autoPlayInterval={2000}
2222
data={defaultDataWith6Colors}
2323
defaultScrollOffsetValue={scrollOffsetValue}
24-
style={{ width: "100%" }}
24+
style={{ width: window.width, height: 258 }}
2525
onScrollStart={() => {
2626
console.log("Scroll start");
2727
}}

example/app/app/demos/basic-layouts/normal/index.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import { useAdvancedSettings } from "@/hooks/useSettings";
55
import { CaptureWrapper } from "@/store/CaptureProvider";
66
import { renderItem } from "@/utils/render-item";
77
import * as React from "react";
8+
import type { StyleProp, ViewStyle } from "react-native";
89
import { useSharedValue } from "react-native-reanimated";
9-
import type { ICarouselInstance } from "react-native-reanimated-carousel";
10+
import type { ICarouselInstance, TCarouselProps } from "react-native-reanimated-carousel";
1011
import Carousel from "react-native-reanimated-carousel";
1112
import { Stack } from "tamagui";
1213

@@ -20,12 +21,10 @@ function Index() {
2021
autoPlayInterval: 2000,
2122
autoPlayReverse: false,
2223
data: defaultDataWith6Colors,
23-
height: 258,
2424
loop: true,
2525
pagingEnabled: true,
2626
snapEnabled: true,
2727
vertical: false,
28-
width: window.width,
2928
},
3029
});
3130

@@ -37,7 +36,10 @@ function Index() {
3736
ref={ref}
3837
defaultScrollOffsetValue={scrollOffsetValue}
3938
testID={"xxx"}
40-
style={{ width: "100%" }}
39+
style={{
40+
height: 258,
41+
width: window.width,
42+
}}
4143
onScrollStart={() => {
4244
console.log("Scroll start");
4345
}}

example/app/app/demos/basic-layouts/parallax/demo.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,21 @@ function Index() {
1515
<Carousel
1616
autoPlayInterval={2000}
1717
data={defaultDataWith6Colors}
18-
height={258}
1918
loop={true}
2019
pagingEnabled={true}
2120
snapEnabled={true}
22-
width={window.width}
2321
style={{
2422
width: window.width,
23+
height: 258,
2524
}}
2625
mode="parallax"
2726
modeConfig={{
2827
parallaxScrollingScale: 0.9,
2928
parallaxScrollingOffset: 50,
3029
}}
31-
onProgressChange={progress}
30+
onProgressChange={(offsetProgress, absoluteProgress) => {
31+
progress.value = absoluteProgress;
32+
}}
3233
renderItem={renderItem({ rounded: true })}
3334
/>
3435
</View>

example/app/app/demos/basic-layouts/parallax/index.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,10 @@ function Index() {
2323
autoPlayInterval: 2000,
2424
autoPlayReverse: false,
2525
data: defaultDataWith6Colors,
26-
height: 258,
2726
loop: true,
2827
pagingEnabled: true,
2928
snapEnabled: true,
3029
vertical: false,
31-
width: PAGE_WIDTH,
3230
},
3331
});
3432

@@ -40,13 +38,16 @@ function Index() {
4038
{...advancedSettings}
4139
style={{
4240
width: PAGE_WIDTH,
41+
height: 258,
4342
}}
4443
mode="parallax"
4544
modeConfig={{
4645
parallaxScrollingScale: 0.9,
4746
parallaxScrollingOffset: 50,
4847
}}
49-
onProgressChange={progress}
48+
onProgressChange={(offsetProgress, absoluteProgress) => {
49+
progress.value = absoluteProgress;
50+
}}
5051
renderItem={renderItem({ rounded: true })}
5152
/>
5253
</CaptureWrapper>

0 commit comments

Comments
 (0)