@payfit/unity-components 2.9.7 → 2.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/esm/components/carousel/Carousel.context.d.ts +60 -0
  2. package/dist/esm/components/carousel/Carousel.context.js +14 -0
  3. package/dist/esm/components/carousel/Carousel.d.ts +72 -0
  4. package/dist/esm/components/carousel/Carousel.js +106 -0
  5. package/dist/esm/components/carousel/Carousel.options.d.ts +24 -0
  6. package/dist/esm/components/carousel/Carousel.options.js +64 -0
  7. package/dist/esm/components/carousel/hooks/useCarouselAccessibility.d.ts +21 -0
  8. package/dist/esm/components/carousel/hooks/useCarouselAccessibility.js +87 -0
  9. package/dist/esm/components/carousel/hooks/useCarouselState.d.ts +14 -0
  10. package/dist/esm/components/carousel/hooks/useCarouselState.js +62 -0
  11. package/dist/esm/components/carousel/parts/CarouselContent.d.ts +103 -0
  12. package/dist/esm/components/carousel/parts/CarouselContent.js +69 -0
  13. package/dist/esm/components/carousel/parts/CarouselHeader.d.ts +87 -0
  14. package/dist/esm/components/carousel/parts/CarouselHeader.js +58 -0
  15. package/dist/esm/components/carousel/parts/CarouselNav.d.ts +59 -0
  16. package/dist/esm/components/carousel/parts/CarouselNav.js +80 -0
  17. package/dist/esm/components/carousel/parts/CarouselSlide.d.ts +38 -0
  18. package/dist/esm/components/carousel/parts/CarouselSlide.js +35 -0
  19. package/dist/esm/components/carousel/types.d.ts +8 -0
  20. package/dist/esm/components/icon-button/IconButton.d.ts +1 -0
  21. package/dist/esm/hooks/use-responsive-value.d.ts +11 -0
  22. package/dist/esm/hooks/use-responsive-value.js +29 -0
  23. package/dist/esm/index.d.ts +5 -0
  24. package/dist/esm/index.js +87 -72
  25. package/dist/esm/utils/field-revalidate-logic.d.ts +1 -1
  26. package/dist/esm/utils/field-revalidate-logic.js +10 -12
  27. package/i18n/en-GB.json +13 -0
  28. package/i18n/es-ES.json +13 -0
  29. package/i18n/fr-FR.json +13 -0
  30. package/package.json +13 -10
