eva-css-for-tailwind 1.0.0
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/README.md +226 -0
- package/dist/cli.js +400 -0
- package/dist/index.d.mts +121 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +369 -0
- package/dist/index.mjs +332 -0
- package/package.json +30 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
// src/clamp.ts
|
|
2
|
+
function round2(n) {
|
|
3
|
+
return Math.round(n * 100) / 100;
|
|
4
|
+
}
|
|
5
|
+
function getPercent(size, screen, ratio = 100) {
|
|
6
|
+
return round2(size / screen * ratio);
|
|
7
|
+
}
|
|
8
|
+
function toRem(size) {
|
|
9
|
+
return size / 16;
|
|
10
|
+
}
|
|
11
|
+
function getMinRem(percent, min) {
|
|
12
|
+
return round2(percent * min);
|
|
13
|
+
}
|
|
14
|
+
function getMaxRem(percent, max) {
|
|
15
|
+
return round2(percent * max);
|
|
16
|
+
}
|
|
17
|
+
function getVW(percent) {
|
|
18
|
+
return round2(percent);
|
|
19
|
+
}
|
|
20
|
+
function getFinalMinDiv(size, ratio) {
|
|
21
|
+
return round2(size / ratio);
|
|
22
|
+
}
|
|
23
|
+
function getFinalMinMulti(size, ratio) {
|
|
24
|
+
return round2(size * ratio);
|
|
25
|
+
}
|
|
26
|
+
function vwLight(calcPercent, sizeRem) {
|
|
27
|
+
return {
|
|
28
|
+
vw: round2(getVW(calcPercent) / 4),
|
|
29
|
+
offset: round2(sizeRem / 1.33)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function vwMedium(calcPercent, sizeRem) {
|
|
33
|
+
return {
|
|
34
|
+
vw: round2(getVW(calcPercent) / 2),
|
|
35
|
+
offset: round2(sizeRem / 2)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function vwStrong(calcPercent, sizeRem) {
|
|
39
|
+
return {
|
|
40
|
+
vw: round2(getVW(calcPercent) / 1.33),
|
|
41
|
+
offset: round2(sizeRem / 4)
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function vwExtrem(calcPercentEz, remMin) {
|
|
45
|
+
return {
|
|
46
|
+
vw: getVW(calcPercentEz),
|
|
47
|
+
offset: round2(-remMin)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function formatClamp(min, fluid, max) {
|
|
51
|
+
const minStr = `${round2(min)}rem`;
|
|
52
|
+
const maxStr = `${round2(max)}rem`;
|
|
53
|
+
const sign = fluid.offset >= 0 ? "+" : "-";
|
|
54
|
+
const absOffset = round2(Math.abs(fluid.offset));
|
|
55
|
+
const fluidStr = `${fluid.vw}vw ${sign} ${absOffset}rem`;
|
|
56
|
+
return `clamp(${minStr}, ${fluidStr}, ${maxStr})`;
|
|
57
|
+
}
|
|
58
|
+
function generateSpacingClamp(sizePx, screen, phi, min, max, ez, intensity) {
|
|
59
|
+
const calcPercent = getPercent(sizePx, screen);
|
|
60
|
+
const calcPercentEz = getPercent(sizePx, screen, ez);
|
|
61
|
+
const sizeRem = toRem(sizePx);
|
|
62
|
+
const remMin = getMinRem(calcPercent, min);
|
|
63
|
+
const remMax = getMaxRem(calcPercent, max);
|
|
64
|
+
switch (intensity) {
|
|
65
|
+
// __ = extreme (most fluid)
|
|
66
|
+
case "__": {
|
|
67
|
+
const fluid = vwExtrem(calcPercentEz, remMin);
|
|
68
|
+
return formatClamp(min, fluid, remMax);
|
|
69
|
+
}
|
|
70
|
+
// _ = strong
|
|
71
|
+
case "_": {
|
|
72
|
+
const finalMin = getFinalMinDiv(remMin, phi);
|
|
73
|
+
const fluid = vwStrong(calcPercent, sizeRem);
|
|
74
|
+
return formatClamp(finalMin, fluid, remMax);
|
|
75
|
+
}
|
|
76
|
+
// '' = normal (default)
|
|
77
|
+
case "": {
|
|
78
|
+
const fluid = vwMedium(calcPercent, sizeRem);
|
|
79
|
+
return formatClamp(remMin, fluid, remMax);
|
|
80
|
+
}
|
|
81
|
+
// - = light (least fluid)
|
|
82
|
+
case "-": {
|
|
83
|
+
const finalMin = getFinalMinMulti(remMin, phi);
|
|
84
|
+
const fluid = vwLight(calcPercent, sizeRem);
|
|
85
|
+
return formatClamp(finalMin, fluid, remMax);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function generateFontClamp(sizePx, screen, phi, min, max, intensity) {
|
|
90
|
+
const calcPercent = getPercent(sizePx, screen);
|
|
91
|
+
const sizeRem = toRem(sizePx);
|
|
92
|
+
const remMin = getMinRem(calcPercent, min);
|
|
93
|
+
const remMax = getMaxRem(calcPercent, max);
|
|
94
|
+
switch (intensity) {
|
|
95
|
+
// __ = most fluid (uses vw-strong + min/phi)
|
|
96
|
+
case "__": {
|
|
97
|
+
const finalMin = getFinalMinDiv(remMin, phi);
|
|
98
|
+
const fluid = vwStrong(calcPercent, sizeRem);
|
|
99
|
+
return formatClamp(finalMin, fluid, remMax);
|
|
100
|
+
}
|
|
101
|
+
// _ = medium (uses vw-medium + remMin)
|
|
102
|
+
case "_": {
|
|
103
|
+
const fluid = vwMedium(calcPercent, sizeRem);
|
|
104
|
+
return formatClamp(remMin, fluid, remMax);
|
|
105
|
+
}
|
|
106
|
+
// '' = least fluid (uses vw-light + min*phi)
|
|
107
|
+
case "": {
|
|
108
|
+
const finalMin = getFinalMinMulti(remMin, phi);
|
|
109
|
+
const fluid = vwLight(calcPercent, sizeRem);
|
|
110
|
+
return formatClamp(finalMin, fluid, remMax);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/types.ts
|
|
116
|
+
var PROPERTY_MAP = {
|
|
117
|
+
// Sizing
|
|
118
|
+
h: "height",
|
|
119
|
+
w: "width",
|
|
120
|
+
"min-h": "min-height",
|
|
121
|
+
"min-w": "min-width",
|
|
122
|
+
"max-w": "max-width",
|
|
123
|
+
"max-h": "max-height",
|
|
124
|
+
// Padding
|
|
125
|
+
p: "padding",
|
|
126
|
+
px: "padding-inline",
|
|
127
|
+
py: "padding-block",
|
|
128
|
+
pt: "padding-top",
|
|
129
|
+
pr: "padding-right",
|
|
130
|
+
pb: "padding-bottom",
|
|
131
|
+
pl: "padding-left",
|
|
132
|
+
// Margin
|
|
133
|
+
m: "margin",
|
|
134
|
+
mx: "margin-inline",
|
|
135
|
+
my: "margin-block",
|
|
136
|
+
mt: "margin-top",
|
|
137
|
+
mr: "margin-right",
|
|
138
|
+
mb: "margin-bottom",
|
|
139
|
+
ml: "margin-left",
|
|
140
|
+
// Layout
|
|
141
|
+
gap: "gap",
|
|
142
|
+
// Borders
|
|
143
|
+
rounded: "border-radius"
|
|
144
|
+
};
|
|
145
|
+
var FONT_PROPERTY_MAP = {
|
|
146
|
+
text: "font-size"
|
|
147
|
+
};
|
|
148
|
+
var SPACING_INTENSITIES = ["__", "_", "", "-"];
|
|
149
|
+
var FONT_INTENSITIES = ["__", "_", ""];
|
|
150
|
+
function resolveConfig(config) {
|
|
151
|
+
return {
|
|
152
|
+
sizes: config.sizes,
|
|
153
|
+
fontSizes: config.fontSizes,
|
|
154
|
+
screen: config.screen ?? 1440,
|
|
155
|
+
phi: config.phi ?? 1.61803398875,
|
|
156
|
+
fontPhi: config.fontPhi ?? 1.3,
|
|
157
|
+
min: config.min ?? 0.5,
|
|
158
|
+
fontMin: config.fontMin ?? 0.5,
|
|
159
|
+
max: config.max ?? 1,
|
|
160
|
+
ez: config.ez ?? 142.4,
|
|
161
|
+
defaultIntensity: config.defaultIntensity ?? ""
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// src/generator.ts
|
|
166
|
+
function parseClass(className) {
|
|
167
|
+
const match = className.match(/^(.+)-\[(\d+(?:\.\d+)?)(px|rem)\]$/);
|
|
168
|
+
if (!match) return null;
|
|
169
|
+
const [, prefix, valueStr, unit] = match;
|
|
170
|
+
const value = parseFloat(valueStr);
|
|
171
|
+
if (prefix in FONT_PROPERTY_MAP) {
|
|
172
|
+
const sizePx = unit === "rem" ? value * 16 : value;
|
|
173
|
+
return {
|
|
174
|
+
raw: className,
|
|
175
|
+
prefix,
|
|
176
|
+
property: FONT_PROPERTY_MAP[prefix],
|
|
177
|
+
size: sizePx,
|
|
178
|
+
unit,
|
|
179
|
+
type: "font"
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
if (prefix in PROPERTY_MAP) {
|
|
183
|
+
const sizePx = unit === "rem" ? value * 16 : value;
|
|
184
|
+
return {
|
|
185
|
+
raw: className,
|
|
186
|
+
prefix,
|
|
187
|
+
property: PROPERTY_MAP[prefix],
|
|
188
|
+
size: sizePx,
|
|
189
|
+
unit,
|
|
190
|
+
type: "spacing"
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
function generateClamp(sizePx, type, intensity, config) {
|
|
196
|
+
const cfg = resolveConfig({
|
|
197
|
+
sizes: [],
|
|
198
|
+
fontSizes: [],
|
|
199
|
+
...config
|
|
200
|
+
});
|
|
201
|
+
if (type === "font") {
|
|
202
|
+
return generateFontClamp(
|
|
203
|
+
sizePx,
|
|
204
|
+
cfg.screen,
|
|
205
|
+
cfg.fontPhi,
|
|
206
|
+
cfg.fontMin,
|
|
207
|
+
cfg.max,
|
|
208
|
+
intensity ?? ""
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
return generateSpacingClamp(
|
|
212
|
+
sizePx,
|
|
213
|
+
cfg.screen,
|
|
214
|
+
cfg.phi,
|
|
215
|
+
cfg.min,
|
|
216
|
+
cfg.max,
|
|
217
|
+
cfg.ez,
|
|
218
|
+
intensity ?? ""
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
function generateVars(config) {
|
|
222
|
+
const cfg = resolveConfig(config);
|
|
223
|
+
const lines = [":root {"];
|
|
224
|
+
for (const size of cfg.sizes) {
|
|
225
|
+
lines.push(` /* ---- ${size}px ---- */`);
|
|
226
|
+
for (const intensity of SPACING_INTENSITIES) {
|
|
227
|
+
const clamp = generateSpacingClamp(
|
|
228
|
+
size,
|
|
229
|
+
cfg.screen,
|
|
230
|
+
cfg.phi,
|
|
231
|
+
cfg.min,
|
|
232
|
+
cfg.max,
|
|
233
|
+
cfg.ez,
|
|
234
|
+
intensity
|
|
235
|
+
);
|
|
236
|
+
lines.push(` --${size}${intensity}: ${clamp};`);
|
|
237
|
+
}
|
|
238
|
+
lines.push("");
|
|
239
|
+
}
|
|
240
|
+
for (const size of cfg.fontSizes) {
|
|
241
|
+
lines.push(` /* ---- fs-${size}px ---- */`);
|
|
242
|
+
for (const intensity of FONT_INTENSITIES) {
|
|
243
|
+
const clamp = generateFontClamp(
|
|
244
|
+
size,
|
|
245
|
+
cfg.screen,
|
|
246
|
+
cfg.fontPhi,
|
|
247
|
+
cfg.fontMin,
|
|
248
|
+
cfg.max,
|
|
249
|
+
intensity
|
|
250
|
+
);
|
|
251
|
+
lines.push(` --fs-${size}${intensity}: ${clamp};`);
|
|
252
|
+
}
|
|
253
|
+
lines.push("");
|
|
254
|
+
}
|
|
255
|
+
lines.push("}");
|
|
256
|
+
return lines.join("\n");
|
|
257
|
+
}
|
|
258
|
+
function escapeTwClass(prefix, value, suffix) {
|
|
259
|
+
return `.${prefix}-\\[${value}\\]${suffix}`;
|
|
260
|
+
}
|
|
261
|
+
function generateClassOverrides(classes, config) {
|
|
262
|
+
const cfg = resolveConfig({ sizes: [], fontSizes: [], ...config });
|
|
263
|
+
const lines = [];
|
|
264
|
+
for (const cls of classes) {
|
|
265
|
+
const parsed = parseClass(cls);
|
|
266
|
+
if (!parsed) continue;
|
|
267
|
+
const valueStr = parsed.unit === "rem" ? `${parsed.size / 16}rem` : `${parsed.size}px`;
|
|
268
|
+
if (parsed.type === "font") {
|
|
269
|
+
for (const intensity of FONT_INTENSITIES) {
|
|
270
|
+
const varRef = `var(--fs-${parsed.size}${intensity})`;
|
|
271
|
+
const selector = escapeTwClass(parsed.prefix, valueStr, intensity);
|
|
272
|
+
lines.push(`${selector} { ${parsed.property}: ${varRef} }`);
|
|
273
|
+
}
|
|
274
|
+
} else {
|
|
275
|
+
for (const intensity of SPACING_INTENSITIES) {
|
|
276
|
+
const varRef = `var(--${parsed.size}${intensity})`;
|
|
277
|
+
const selector = escapeTwClass(parsed.prefix, valueStr, intensity);
|
|
278
|
+
lines.push(`${selector} { ${parsed.property}: ${varRef} }`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
lines.push("");
|
|
282
|
+
}
|
|
283
|
+
return lines.join("\n");
|
|
284
|
+
}
|
|
285
|
+
function generateTheme(config) {
|
|
286
|
+
const cfg = resolveConfig(config);
|
|
287
|
+
const lines = ["@theme {"];
|
|
288
|
+
for (const size of cfg.sizes) {
|
|
289
|
+
lines.push(` --spacing-${size}: var(--${size}${cfg.defaultIntensity});`);
|
|
290
|
+
}
|
|
291
|
+
if (cfg.sizes.length > 0 && cfg.fontSizes.length > 0) {
|
|
292
|
+
lines.push("");
|
|
293
|
+
}
|
|
294
|
+
const fontSuffix = cfg.defaultIntensity === "-" ? "" : cfg.defaultIntensity;
|
|
295
|
+
for (const size of cfg.fontSizes) {
|
|
296
|
+
lines.push(` --font-size-${size}: var(--fs-${size}${fontSuffix});`);
|
|
297
|
+
}
|
|
298
|
+
lines.push("}");
|
|
299
|
+
return lines.join("\n");
|
|
300
|
+
}
|
|
301
|
+
function generateBridge(config) {
|
|
302
|
+
const sections = [
|
|
303
|
+
"/* =============================================================",
|
|
304
|
+
" EVA CSS \u2014 Tailwind Fluid Bridge",
|
|
305
|
+
" Generated by eva-css-for-tailwind",
|
|
306
|
+
" ============================================================= */",
|
|
307
|
+
"",
|
|
308
|
+
generateVars(config)
|
|
309
|
+
];
|
|
310
|
+
if (!config.classes) {
|
|
311
|
+
sections.push("");
|
|
312
|
+
sections.push(generateTheme(config));
|
|
313
|
+
}
|
|
314
|
+
if (config.classes && config.classes.length > 0) {
|
|
315
|
+
sections.push("");
|
|
316
|
+
sections.push(generateClassOverrides(config.classes, config));
|
|
317
|
+
}
|
|
318
|
+
return sections.join("\n");
|
|
319
|
+
}
|
|
320
|
+
export {
|
|
321
|
+
FONT_INTENSITIES,
|
|
322
|
+
FONT_PROPERTY_MAP,
|
|
323
|
+
PROPERTY_MAP,
|
|
324
|
+
SPACING_INTENSITIES,
|
|
325
|
+
generateBridge,
|
|
326
|
+
generateClamp,
|
|
327
|
+
generateClassOverrides,
|
|
328
|
+
generateTheme,
|
|
329
|
+
generateVars,
|
|
330
|
+
parseClass,
|
|
331
|
+
resolveConfig
|
|
332
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "eva-css-for-tailwind",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Fluid design tokens bridge for yCode — converts Tailwind pixel values to clamp()",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"eva-css-for-tailwind": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.mjs",
|
|
15
|
+
"require": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": ["dist"],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"dev": "tsup --watch",
|
|
22
|
+
"test": "node --test src/**/*.test.ts"
|
|
23
|
+
},
|
|
24
|
+
"keywords": ["eva-css", "ycode", "tailwind", "fluid", "clamp", "responsive"],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"tsup": "^8.0.0",
|
|
28
|
+
"typescript": "^5.4.0"
|
|
29
|
+
}
|
|
30
|
+
}
|