@latte-macchiat-io/latte-vanilla-components 0.0.177 → 0.0.179

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 (72) hide show
  1. package/package.json +3 -1
  2. package/src/assets/styles/mediaqueries.tsx +24 -0
  3. package/src/components/Actions/Actions.tsx +132 -0
  4. package/src/components/Actions/export.tsx +4 -0
  5. package/src/components/{Main/stories.ts → Actions/stories.tsx} +14 -13
  6. package/src/components/Button/Button.tsx +132 -0
  7. package/src/components/Button/export.tsx +5 -0
  8. package/src/components/Carousel/Carousel.tsx +328 -0
  9. package/src/components/Carousel/export.tsx +4 -0
  10. package/src/components/Columns/Columns.tsx +142 -0
  11. package/src/components/Columns/export.tsx +5 -0
  12. package/src/components/ConsentCookie/ConsentCookie.tsx +202 -0
  13. package/src/components/ConsentCookie/export.tsx +4 -0
  14. package/src/components/{Icon/stories.ts → ConsentCookie/stories.tsx} +7 -8
  15. package/src/components/Footer/Footer.tsx +130 -0
  16. package/src/components/Footer/export.tsx +4 -0
  17. package/src/components/Footer/stories.tsx +26 -0
  18. package/src/components/Form/Form.tsx +127 -0
  19. package/src/components/Form/Row/Row.tsx +137 -0
  20. package/src/components/Form/Row/index.tsx +0 -0
  21. package/src/components/Form/Row/stories.tsx +41 -0
  22. package/src/components/Form/TextField/Input/Input.tsx +139 -0
  23. package/src/components/Form/TextField/Input/export.tsx +6 -0
  24. package/src/components/Form/TextField/Label/Label.tsx +133 -0
  25. package/src/components/Form/TextField/Label/export.tsx +4 -0
  26. package/src/components/Form/TextField/TextField.tsx +200 -0
  27. package/src/components/Form/TextField/Textarea/Textarea.tsx +135 -0
  28. package/src/components/Form/TextField/Textarea/export.tsx +6 -0
  29. package/src/components/Form/TextField/Textarea/stories.tsx +44 -0
  30. package/src/components/Form/TextField/export.tsx +4 -0
  31. package/src/components/Form/export.tsx +4 -0
  32. package/src/components/Header/Header.tsx +158 -0
  33. package/src/components/Header/HeaderOverlay/index.tsx +32 -0
  34. package/src/components/Header/ToggleNav/index.tsx +32 -0
  35. package/src/components/Header/export.tsx +4 -0
  36. package/src/components/Header/stories.tsx +26 -0
  37. package/src/components/Icon/Icon.tsx +159 -0
  38. package/src/components/Icon/export.tsx +4 -0
  39. package/src/components/KeyNumber/KeyNumber.tsx +166 -0
  40. package/src/components/KeyNumber/export.tsx +4 -0
  41. package/src/components/LanguageSwitcher/LanguageSwitcher.tsx +168 -0
  42. package/src/components/LanguageSwitcher/export.tsx +4 -0
  43. package/src/components/Logo/Logo.tsx +137 -0
  44. package/src/components/Logo/export.tsx +4 -0
  45. package/src/components/Logo/stories.tsx +28 -0
  46. package/src/components/Main/Main.tsx +130 -0
  47. package/src/components/Main/export.tsx +4 -0
  48. package/src/components/Modal/Modal.tsx +194 -0
  49. package/src/components/Modal/export.tsx +4 -0
  50. package/src/components/Modal/types.tsx +5 -0
  51. package/src/components/Nav/Nav.tsx +129 -0
  52. package/src/components/Nav/export.tsx +4 -0
  53. package/src/components/Nav/stories.tsx +28 -0
  54. package/src/components/NavLegal/NavLegal.tsx +133 -0
  55. package/src/components/NavLegal/export.tsx +4 -0
  56. package/src/components/NavLegal/stories.tsx +28 -0
  57. package/src/components/NavLegal/types.tsx +1 -0
  58. package/src/components/NavSocial/NavSocial.tsx +169 -0
  59. package/src/components/NavSocial/export.tsx +5 -0
  60. package/src/components/{Columns/stories.ts → NavSocial/stories.tsx} +12 -14
  61. package/src/components/NavSocial/types.tsx +1 -0
  62. package/src/components/Section/Section.tsx +130 -0
  63. package/src/components/Section/export.tsx +6 -0
  64. package/src/components/ToRemove/ToRemove.tsx +3 -0
  65. package/src/components/Video/Video.tsx +243 -0
  66. package/src/components/Video/export.tsx +2 -0
  67. package/src/components/VideoFullWidth/VideoFullWidth.tsx +152 -0
  68. package/src/components/VideoFullWidth/export.tsx +2 -0
  69. package/src/index.ts +1 -1
  70. package/src/components/Button/stories.ts +0 -127
  71. package/src/components/Section/stories.ts +0 -64
  72. /package/src/utils/{theme.css.ts → theme.ts} +0 -0
