@latte-macchiat-io/latte-vanilla-components 0.0.248 → 0.0.250

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@latte-macchiat-io/latte-vanilla-components",
3
- "version": "0.0.248",
3
+ "version": "0.0.250",
4
4
  "description": "Beautiful components for amazing projects, with a touch of Vanilla 🥤",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -1,5 +1,6 @@
1
1
  const themeHeaderBase = {
2
2
  header: {
3
+ isFixed: 'true',
3
4
  fontSize: '1.2em',
4
5
  height: {
5
6
  mobile: '15px',
@@ -1,9 +1,8 @@
1
1
  import { style } from '@vanilla-extract/css';
2
- import { calc } from '@vanilla-extract/css-utils';
3
2
  import { recipe, type RecipeVariants } from '@vanilla-extract/recipes';
4
3
 
5
4
  import { themeContract } from '../../theme/contract.css';
6
- import { generateResponsiveMedia } from '../../utils/generateResponsiveMedia';
5
+ import { calcResponsiveSubtract, generateResponsiveMedia } from '../../utils/generateResponsiveMedia';
7
6
 
8
7
  export const sectionRecipe = recipe(
9
8
  {
@@ -71,7 +70,11 @@ export const sectionRecipe = recipe(
71
70
  },
72
71
  isHeaderFixed: {
73
72
  true: {
74
- // minHeight: calc.subtract('100vh', themeContract.header.height),
73
+ '@media': {
74
+ ...generateResponsiveMedia({
75
+ minHeight: calcResponsiveSubtract('100vh', themeContract.header.height),
76
+ }),
77
+ },
75
78
  },
76
79
  false: {
77
80
  minHeight: '100vh',
@@ -103,6 +106,7 @@ export const sectionRecipe = recipe(
103
106
  align: 'left',
104
107
  isDark: false,
105
108
  isFullHeight: false,
109
+ isHeaderFixed: themeContract.header.isFixed ? true : false,
106
110
  withPaddingTop: true,
107
111
  withPaddingBottom: true,
108
112
  variant: 'transparent',
@@ -3,6 +3,14 @@ const themeVideoBase = {
3
3
  playButton: {
4
4
  border: 'none',
5
5
  borderRadius: '1000px',
6
+ iconSize: {
7
+ mobile: '50px',
8
+ sm: '50px',
9
+ md: '50px',
10
+ lg: '75px',
11
+ xl: '75px',
12
+ '2xl': '75px',
13
+ },
6
14
  iconColor: '#FF7377',
7
15
  backgroundColor: '#FF7377',
8
16
  width: {
@@ -25,6 +33,14 @@ const themeVideoBase = {
25
33
  pauseButton: {
26
34
  border: 'none',
27
35
  borderRadius: '1000px',
36
+ iconSize: {
37
+ mobile: '50px',
38
+ sm: '50px',
39
+ md: '50px',
40
+ lg: '75px',
41
+ xl: '75px',
42
+ '2xl': '75px',
43
+ },
28
44
  iconColor: '#FF7377',
29
45
  backgroundColor: '#FF7377',
30
46
  width: {
@@ -47,6 +63,14 @@ const themeVideoBase = {
47
63
  soundButton: {
48
64
  border: 'none',
49
65
  borderRadius: '1000px',
66
+ iconSize: {
67
+ mobile: '50px',
68
+ sm: '50px',
69
+ md: '50px',
70
+ lg: '75px',
71
+ xl: '75px',
72
+ '2xl': '75px',
73
+ },
50
74
  iconColor: '#FF7377',
51
75
  backgroundColor: '#FF7377',
52
76
  width: {
@@ -69,6 +93,14 @@ const themeVideoBase = {
69
93
  closeButton: {
70
94
  border: 'none',
71
95
  borderRadius: '1000px',
96
+ iconSize: {
97
+ mobile: '50px',
98
+ sm: '50px',
99
+ md: '50px',
100
+ lg: '75px',
101
+ xl: '75px',
102
+ '2xl': '75px',
103
+ },
72
104
  iconColor: '#FF7377',
73
105
  backgroundColor: '#FF7377',
74
106
  width: {
@@ -149,6 +149,7 @@ export const themeContract = createGlobalThemeContract({
149
149
  },
150
150
  },
151
151
  header: {
152
+ isFixed: 'latte-header-isFixed',
152
153
  fontSize: 'latte-header-fontSize',
153
154
  backgroundColor: 'latte-header-backgroundColor',
154
155
  height: {
@@ -1,19 +1,102 @@
1
- import { Breakpoints, queries } from '../styles/mediaqueries';
1
+ // utils/generateResponsiveMedia.ts
2
+ import { queries } from '../styles/mediaqueries';
2
3
 
3
- type ResponsiveProps = Record<string, Record<Breakpoints, string>>;
4
+ /**
5
+ * Breakpoint keys you support (should match your queries object).
6
+ */
7
+ type BreakpointKey = 'mobile' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
8
+ const BPS: BreakpointKey[] = ['mobile', 'sm', 'md', 'lg', 'xl', '2xl'];
4
9
 
5
- export function generateResponsiveMedia(properties: ResponsiveProps) {
10
+ /**
11
+ * Responsive values can be a plain string/number or anything with a toString().
12
+ */
13
+ type ResponsiveValue = string | number | { toString(): string };
14
+ type BreakpointMap = Partial<Record<BreakpointKey, ResponsiveValue>>;
15
+
16
+ /**
17
+ * Generate responsive media queries for a set of CSS properties.
18
+ *
19
+ * Example:
20
+ * generateResponsiveMedia({
21
+ * width: { mobile: '100%', md: '50%' },
22
+ * padding: '20px'
23
+ * })
24
+ *
25
+ * => {
26
+ * '@media (min-width:...)': { width: '50%', padding: '20px' },
27
+ * ...
28
+ * }
29
+ */
30
+ export function generateResponsiveMedia(properties: Record<string, ResponsiveValue | BreakpointMap>) {
6
31
  const result: Record<string, Record<string, string>> = {};
7
32
 
8
- Object.entries(properties).forEach(([cssProp, breakpointsMap]) => {
9
- Object.entries(breakpointsMap).forEach(([bp, token]) => {
10
- const key = bp as Breakpoints;
11
- const mediaQuery = queries[key];
33
+ const toCssValue = (v: ResponsiveValue) => {
34
+ const s = String(v);
35
+ // if it's a CSS variable token, wrap with var(...)
36
+ return s.startsWith('--') ? `var(${s})` : s;
37
+ };
38
+
39
+ for (const [cssProp, valOrMap] of Object.entries(properties)) {
40
+ const isMapLike =
41
+ valOrMap && typeof valOrMap === 'object' && !Array.isArray(valOrMap) && Object.keys(valOrMap).some((k) => BPS.includes(k as BreakpointKey));
12
42
 
13
- if (!result[mediaQuery]) result[mediaQuery] = {};
14
- result[mediaQuery][cssProp] = token.startsWith('--') ? `var(${token})` : token;
15
- });
16
- });
43
+ if (isMapLike) {
44
+ const map = valOrMap as BreakpointMap;
45
+ for (const bp of BPS) {
46
+ const token = map[bp];
47
+ if (token === undefined) continue;
48
+ const media = queries[bp as keyof typeof queries];
49
+ if (!result[media]) result[media] = {};
50
+ result[media][cssProp] = toCssValue(token);
51
+ }
52
+ } else {
53
+ // single value => apply to all breakpoints
54
+ const token = valOrMap as ResponsiveValue;
55
+ for (const bp of BPS) {
56
+ const media = queries[bp as keyof typeof queries];
57
+ if (!result[media]) result[media] = {};
58
+ result[media][cssProp] = toCssValue(token);
59
+ }
60
+ }
61
+ }
17
62
 
18
63
  return result;
19
64
  }
65
+
66
+ /**
67
+ * Generate a responsive calc() subtraction: calc(base - other).
68
+ *
69
+ * - base: static value (string/number), e.g. "100vh"
70
+ * - other: either a single value or a BreakpointMap
71
+ *
72
+ * Example:
73
+ * calcResponsiveSubtract('100vh', { mobile: '50px', md: '80px' })
74
+ *
75
+ * => {
76
+ * mobile: "calc(100vh - 50px)",
77
+ * md: "calc(100vh - 80px)"
78
+ * }
79
+ */
80
+ export function calcResponsiveSubtract(base: ResponsiveValue, other: ResponsiveValue | BreakpointMap): BreakpointMap {
81
+ const build = (otherVal: ResponsiveValue) => `calc(${String(base)} - ${String(otherVal)})`;
82
+
83
+ const out: BreakpointMap = {};
84
+
85
+ const isMapLike = other && typeof other === 'object' && !Array.isArray(other) && Object.keys(other).some((k) => BPS.includes(k as BreakpointKey));
86
+
87
+ if (isMapLike) {
88
+ const map = other as BreakpointMap;
89
+ for (const bp of BPS) {
90
+ const token = map[bp];
91
+ if (token === undefined) continue;
92
+ out[bp] = build(token);
93
+ }
94
+ } else {
95
+ const token = other as ResponsiveValue;
96
+ for (const bp of BPS) {
97
+ out[bp] = build(token);
98
+ }
99
+ }
100
+
101
+ return out;
102
+ }