Skip to content

Commit 27fa32e

Browse files
authored
[Feature] Initial page index (#1090)
2 parents 64c86a3 + f91542a commit 27fa32e

File tree

10 files changed

+108
-9
lines changed

10 files changed

+108
-9
lines changed

docs/api/autoplay.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ For accessibility, the carousel will pause when the user is interacting with it.
2525
#### Code
2626

2727
```tsx
28-
<Carousel autoplay={true} autoplayInterval={1000} wrapMode="wrap">
28+
<Carousel autoplay={true} autoplayInterval={1000} wrapMode="wrap">
2929
<img src="pexels-01.jpg" />
3030
<img src="pexels-02.jpg" />
3131
<img src="pexels-03.jpg" />

docs/api/index.mdx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,12 @@ Feel free to mix React components and HTML elements as children. Nuka Carousel w
7878

7979
:::caution
8080

81-
Nuka Carousel uses a flex container for its magic
82-
83-
:::
81+
### Nuka Carousel uses a flex container to hold its contents.
8482

8583
In order for Nuka to measure your slides, they must have a width that can be calculated.
8684

85+
:::
86+
8787
### Images
8888

8989
If you're using images, Nuka will correctly calculate the width and height of the image after it has loaded.
@@ -114,6 +114,12 @@ However, it's recommended to set the width and height of the image in the HTML t
114114

115115
When using HTML block elements, such as `div`, you must set the min width in the HTML.
116116

117+
:::info
118+
119+
Most of the examples use <a href="https://tailwindcss.com/" target="_blank">Tailwind</a> classes for styling
120+
121+
:::
122+
117123
```jsx
118124
.demo-slide {
119125
min-width: 300px;
@@ -145,5 +151,5 @@ function CarouselImage() {
145151
<CarouselImage />
146152
<CarouselImage />
147153
<CarouselImage />
148-
</Carousel>
154+
</Carousel>;
149155
```

docs/api/initial-page.mdx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
sidebar_position: 4
3+
---
4+
5+
import { Carousel } from 'nuka-carousel';
6+
7+
# Initial Page
8+
9+
The carousel can start on any index within bounds of its length. Anything out of bounds will default back to `0` for its index. This list is `0` indexed.
10+
11+
| Prop Name | Type | Default Value |
12+
| :------------ | :----- | :------------ |
13+
| `initialPage` | number | `0` |
14+
15+
### Example
16+
17+
<Carousel initialPage={1}>
18+
<img src="/open-source/nuka-carousel/img/pexels-01.jpg" />
19+
<img src="/open-source/nuka-carousel/img/pexels-02.jpg" />
20+
<img src="/open-source/nuka-carousel/img/pexels-03.jpg" />
21+
</Carousel>
22+
23+
#### Code
24+
25+
```tsx
26+
<Carousel initialPage={1}>
27+
<img src="/open-source/nuka-carousel/img/pexels-01.jpg" />
28+
<img src="/open-source/nuka-carousel/img/pexels-02.jpg" />
29+
<img src="/open-source/nuka-carousel/img/pexels-03.jpg" />
30+
</Carousel>
31+
```

docs/v8-upgrade-guide.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ The following props were removed becuase they are no longer valid or replaced by
4545
- `pauseOnHover` - Enabled by default. See the <Link to="/docs/api/autoplay">autoplay</Link> docs.
4646
- `renderTop{direction}Controls`
4747
- `scrollMode` - Defaults to `remainder`.
48-
- `slideIndex`
48+
- `slideIndex` - Use <Link to="/docs/api/initial-page">initialPage</Link> to start on a certain page, use <Link to="/docs/api/methods#progression">goToPage</Link> to change indices on command.
4949
- `slidesToShow` - Now based on media queries and how large the slides are.
5050
- `speed` - Controlled by native browser settings.
5151
- `style` - See the <Link to="/docs/api">style guide</Link>.

packages/nuka/src/Carousel/Carousel.css

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,15 @@
1717
}
1818
.nuka-overflow {
1919
overflow: scroll;
20-
scroll-behavior: smooth;
2120
-ms-overflow-style: none; /* IE and Edge */
2221
scrollbar-width: none; /* Firefox */
2322
}
23+
.nuka-overflow.scroll-smooth {
24+
scroll-behavior: smooth;
25+
}
26+
.nuka-overflow.scroll-auto {
27+
scroll-behavior: auto;
28+
}
2429
.nuka-overflow::-webkit-scrollbar {
2530
display: none;
2631
}

packages/nuka/src/Carousel/Carousel.stories.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,20 @@ export const GoToPage: Story = {
169169
},
170170
};
171171

172+
export const InitialPage: Story = {
173+
args: {
174+
initialPage: 2,
175+
scrollDistance: 'slide',
176+
children: (
177+
<>
178+
{[...Array(10)].map((_, index) => (
179+
<ExampleSlide key={index} index={index} />
180+
))}
181+
</>
182+
),
183+
},
184+
};
185+
172186
export const BeforeSlide: Story = {
173187
args: {
174188
beforeSlide: (currentSlideIndex, endSlideIndex) =>

packages/nuka/src/Carousel/Carousel.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export const Carousel = forwardRef<SlideHandle, CarouselProps>(
5959
swiping,
6060
title,
6161
wrapMode,
62+
initialPage,
6263
} = options;
6364

6465
const carouselRef = useRef<HTMLDivElement | null>(null);
@@ -76,6 +77,7 @@ export const Carousel = forwardRef<SlideHandle, CarouselProps>(
7677
const { currentPage, goBack, goForward, goToPage } = usePaging({
7778
totalPages,
7879
wrapMode,
80+
initialPage,
7981
});
8082

8183
// -- handle touch scroll events
@@ -145,8 +147,12 @@ export const Carousel = forwardRef<SlideHandle, CarouselProps>(
145147
containerRef.current.scrollLeft = scrollOffset[currentPage];
146148
afterSlide && setTimeout(() => afterSlide(endSlideIndex), 0);
147149
previousPageRef.current = currentPage;
150+
if (initialPage === undefined || currentPage === initialPage) {
151+
containerRef.current.classList.remove('scroll-auto');
152+
containerRef.current.classList.add('scroll-smooth');
153+
}
148154
}
149-
}, [currentPage, scrollOffset, beforeSlide, afterSlide]);
155+
}, [currentPage, scrollOffset, beforeSlide, afterSlide, initialPage]);
150156

151157
const containerClassName = cls(
152158
'nuka-container',

packages/nuka/src/hooks/use-paging.test.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,32 @@ describe('usePaging', () => {
9494
});
9595
expect(result.current.currentPage).toBe(0);
9696
});
97+
98+
it('should start at index 0 if not given an initial page index', () => {
99+
const { result } = renderHook(() =>
100+
usePaging({ totalPages: 5, wrapMode: 'wrap' }),
101+
);
102+
expect(result.current.currentPage).toBe(0);
103+
});
104+
105+
it('should start at the given initial page index', () => {
106+
const { result } = renderHook(() =>
107+
usePaging({ totalPages: 5, wrapMode: 'wrap', initialPage: 2 }),
108+
);
109+
expect(result.current.currentPage).toBe(2);
110+
});
111+
112+
it('should start at in bound indices if initial page is out of bounds', () => {
113+
const { result } = renderHook(() =>
114+
usePaging({ totalPages: 5, wrapMode: 'wrap', initialPage: 200 }),
115+
);
116+
expect(result.current.currentPage).toBe(5);
117+
});
118+
119+
it('should start at 0 indices if initial page is out of bounds', () => {
120+
const { result } = renderHook(() =>
121+
usePaging({ totalPages: 5, wrapMode: 'wrap', initialPage: -2 }),
122+
);
123+
expect(result.current.currentPage).toBe(0);
124+
});
97125
});

packages/nuka/src/hooks/use-paging.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from 'react';
1+
import { useEffect, useState } from 'react';
22

33
import { CarouselProps } from '../types';
44

@@ -12,14 +12,22 @@ type UsePagingReturnType = {
1212
type PagingProps = {
1313
totalPages: number;
1414
wrapMode: CarouselProps['wrapMode'];
15+
initialPage?: number;
1516
};
1617

1718
export function usePaging({
1819
totalPages,
1920
wrapMode,
21+
initialPage,
2022
}: PagingProps): UsePagingReturnType {
2123
const [currentPage, setCurrentPage] = useState(0);
2224

25+
useEffect(() => {
26+
if (initialPage) {
27+
setCurrentPage(Math.max(0, Math.min(initialPage, totalPages)));
28+
}
29+
}, [initialPage, totalPages]);
30+
2331
const goToPage = (idx: number) => {
2432
if (idx < 0 || idx >= totalPages) return;
2533
setCurrentPage(idx);

packages/nuka/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export type CarouselProps = CarouselCallbacks & {
2525
swiping?: boolean;
2626
title?: string;
2727
wrapMode?: 'nowrap' | 'wrap';
28+
initialPage?: number;
2829
};
2930

3031
export type SlideHandle = {

0 commit comments

Comments
 (0)