@@ -0,0 +1,5 @@
1
+ // export { NavSocial } from '.';
2
+ // export type { NavSocialProps } from '.';
3
+
4
+ // export type { Social as SocialType } from './types';
5
+ // export { styles as NavSocialStyles } from './styles.css';
@@ -1,10 +1,11 @@
1
1
  // import type { Meta, StoryObj } from '@storybook/react';
2
- // import { Columns } from '.';
2
+ //
3
+ // import { NavSocial } from '../../index';
3
4
  //
4
5
  // // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
5
- // const meta = {
6
- // title: 'Latte Components / Layout / Columns',
7
- // component: Columns,
6
+ // const meta: Meta<typeof NavSocial> = {
7
+ // title: 'Latte Components / 6. Nav / Social',
8
+ // component: NavSocial,
8
9
  // parameters: {
9
10
  // // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
10
11
  // layout: 'centered',
@@ -14,7 +15,7 @@
14
15
  // // More on argTypes: https://storybook.js.org/docs/api/argtypes
15
16
  // argTypes: {},
16
17
  // // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
17
- // } satisfies Meta<typeof Columns>;
18
+ // };
18
19
  //
19
20
  // export default meta;
20
21
  // type Story = StoryObj<typeof meta>;
@@ -22,14 +23,11 @@
22
23
  // // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
23
24
  // export const Default: Story = {
24
25
  // args: {
25
- // columns: [6, 6],
26
- // children: '<div>Column 1</div> <div>Column 2</div>',
27
- // },
28
- // };
29
- //
30
- // export const Default3Col: Story = {
31
- // args: {
32
- // columns: [4, 4, 4],
33
- // children: '<div>Column 1</div> <div>Column 2</div> <div>Column 3</div>',
26
+ // navSocial: [
27
+ // {
28
+ // name: 'instagram',
29
+ // link: 'https://www.instagram.com/',
30
+ // },
31
+ // ],
34
32
  // },
35
33
  // };
