@latte-macchiat-io/latte-vanilla-components 0.0.190 → 0.0.192

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 (101) hide show
  1. package/README.md +16 -6
  2. package/package.json +4 -1
  3. package/src/components/Actions/index.tsx +20 -0
  4. package/src/components/Actions/styles.css.ts +54 -0
  5. package/src/components/Button/index.tsx +29 -0
  6. package/src/components/Button/stories.tsx +4 -22
  7. package/src/components/Button/styles.css.ts +131 -0
  8. package/src/components/Carousel/{Carousel.tsx → index.tsx} +18 -115
  9. package/src/components/Carousel/styles.css.ts +176 -0
  10. package/src/components/Columns/index.tsx +36 -0
  11. package/src/components/Columns/styles.css.ts +70 -0
  12. package/src/components/ConsentCookie/ConsentCookie.css.ts +1 -1
  13. package/src/components/ConsentCookie/ConsentCookie.tsx +3 -3
  14. package/src/components/Footer/index.tsx +21 -0
  15. package/src/components/Footer/styles.css.ts +33 -0
  16. package/src/components/Form/Form.css.ts +1 -1
  17. package/src/components/Form/Row/Row.css.ts +1 -1
  18. package/src/components/Form/TextField/Input/Input.css.ts +1 -1
  19. package/src/components/Form/TextField/Label/Label.css.ts +1 -1
  20. package/src/components/Form/TextField/TextField.css.ts +1 -1
  21. package/src/components/Form/TextField/Textarea/Textarea.css.ts +1 -1
  22. package/src/components/Header/index.tsx +53 -0
  23. package/src/components/Header/styles.css.ts +89 -0
  24. package/src/components/Heading/index.tsx +22 -0
  25. package/src/components/Heading/styles.css.ts +66 -0
  26. package/src/components/Heading/types.tsx +1 -0
  27. package/src/components/Icon/index.tsx +25 -0
  28. package/src/components/Icon/style.css.ts +11 -0
  29. package/src/components/KeyNumber/index.tsx +51 -0
  30. package/src/components/KeyNumber/styles.css.ts +76 -0
  31. package/src/components/LanguageSwitcher/index.tsx +80 -0
  32. package/src/components/LanguageSwitcher/{LanguageSwitcher.css.ts → styles.css.ts} +1 -1
  33. package/src/components/Logo/index.tsx +13 -0
  34. package/src/components/Logo/styles.css.ts +14 -0
  35. package/src/components/Main/index.tsx +17 -0
  36. package/src/components/Main/styles.css.ts +14 -0
  37. package/src/components/Modal/index.tsx +42 -0
  38. package/src/components/Modal/stories.tsx +14 -358
  39. package/src/components/Modal/styles.css.ts +90 -0
  40. package/src/components/Nav/index.tsx +22 -0
  41. package/src/components/Nav/styles.css.ts +30 -0
  42. package/src/components/NavLegal/index.tsx +17 -0
  43. package/src/components/NavLegal/styles.css.ts +20 -0
  44. package/src/components/NavSocial/index.tsx +32 -0
  45. package/src/components/NavSocial/styles.css.ts +33 -0
  46. package/src/components/Section/index.tsx +20 -0
  47. package/src/components/Section/stories.tsx +5 -57
  48. package/src/components/Section/styles.css.ts +106 -0
  49. package/src/components/ThemeTest/ThemeTest.css.ts +11 -0
  50. package/src/components/ThemeTest/ThemeTest.tsx +12 -0
  51. package/src/components/ThemeToggle/ThemeToggle.tsx +30 -0
  52. package/src/components/Video/index.tsx +117 -0
  53. package/src/components/Video/styles.css.ts +200 -0
  54. package/src/index.ts +29 -41
  55. package/src/styles/mediaqueries.ts +2 -0
  56. package/src/styles/sprinkles.css.ts +11 -8
  57. package/src/theme/baseThemeValues.ts +1235 -0
  58. package/src/theme/contract.css.ts +676 -0
  59. package/src/{themes → theme}/createTheme.ts +40 -1
  60. package/src/theme/default.css.ts +10 -0
  61. package/src/utils/combineResponsive.ts +9 -0
  62. package/src/utils/generateResponsiveMedia.ts +19 -0
  63. package/src/components/Actions/Actions.css.ts +0 -113
  64. package/src/components/Actions/Actions.tsx +0 -132
  65. package/src/components/Button/Button.css.ts +0 -119
  66. package/src/components/Button/Button.tsx +0 -132
  67. package/src/components/Carousel/Carousel.css.ts +0 -179
  68. package/src/components/Columns/Columns.css.ts +0 -185
  69. package/src/components/Columns/Columns.tsx +0 -142
  70. package/src/components/Footer/Footer.css.ts +0 -108
  71. package/src/components/Footer/Footer.tsx +0 -130
  72. package/src/components/Header/Header.css.ts +0 -111
  73. package/src/components/Header/Header.tsx +0 -158
  74. package/src/components/Icon/Icon.css.ts +0 -101
  75. package/src/components/Icon/Icon.tsx +0 -159
  76. package/src/components/KeyNumber/KeyNumber.css.ts +0 -158
  77. package/src/components/KeyNumber/KeyNumber.tsx +0 -166
  78. package/src/components/LanguageSwitcher/LanguageSwitcher.tsx +0 -168
  79. package/src/components/Logo/Logo.css.ts +0 -98
  80. package/src/components/Logo/Logo.tsx +0 -137
  81. package/src/components/Main/Main.css.ts +0 -62
  82. package/src/components/Main/Main.tsx +0 -130
  83. package/src/components/Modal/Modal.css.ts +0 -203
  84. package/src/components/Modal/Modal.tsx +0 -194
  85. package/src/components/Nav/Nav.css.ts +0 -123
  86. package/src/components/Nav/Nav.tsx +0 -130
  87. package/src/components/NavLegal/NavLegal.css.ts +0 -121
  88. package/src/components/NavLegal/NavLegal.tsx +0 -133
  89. package/src/components/NavSocial/NavSocial.css.ts +0 -121
  90. package/src/components/NavSocial/NavSocial.tsx +0 -169
  91. package/src/components/Section/Section.css.ts +0 -101
  92. package/src/components/Section/Section.tsx +0 -130
  93. package/src/components/Video/Video.css.ts +0 -210
  94. package/src/components/Video/Video.tsx +0 -243
  95. package/src/components/VideoFullWidth/VideoFullWidth.css.ts +0 -50
  96. package/src/components/VideoFullWidth/VideoFullWidth.tsx +0 -152
  97. package/src/components/VideoFullWidth/export.tsx +0 -2
  98. package/src/themes/baseThemeValues.ts +0 -160
  99. package/src/themes/contract.css.ts +0 -83
  100. package/src/types/withClassName.ts +0 -4
  101. /package/src/{utils → components/ConsentCookie}/cookie.ts +0 -0
