Skip to content

Commit 6c578d4

Browse files
committed
feat(carousel): indicator and progress text
1 parent 3ea1ba3 commit 6c578d4

28 files changed

+344
-10
lines changed

packages/react/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
## [Unreleased]
22

3+
### Added
4+
5+
- **Carousel**:
6+
- Added `Carousel.AutoplayIndicator` component for conditionally rendering content based on autoplay state
7+
- Added `Carousel.ProgressText` component for displaying current page progress (e.g., "1 / 5")
8+
39
## [5.27.1] - 2025-11-02
410

511
### Fixed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { ReactNode } from 'react'
2+
import { useCarouselContext } from './use-carousel-context'
3+
4+
export interface CarouselAutoplayIndicatorBaseProps {
5+
/**
6+
* The content to render when autoplay is paused.
7+
*/
8+
paused: ReactNode
9+
/**
10+
* The content to render when autoplay is playing.
11+
*/
12+
playing: ReactNode
13+
}
14+
export interface CarouselAutoplayIndicatorProps extends CarouselAutoplayIndicatorBaseProps {}
15+
16+
export const CarouselAutoplayIndicator = (props: CarouselAutoplayIndicatorProps) => {
17+
const carousel = useCarouselContext()
18+
return <>{carousel.isPlaying ? props.paused : props.playing}</>
19+
}
20+
21+
CarouselAutoplayIndicator.displayName = 'CarouselAutoplayIndicator'
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { forwardRef, useMemo } from 'react'
2+
import { type HTMLProps, type PolymorphicProps, ark } from '../factory'
3+
import { carouselAnatomy } from './carousel.anatomy'
4+
import { useCarouselContext } from './use-carousel-context'
5+
6+
const parts = carouselAnatomy.build()
7+
8+
export interface CarouselProgressTextBaseProps extends PolymorphicProps {}
9+
export interface CarouselProgressTextProps extends HTMLProps<'span'>, CarouselProgressTextBaseProps {}
10+
11+
export const CarouselProgressText = forwardRef<HTMLSpanElement, CarouselProgressTextProps>((props, ref) => {
12+
const carousel = useCarouselContext()
13+
14+
const progressText = useMemo(() => {
15+
const currentPage = carousel.page + 1
16+
const totalPages = carousel.pageSnapPoints.length
17+
return `${currentPage} / ${totalPages}`
18+
}, [carousel.page, carousel.pageSnapPoints.length])
19+
20+
return (
21+
<ark.span ref={ref} {...parts.progressText.attrs} {...props}>
22+
{props.children || progressText}
23+
</ark.span>
24+
)
25+
})
26+
27+
CarouselProgressText.displayName = 'CarouselProgressText'
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
export { anatomy as carouselAnatomy } from '@zag-js/carousel'
1+
import { anatomy } from '@zag-js/carousel'
2+
3+
export const carouselAnatomy = anatomy.extendWith('progressText')

packages/react/src/components/carousel/carousel.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
export type { AutoplayStatusDetails, DragStatusDetails, PageChangeDetails } from '@zag-js/carousel'
2+
export {
3+
CarouselAutoplayIndicator as AutoplayIndicator,
4+
type CarouselAutoplayIndicatorBaseProps as AutoplayIndicatorBaseProps,
5+
type CarouselAutoplayIndicatorProps as AutoplayIndicatorProps,
6+
} from './carousel-autoplay-indicator'
7+
export {
8+
CarouselProgressText as ProgressText,
9+
type CarouselProgressTextBaseProps as ProgressTextBaseProps,
10+
type CarouselProgressTextProps as ProgressTextProps,
11+
} from './carousel-progress-text'
212
export {
313
CarouselAutoplayTrigger as AutoplayTrigger,
414
type CarouselAutoplayTriggerBaseProps as AutoplayTriggerBaseProps,

packages/react/src/components/carousel/examples/autoplay.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ export const Autoplay = () => {
77
<Carousel.Root slideCount={images.length} autoplay loop>
88
<Carousel.Control>
99
<Carousel.AutoplayTrigger>
10-
<Carousel.Context>{({ isPlaying }) => (isPlaying ? 'Pause' : 'Play')}</Carousel.Context>
10+
<Carousel.AutoplayIndicator paused="Pause" playing="Play" />
1111
</Carousel.AutoplayTrigger>
12+
<Carousel.ProgressText />
1213
</Carousel.Control>
1314
<Carousel.IndicatorGroup>
1415
{images.map((_, index) => (

packages/react/src/components/carousel/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ export type {
33
DragStatusDetails as CarouselDragStatusDetails,
44
PageChangeDetails as CarouselPageChangeDetails,
55
} from '@zag-js/carousel'
6+
export {
7+
CarouselAutoplayIndicator,
8+
type CarouselAutoplayIndicatorBaseProps,
9+
type CarouselAutoplayIndicatorProps,
10+
} from './carousel-autoplay-indicator'
11+
export {
12+
CarouselProgressText,
13+
type CarouselProgressTextBaseProps,
14+
type CarouselProgressTextProps,
15+
} from './carousel-progress-text'
616
export {
717
CarouselAutoplayTrigger,
818
type CarouselAutoplayTriggerBaseProps,

packages/solid/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
## [Unreleased]
22

3+
### Added
4+
5+
- **Carousel**:
6+
- Added `Carousel.AutoplayIndicator` component for conditionally rendering content based on autoplay state
7+
- Added `Carousel.ProgressText` component for displaying current page progress (e.g., "1 / 5")
8+
39
## [5.27.1] - 2025-11-02
410

511
### Fixed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Show, type JSX } from 'solid-js'
2+
import { useCarouselContext } from './use-carousel-context'
3+
4+
export interface CarouselAutoplayIndicatorBaseProps {
5+
/**
6+
* The content to render when autoplay is paused.
7+
*/
8+
paused: JSX.Element
9+
/**
10+
* The content to render when autoplay is playing.
11+
*/
12+
playing: JSX.Element
13+
}
14+
export interface CarouselAutoplayIndicatorProps extends CarouselAutoplayIndicatorBaseProps {}
15+
16+
export const CarouselAutoplayIndicator = (props: CarouselAutoplayIndicatorProps) => {
17+
const api = useCarouselContext()
18+
return (
19+
<Show when={api().isPlaying} fallback={props.playing}>
20+
{props.paused}
21+
</Show>
22+
)
23+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { createMemo } from 'solid-js'
2+
import { type HTMLProps, type PolymorphicProps, ark } from '../factory'
3+
import { carouselAnatomy } from './carousel.anatomy'
4+
import { useCarouselContext } from './use-carousel-context'
5+
6+
const parts = carouselAnatomy.build()
7+
8+
export interface CarouselProgressTextBaseProps extends PolymorphicProps<'span'> {}
9+
export interface CarouselProgressTextProps extends HTMLProps<'span'>, CarouselProgressTextBaseProps {}
10+
11+
export const CarouselProgressText = (props: CarouselProgressTextProps) => {
12+
const api = useCarouselContext()
13+
14+
const progressText = createMemo(() => {
15+
const currentPage = api().page + 1
16+
const totalPages = api().pageSnapPoints.length
17+
return `${currentPage} / ${totalPages}`
18+
})
19+
20+
return (
21+
<ark.span {...parts.progressText.attrs} {...props}>
22+
{props.children || progressText()}
23+
</ark.span>
24+
)
25+
}

0 commit comments

Comments
 (0)