@latte-macchiat-io/latte-vanilla-components 0.0.333 → 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,7 +2,6 @@
|
|
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,
|
@@ -17,27 +16,38 @@ import {
|
|
17
16
|
carouselSlide,
|
18
17
|
type CarouselVariants,
|
19
18
|
} from './styles.css';
|
20
|
-
|
21
19
|
import { breakpoints } from '../../styles/mediaqueries';
|
22
|
-
|
23
20
|
import { useWindowSize } from '../../utils/useWindowSize';
|
24
|
-
|
25
21
|
import { Icon } from '../Icon';
|
26
22
|
|
27
23
|
export type CarouselProps = React.HTMLAttributes<HTMLDivElement> &
|
28
24
|
CarouselVariants &
|
29
25
|
CarouselNavVariants &
|
30
26
|
CarouselContentVariants & {
|
31
|
-
gap?: number;
|
32
27
|
data: ReactNode[];
|
28
|
+
gap?: number | Partial<Record<keyof typeof breakpoints, number>>;
|
33
29
|
itemsPerView?: number;
|
34
30
|
showBullets?: boolean;
|
35
31
|
showNavButtons?: boolean;
|
36
|
-
|
37
32
|
autoplay?: boolean;
|
38
33
|
autoplayInterval?: number;
|
39
34
|
};
|
40
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
|
+
|
41
51
|
export const Carousel = ({
|
42
52
|
data,
|
43
53
|
overflow,
|
@@ -63,7 +73,6 @@ export const Carousel = ({
|
|
63
73
|
const isTablet = windowWidth !== undefined && windowWidth > breakpoints.md;
|
64
74
|
const isDesktop = windowWidth !== undefined && windowWidth > breakpoints.lg;
|
65
75
|
|
66
|
-
// Adapter le nombre d’items visibles selon le viewport
|
67
76
|
useEffect(() => {
|
68
77
|
if (isDesktop) {
|
69
78
|
setVisibleItems(itemsPerView);
|
@@ -74,12 +83,12 @@ export const Carousel = ({
|
|
74
83
|
}
|
75
84
|
}, [isTablet, isDesktop, itemsPerView]);
|
76
85
|
|
77
|
-
// Calcul largeur d’un item
|
78
86
|
useEffect(() => {
|
79
87
|
const calculateItemWidth = () => {
|
80
88
|
if (carouselRef.current) {
|
81
89
|
const containerWidth = carouselRef.current.getBoundingClientRect().width;
|
82
|
-
const
|
90
|
+
const currentGap = getResponsiveValue(gap, windowWidth);
|
91
|
+
const totalGap = (visibleItems - 1) * currentGap;
|
83
92
|
setItemWidth((containerWidth - totalGap) / visibleItems);
|
84
93
|
}
|
85
94
|
};
|
@@ -87,23 +96,19 @@ export const Carousel = ({
|
|
87
96
|
calculateItemWidth();
|
88
97
|
window.addEventListener('resize', calculateItemWidth);
|
89
98
|
return () => window.removeEventListener('resize', calculateItemWidth);
|
90
|
-
}, [visibleItems, gap]);
|
99
|
+
}, [visibleItems, gap, windowWidth]);
|
91
100
|
|
92
|
-
// Autoplay
|
93
101
|
useEffect(() => {
|
94
102
|
if (!autoplay) return;
|
95
|
-
|
96
103
|
const interval = setInterval(() => {
|
97
104
|
setCurrentIndex((prev) => {
|
98
105
|
const maxIndex = Math.max(0, data.length - visibleItems);
|
99
106
|
return prev >= maxIndex ? 0 : prev + 1;
|
100
107
|
});
|
101
108
|
}, autoplayInterval);
|
102
|
-
|
103
109
|
return () => clearInterval(interval);
|
104
110
|
}, [autoplay, autoplayInterval, data.length, visibleItems]);
|
105
111
|
|
106
|
-
// Swipe mobile
|
107
112
|
useEffect(() => {
|
108
113
|
const carousel = carouselRef.current;
|
109
114
|
if (!carousel) return;
|
@@ -156,7 +161,8 @@ export const Carousel = ({
|
|
156
161
|
setCurrentIndex(Math.min(index, maxIndex));
|
157
162
|
};
|
158
163
|
|
159
|
-
const
|
164
|
+
const currentGap = getResponsiveValue(gap, windowWidth);
|
165
|
+
const translateX = -(currentIndex * (itemWidth + currentGap));
|
160
166
|
const maxIndex = Math.max(0, data.length - visibleItems);
|
161
167
|
|
162
168
|
return (
|
@@ -166,7 +172,7 @@ export const Carousel = ({
|
|
166
172
|
ref={slideRef}
|
167
173
|
className={carouselSlide}
|
168
174
|
style={{
|
169
|
-
gap: `${
|
175
|
+
gap: `${currentGap}px`,
|
170
176
|
transform: `translateX(${translateX}px)`,
|
171
177
|
}}>
|
172
178
|
{data.map((item, index) => (
|