Skip to content

Commit

Permalink
[Feature] Initial page index (#1090)
Browse files Browse the repository at this point in the history
  • Loading branch information
melvin-chen authored Jan 16, 2025
2 parents 64c86a3 + f91542a commit 27fa32e
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 9 deletions.
2 changes: 1 addition & 1 deletion docs/api/autoplay.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ For accessibility, the carousel will pause when the user is interacting with it.
#### Code

```tsx
<Carousel autoplay={true} autoplayInterval={1000} wrapMode="wrap">
<Carousel autoplay={true} autoplayInterval={1000} wrapMode="wrap">
<img src="pexels-01.jpg" />
<img src="pexels-02.jpg" />
<img src="pexels-03.jpg" />
Expand Down
14 changes: 10 additions & 4 deletions docs/api/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ Feel free to mix React components and HTML elements as children. Nuka Carousel w

:::caution

Nuka Carousel uses a flex container for its magic

:::
### Nuka Carousel uses a flex container to hold its contents.

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

:::

### Images

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

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

:::info

Most of the examples use <a href="https://tailwindcss.com/" target="_blank">Tailwind</a> classes for styling

:::

```jsx
.demo-slide {
min-width: 300px;
Expand Down Expand Up @@ -145,5 +151,5 @@ function CarouselImage() {
<CarouselImage />
<CarouselImage />
<CarouselImage />
</Carousel>
</Carousel>;
```
31 changes: 31 additions & 0 deletions docs/api/initial-page.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
sidebar_position: 4
---

import { Carousel } from 'nuka-carousel';

# Initial Page

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.

| Prop Name | Type | Default Value |
| :------------ | :----- | :------------ |
| `initialPage` | number | `0` |

### Example

<Carousel initialPage={1}>
<img src="/open-source/nuka-carousel/img/pexels-01.jpg" />
<img src="/open-source/nuka-carousel/img/pexels-02.jpg" />
<img src="/open-source/nuka-carousel/img/pexels-03.jpg" />
</Carousel>

#### Code

```tsx
<Carousel initialPage={1}>
<img src="/open-source/nuka-carousel/img/pexels-01.jpg" />
<img src="/open-source/nuka-carousel/img/pexels-02.jpg" />
<img src="/open-source/nuka-carousel/img/pexels-03.jpg" />
</Carousel>
```
2 changes: 1 addition & 1 deletion docs/v8-upgrade-guide.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ The following props were removed becuase they are no longer valid or replaced by
- `pauseOnHover` - Enabled by default. See the <Link to="/docs/api/autoplay">autoplay</Link> docs.
- `renderTop{direction}Controls`
- `scrollMode` - Defaults to `remainder`.
- `slideIndex`
- `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.
- `slidesToShow` - Now based on media queries and how large the slides are.
- `speed` - Controlled by native browser settings.
- `style` - See the <Link to="/docs/api">style guide</Link>.
Expand Down
7 changes: 6 additions & 1 deletion packages/nuka/src/Carousel/Carousel.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@
}
.nuka-overflow {
overflow: scroll;
scroll-behavior: smooth;
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
.nuka-overflow.scroll-smooth {
scroll-behavior: smooth;
}
.nuka-overflow.scroll-auto {
scroll-behavior: auto;
}
.nuka-overflow::-webkit-scrollbar {
display: none;
}
Expand Down
14 changes: 14 additions & 0 deletions packages/nuka/src/Carousel/Carousel.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,20 @@ export const GoToPage: Story = {
},
};

export const InitialPage: Story = {
args: {
initialPage: 2,
scrollDistance: 'slide',
children: (
<>
{[...Array(10)].map((_, index) => (
<ExampleSlide key={index} index={index} />
))}
</>
),
},
};

export const BeforeSlide: Story = {
args: {
beforeSlide: (currentSlideIndex, endSlideIndex) =>
Expand Down
8 changes: 7 additions & 1 deletion packages/nuka/src/Carousel/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export const Carousel = forwardRef<SlideHandle, CarouselProps>(
swiping,
title,
wrapMode,
initialPage,
} = options;

const carouselRef = useRef<HTMLDivElement | null>(null);
Expand All @@ -76,6 +77,7 @@ export const Carousel = forwardRef<SlideHandle, CarouselProps>(
const { currentPage, goBack, goForward, goToPage } = usePaging({
totalPages,
wrapMode,
initialPage,
});

// -- handle touch scroll events
Expand Down Expand Up @@ -145,8 +147,12 @@ export const Carousel = forwardRef<SlideHandle, CarouselProps>(
containerRef.current.scrollLeft = scrollOffset[currentPage];
afterSlide && setTimeout(() => afterSlide(endSlideIndex), 0);
previousPageRef.current = currentPage;
if (initialPage === undefined || currentPage === initialPage) {
containerRef.current.classList.remove('scroll-auto');
containerRef.current.classList.add('scroll-smooth');
}
}
}, [currentPage, scrollOffset, beforeSlide, afterSlide]);
}, [currentPage, scrollOffset, beforeSlide, afterSlide, initialPage]);

const containerClassName = cls(
'nuka-container',
Expand Down
28 changes: 28 additions & 0 deletions packages/nuka/src/hooks/use-paging.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,32 @@ describe('usePaging', () => {
});
expect(result.current.currentPage).toBe(0);
});

it('should start at index 0 if not given an initial page index', () => {
const { result } = renderHook(() =>
usePaging({ totalPages: 5, wrapMode: 'wrap' }),
);
expect(result.current.currentPage).toBe(0);
});

it('should start at the given initial page index', () => {
const { result } = renderHook(() =>
usePaging({ totalPages: 5, wrapMode: 'wrap', initialPage: 2 }),
);
expect(result.current.currentPage).toBe(2);
});

it('should start at in bound indices if initial page is out of bounds', () => {
const { result } = renderHook(() =>
usePaging({ totalPages: 5, wrapMode: 'wrap', initialPage: 200 }),
);
expect(result.current.currentPage).toBe(5);
});

it('should start at 0 indices if initial page is out of bounds', () => {
const { result } = renderHook(() =>
usePaging({ totalPages: 5, wrapMode: 'wrap', initialPage: -2 }),
);
expect(result.current.currentPage).toBe(0);
});
});
10 changes: 9 additions & 1 deletion packages/nuka/src/hooks/use-paging.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';

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

Expand All @@ -12,14 +12,22 @@ type UsePagingReturnType = {
type PagingProps = {
totalPages: number;
wrapMode: CarouselProps['wrapMode'];
initialPage?: number;
};

export function usePaging({
totalPages,
wrapMode,
initialPage,
}: PagingProps): UsePagingReturnType {
const [currentPage, setCurrentPage] = useState(0);

useEffect(() => {
if (initialPage) {
setCurrentPage(Math.max(0, Math.min(initialPage, totalPages)));
}
}, [initialPage, totalPages]);

const goToPage = (idx: number) => {
if (idx < 0 || idx >= totalPages) return;
setCurrentPage(idx);
Expand Down
1 change: 1 addition & 0 deletions packages/nuka/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type CarouselProps = CarouselCallbacks & {
swiping?: boolean;
title?: string;
wrapMode?: 'nowrap' | 'wrap';
initialPage?: number;
};

export type SlideHandle = {
Expand Down

0 comments on commit 27fa32e

Please sign in to comment.