@latte-macchiat-io/latte-vanilla-components 0.0.332 → 0.0.334
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.
package/package.json
CHANGED
@@ -2,42 +2,55 @@
|
|
2
2
|
|
3
3
|
import { clsx } from 'clsx';
|
4
4
|
import { ReactNode, useEffect, useRef, useState } from 'react';
|
5
|
-
|
6
5
|
import {
|
7
6
|
carouselBullet,
|
8
7
|
carouselBulletActive,
|
9
8
|
carouselBullets,
|
10
9
|
carouselContent,
|
10
|
+
type CarouselContentVariants,
|
11
11
|
carouselItem,
|
12
12
|
carouselNav,
|
13
13
|
carouselNavButton,
|
14
|
-
CarouselNavVariants,
|
14
|
+
type CarouselNavVariants,
|
15
15
|
carouselRecipe,
|
16
16
|
carouselSlide,
|
17
17
|
type CarouselVariants,
|
18
18
|
} from './styles.css';
|
19
|
-
|
20
19
|
import { breakpoints } from '../../styles/mediaqueries';
|
21
|
-
|
22
20
|
import { useWindowSize } from '../../utils/useWindowSize';
|
23
|
-
|
24
21
|
import { Icon } from '../Icon';
|
25
22
|
|
26
23
|
export type CarouselProps = React.HTMLAttributes<HTMLDivElement> &
|
27
24
|
CarouselVariants &
|
28
|
-
CarouselNavVariants &
|
29
|
-
|
25
|
+
CarouselNavVariants &
|
26
|
+
CarouselContentVariants & {
|
30
27
|
data: ReactNode[];
|
28
|
+
gap?: number | Partial<Record<keyof typeof breakpoints, number>>;
|
31
29
|
itemsPerView?: number;
|
32
30
|
showBullets?: boolean;
|
33
31
|
showNavButtons?: boolean;
|
34
|
-
|
35
32
|
autoplay?: boolean;
|
36
33
|
autoplayInterval?: number;
|
37
34
|
};
|
38
35
|
|
36
|
+
const getResponsiveValue = (values: number | Partial<Record<keyof typeof breakpoints, number>>, width: number | undefined): number => {
|
37
|
+
if (typeof values === 'number') return values;
|
38
|
+
|
39
|
+
const bpOrder: (keyof typeof breakpoints)[] = ['mobile', 'sm', 'md', 'lg', 'xl', '2xl'];
|
40
|
+
let currentValue: number = values.mobile ?? 0;
|
41
|
+
|
42
|
+
for (const bp of bpOrder) {
|
43
|
+
if (width && width >= breakpoints[bp] && values[bp] !== undefined) {
|
44
|
+
currentValue = values[bp]!;
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
return currentValue;
|
49
|
+
};
|
50
|
+
|
39
51
|
export const Carousel = ({
|
40
52
|
data,
|
53
|
+
overflow,
|
41
54
|
itemsPerView = 1,
|
42
55
|
showNavButtons = false,
|
43
56
|
showBullets = false,
|
@@ -60,7 +73,6 @@ export const Carousel = ({
|
|
60
73
|
const isTablet = windowWidth !== undefined && windowWidth > breakpoints.md;
|
61
74
|
const isDesktop = windowWidth !== undefined && windowWidth > breakpoints.lg;
|
62
75
|
|
63
|
-
// Adapter le nombre d’items visibles selon le viewport
|
64
76
|
useEffect(() => {
|
65
77
|
if (isDesktop) {
|
66
78
|
setVisibleItems(itemsPerView);
|
@@ -71,12 +83,12 @@ export const Carousel = ({
|
|
71
83
|
}
|
72
84
|
}, [isTablet, isDesktop, itemsPerView]);
|
73
85
|
|
74
|
-
// Calcul largeur d’un item
|
75
86
|
useEffect(() => {
|
76
87
|
const calculateItemWidth = () => {
|
77
88
|
if (carouselRef.current) {
|
78
89
|
const containerWidth = carouselRef.current.getBoundingClientRect().width;
|
79
|
-
const
|
90
|
+
const currentGap = getResponsiveValue(gap, windowWidth);
|
91
|
+
const totalGap = (visibleItems - 1) * currentGap;
|
80
92
|
setItemWidth((containerWidth - totalGap) / visibleItems);
|
81
93
|
}
|
82
94
|
};
|
@@ -84,23 +96,19 @@ export const Carousel = ({
|
|
84
96
|
calculateItemWidth();
|
85
97
|
window.addEventListener('resize', calculateItemWidth);
|
86
98
|
return () => window.removeEventListener('resize', calculateItemWidth);
|
87
|
-
}, [visibleItems, gap]);
|
99
|
+
}, [visibleItems, gap, windowWidth]);
|
88
100
|
|
89
|
-
// Autoplay
|
90
101
|
useEffect(() => {
|
91
102
|
if (!autoplay) return;
|
92
|
-
|
93
103
|
const interval = setInterval(() => {
|
94
104
|
setCurrentIndex((prev) => {
|
95
105
|
const maxIndex = Math.max(0, data.length - visibleItems);
|
96
106
|
return prev >= maxIndex ? 0 : prev + 1;
|
97
107
|
});
|
98
108
|
}, autoplayInterval);
|
99
|
-
|
100
109
|
return () => clearInterval(interval);
|
101
110
|
}, [autoplay, autoplayInterval, data.length, visibleItems]);
|
102
111
|
|
103
|
-
// Swipe mobile
|
104
112
|
useEffect(() => {
|
105
113
|
const carousel = carouselRef.current;
|
106
114
|
if (!carousel) return;
|
@@ -153,17 +161,18 @@ export const Carousel = ({
|
|
153
161
|
setCurrentIndex(Math.min(index, maxIndex));
|
154
162
|
};
|
155
163
|
|
156
|
-
const
|
164
|
+
const currentGap = getResponsiveValue(gap, windowWidth);
|
165
|
+
const translateX = -(currentIndex * (itemWidth + currentGap));
|
157
166
|
const maxIndex = Math.max(0, data.length - visibleItems);
|
158
167
|
|
159
168
|
return (
|
160
169
|
<div className={clsx(carouselRecipe({ isFullWidth }), className)}>
|
161
|
-
<div ref={carouselRef} className={carouselContent}>
|
170
|
+
<div ref={carouselRef} className={carouselContent({ overflow })}>
|
162
171
|
<div
|
163
172
|
ref={slideRef}
|
164
173
|
className={carouselSlide}
|
165
174
|
style={{
|
166
|
-
gap: `${
|
175
|
+
gap: `${currentGap}px`,
|
167
176
|
transform: `translateX(${translateX}px)`,
|
168
177
|
}}>
|
169
178
|
{data.map((item, index) => (
|
@@ -56,11 +56,23 @@ export const carouselRecipe = recipe(
|
|
56
56
|
'carousel'
|
57
57
|
);
|
58
58
|
|
59
|
-
export const carouselContent =
|
59
|
+
export const carouselContent = recipe(
|
60
60
|
{
|
61
|
-
|
62
|
-
|
63
|
-
|
61
|
+
base: {
|
62
|
+
width: '100%',
|
63
|
+
position: 'relative',
|
64
|
+
},
|
65
|
+
|
66
|
+
variants: {
|
67
|
+
overflow: {
|
68
|
+
hidden: { overflow: 'hidden' },
|
69
|
+
visible: { overflow: 'visible' },
|
70
|
+
},
|
71
|
+
},
|
72
|
+
|
73
|
+
defaultVariants: {
|
74
|
+
overflow: 'hidden',
|
75
|
+
},
|
64
76
|
},
|
65
77
|
'carousel-content'
|
66
78
|
);
|
@@ -254,4 +266,5 @@ export const carouselBulletActive = style(
|
|
254
266
|
);
|
255
267
|
|
256
268
|
export type CarouselVariants = RecipeVariants<typeof carouselRecipe>;
|
269
|
+
export type CarouselContentVariants = RecipeVariants<typeof carouselContent>;
|
257
270
|
export type CarouselNavVariants = RecipeVariants<typeof carouselNav>;
|