@@ -0,0 +1,60 @@
1
+ import { EmblaCarouselApi, EmblaCarouselRef } from './types.js';
2
+ import * as React from 'react';
3
+ /**
4
+ * Context type for the Carousel component.
5
+ * Provides shared state and methods to all carousel sub-components.
6
+ */
7
+ type CarouselContextProps = {
8
+ /** Ref to the Embla carousel viewport element */
9
+ carouselRef: EmblaCarouselRef;
10
+ /** Embla Carousel API instance */
11
+ api: EmblaCarouselApi;
12
+ /** Navigate to the previous slide or page */
13
+ goToPrev: () => void;
14
+ /** Navigate to the next slide or page */
15
+ goToNext: () => void;
16
+ /** Navigate to a specific snap index */
17
+ goTo: (index: number) => void;
18
+ /** Check if navigation to next is possible */
19
+ canGoToNext: () => boolean | undefined;
20
+ /** Check if navigation to previous is possible */
21
+ canGoToPrev: () => boolean | undefined;
22
+ /** Set of slide indexes currently visible in the viewport */
23
+ visibleSlideIndexes: ReadonlySet<number>;
24
+ /** Current snap/page index (0-based) */
25
+ selectedSnap: number;
26
+ /** Total number of snaps/pages */
27
+ snapCount: number;
28
+ /** Generated IDs for accessibility attributes */
29
+ a11yIds: {
30
+ root: string;
31
+ track: string;
32
+ previousButton: string;
33
+ nextButton: string;
34
+ title: string;
35
+ };
36
+ };
37
+ /**
38
+ * Context for sharing carousel state between components.
39
+ * @internal
40
+ */
41
+ export declare const CarouselContext: React.Context<CarouselContextProps | null>;
42
+ /**
43
+ * Hook to access the carousel context.
44
+ * Must be used within a `Carousel` component.
45
+ * @returns {CarouselContextProps} Carousel context value
46
+ * @throws {Error} If used outside of a Carousel component
47
+ * @example
48
+ * ```tsx
49
+ * function CustomCarouselPart() {
50
+ * const { goToNext, canGoToNext } = useCarousel()
51
+ * return (
52
+ * <button onClick={goToNext} disabled={!canGoToNext()}>
53
+ * Next
54
+ * </button>
55
+ * )
56
+ * }
57
+ * ```
58
+ */
59
+ export declare function useCarousel(): CarouselContextProps;
60
+ export {};
@@ -0,0 +1,14 @@
1
+ import * as t from "react";
2
+ const o = t.createContext(
3
+ null
4
+ );
5
+ function n() {
6
+ const e = t.useContext(o);
7
+ if (!e)
8
+ throw new Error("useCarousel must be used within a Carousel Component");
9
+ return e;
10
+ }
11
+ export {
12
+ o as CarouselContext,
13
+ n as useCarousel
14
+ };
@@ -0,0 +1,72 @@
1
+ import { ReactNode } from 'react';
2
+ import { CarouselOptions } from './types.js';
3
+ export declare const carousel: import('tailwind-variants').TVReturnType<{} | {} | {}, undefined, "uy:relative uy:flex uy:flex-col uy:gap-200 uy:md:gap-300", {} | {}, undefined, import('tailwind-variants').TVReturnType<unknown, undefined, "uy:relative uy:flex uy:flex-col uy:gap-200 uy:md:gap-300", unknown, unknown, undefined>>;
4
+ export interface CarouselProps {
5
+ options?: Pick<NonNullable<CarouselOptions>, 'align' | 'loop' | 'slidesToScroll' | 'containScroll' | 'inViewThreshold' | 'inViewMargin' | 'duration' | 'draggable' | 'dragFree' | 'dragThreshold' | 'ssr'>;
6
+ /**
7
+ * Accessible label for the carousel region.
8
+ * When provided, takes precedence over the title set in `CarouselHeader` for labeling.
9
+ */
10
+ 'aria-label'?: string;
11
+ /** Additional CSS classes for the root element. */
12
+ className?: string;
13
+ children: ReactNode;
14
+ }
15
+ /**
16
+ * Root container of the Carousel. Manages shared state and provides context to all sub-components.
17
+ * The Carousel component displays a series of slides in a horizontal, scrollable layout. It's built
18
+ * on top of Embla Carousel and provides accessible navigation via keyboard, mouse, and touch.
19
+ * ## Composition
20
+ * Compose the Carousel with its child components:
21
+ * - `CarouselHeader` – Optional header with title and action slot
22
+ * - `CarouselContent` – Scrollable viewport that houses slides
23
+ * - `CarouselSlide` – Individual slide wrapper
24
+ * ## Features
25
+ * - **Responsive**: Configure slides per page and spacing per breakpoint
26
+ * - **Accessible**: Full keyboard navigation (Arrow keys, PageUp/PageDown, Home/End)
27
+ * - **Touch-enabled**: Native swipe gestures on mobile
28
+ * - **Flexible layout**: Control alignment, looping, and scroll behavior
29
+ * - **Screen reader support**: ARIA labels and live region announcements
30
+ * @example
31
+ * ```tsx
32
+ * import { Carousel, CarouselContent, CarouselHeader, CarouselSlide } from '@payfit/unity-components'
33
+ *
34
+ * <Carousel>
35
+ * <CarouselHeader title="Featured items" />
36
+ * <CarouselContent itemsPerPage={3} gap="$200">
37
+ * <CarouselSlide>Item 1</CarouselSlide>
38
+ * <CarouselSlide>Item 2</CarouselSlide>
39
+ * <CarouselSlide>Item 3</CarouselSlide>
40
+ * </CarouselContent>
41
+ * </Carousel>
42
+ * ```
43
+ * @example
44
+ * ```tsx
45
+ * <Carousel>
46
+ * <CarouselHeader title="Responsive carousel" />
47
+ * <CarouselContent
48
+ * itemsPerPage={{ base: 1, md: 2, lg: 3 }}
49
+ * gap={{ base: '$100', md: '$200' }}
50
+ * >
51
+ * {slides.map((slide) => (
52
+ * <CarouselSlide key={slide.id}>{slide.content}</CarouselSlide>
53
+ * ))}
54
+ * </CarouselContent>
55
+ * </Carousel>
56
+ * ```
57
+ * ## Accessibility
58
+ * - Arrow keys navigate between individual slides
59
+ * - PageUp/PageDown jump to the first slide of the next/previous page
60
+ * - Home/End keys jump to the first/last slide
61
+ * - Tab key exits the carousel to the next focusable element
62
+ * - Screen readers announce the current slide and total count
63
+ * @param {CarouselProps} props - Component props
64
+ * @param {CarouselProps['options']} props.options - Embla Carousel configuration options
65
+ * @param {CarouselProps['aria-label']} props.aria-label - Accessible label for the carousel region (overrides title from CarouselHeader)
66
+ * @param {CarouselProps['className']} props.className - Additional CSS classes
67
+ * @param {CarouselProps['children']} props.children - Carousel content (CarouselHeader, CarouselContent, CarouselSlide)
68
+ * @see {@link CarouselProps} for all available props
69
+ * @see {@link https://www.embla-carousel.com/api/options/|Embla Carousel Options}
70
+ */
71
+ declare const Carousel: import('react').ForwardRefExoticComponent<CarouselProps & import('react').RefAttributes<HTMLDivElement>>;
72
+ export { Carousel };
@@ -0,0 +1,106 @@
1
+ import { jsx as r, jsxs as I } from "react/jsx-runtime";
2
+ import { forwardRef as R, useMemo as h } from "react";
3
+ import { uyTv as j } from "@payfit/unity-themes";
4
+ import w from "embla-carousel-accessibility";
5
+ import A from "embla-carousel-react";
6
+ import { useIntl as M } from "react-intl";
7
+ import { CarouselContext as P } from "./Carousel.context.js";
8
+ import { createCarouselAccessibilityOptions as D } from "./Carousel.options.js";
9
+ import { useCarouselAccessibility as G } from "./hooks/useCarouselAccessibility.js";
10
+ import { useCarouselState as K } from "./hooks/useCarouselState.js";
11
+ import { CarouselNav as O } from "./parts/CarouselNav.js";
12
+ const E = j({
13
+ base: "uy:relative uy:flex uy:flex-col uy:gap-200 uy:md:gap-300"
14
+ }), k = R(
15
+ ({
16
+ children: t,
17
+ className: u,
18
+ options: s = {
19
+ slidesToScroll: "auto"
20
+ },
21
+ "aria-label": a,
22
+ ...c
23
+ }, n) => {
24
+ const e = M(), m = h(
25
+ () => D(e),
26
+ [e]
27
+ ), [d, o] = A(
28
+ {
29
+ draggable: !0,
30
+ ...s,
31
+ axis: "x"
32
+ },
33
+ [w(m)]
34
+ ), {
35
+ canGoToNext: p,
36
+ canGoToPrev: f,
37
+ visibleSlideIndexes: i,
38
+ focusedSlideIndex: y,
39
+ goToPrev: v,
40
+ goToNext: x,
41
+ goTo: g,
42
+ goToSlide: b,
43
+ selectedSnap: C,
44
+ snapCount: T
45
+ } = K(o), { liveRegionRef: N, a11yIds: l, onKeyDown: S } = G({
46
+ api: o,
47
+ visibleSlideIndexes: i,
48
+ focusedSlideIndex: y,
49
+ loop: s.loop ?? !1,
50
+ goToSlide: b
51
+ });
52
+ return /* @__PURE__ */ r(
53
+ P.Provider,
54
+ {
55
+ value: {
56
+ carouselRef: d,
57
+ api: o,
58
+ goToNext: x,
59
+ goToPrev: v,
60
+ goTo: g,
61
+ canGoToPrev: f,
62
+ canGoToNext: p,
63
+ visibleSlideIndexes: i,
64
+ selectedSnap: C,
65
+ snapCount: T,
66
+ a11yIds: l
67
+ },
68
+ children: /* @__PURE__ */ I(
69
+ "div",
70
+ {
71
+ ref: n,
72
+ className: E({ className: u }),
73
+ role: "region",
74
+ "aria-roledescription": e.formatMessage({
75
+ id: "unity:component:carousel:roledescription",
76
+ defaultMessage: "carousel"
77
+ }),
78
+ "aria-label": a,
79
+ "aria-labelledby": a ? void 0 : l.title,
80
+ "data-unity-slot": "carousel",
81
+ onKeyDownCapture: S,
82
+ ...c,
83
+ children: [
84
+ t,
85
+ /* @__PURE__ */ r(O, { className: "uy:flex uy:justify-center uy:md:hidden" }),
86
+ /* @__PURE__ */ r(
87
+ "div",
88
+ {
89
+ ref: N,
90
+ "aria-live": "polite",
91
+ "aria-atomic": "true",
92
+ className: "uy:sr-only"
93
+ }
94
+ )
95
+ ]
96
+ }
97
+ )
98
+ }
99
+ );
100
+ }
101
+ );
102
+ k.displayName = "Carousel";
103
+ export {
104
+ k as Carousel,
105
+ E as carousel
106
+ };
@@ -0,0 +1,24 @@
1
+ import { AccessibilityOptionsType } from 'embla-carousel-accessibility';
2
+ import { IntlShape } from 'react-intl';
3
+ type AriaTextCallbackType = AccessibilityOptionsType['slideAriaLabel'];
4
+ /**
5
+ * Creates a function that generates aria labels for carousel slides
6
+ * based on grouping configuration.
7
+ * @param intl - The react-intl instance for translations
8
+ * @returns A callback function for the Embla accessibility plugin
9
+ */
10
+ export declare function createSlideAriaLabel(intl: IntlShape): AriaTextCallbackType;
11
+ /**
12
+ * Creates a function that generates live region content for announcing
13
+ * slide changes to screen readers.
14
+ * @param intl - The react-intl instance for translations
15
+ * @returns A callback function for the Embla accessibility plugin
16
+ */
17
+ export declare function createLiveRegionContent(intl: IntlShape): AriaTextCallbackType;
18
+ /**
19
+ * Creates the default accessibility options for the Embla carousel plugin.
20
+ * @param intl - The react-intl instance for translations
21
+ * @returns Options object for the Embla Accessibility plugin
22
+ */
23
+ export declare function createCarouselAccessibilityOptions(intl: IntlShape): AccessibilityOptionsType;
24
+ export {};
@@ -0,0 +1,64 @@
1
+ function g(e) {
2
+ return (i, a, l, s, r, n) => {
3
+ const o = a + 1, u = l + 1, t = r + 1;
4
+ return i ? a === l ? e.formatMessage(
5
+ {
6
+ id: "unity:component:carousel:a11y:slide:label:group-single",
7
+ defaultMessage: "Slide {slide} of {totalSlides} (group {snap} of {totalSnaps})"
8
+ },
9
+ { slide: o, totalSlides: s, snap: t, totalSnaps: n }
10
+ ) : e.formatMessage(
11
+ {
12
+ id: "unity:component:carousel:a11y:slide:label:group-multiple",
13
+ defaultMessage: "Slides {slide}-{lastSlide} of {totalSlides} (group {snap} of {totalSnaps})"
14
+ },
15
+ { slide: o, lastSlide: u, totalSlides: s, snap: t, totalSnaps: n }
16
+ ) : e.formatMessage(
17
+ {
18
+ id: "unity:component:carousel:a11y:slide:label:single",
19
+ defaultMessage: "Slide {slide} of {totalSlides}"
20
+ },
21
+ { slide: o, totalSlides: s }
22
+ );
23
+ };
24
+ }
25
+ function c(e) {
26
+ return (i, a, l, s, r, n) => {
27
+ const o = a + 1, u = l + 1, t = r + 1;
28
+ return i ? a === l ? e.formatMessage(
29
+ {
30
+ id: "unity:component:carousel:a11y:live-region:group-single",
31
+ defaultMessage: "Showing slide {slide} of {totalSlides} (group {snap} of {totalSnaps})"
32
+ },
33
+ { slide: o, totalSlides: s, snap: t, totalSnaps: n }
34
+ ) : e.formatMessage(
35
+ {
36
+ id: "unity:component:carousel:a11y:live-region:group-multiple",
37
+ defaultMessage: "Showing slides {slide}-{lastSlide} of {totalSlides} (group {snap} of {totalSnaps})"
38
+ },
39
+ { slide: o, lastSlide: u, totalSlides: s, snap: t, totalSnaps: n }
40
+ ) : e.formatMessage(
41
+ {
42
+ id: "unity:component:carousel:a11y:live-region:single",
43
+ defaultMessage: "Showing slide {slide} of {totalSlides}"
44
+ },
45
+ { slide: o, totalSlides: s }
46
+ );
47
+ };
48
+ }
49
+ function d(e) {
50
+ return {
51
+ announceChanges: !0,
52
+ carouselAriaLabel: e.formatMessage({
53
+ id: "unity:component:carousel:a11y:carousel:label",
54
+ defaultMessage: "Carousel"
55
+ }),
56
+ slideAriaLabel: g(e),
57
+ liveRegionContent: c(e)
58
+ };
59
+ }
60
+ export {
61
+ d as createCarouselAccessibilityOptions,
62
+ c as createLiveRegionContent,
63
+ g as createSlideAriaLabel
64
+ };
@@ -0,0 +1,21 @@
1
+ import { EmblaCarouselType } from 'embla-carousel';
2
+ import { KeyboardEvent, RefObject } from 'react';
3
+ export interface UseCarouselAccessibilityOptions {
4
+ api: EmblaCarouselType | undefined;
5
+ visibleSlideIndexes: ReadonlySet<number>;
6
+ focusedSlideIndex: number | null;
7
+ loop?: boolean;
8
+ goToSlide: (slideIndex: number) => void;
9
+ }
10
+ export interface UseCarouselAccessibilityReturn {
11
+ liveRegionRef: RefObject<HTMLDivElement>;
12
+ a11yIds: {
13
+ root: string;
14
+ track: string;
15
+ previousButton: string;
16
+ nextButton: string;
17
+ title: string;
18
+ };
19
+ onKeyDown: (e: KeyboardEvent<HTMLDivElement>) => void;
20
+ }
21
+ export declare function useCarouselAccessibility({ api, visibleSlideIndexes, focusedSlideIndex, loop, goToSlide, }: UseCarouselAccessibilityOptions): UseCarouselAccessibilityReturn;
@@ -0,0 +1,87 @@
1
+ import { useRef as k, useEffect as _, useCallback as D } from "react";
2
+ import "embla-carousel-accessibility";
3
+ import { useId as x } from "react-aria";
4
+ function E({
5
+ api: e,
6
+ visibleSlideIndexes: d,
7
+ focusedSlideIndex: o,
8
+ loop: u = !1,
9
+ goToSlide: c
10
+ }) {
11
+ const v = k(null), n = k(!1), l = x(), h = {
12
+ root: `carousel-${l}__root`,
13
+ title: `carousel-${l}__title`,
14
+ track: `carousel-${l}__track`,
15
+ previousButton: `carousel-${l}__previous-button`,
16
+ nextButton: `carousel-${l}__next-button`
17
+ };
18
+ _(() => {
19
+ if (!e) return;
20
+ const r = e.plugins().accessibility;
21
+ !r || !v.current || r.setupLiveRegion(v.current);
22
+ }, [e]), _(() => {
23
+ if (!e) return;
24
+ const r = e.slideNodes();
25
+ r.forEach((a, i) => {
26
+ i === o ? (a.setAttribute("tabindex", "0"), a.removeAttribute("inert")) : (a.setAttribute("tabindex", "-1"), d.has(i) ? a.removeAttribute("inert") : a.setAttribute("inert", ""));
27
+ }), n.current && o !== null && (n.current = !1, r[o]?.focus({ preventScroll: !0 }));
28
+ }, [e, d, o]);
29
+ const m = D(
30
+ (r) => {
31
+ if (!e) return;
32
+ const i = e.slideNodes().length, s = o ?? 0;
33
+ switch (r.key) {
34
+ case "ArrowLeft": {
35
+ r.preventDefault();
36
+ const t = s > 0 ? s - 1 : u ? i - 1 : s;
37
+ t !== s && (n.current = !0, c(t));
38
+ break;
39
+ }
40
+ case "ArrowRight": {
41
+ r.preventDefault();
42
+ const t = s < i - 1 ? s + 1 : u ? 0 : s;
43
+ t !== s && (n.current = !0, c(t));
44
+ break;
45
+ }
46
+ case "Home": {
47
+ r.preventDefault(), u || (n.current = !0, c(0));
48
+ break;
49
+ }
50
+ case "End": {
51
+ if (r.preventDefault(), !u) {
52
+ const t = i - 1;
53
+ n.current = !0, c(t);
54
+ }
55
+ break;
56
+ }
57
+ case "PageUp": {
58
+ r.preventDefault();
59
+ const t = e.selectedSnap(), p = e.snapList().length, f = t > 0 ? t - 1 : u ? p - 1 : t;
60
+ if (f !== t) {
61
+ const b = e.internalEngine(), g = b.slidesToScroll.groupSlides(
62
+ b.slideIndexes
63
+ )[f]?.[0];
64
+ g !== void 0 && (n.current = !0, c(g));
65
+ }
66
+ break;
67
+ }
68
+ case "PageDown": {
69
+ r.preventDefault();
70
+ const t = e.selectedSnap(), p = e.snapList().length, f = t < p - 1 ? t + 1 : u ? 0 : t;
71
+ if (f !== t) {
72
+ const b = e.internalEngine(), g = b.slidesToScroll.groupSlides(
73
+ b.slideIndexes
74
+ )[f]?.[0];
75
+ g !== void 0 && (n.current = !0, c(g));
76
+ }
77
+ break;
78
+ }
79
+ }
80
+ },
81
+ [e, u, o, c]
82
+ );
83
+ return { liveRegionRef: v, a11yIds: h, onKeyDown: m };
84
+ }
85
+ export {
86
+ E as useCarouselAccessibility
87
+ };
@@ -0,0 +1,14 @@
1
+ import { EmblaCarouselApi } from '../types.js';
2
+ export interface UseCarouselReturn {
3
+ selectedSnap: number;
4
+ snapCount: number;
5
+ visibleSlideIndexes: Set<number>;
6
+ focusedSlideIndex: number | null;
7
+ goToPrev: () => void;
8
+ goToNext: () => void;
9
+ goTo: (index: number) => void;
10
+ canGoToPrev: () => boolean | undefined;
11
+ canGoToNext: () => boolean | undefined;
12
+ goToSlide: (slideIndex: number) => void;
13
+ }
14
+ export declare function useCarouselState(emblaApi: EmblaCarouselApi): UseCarouselReturn;
@@ -0,0 +1,62 @@
1
+ import { useState as d, useRef as h, useCallback as s, useEffect as L } from "react";
2
+ function y(e) {
3
+ const [I, l] = d(0), [G, x] = d(0), [w, T] = d(
4
+ () => /* @__PURE__ */ new Set()
5
+ ), [N, u] = d(
6
+ null
7
+ ), i = h(!1), c = s(() => {
8
+ if (!e) return { visible: /* @__PURE__ */ new Set(), focused: null };
9
+ const n = e.selectedSnap(), o = e.internalEngine(), t = (o.slidesToScroll.groupSlides(o.slideIndexes)[n] ?? [])[0] ?? null, g = e.slidesInView(), v = new Set(g);
10
+ return t !== null && v.add(t), {
11
+ visible: v,
12
+ focused: t
13
+ };
14
+ }, [e]), S = s(() => {
15
+ if (!e) return;
16
+ const n = e.selectedSnap();
17
+ l(n);
18
+ const o = c();
19
+ T(o.visible), i.current || u(o.focused);
20
+ }, [e, c]), f = s(() => {
21
+ if (!e) return;
22
+ x(e.snapList().length);
23
+ const n = e.selectedSnap();
24
+ l(n);
25
+ }, [e]);
26
+ L(() => {
27
+ if (!e) return;
28
+ x(e.snapList().length);
29
+ const n = c();
30
+ return T(n.visible), u(n.focused), e.on("select", S), e.on("resize", f), () => {
31
+ e.off("select", S), e.off("resize", f);
32
+ };
33
+ }, [e, S, f, c]);
34
+ const C = s(() => e?.goToPrev(), [e]), P = s(() => e?.goToNext(), [e]), a = s((n) => e?.goTo(n), [e]), z = s(() => e?.canGoToPrev(), [e]), E = s(() => e?.canGoToNext(), [e]), R = s(
35
+ (n) => {
36
+ if (!e) return;
37
+ i.current = !0, u(n);
38
+ const o = e.internalEngine(), r = o.slidesToScroll.groupSlides(o.slideIndexes).findIndex(
39
+ (g) => g.includes(n)
40
+ ), t = e.selectedSnap();
41
+ r !== -1 && r !== t && e.goTo(r), setTimeout(() => {
42
+ i.current = !1;
43
+ }, 0);
44
+ },
45
+ [e]
46
+ );
47
+ return {
48
+ selectedSnap: I,
49
+ snapCount: G,
50
+ visibleSlideIndexes: w,
51
+ focusedSlideIndex: N,
52
+ goToPrev: C,
53
+ goToNext: P,
54
+ goTo: a,
55
+ canGoToPrev: z,
56
+ canGoToNext: E,
57
+ goToSlide: R
58
+ };
59
+ }
60
+ export {
61
+ y as useCarouselState
62
+ };
@@ -0,0 +1,103 @@
1
+ import { PropsWithChildren } from 'react';
2
+ import { ResponsiveValue } from '../../../hooks/use-responsive-value.js';
3
+ import { SpacingToken } from '../../../utils/spacing.js';
4
+ export declare const carouselContent: import('tailwind-variants').TVReturnType<{
5
+ [key: string]: {
6
+ [key: string]: import('tailwind-merge').ClassNameValue | {
7
+ track?: import('tailwind-merge').ClassNameValue;
8
+ root?: import('tailwind-merge').ClassNameValue;
9
+ };
10
+ };
11
+ } | {
12
+ [x: string]: {
13
+ [x: string]: import('tailwind-merge').ClassNameValue | {
14
+ track?: import('tailwind-merge').ClassNameValue;
15
+ root?: import('tailwind-merge').ClassNameValue;
16
+ };
17
+ };
18
+ } | {}, {
19
+ root: string[];
20
+ track: string[];
21
+ }, undefined, {
22
+ [key: string]: {
23
+ [key: string]: import('tailwind-merge').ClassNameValue | {
24
+ track?: import('tailwind-merge').ClassNameValue;
25
+ root?: import('tailwind-merge').ClassNameValue;
26
+ };
27
+ };
28
+ } | {}, {
29
+ root: string[];
30
+ track: string[];
31
+ }, import('tailwind-variants').TVReturnType<unknown, {
32
+ root: string[];
33
+ track: string[];
34
+ }, undefined, unknown, unknown, undefined>>;
35
+ export interface CarouselContentProps extends PropsWithChildren {
36
+ /**
37
+ * Number of slides visible at once, optionally configured per breakpoint.
38
+ * @example
39
+ * itemsPerPage={3}
40
+ * itemsPerPage={{ base: 1, md: 2, lg: 3 }}
41
+ */
42
+ itemsPerPage?: number | ResponsiveValue<number>;
43
+ /** Gap between slides — Unity spacing token only (e.g. `'$200'`). */
44
+ gap?: SpacingToken | ResponsiveValue<SpacingToken>;
45
+ /** Additional padding to add to the first and last slides, for visual alignment purposes */
46
+ trackPadding?: {
47
+ start?: SpacingToken | ResponsiveValue<SpacingToken>;
48
+ end?: SpacingToken | ResponsiveValue<SpacingToken>;
49
+ };
50
+ /** Additional CSS classes for the viewport element. */
51
+ className?: string;
52
+ /**
53
+ * Negative horizontal margin to apply to the carousel viewport, for cases where you place the carousel inside a padded container
54
+ */
55
+ trackOffset?: number | SpacingToken | ResponsiveValue<number | SpacingToken>;
56
+ }
57
+ /**
58
+ * The scrollable viewport that houses carousel slides.
59
+ * `CarouselContent` controls the visual layout of the carousel: how many slides are visible
60
+ * at once, spacing between slides, and optional padding to create a "peek" effect showing
61
+ * adjacent slides.
62
+ * ## Layout Control
63
+ * - **itemsPerPage**: Number of slides visible at once (supports fractional values like `2.5`)
64
+ * - **gap**: Spacing between slides (Unity spacing tokens only, e.g., `'$200'`)
65
+ * - **trackPadding**: Padding on start/end edges to align with the header, in cases where you use `trackOffset`
66
+ * - **trackOffset**: Horizontal offset to align slides with page content
67
+ * ## Responsive Layout
68
+ * All layout props support responsive values using the `{ base, md, lg }` syntax:
69
+ * @example
70
+ * ```tsx
71
+ * <CarouselContent
72
+ * itemsPerPage={{ base: 1, md: 2, lg: 3 }}
73
+ * gap={{ base: '$100', md: '$200' }}
74
+ * trackPadding={{ end: { base: '$100', md: '$200' } }}
75
+ * >
76
+ * <CarouselSlide>Slide 1</CarouselSlide>
77
+ * <CarouselSlide>Slide 2</CarouselSlide>
78
+ * </CarouselContent>
79
+ * ```
80
+ * ## Fractional Items Per Page
81
+ * Use fractional values to create a "bleeding" effect where the next slide is partially visible:
82
+ * @example
83
+ * ```tsx
84
+ * <CarouselContent itemsPerPage={2.3} gap="$200">
85
+ * <CarouselSlide>Slide 1</CarouselSlide>
86
+ * <CarouselSlide>Slide 2</CarouselSlide>
87
+ * <CarouselSlide>Slide 3</CarouselSlide>
88
+ * </CarouselContent>
89
+ * ```
90
+ * @param {CarouselContentProps} props - Component props
91
+ * @param {CarouselContentProps['itemsPerPage']} props.itemsPerPage - Number of slides visible at once
92
+ * @param {CarouselContentProps['gap']} props.gap - Spacing between slides (Unity spacing tokens)
93
+ * @param {CarouselContentProps['trackPadding']} props.trackPadding - Padding to reveal adjacent slides
94
+ * @param {CarouselContentProps['trackOffset']} props.trackOffset - Horizontal offset for alignment
95
+ * @param {CarouselContentProps['className']} props.className - Additional CSS classes
96
+ * @param {CarouselContentProps['children']} props.children - CarouselSlide components
97
+ * @see {@link CarouselContentProps} for all available props
98
+ */
99
+ declare function CarouselContent({ className, children, itemsPerPage: responsiveItemsPerPage, gap: responsiveGap, trackPadding: responsiveTrackPadding, trackOffset: responsiveTrackOffset, }: CarouselContentProps): import("react/jsx-runtime").JSX.Element;
100
+ declare namespace CarouselContent {
101
+ var displayName: string;
102
+ }
103
+ export { CarouselContent };