@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
@@ -0,0 +1,176 @@
1
+ import { globalStyle, style } from '@vanilla-extract/css';
2
+ import { calc } from '@vanilla-extract/css-utils';
3
+ import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
4
+
5
+ import { queries } from '../../styles/mediaqueries';
6
+ import { themeContract } from '../../theme/contract.css';
7
+
8
+ import { combineResponsive } from '../../utils/combineResponsive';
9
+ import { generateResponsiveMedia } from '../../utils/generateResponsiveMedia';
10
+
11
+ export const carouselRecipe = recipe({
12
+ base: {
13
+ width: '100%',
14
+ overflow: 'hidden',
15
+ position: 'relative',
16
+ },
17
+
18
+ variants: {
19
+ isFullWidth: {
20
+ true: {
21
+ width: '100vw',
22
+
23
+ marginLeft: calc(themeContract.global.paddingLeft.mobile).negate().toString(),
24
+ marginRight: calc(themeContract.global.paddingRight.mobile).negate().toString(),
25
+
26
+ '@media': {
27
+ [queries.sm]: {
28
+ marginLeft: calc(themeContract.global.paddingLeft.sm).negate().toString(),
29
+ marginRight: calc(themeContract.global.paddingRight.sm).negate().toString(),
30
+ },
31
+ [queries.md]: {
32
+ marginLeft: calc(themeContract.global.paddingLeft.md).negate().toString(),
33
+ marginRight: calc(themeContract.global.paddingRight.md).negate().toString(),
34
+ },
35
+ [queries.lg]: {
36
+ marginLeft: calc(themeContract.global.paddingLeft.lg).negate().toString(),
37
+ marginRight: calc(themeContract.global.paddingRight.lg).negate().toString(),
38
+ },
39
+ [queries.xl]: {
40
+ marginLeft: calc(themeContract.global.paddingLeft.xl).negate().toString(),
41
+ marginRight: calc(themeContract.global.paddingRight.xl).negate().toString(),
42
+ },
43
+ [queries['2xl']]: {
44
+ marginLeft: `calc((100vw - ${themeContract.maxWidth}) / -2)`,
45
+ marginRight: `calc((100vw - ${themeContract.maxWidth}) / -2)`,
46
+ },
47
+ },
48
+ },
49
+ },
50
+ },
51
+
52
+ defaultVariants: {
53
+ isFullWidth: false,
54
+ },
55
+ });
56
+
57
+ export const carouselContent = style({
58
+ width: '100%',
59
+ position: 'relative',
60
+ });
61
+
62
+ export const carouselSlide = style({
63
+ display: 'flex',
64
+ position: 'relative',
65
+ willChange: 'transform',
66
+ transition: 'transform 0.3s ease-in-out',
67
+ });
68
+
69
+ export const carouselItem = style({
70
+ width: '100%',
71
+ flexShrink: 0,
72
+ display: 'flex',
73
+ position: 'relative',
74
+ alignItems: 'stretch',
75
+ });
76
+
77
+ globalStyle(`${carouselItem} > div`, {
78
+ '@media': {
79
+ ...generateResponsiveMedia({
80
+ paddingBottom: combineResponsive(themeContract.carousel.bullet.height, themeContract.carousel.bullet.bottom),
81
+ }),
82
+ },
83
+ });
84
+
85
+ export const carouselNav = style({
86
+ left: 0,
87
+ right: 0,
88
+ bottom: 0,
89
+ zIndex: 30,
90
+ width: '100%',
91
+ display: 'flex',
92
+ position: 'absolute',
93
+ pointerEvents: 'none',
94
+ justifyContent: 'flex-end',
95
+
96
+ gap: themeContract.space.sm,
97
+ padding: themeContract.space.md,
98
+ maxWidth: themeContract.maxWidth,
99
+ });
100
+
101
+ export const carouselNavButton = style({
102
+ border: 'none',
103
+ display: 'flex',
104
+ cursor: 'pointer',
105
+ alignItems: 'center',
106
+ pointerEvents: 'auto',
107
+ justifyContent: 'center',
108
+ transition: 'all 0.3s ease-in-out',
109
+
110
+ borderRadius: themeContract.carousel.nav.borderRadius,
111
+ backgroundColor: themeContract.carousel.nav.backgroundColor,
112
+
113
+ ':hover': {
114
+ transform: 'scale(1.1)',
115
+ color: themeContract.colors.background,
116
+ backgroundColor: themeContract.colors.primary,
117
+ },
118
+
119
+ ':disabled': {
120
+ opacity: '0.5',
121
+ transform: 'none',
122
+ pointerEvents: 'none',
123
+ },
124
+
125
+ '@media': {
126
+ ...generateResponsiveMedia({
127
+ width: themeContract.carousel.nav.width,
128
+ height: themeContract.carousel.nav.height,
129
+ }),
130
+ },
131
+ });
132
+
133
+ export const carouselBullets = style({
134
+ left: 0,
135
+ right: 0,
136
+ display: 'flex',
137
+ alignItems: 'center',
138
+ position: 'absolute',
139
+ justifyContent: 'center',
140
+
141
+ '@media': {
142
+ ...generateResponsiveMedia({
143
+ gap: themeContract.carousel.bullet.gap,
144
+ bottom: themeContract.carousel.bullet.bottom,
145
+ }),
146
+
147
+ [queries.lg]: {},
148
+ },
149
+ });
150
+
151
+ export const carouselBullet = style({
152
+ border: 'none',
153
+ cursor: 'pointer',
154
+ transition: 'all 0.3s ease-in-out',
155
+
156
+ borderRadius: themeContract.carousel.bullet.borderRadius,
157
+ backgroundColor: themeContract.carousel.bullet.backgroundColor,
158
+
159
+ ':hover': {
160
+ transform: 'scale(1.2)',
161
+ },
162
+
163
+ '@media': {
164
+ ...generateResponsiveMedia({
165
+ width: themeContract.carousel.bullet.width,
166
+ height: themeContract.carousel.bullet.height,
167
+ }),
168
+ },
169
+ });
170
+
171
+ export const carouselBulletActive = style({
172
+ pointerEvents: 'none',
173
+ backgroundColor: themeContract.carousel.bullet.activeBackgroundColor,
174
+ });
175
+
176
+ export type CarouselVariants = RecipeVariants<typeof carouselRecipe>;
@@ -0,0 +1,36 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ 'use client';
3
+
4
+ import { clsx } from 'clsx';
5
+ import { forwardRef } from 'react';
6
+
7
+ import { columnItem, columnsRecipe } from './styles.css';
8
+
9
+ export type ColumnsProps = React.HTMLAttributes<HTMLDivElement> & {
10
+ css?: string;
11
+ columns: number[];
12
+ align: any;
13
+ vAlign: any;
14
+ children: React.ReactNode;
15
+ };
16
+
17
+ export const Columns = forwardRef<HTMLDivElement, ColumnsProps>(({ align, vAlign, columns, children, className, css }, ref) => {
18
+ return (
19
+ <div ref={ref} className={clsx(columnsRecipe({ align, vAlign }), css, className)}>
20
+ {Array.isArray(children) &&
21
+ children.map((child, index) => (
22
+ <div
23
+ key={index}
24
+ className={columnItem}
25
+ style={{
26
+ flex: columns[index],
27
+ maxWidth: `${columns[index]}%`,
28
+ }}>
29
+ {child}
30
+ </div>
31
+ ))}
32
+ </div>
33
+ );
34
+ });
35
+
36
+ Columns.displayName = 'Columns';
@@ -0,0 +1,70 @@
1
+ import { style } from '@vanilla-extract/css';
2
+ import { recipe } from '@vanilla-extract/recipes';
3
+ import { queries } from '../../styles/mediaqueries';
4
+ import { themeContract } from '../../theme/contract.css';
5
+ import { generateResponsiveMedia } from '../../utils/generateResponsiveMedia';
6
+
7
+ export const columnsRecipe = recipe({
8
+ base: [
9
+ {
10
+ width: '100%',
11
+ display: 'flex',
12
+ flexWrap: 'wrap',
13
+ flexDirection: 'column',
14
+
15
+ '@media': {
16
+ ...generateResponsiveMedia({
17
+ gap: themeContract.columns.gap,
18
+ }),
19
+
20
+ [queries.sm]: {
21
+ flexDirection: 'row',
22
+ },
23
+ },
24
+ },
25
+ ],
26
+
27
+ variants: {
28
+ align: {
29
+ left: {
30
+ textAlign: 'left',
31
+ },
32
+ center: {
33
+ textAlign: 'center',
34
+ },
35
+ right: {
36
+ textAlign: 'right',
37
+ },
38
+ },
39
+ vAlign: {
40
+ top: {
41
+ alignItems: 'flex-start',
42
+ justifyContent: 'flex-start',
43
+ },
44
+ center: {
45
+ alignItems: 'center',
46
+ justifyContent: 'center',
47
+ },
48
+ bottom: {
49
+ alignItems: 'flex-end',
50
+ justifyContent: 'flex-end',
51
+ },
52
+ },
53
+ },
54
+
55
+ defaultVariants: {
56
+ vAlign: 'top',
57
+ },
58
+ });
59
+
60
+ export const columnItem = style({
61
+ minWidth: 0,
62
+ flex: '0 0 100%',
63
+ position: 'relative',
64
+
65
+ '@media': {
66
+ [queries.md]: {
67
+ flex: 'unset',
68
+ },
69
+ },
70
+ });
@@ -1,7 +1,7 @@
1
1
  import { keyframes, style } from '@vanilla-extract/css';