@@ -0,0 +1 @@
1
+ export type Social = 'instagram' | 'linkedIn' | 'facebook' | 'pinterest' | 'spotify' | 'X' | 'youtube' | 'tiktok';
@@ -0,0 +1,130 @@
1
+ 'use client';
2
+
3
+ import { clsx } from 'clsx';
4
+ import { forwardRef } from 'react';
5
+ import { sectionRecipe, type SectionVariants } from './Section.css';
6
+ import { sprinkles, type Sprinkles } from '../../styles/sprinkles.css';
7
+
8
+ export interface SectionProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>, Sprinkles, NonNullable<SectionVariants> {
9
+ css?: string;
10
+ as?: 'section' | 'div' | 'main' | 'article' | 'aside';
11
+ }
12
+
13
+ export const Section = forwardRef<HTMLDivElement, SectionProps>(
14
+ (
15
+ {
16
+ children,
17
+ align,
18
+ isDark,
19
+ isFullHeight,
20
+ spacing,
21
+ as: Component = 'section',
22
+ css,
23
+ className,
24
+ // Extract sprinkles props
25
+ margin,
26
+ marginTop,
27
+ marginBottom,
28
+ marginLeft,
29
+ marginRight,
30
+ padding,
31
+ paddingTop,
32
+ paddingBottom,
33
+ paddingLeft,
34
+ paddingRight,
35
+ gap,
36
+ display,
37
+ flexDirection,
38
+ justifyContent,
39
+ flexWrap,
40
+ flex,
41
+ width,
42
+ height,
43
+ minWidth,
44
+ maxWidth,
45
+ minHeight,
46
+ position,
47
+ top,
48
+ bottom,
49
+ left,
50
+ right,
51
+ zIndex,
52
+ fontSize,
53
+ fontFamily,
54
+ lineHeight,
55
+ textAlign,
56
+ fontWeight,
57
+ color,
58
+ backgroundColor,
59
+ borderRadius,
60
+ borderWidth,
61
+ borderStyle,
62
+ borderColor,
63
+ boxShadow,
64
+ opacity,
65
+ overflow,
66
+ overflowX,
67
+ overflowY,
68
+ ...htmlProps
69
+ },
70
+ ref
71
+ ) => {
72
+ return (
73
+ <Component
74
+ ref={ref}
75
+ className={clsx(
76
+ sectionRecipe({ align, isDark, isFullHeight, spacing }),
77
+ sprinkles({
78
+ margin,
79
+ marginTop,
80
+ marginBottom,
81
+ marginLeft,
82
+ marginRight,
83
+ padding,
84
+ paddingTop,
85
+ paddingBottom,
86
+ paddingLeft,
87
+ paddingRight,
88
+ gap,
89
+ display,
90
+ flexDirection,
91
+ justifyContent,
92
+ flexWrap,
93
+ flex,
94
+ width,
95
+ height,
96
+ minWidth,
97
+ maxWidth,
98
+ minHeight,
99
+ position,
100
+ top,
101
+ bottom,
102
+ left,
103
+ right,
104
+ zIndex,
105
+ fontSize,
106
+ fontFamily,
107
+ lineHeight,
108
+ textAlign,
109
+ fontWeight,
110
+ color,
111
+ backgroundColor,
112
+ borderRadius,
113
+ borderWidth,
114
+ borderStyle,
115
+ borderColor,
116
+ boxShadow,
117
+ opacity,
118
+ overflow,
119
+ overflowX,
120
+ overflowY,
121
+ }),
122
+ css,
123
+ className
124
+ )}
125
+ {...htmlProps}>
126
+ {children}
127
+ </Component>
128
+ );
129
+ }
130
+ );
@@ -0,0 +1,6 @@
1
+ // export { Section } from '.';
2
+ // export type { SectionProps } from '.';
3
+ // export { Align as SectionAlign } from './types';
4
+
5
+ // export * as allStyles from './styles.css';
6
+ // export { styles as SectionStyles } from './styles.css';
@@ -0,0 +1,3 @@
1
+ export const ToRemove = () => {
2
+ return <div>ToRemove</div>;
3
+ };
@@ -0,0 +1,243 @@
1
+ import { clsx } from 'clsx';
2
+ import { forwardRef, useEffect, useRef, useState } from 'react';
3
+ import {
4
+ closeButton,
5
+ pauseButton,
6
+ playButton,
7
+ posterImage,
8
+ soundButton,
9
+ videoElement,
10
+ videoPoster,
11
+ videoRecipe,
12
+ type VideoVariants,
13
+ } from './Video.css';
14
+ import { sprinkles, type Sprinkles } from '../../styles/sprinkles.css';
15
+ import { Icon } from '../Icon/Icon';
16
+
17
+ export interface VideoProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>, Sprinkles, NonNullable<VideoVariants> {
18
+ css?: string;
19
+ video: string;
20
+ poster?: string;
21
+ isAutoPlay?: boolean;
22
+ startMuted?: boolean;
23
+ showControls?: boolean;
24
+ hidePlayButton?: boolean;
25
+ isVideoFullWidth?: boolean;
26
+ isPlayingFullScreen?: boolean;
27
+ onPlay?: () => void;
28
+ onClose?: () => void;
29
+ onEnded?: () => void;
30
+ }
31
+
32
+ export const Video = forwardRef<HTMLDivElement, VideoProps>(
33
+ (
34
+ {
35
+ video,
36
+ poster,
37
+ isAutoPlay = false,
38
+ startMuted = false,
39
+ showControls = false,
40
+ hidePlayButton = false,
41
+ isVideoFullWidth = false,
42
+ isPlayingFullScreen = false,
43
+ onPlay,
44
+ onClose,
45
+ onEnded,
46
+ size,
47
+ aspectRatio,
48
+ css,
49
+ className,
50
+ // Extract sprinkles props
51
+ margin,
52
+ marginTop,
53
+ marginBottom,
54
+ marginLeft,
55
+ marginRight,
56
+ padding,
57
+ paddingTop,
58
+ paddingBottom,
59
+ paddingLeft,
60
+ paddingRight,
61
+ gap,
62
+ display,
63
+ flexDirection,
64
+ justifyContent,
65
+ flexWrap,
66
+ flex,
67
+ width,
68
+ height,
69
+ minWidth,
70
+ maxWidth,
71
+ minHeight,
72
+ position,
73
+ top,
74
+ bottom,
75
+ left,
76
+ right,
77
+ zIndex,
78
+ fontSize,
79
+ fontFamily,
80
+ lineHeight,
81
+ textAlign,
82
+ fontWeight,
83
+ color,
84
+ backgroundColor,
85
+ borderRadius,
86
+ borderWidth,
87
+ borderStyle,
88
+ borderColor,
89
+ boxShadow,
90
+ opacity,
91
+ overflow,
92
+ overflowX,
93
+ overflowY,
94
+ ...htmlProps
95
+ },
96
+ ref
97
+ ) => {
98
+ const videoRef = useRef<HTMLVideoElement>(null);
99
+ const [isPlaying, setIsPlaying] = useState(false);
100
+ const [isMuted, setIsMuted] = useState(isAutoPlay || startMuted);
101
+
102
+ const playVideo = () => {
103
+ if (onPlay) onPlay();
104
+ videoRef.current?.play();
105
+ setIsPlaying(true);
106
+ };
107
+
108
+ const closeVideo = () => {
109
+ if (onClose) onClose();
110
+ videoRef.current?.pause();
111
+ setIsPlaying(false);
112
+ };
113
+
114
+ const pauseVideo = () => {
115
+ videoRef.current?.pause();
116
+ setIsPlaying(false);
117
+ };
118
+
119
+ const toggleMutedVideo = () => {
120
+ const newIsMuted = !isMuted;
121
+ setIsMuted(newIsMuted);
122
+ if (videoRef.current) videoRef.current.muted = newIsMuted;
123
+ };
124
+
125
+ const handleVideoEnded = () => {
126
+ if (onEnded) onEnded();
127
+ closeVideo();
128
+ };
129
+
130
+ const onEscape = (event: KeyboardEvent) => {
131
+ if (event.key === 'Escape') closeVideo();
132
+ };
133
+
134
+ useEffect(() => {
135
+ window.addEventListener('keydown', onEscape);
136
+
137
+ return () => {
138
+ window.removeEventListener('keydown', onEscape);
139
+ };
140
+ }, []);
141
+
142
+ useEffect(() => {
143
+ if (videoRef.current) {
144
+ videoRef.current.muted = isMuted;
145
+ }
146
+ }, [isMuted]);
147
+
148
+ return (
149
+ <div
150
+ ref={ref}
151
+ className={clsx(
152
+ videoRecipe({
153
+ size: isVideoFullWidth ? 'fullWidth' : size,
154
+ aspectRatio,
155
+ }),
156
+ sprinkles({
157
+ margin,
158
+ marginTop,
159
+ marginBottom,
160
+ marginLeft,
161
+ marginRight,
162
+ padding,
163
+ paddingTop,
164
+ paddingBottom,
165
+ paddingLeft,
166
+ paddingRight,
167
+ gap,
168
+ display,
169
+ flexDirection,
170
+ justifyContent,
171
+ flexWrap,
172
+ flex,
173
+ width,
174
+ height,
175
+ minWidth,
176
+ maxWidth,
177
+ minHeight,
178
+ position,
179
+ top,
180
+ bottom,
181
+ left,
182
+ right,
183
+ zIndex,
184
+ fontSize,
185
+ fontFamily,
186
+ lineHeight,
187
+ textAlign,
188
+ fontWeight,
189
+ color,
190
+ backgroundColor,
191
+ borderRadius,
192
+ borderWidth,
193
+ borderStyle,
194
+ borderColor,
195
+ boxShadow,
196
+ opacity,
197
+ overflow,
198
+ overflowX,
199
+ overflowY,
200
+ }),
201
+ css,
202
+ className
203
+ )}
204
+ {...htmlProps}>
205
+ <video ref={videoRef} className={videoElement} playsInline muted={isMuted} autoPlay={isAutoPlay} onEnded={handleVideoEnded}>
206
+ <source src={video} type="video/mp4" />
207
+ </video>
208
+
209
+ {poster && (
210
+ <div className={videoPoster} data-playing={isPlaying}>
211
+ <img src={poster} alt="Video poster" className={posterImage} sizes="2560" />
212
+ </div>
213
+ )}
214
+
215
+ {!hidePlayButton && !isAutoPlay && (
216
+ <button className={playButton} data-playing={isPlaying} onClick={playVideo} aria-label="Play video" type="button">
217
+ <Icon icon="play" size="lg" />
218
+ </button>
219
+ )}
220
+
221
+ {isPlayingFullScreen && (
222
+ <button className={closeButton} onClick={closeVideo} aria-label="Close video" type="button">
223
+ <Icon icon="close" size="md" />
224
+ </button>
225
+ )}
226
+
227
+ {isPlaying && showControls && (
228
+ <button className={pauseButton} onClick={pauseVideo} aria-label="Pause video" type="button">
229
+ <Icon icon="pause" size="md" />
230
+ </button>
231
+ )}
232
+
233
+ {showControls && (
234
+ <button className={soundButton} onClick={toggleMutedVideo} aria-label={isMuted ? 'Unmute video' : 'Mute video'} type="button">
235
+ <Icon icon={isMuted ? 'volumeMute' : 'volumeUp'} size="md" />
236
+ </button>
237
+ )}
238
+ </div>
239
+ );
240
+ }
241
+ );
242
+
243
+ Video.displayName = 'Video';
@@ -0,0 +1,2 @@
1
+ // export { Video } from '.';
2
+ // export type { VideoProps } from '.';
@@ -0,0 +1,152 @@
1
+ import { clsx } from 'clsx';
2
+ import { forwardRef } from 'react';
3
+ import { videoFullWidthRecipe, type VideoFullWidthVariants } from './VideoFullWidth.css';
4
+ import { sprinkles, type Sprinkles } from '../../styles/sprinkles.css';
5
+ import { Video } from '../Video/Video';
6
+
7
+ export interface VideoFullWidthProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>, Sprinkles, NonNullable<VideoFullWidthVariants> {
8
+ css?: string;
9
+ video: string;
10
+ poster?: string;
11
+ isAutoPlay?: boolean;
12
+ startMuted?: boolean;
13
+ showControls?: boolean;
14
+ onPlay?: () => void;
15
+ onClose?: () => void;
16
+ onEnded?: () => void;
17
+ }
18
+
19
+ export const VideoFullWidth = forwardRef<HTMLDivElement, VideoFullWidthProps>(
20
+ (
21
+ {
22
+ video,
23
+ poster,
24
+ isAutoPlay = false,
25
+ startMuted = false,
26
+ showControls = false,
27
+ onPlay,
28
+ onClose,
29
+ onEnded,
30
+ aspectRatio,
31
+ css,
32
+ className,
33
+ // Extract sprinkles props
34
+ margin,
35
+ marginTop,
36
+ marginBottom,
37
+ marginLeft,
38
+ marginRight,
39
+ padding,
40
+ paddingTop,
41
+ paddingBottom,
42
+ paddingLeft,
43
+ paddingRight,
44
+ gap,
45
+ display,
46
+ flexDirection,
47
+ justifyContent,
48
+ flexWrap,
49
+ flex,
50
+ width,
51
+ height,
52
+ minWidth,
53
+ maxWidth,
54
+ minHeight,
55
+ position,
56
+ top,
57
+ bottom,
58
+ left,
59
+ right,
60
+ zIndex,
61
+ fontSize,
62
+ fontFamily,
63
+ lineHeight,
64
+ textAlign,
65
+ fontWeight,
66
+ color,
67
+ backgroundColor,
68
+ borderRadius,
69
+ borderWidth,
70
+ borderStyle,
71
+ borderColor,
72
+ boxShadow,
73
+ opacity,
74
+ overflow,
75
+ overflowX,
76
+ overflowY,
77
+ ...htmlProps
78
+ },
79
+ ref
80
+ ) => {
81
+ return (
82
+ <div
83
+ ref={ref}
84
+ className={clsx(
85
+ videoFullWidthRecipe({ aspectRatio }),
86
+ sprinkles({
87
+ margin,
88
+ marginTop,
89
+ marginBottom,
90
+ marginLeft,
91
+ marginRight,
92
+ padding,
93
+ paddingTop,
94
+ paddingBottom,
95
+ paddingLeft,
96
+ paddingRight,
97
+ gap,
98
+ display,
99
+ flexDirection,
100
+ justifyContent,
101
+ flexWrap,
102
+ flex,
103
+ width,
104
+ height,
105
+ minWidth,
106
+ maxWidth,
107
+ minHeight,
108
+ position,
109
+ top,
110
+ bottom,
111
+ left,
112
+ right,
113
+ zIndex,
114
+ fontSize,
115
+ fontFamily,
116
+ lineHeight,
117
+ textAlign,
118
+ fontWeight,
119
+ color,
120
+ backgroundColor,
121
+ borderRadius,
122
+ borderWidth,
123
+ borderStyle,
124
+ borderColor,
125
+ boxShadow,
126
+ opacity,
127
+ overflow,
128
+ overflowX,
129
+ overflowY,
130
+ }),
131
+ css,
132
+ className
133
+ )}
134
+ {...htmlProps}>
135
+ <Video
136
+ video={video}
137
+ poster={poster}
138
+ isAutoPlay={isAutoPlay}
139
+ startMuted={startMuted}
140
+ showControls={showControls}
141
+ onPlay={onPlay}
142
+ onClose={onClose}
143
+ onEnded={onEnded}
144
+ isVideoFullWidth
145
+ size="fullWidth"
146
+ />
147
+ </div>
148
+ );
149
+ }
150
+ );
151
+
152
+ VideoFullWidth.displayName = 'VideoFullWidth';
@@ -0,0 +1,2 @@
1
+ // export { VideoFullWidth } from './VideoFullWidth';
2
+ // export type { VideoFullWidthProps } from './VideoFullWidth';
package/src/index.ts CHANGED
@@ -87,7 +87,7 @@ export { type TextareaVariants } from './components/Form/TextField/Textarea/Text
87
87
  export { ToRemove } from './components/ToRemove/ToRemove';
88
88
 
89
89
  // Theme utilities
90
- export { createDarkTheme, createLightTheme, type ThemeOverrides } from './utils/theme.css';
90
+ export { createDarkTheme, createLightTheme, type ThemeOverrides } from './utils/theme';
91
91
  // Theme contract and values
92
92
  export { themeContract } from './theme/contract.css';
93
93
  export { baseLightTheme, baseDarkTheme } from './theme/baseThemeValues';