package/README.md CHANGED
@@ -1,7 +1,9 @@
1
- # 🥤 Latte Vanilla Components
1
+ # 🥤 Latte Vanilla Components [![npm version](https://img.shields.io/npm/v/@latte-macchiat-io/latte-vanilla-components?style=flat-square)](https://www.npmjs.com/package/@latte-macchiat-io/latte-vanilla-components)
2
2
 
3
- Beautiful, type-safe React components powered by Vanilla Extract CSS. Build modern interfaces with a professional design
4
- system that's both powerful and easy to use.
3
+ Beautiful, type-safe React components powered by Vanilla Extract CSS for amazing projects, with a touch of Vanilla 🥤
4
+
5
+ Intended for internal use by the 👩‍💻🧑‍💻 [latte-macchiat.io](https://latte-macchiat.io) team, we can't offer official support, but feel free to reach out
6
+ with questions, feedback or project ideas!
5
7
 
6
8
  ## ✨ Features
7
9
 
@@ -12,6 +14,14 @@ system that's both powerful and easy to use.
12
14
  - ⚡ **Developer Experience** - Hot reloading, IntelliSense, documentation
13
15
  - 🎯 **Production Ready** - Optimized builds, minimal bundle size
14
16
 
17
+ ## 🤓 Philosophy
18
+
19
+ This library is shipped as raw code (ESM + TypeScript) to be compiled in your project, allowing full
20
+ customization and tree-shaking. It is not a pre-built design system, but rather a set of building blocks
21
+ to create your own unique designs.
22
+
23
+ You will need to set up Vanilla Extract in your build system (Next.js, Vite, etc.) to use this library.
24
+
15
25
  ## 📦 Installation
16
26
 
17
27
  ```bash
@@ -30,7 +40,7 @@ yarn add @latte-macchiat-io/latte-vanilla-components
30
40
 
31
41
  ```typescript
32
42
  // src/styles/theme.css.ts
33
- import {createDarkTheme, createLightTheme} from "@latte-macchiat-io/latte-vanilla-components";
43
+ import { createDarkTheme, createLightTheme } from "@latte-macchiat-io/latte-vanilla-components";
34
44
 
35
45
  // Create and apply the default light theme (minimal setup)
36
46
  createLightTheme();
@@ -221,8 +231,8 @@ All components are mobile-first and responsive:
221
231
 
222
232
  ```typescript
223
233
  // next.config.js
224
- import type {NextConfig} from "next";
225
- import {createVanillaExtractPlugin} from "@vanilla-extract/next-plugin";
234
+ import type { NextConfig } from "next";
235
+ import { createVanillaExtractPlugin } from "@vanilla-extract/next-plugin";
226
236
 
227
237
  const nextConfig: NextConfig = {
228
238
  /* config options here */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@latte-macchiat-io/latte-vanilla-components",
3
- "version": "0.0.190",
3
+ "version": "0.0.192",
4
4
  "description": "Beautiful components for amazing projects, with a touch of Vanilla 🥤",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -65,6 +65,9 @@
65
65
  "plugin:storybook/recommended"
66
66
  ]
67
67
  },
68
+ "dependencies": {
69
+ "@vanilla-extract/css-utils": "^0.1.6"
70
+ },
68
71
  "scripts": {
69
72
  "build": "echo \"Source-only distribution - no build needed\"",
70
73
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+
3
+ import { clsx } from 'clsx';
4
+ import { forwardRef } from 'react';
5
+
6
+ import { actionsRecipe, type ActionsVariants } from './styles.css';
7
+
8
+ export type ActionsProps = React.HTMLAttributes<HTMLDivElement> &
9
+ ActionsVariants & {
10
+ css?: string;
11
+ children: React.ReactNode;
12
+ };
13
+
14
+ export const Actions = forwardRef<HTMLDivElement, ActionsProps>(({ align, direction, css, className, children }, ref) => (
15
+ <div ref={ref} className={clsx(actionsRecipe({ align, direction }), css, className)}>
16
+ {children}
17
+ </div>
18
+ ));
19
+
20
+ Actions.displayName = 'Actions';
@@ -0,0 +1,54 @@
1
+ import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
2
+
3
+ import { themeContract } from '../../theme/contract.css';
4
+ import { generateResponsiveMedia } from '../../utils/generateResponsiveMedia';
5
+
6
+ export const actionsRecipe = recipe({
7
+ base: [
8
+ {
9
+ width: '100%',
10
+ display: 'flex',
11
+ flexWrap: 'wrap',
12
+
13
+ '@media': {
14
+ ...generateResponsiveMedia({
15
+ gap: themeContract.actions.gap,
16
+ paddingTop: themeContract.actions.paddingBottom,
17
+ paddingBottom: themeContract.actions.paddingBottom,
18
+ }),
19
+ },
20
+ },
21
+ ],
22
+
23
+ variants: {
24
+ align: {
25
+ left: {
26
+ alignItems: 'flex-start',
27
+ justifyContent: 'flex-start',
28
+ },
29
+ center: {
30
+ alignItems: 'center',
31
+ justifyContent: 'center',
32
+ },
33
+ right: {
34
+ alignItems: 'flex-end',
35
+ justifyContent: 'flex-end',
36
+ },
37
+ },
38
+ direction: {
39
+ row: {
40
+ flexDirection: 'row',
41
+ },
42
+ column: {
43
+ flexDirection: 'column',
44
+ },
45
+ },
46
+ },
47
+
48
+ defaultVariants: {
49
+ align: 'left',
50
+ direction: 'row',
51
+ },
52
+ });
53
+
54
+ export type ActionsVariants = RecipeVariants<typeof actionsRecipe>;
@@ -0,0 +1,29 @@
1
+ 'use client';
2
+
3
+ import { clsx } from 'clsx';
4
+ import { type ComponentPropsWithoutRef, forwardRef } from 'react';
5
+
6
+ import { buttonRecipe, type ButtonVariants } from './styles.css';
7
+
8
+ export type ButtonProps = ComponentPropsWithoutRef<'button'> &
9
+ ButtonVariants & {
10
+ css?: string;
11
+ isPending?: boolean;
12
+ isDisabled?: boolean;
13
+ };
14
+
15
+ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
16
+ ({ variant, style, size, fullWidth, isPending = false, isDisabled, css, className, children, onClick }, ref) => {
17
+ return (
18
+ <button
19
+ ref={ref}
20
+ onClick={onClick}
21
+ disabled={isDisabled || isPending}
22
+ className={clsx(buttonRecipe({ variant, style, size, fullWidth }), css, className)}>
23
+ {isPending ? 'Loading…' : children}
24
+ </button>
25
+ );
26
+ }
27
+ );
28
+
29
+ Button.displayName = 'Button';
@@ -1,7 +1,7 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite';
2
2
  import React from 'react';
3
- import { Button } from './Button';
4
- import { Section } from '../Section/Section';
3
+ import { Section } from '../Section';
4
+ import { Button } from '.';
5
5
 
6
6
  const meta: Meta<typeof Button> = {
7
7
  title: 'Interactive Components/Button',
@@ -74,13 +74,6 @@ export const Secondary: Story = {
74
74
  },
75
75
  };
76
76
 
77
- export const Ghost: Story = {
78
- args: {
79
- variant: 'ghost',
80
- children: 'Ghost Button',
81
- },
82
- };
83
-
84
77
  // Size Variants
85
78
  export const Small: Story = {
86
79
  args: {
@@ -141,7 +134,6 @@ export const AllVariants: Story = {
141
134
  <div style={{ display: 'flex', gap: '1rem', flexWrap: 'wrap', alignItems: 'center' }}>
142
135
  <Button variant="primary">Primary</Button>
143
136
  <Button variant="secondary">Secondary</Button>
144
- <Button variant="ghost">Ghost</Button>
145
137
  </div>
146
138
  </Section>
147
139
  ),
@@ -202,15 +194,12 @@ export const InteractiveExample: Story = {
202
194
  <div style={{ display: 'flex', gap: '0.5rem' }}>
203
195
  <Button variant="primary">Save</Button>
204
196
  <Button variant="secondary">Cancel</Button>
205
- <Button variant="danger">Delete</Button>
206
197
  </div>
207
198
  </div>
208
199
 
209
200
  <div>
210
201
  <h3>Navigation</h3>
211
202
  <div style={{ display: 'flex', gap: '0.5rem' }}>
212
- <Button variant="ghost">← Back</Button>
213
- <Button variant="ghost">Skip</Button>
214
203
  <Button variant="primary">Next →</Button>
215
204
  </div>
216
205
  </div>
@@ -231,15 +220,8 @@ export const WithCustomStyling: Story = {
231
220
  render: () => (
232
221
  <Section>
233
222
  <div style={{ display: 'flex', gap: '1rem', flexDirection: 'column' }}>
234
- <Button variant="primary" borderRadius="full" padding="lg">
235
- Rounded Button
236
- </Button>
237
- <Button variant="secondary" fontSize="lg" fontWeight="bold">
238
- Large Text Button
239
- </Button>
240
- <Button variant="ghost" boxShadow="lg">
241
- Shadow Button
242
- </Button>
223
+ <Button variant="primary">Rounded Button</Button>
224
+ <Button variant="secondary">Large Text Button</Button>
243
225
  </div>
244
226
  </Section>
245
227
  ),
@@ -0,0 +1,131 @@
1
+ import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
2
+
3
+ import { themeContract } from '../../theme/contract.css';
4
+ import { generateResponsiveMedia } from '../../utils/generateResponsiveMedia';
5
+
6
+ export const buttonRecipe = recipe({
7
+ base: {
8
+ border: 'none',
9
+ outline: 'none',
10
+ cursor: 'pointer',
11
+ alignItems: 'center',
12
+ textDecoration: 'none',
13
+ display: 'inline-flex',
14
+ justifyContent: 'center',
15
+
16
+ minWidth: themeContract.button.minWidth,
17
+ fontWeight: themeContract.button.fontWeight,
18
+ transition: themeContract.button.transition,
19
+ fontFamily: themeContract.button.fontFamily,
20
+ borderRadius: themeContract.button.borderRadius,
21
+ letterSpacing: themeContract.button.letterSpacing,
22
+
23
+ ':hover': {
24
+ opacity: '0.8',
25
+ },
26
+
27
+ ':active': {},
28
+
29
+ ':focus-visible': {},
30
+
31
+ ':disabled': {
32
+ opacity: '0.5',
33
+ pointerEvents: 'none',
34
+ },
35
+ },
36
+
37
+ variants: {
38
+ variant: {
39
+ primary: {
40
+ color: themeContract.button.variant.primary.color,
41
+ backgroundColor: themeContract.button.variant.primary.backgroundColor,
42
+ },
43
+
44
+ secondary: {
45
+ color: themeContract.button.variant.secondary.color,
46
+ backgroundColor: themeContract.button.variant.secondary.backgroundColor,
47
+ },
48
+ },
49
+
50
+ style: {
51
+ outline: {
52
+ backgroundColor: 'transparent',
53
+ },
54
+ },
55
+
56
+ size: {
57
+ sm: [
58
+ {
59
+ fontSize: themeContract.fontSizes.sm,
60
+
61
+ '@media': {
62
+ ...generateResponsiveMedia({
63
+ paddingTop: themeContract.button.size.small.paddingTop,
64
+ paddingLeft: themeContract.button.size.small.paddingLeft,
65
+ paddingRight: themeContract.button.size.small.paddingRight,
66
+ paddingBottom: themeContract.button.size.small.paddingBottom,
67
+ }),
68
+ },
69
+ },
70
+ ],
71
+ md: [
72
+ {
73
+ fontSize: themeContract.fontSizes.md,
74
+
75
+ '@media': {
76
+ ...generateResponsiveMedia({
77
+ paddingTop: themeContract.button.size.medium.paddingTop,
78
+ paddingLeft: themeContract.button.size.medium.paddingLeft,
79
+ paddingRight: themeContract.button.size.medium.paddingRight,
80
+ paddingBottom: themeContract.button.size.medium.paddingBottom,
81
+ }),
82
+ },
83
+ },
84
+ ],
85
+ lg: [
86
+ {
87
+ fontSize: themeContract.fontSizes.lg,
88
+
89
+ '@media': {
90
+ ...generateResponsiveMedia({
91
+ paddingTop: themeContract.button.size.large.paddingTop,
92
+ paddingLeft: themeContract.button.size.large.paddingLeft,
93
+ paddingRight: themeContract.button.size.large.paddingRight,
94
+ paddingBottom: themeContract.button.size.large.paddingBottom,
95
+ }),
96
+ },
97
+ },
98
+ ],
99
+ },
100
+
101
+ fullWidth: {
102
+ true: {
103
+ width: '100%',
104
+ },
105
+ },
106
+ },
107
+
108
+ compoundVariants: [
109
+ {
110
+ variants: { variant: 'primary', style: 'outline' },
111
+ style: {
112
+ color: themeContract.button.variant.primary.backgroundColor,
113
+ border: `1px solid ${themeContract.button.variant.primary.backgroundColor}`,
114
+ },
115
+ },
116
+ {
117
+ variants: { variant: 'secondary', style: 'outline' },
118
+ style: {
119
+ color: themeContract.button.variant.secondary.backgroundColor,
120
+ border: `1px solid ${themeContract.button.variant.secondary.backgroundColor}`,
121
+ },
122
+ },
123
+ ],
124
+
125
+ defaultVariants: {
126
+ size: 'md',
127
+ variant: 'primary',
128
+ },
129
+ });
130
+
131
+ export type ButtonVariants = RecipeVariants<typeof buttonRecipe>;
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import { clsx } from 'clsx';
3
3
  import { forwardRef, ReactNode, useEffect, useRef, useState } from 'react';
4
+
4
5
  import {
5
6
  carouselBullet,
6
7
  carouselBulletActive,
@@ -12,10 +13,10 @@ import {
12
13
  carouselRecipe,
13
14
  carouselSlide,
14
15
  type CarouselVariants,
15
- } from './Carousel.css';
16
+ } from './styles.css';
17
+
16
18
  import { breakpoints } from '../../styles/mediaqueries';
17
- import { sprinkles, type Sprinkles } from '../../styles/sprinkles.css';
18
- import { Icon } from '../Icon/Icon';
19
+ import { Icon } from '../Icon';
19
20
 
20
21
  interface UseWindowSizeReturn {
21
22
  width: number | undefined;
@@ -45,7 +46,7 @@ const useWindowSize = (): UseWindowSizeReturn => {
45
46
  return windowSize;
46
47
  };
47
48
 
48
- export interface CarouselProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color' | 'gap'>, Sprinkles, NonNullable<CarouselVariants> {
49
+ export interface CarouselProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color' | 'gap'>, NonNullable<CarouselVariants> {
49
50
  css?: string;
50
51
  data: ReactNode[];
51
52
  itemsPerView?: number;
@@ -53,8 +54,7 @@ export interface CarouselProps extends Omit<React.HTMLAttributes<HTMLDivElement>
53
54
  showBullets?: boolean;
54
55
  autoplay?: boolean;
55
56
  autoplayInterval?: number;
56
- gap?: any;
57
- as?: 'div' | 'section';
57
+ gap?: number; // simple px value
58
58
  }
59
59
 
60
60
  export const Carousel = forwardRef<HTMLDivElement, CarouselProps>(
@@ -67,53 +67,9 @@ export const Carousel = forwardRef<HTMLDivElement, CarouselProps>(
67
67
  autoplay = false,
68
68
  autoplayInterval = 3000,
69
69
  gap = 16,
70
- fullWidth,
71
- as: Component = 'div',
70
+ isFullWidth,
72
71
  css,
73
72
  className,
74
- // Extract sprinkles props
75
- margin,
76
- marginTop,
77
- marginBottom,
78
- marginLeft,
79
- marginRight,
80
- padding,
81
- paddingTop,
82
- paddingBottom,
83
- paddingLeft,
84
- paddingRight,
85
- display,
86
- flexDirection,
87
- justifyContent,
88
- flexWrap,
89
- flex,
90
- width,
91
- height,
92
- minWidth,
93
- maxWidth,
94
- minHeight,
95
- position,
96
- top,
97
- bottom,
98
- left,
99
- right,
100
- zIndex,
101
- fontSize,
102
- fontFamily,
103
- lineHeight,
104
- textAlign,
105
- fontWeight,
106
- color,
107
- backgroundColor,
108
- borderRadius,
109
- borderWidth,
110
- borderStyle,
111
- borderColor,
112
- boxShadow,
113
- opacity,
114
- overflow,
115
- overflowX,
116
- overflowY,
117
73
  ...htmlProps
118
74
  },
119
75
  ref
@@ -129,7 +85,7 @@ export const Carousel = forwardRef<HTMLDivElement, CarouselProps>(
129
85
  const isTablet = windowWidth !== undefined && windowWidth > breakpoints.md;
130
86
  const isDesktop = windowWidth !== undefined && windowWidth > breakpoints.lg;
131
87
 
132
- // Calculate visible items based on screen size
88
+ // 🔹 Adapter le nombre d’items visibles selon le viewport
133
89
  useEffect(() => {
134
90
  if (isDesktop) {
135
91
  setVisibleItems(itemsPerView);
@@ -140,7 +96,7 @@ export const Carousel = forwardRef<HTMLDivElement, CarouselProps>(
140
96
  }
141
97
  }, [isTablet, isDesktop, itemsPerView]);
142
98
 
143
- // Calculate item width
99
+ // 🔹 Calcul largeur d’un item
144
100
  useEffect(() => {
145
101
  const calculateItemWidth = () => {
146
102
  if (carouselRef.current) {
@@ -155,7 +111,7 @@ export const Carousel = forwardRef<HTMLDivElement, CarouselProps>(
155
111
  return () => window.removeEventListener('resize', calculateItemWidth);
156
112
  }, [visibleItems, gap]);
157
113
 
158
- // Autoplay functionality
114
+ // 🔹 Autoplay
159
115
  useEffect(() => {
160
116
  if (!autoplay) return;
161
117
 
@@ -169,7 +125,7 @@ export const Carousel = forwardRef<HTMLDivElement, CarouselProps>(
169
125
  return () => clearInterval(interval);
170
126
  }, [autoplay, autoplayInterval, data.length, visibleItems]);
171
127
 
172
- // Touch/swipe handling
128
+ // 🔹 Swipe mobile
173
129
  useEffect(() => {
174
130
  const carousel = carouselRef.current;
175
131
  if (!carousel) return;
@@ -192,10 +148,8 @@ export const Carousel = forwardRef<HTMLDivElement, CarouselProps>(
192
148
 
193
149
  if (Math.abs(diff) > swipeThreshold) {
194
150
  if (diff > 0) {
195
- // Swipe left - next
196
151
  handleNext();
197
152
  } else {
198
- // Swipe right - previous
199
153
  handlePrevious();
200
154
  }
201
155
  }
@@ -228,65 +182,14 @@ export const Carousel = forwardRef<HTMLDivElement, CarouselProps>(
228
182
  const maxIndex = Math.max(0, data.length - visibleItems);
229
183
 
230
184
  return (
231
- <Component
232
- ref={ref as any}
233
- className={clsx(
234
- carouselRecipe({ fullWidth }),
235
- sprinkles({
236
- margin,
237
- marginTop,
238
- marginBottom,
239
- marginLeft,
240
- marginRight,
241
- padding,
242
- paddingTop,
243
- paddingBottom,
244
- paddingLeft,
245
- paddingRight,
246
- display,
247
- flexDirection,
248
- justifyContent,
249
- flexWrap,
250
- flex,
251
- width,
252
- height,
253
- minWidth,
254
- maxWidth,
255
- minHeight,
256
- position,
257
- top,
258
- bottom,
259
- left,
260
- right,
261
- zIndex,
262
- fontSize,
263
- fontFamily,
264
- lineHeight,
265
- textAlign,
266
- fontWeight,
267
- color,
268
- backgroundColor,
269
- borderRadius,
270
- borderWidth,
271
- borderStyle,
272
- borderColor,
273
- boxShadow,
274
- opacity,
275
- overflow,
276
- overflowX,
277
- overflowY,
278
- }),
279
- css,
280
- className
281
- )}
282
- {...htmlProps}>
185
+ <div ref={ref as any} className={clsx(carouselRecipe({ isFullWidth }), css, className)} {...htmlProps}>
283
186
  <div ref={carouselRef} className={carouselContent}>
284
187
  <div
285
188
  ref={slideRef}
286
189
  className={carouselSlide}
287
190
  style={{
288
- transform: `translateX(${translateX}px)`,
289
191
  gap: `${gap}px`,
192
+ transform: `translateX(${translateX}px)`,
290
193
  }}>
291
194
  {data.map((item, index) => (
292
195
  <div key={index} className={carouselItem} style={{ width: `${itemWidth}px` }}>
@@ -299,10 +202,10 @@ export const Carousel = forwardRef<HTMLDivElement, CarouselProps>(
299
202
  {showNavButtons && (
300
203
  <div className={carouselNav}>
301
204
  <button type="button" className={carouselNavButton} onClick={handlePrevious} disabled={currentIndex === 0} aria-label="Previous slide">
302
- <Icon icon="arrowBack" size="md" />
205
+ <Icon icon="arrowBack" />
303
206
  </button>
304
207
  <button type="button" className={carouselNavButton} onClick={handleNext} disabled={currentIndex >= maxIndex} aria-label="Next slide">
305
- <Icon icon="arrowForward" size="md" />
208
+ <Icon icon="arrowForward" />
306
209
  </button>
307
210
  </div>
308
211
  )}
@@ -313,14 +216,14 @@ export const Carousel = forwardRef<HTMLDivElement, CarouselProps>(
313
216
  <button
314
217
  key={index}
315
218
  type="button"
316
- className={clsx(carouselBullet, index === currentIndex && carouselBulletActive)}
317
- onClick={() => handleBulletClick(index)}
318
219
  aria-label={`Go to slide ${index + 1}`}
220
+ onClick={() => handleBulletClick(index)}
221
+ className={clsx(carouselBullet, index === currentIndex && carouselBulletActive)}
319
222
  />
320
223
  ))}
321
224
  </div>
322
225
  )}
323
- </Component>
226
+ </div>
324
227
  );
325
228
  }
326
229
  );