2
2
  import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
3
3
  import { queries } from '../../styles/mediaqueries';
4
- import { themeContract } from '../../themes/contract.css';
4
+ import { themeContract } from '../../theme/contract.css';
5
5
 
6
6
  const fadeIn = keyframes({
7
7
  from: { opacity: '0' },
@@ -1,9 +1,9 @@
1
1
  import { clsx } from 'clsx';
2
2
  import { forwardRef, useEffect, useState } from 'react';
3
3
  import { consentActions, consentContent, type ConsentCookieVariants, consentRecipe } from './ConsentCookie.css';
4
+ import { getCookie, setCookie } from './cookie';
4
5
  import { sprinkles, type Sprinkles } from '../../styles/sprinkles.css';
5
- import { getCookie, setCookie } from '../../utils/cookie';
6
- import { Button } from '../Button/Button';
6
+ import { Button } from '../Button/';
7
7
 
8
8
  // Declare window object including gtag to avoid TypeScript errors
9
9
  declare const window: Window &
@@ -186,7 +186,7 @@ export const ConsentCookie = forwardRef<HTMLDivElement, ConsentCookieProps>(
186
186
  <div className={consentContent}>
187
187
  {children}
188
188
  <div className={consentActions}>
189
- <Button variant="outline" size="sm" onClick={handleReject}>
189
+ <Button size="sm" onClick={handleReject}>
190
190
  {translations?.actions.reject || 'Reject'}
191
191
  </Button>
192
192
  <Button variant="primary" size="sm" onClick={handleAccept}>
@@ -0,0 +1,21 @@
1
+ 'use client';
2
+
3
+ import { clsx } from 'clsx';
4
+ import { forwardRef } from 'react';
5
+
6
+ import { footerRecipe } from './styles.css';
7
+
8
+ export type FooterProps = React.HTMLAttributes<HTMLDivElement> & {
9
+ css?: string;
10
+ children: React.ReactNode;
11
+ };
12
+
13
+ export const Footer = forwardRef<HTMLDivElement, FooterProps>(({ children, css, className }, ref) => {
14
+ return (
15
+ <footer ref={ref} className={clsx(footerRecipe, css, className)}>
16
+ {children}
17
+ </footer>
18
+ );
19
+ });
20
+
21
+ Footer.displayName = 'Footer';
@@ -0,0 +1,33 @@
1
+ import { style } from '@vanilla-extract/css';
2
+
3
+ import { themeContract } from '../..';
4
+ import { queries } from '../../styles/mediaqueries';
5
+ import { generateResponsiveMedia } from '../../utils/generateResponsiveMedia';
6
+
7
+ export const footerRecipe = style([
8
+ {
9
+ zIndex: 20,
10
+ display: 'flex',
11
+ alignItems: 'center',
12
+ flexDirection: 'column',
13
+ justifyContent: 'space-between',
14
+
15
+ fontSize: themeContract.footer.fontSize,
16
+ backgroundColor: themeContract.footer.backgroundColor,
17
+
18
+ '@media': {
19
+ ...generateResponsiveMedia({
20
+ gap: themeContract.footer.gap,
21
+ height: themeContract.footer.height,
22
+ paddingTop: themeContract.footer.paddingTop,
23
+ paddingLeft: themeContract.global.paddingLeft,
24
+ paddingRight: themeContract.global.paddingRight,
25
+ paddingBottom: themeContract.footer.paddingBottom,
26
+ }),
27
+
28
+ [queries.md]: {
29
+ flexDirection: 'row',
30
+ },
31
+ },
32
+ },
33
+ ]);
@@ -1,6 +1,6 @@
1
1
  import { style } from '@vanilla-extract/css';
2
2
  import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
3
- import { themeContract } from '../../themes/contract.css';
3
+ import { themeContract } from '../../theme/contract.css';
4
4
 
5
5
  const formBase = style({
6
6
  width: '100%',
@@ -1,6 +1,6 @@
1
1
  import { style } from '@vanilla-extract/css';
2
2
  import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
3
- import { themeContract } from '../../../themes/contract.css';
3
+ import { themeContract } from '../../../theme/contract.css';
4
4
 
5
5
  const rowBase = style({
6
6
  display: 'flex',
@@ -1,6 +1,6 @@
1
1
  import { style } from '@vanilla-extract/css';
2
2
  import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
3
- import { themeContract } from '../../../../themes/contract.css';
3
+ import { themeContract } from '../../../../theme/contract.css';
4
4
 
5
5
  const inputBase = style({
6
6
  appearance: 'none',
@@ -1,6 +1,6 @@
1
1
  import { style } from '@vanilla-extract/css';
2
2
  import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
3
- import { themeContract } from '../../../../themes/contract.css';
3
+ import { themeContract } from '../../../../theme/contract.css';
4
4
 
5
5
  const labelBase = style({
6
6
  fontFamily: themeContract.fonts.body,
@@ -1,6 +1,6 @@
1
1
  import { style } from '@vanilla-extract/css';
2
2
  import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
3
- import { themeContract } from '../../../themes/contract.css';
3
+ import { themeContract } from '../../../theme/contract.css';
4
4
 
5
5
  const textFieldBase = style({
6
6
  display: 'flex',
@@ -1,6 +1,6 @@
1
1
  import { style } from '@vanilla-extract/css';
2
2
  import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
3
- import { themeContract } from '../../../../themes/contract.css';
3
+ import { themeContract } from '../../../../theme/contract.css';
4
4
 
5
5
  const textareaBase = style({
6
6
  appearance: 'none',
@@ -0,0 +1,53 @@
1
+ import { clsx } from 'clsx';
2
+ import { forwardRef, useState } from 'react';
3
+
4
+ import { headerOverlayRecipe, headerPlaceholder, headerRecipe, headerToggleNav } from './styles.css';
5
+
6
+ export type HeaderProps = React.HTMLAttributes<HTMLDivElement> & {
7
+ css?: string;
8
+ isFixed?: boolean;
9
+ hideToggleNav?: boolean;
10
+ children: React.ReactNode;
11
+ childrenOverlay?: React.ReactNode;
12
+ childrenToggleNav?: React.ReactNode;
13
+ };
14
+
15
+ export const Header = forwardRef<HTMLDivElement, HeaderProps>(
16
+ (
17
+ {
18
+ children,
19
+ childrenOverlay,
20
+ childrenToggleNav,
21
+ isFixed = false,
22
+ hideToggleNav = false,
23
+
24
+ css,
25
+ className,
26
+ },
27
+ ref
28
+ ) => {
29
+ const [isNavOpen, setNavOpen] = useState(false);
30
+
31
+ const onToggleNav = () => setNavOpen(!isNavOpen);
32
+
33
+ return (
34
+ <>
35
+ <header ref={ref} className={clsx(headerRecipe({ isFixed }), css, className)}>
36
+ {childrenOverlay && <div className={headerOverlayRecipe({ isOpen: isNavOpen })}>{childrenOverlay}</div>}
37
+
38
+ {children}
39
+
40
+ {!hideToggleNav && (
41
+ <button onClick={onToggleNav} aria-label="Toggle navigation" className={headerToggleNav}>
42
+ {childrenToggleNav}
43
+ </button>
44
+ )}
45
+ </header>
46
+
47
+ {isFixed && <div className={headerPlaceholder} />}
48
+ </>
49
+ );
50
+ }
51
+ );
52
+
53
+ Header.displayName = 'Header';
@@ -0,0 +1,89 @@
1
+ import { style } from '@vanilla-extract/css';
2
+ import { recipe } from '@vanilla-extract/recipes';
3
+ import { themeContract } from '../..';
4
+ import { generateResponsiveMedia } from '../../utils/generateResponsiveMedia';
5
+
6
+ export const headerRecipe = recipe({
7
+ base: [
8
+ {
9
+ zIndex: 30,
10
+ width: '100%',
11
+ display: 'flex',
12
+ flexDirection: 'row',
13
+ alignItems: 'center',
14
+ position: 'relative',
15
+ justifyContent: 'space-between',
16
+
17
+ fontSize: themeContract.header.fontSize,
18
+ backgroundColor: themeContract.header.backgroundColor,
19
+
20
+ '@media': {
21
+ ...generateResponsiveMedia({
22
+ gap: themeContract.header.gap,
23
+ height: themeContract.header.height,
24
+ paddingTop: themeContract.header.paddingTop,
25
+ paddingLeft: themeContract.global.paddingLeft,
26
+ paddingRight: themeContract.global.paddingRight,
27
+ paddingBottom: themeContract.header.paddingBottom,
28
+ }),
29
+ },
30
+ },
31
+ ],
32
+
33
+ variants: {
34
+ isFixed: {
35
+ true: { position: 'fixed' },
36
+ false: { position: 'relative' },
37
+ },
38
+ },
39
+
40
+ defaultVariants: {
41
+ isFixed: false,
42
+ },
43
+ });
44
+
45
+ export const headerPlaceholder = style([
46
+ {
47
+ '@media': {
48
+ ...generateResponsiveMedia({
49
+ height: themeContract.header.height,
50
+ }),
51
+ },
52
+ },
53
+ ]);
54
+
55
+ export const headerToggleNav = style([
56
+ {
57
+ border: 0,
58
+ zIndex: 30,
59
+ },
60
+ ]);
61
+
62
+ export const headerOverlayRecipe = recipe({
63
+ base: {
64
+ position: 'fixed',
65
+ inset: 0,
66
+ backgroundColor: 'rgba(0,0,0,0.6)',
67
+ transition: 'opacity 0.3s ease-in-out, visibility 0.3s ease-in-out',
68
+ zIndex: 25,
69
+ },
70
+
71
+ variants: {
72
+ isOpen: {
73
+ true: {
74
+ opacity: 1,
75
+ visibility: 'visible',
76
+ },
77
+ false: {
78
+ opacity: 0,
79
+ visibility: 'hidden',
80
+ },
81
+ },
82
+ },
83
+
84
+ defaultVariants: {
85
+ isOpen: false,
86
+ },
87
+ });
88
+
89
+ export type HeaderOverlayVariants = Parameters<typeof headerOverlayRecipe>[0];
@@ -0,0 +1,22 @@
1
+ import { clsx } from 'clsx';
2
+ import { forwardRef } from 'react';
3
+
4
+ import { headingRecipe, HeadingVariants } from './styles.css';
5
+ import { AllowedHeading } from './types';
6
+
7
+ export type HeadingProps = React.HTMLAttributes<HTMLHeadingElement> &
8
+ HeadingVariants & {
9
+ css?: string;
10
+ as: AllowedHeading;
11
+ children: React.ReactNode;
12
+ };
13
+
14
+ export const Heading = forwardRef<HTMLHeadingElement, HeadingProps>(({ as, size, weight, align, css, className, children }, ref) => {
15
+ const Component = as as AllowedHeading;
16
+
17
+ return (
18
+ <Component ref={ref} className={clsx(headingRecipe({ size, weight, align }), css, className)}>
19
+ {children}
20
+ </Component>
21
+ );
22
+ });
@@ -0,0 +1,66 @@
1
+ import { style } from '@vanilla-extract/css';
2
+ import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
3
+
4
+ import { sprinkles } from '../../../styles/sprinkles.css';
5
+ import { themeContract } from '../../../theme/contract.css';
6
+
7
+ export const headingRecipe = recipe({
8
+ base: style({
9
+ margin: 0,
10
+ padding: 0,
11
+ fontFamily: themeContract.fonts.heading,
12
+ }),
13
+
14
+ variants: {
15
+ size: {
16
+ h1: [
17
+ sprinkles({
18
+ fontSize: { mobile: '2xl', md: '3xl', lg: '4xl' },
19
+ lineHeight: { mobile: 'tight', md: 'tight', lg: 'tight' },
20
+ }),
21
+ ],
22
+ h2: sprinkles({
23
+ fontSize: { mobile: 'xl', md: '2xl', lg: '3xl' },
24
+ lineHeight: { mobile: 'tight', md: 'tight', lg: 'tight' },
25
+ }),
26
+ h3: sprinkles({
27
+ fontSize: { mobile: 'lg', md: 'xl', lg: '2xl' },
28
+ lineHeight: { mobile: 'normal', md: 'tight', lg: 'tight' },
29
+ }),
30
+ h4: sprinkles({
31
+ fontSize: { mobile: 'md', md: 'lg', lg: 'xl' },
32
+ lineHeight: { mobile: 'normal', md: 'normal', lg: 'tight' },
33
+ }),
34
+ h5: sprinkles({
35
+ fontSize: { mobile: 'sm', md: 'md', lg: 'lg' },
36
+ lineHeight: { mobile: 'normal', md: 'normal', lg: 'normal' },
37
+ }),
38
+ h6: sprinkles({
39
+ fontSize: { mobile: 'xs', md: 'sm', lg: 'md' },
40
+ lineHeight: { mobile: 'relaxed', md: 'normal', lg: 'normal' },
41
+ }),
42
+ },
43
+
44
+ weight: {
45
+ light: { fontWeight: themeContract.fontWeights.light },
46
+ normal: { fontWeight: themeContract.fontWeights.normal },
47
+ medium: { fontWeight: themeContract.fontWeights.medium },
48
+ semibold: { fontWeight: themeContract.fontWeights.semibold },
49
+ bold: { fontWeight: themeContract.fontWeights.bold },
50
+ },
51
+
52
+ align: {
53
+ left: { textAlign: 'left' },
54
+ center: { textAlign: 'center' },
55
+ right: { textAlign: 'right' },
56
+ },
57
+ },
58
+
59
+ defaultVariants: {
60
+ size: 'h2',
61
+ align: 'left',
62
+ weight: 'medium',
63
+ },
64
+ });
65
+
66
+ export type HeadingVariants = RecipeVariants<typeof headingRecipe>;
@@ -0,0 +1 @@
1
+ export type AllowedHeading = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
@@ -0,0 +1,25 @@
1
+ import { CSSProperties } from 'react';
2
+
3
+ import path from './path';
4
+
5
+ import { iconRecipe } from './style.css';
6
+ import { themeContract } from '../../theme/contract.css';
7
+
8
+ export type IconProps = {
9
+ icon?: string;
10
+ size?: number;
11
+ color?: string;
12
+ viewBox?: string;
13
+ iconPath?: string;
14
+ styles?: CSSProperties;
15
+ };
16
+
17
+ export const Icon = ({ icon = '', size = 24, styles = {}, iconPath = '', color = themeContract.icon.color, viewBox = '0 0 24 24' }: IconProps) => {
18
+ const d = iconPath || path[icon as keyof typeof path];
19
+
20
+ return (
21
+ <svg className={iconRecipe} viewBox={viewBox} width={`${size}px`} height={`${size}px`} style={styles}>
22
+ <path className={iconPath} d={d} fill={color} />
23
+ </svg>
24
+ );
25
+ };