Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Initial page index #1090

Merged
merged 8 commits into from
Jan 16, 2025
Merged
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
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 @@ -75,6 +76,7 @@ export const Carousel = forwardRef<SlideHandle, CarouselProps>(
const { currentPage, goBack, goForward, goToPage } = usePaging({
totalPages,
wrapMode,
initialPage,
});

// -- handle touch scroll events
Expand Down Expand Up @@ -139,8 +141,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]);

Copy link
Contributor

Choose a reason for hiding this comment

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

This new version makes it render at index 0 and slide to index 1. Seemed to be working better with the previous code.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, yeah that was what I was commenting about #1090 (comment)

Copy link
Member Author

Choose a reason for hiding this comment

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

This is fixed in fcb0049

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
Loading