@udixio/tailwind 0.5.3 → 1.1.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/.eslintrc.mjs +22 -0
- package/CHANGELOG.md +65 -0
- package/{src → dist}/file.d.ts +2 -1
- package/dist/file.d.ts.map +1 -0
- package/dist/index.cjs +360 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +342 -0
- package/dist/plugins-tailwind/index.d.ts.map +1 -0
- package/{src → dist}/tailwind.plugin.d.ts +1 -2
- package/dist/tailwind.plugin.d.ts.map +1 -0
- package/package.json +11 -7
- package/src/file.ts +163 -0
- package/src/index.test.ts +5 -0
- package/src/index.ts +5 -0
- package/src/main.ts +52 -0
- package/src/plugins-tailwind/font.ts +61 -0
- package/src/plugins-tailwind/index.ts +2 -0
- package/src/plugins-tailwind/state.ts +75 -0
- package/src/tailwind.plugin.ts +133 -0
- package/tsconfig.json +16 -0
- package/tsconfig.lib.json +37 -0
- package/tsconfig.spec.json +36 -0
- package/vite.config.ts +54 -0
- package/index.cjs +0 -313
- package/index.js +0 -296
- package/src/file.d.ts.map +0 -1
- package/src/index.d.ts +0 -6
- package/src/index.d.ts.map +0 -1
- package/src/main.d.ts +0 -3
- package/src/main.d.ts.map +0 -1
- package/src/plugins-tailwind/font.d.ts +0 -4
- package/src/plugins-tailwind/font.d.ts.map +0 -1
- package/src/plugins-tailwind/index.d.ts.map +0 -1
- package/src/plugins-tailwind/state.d.ts +0 -3
- package/src/plugins-tailwind/state.d.ts.map +0 -1
- package/src/tailwind.plugin.d.ts.map +0 -1
- /package/{LICENSE → dist/LICENSE} +0 -0
- /package/{src → dist}/plugins-tailwind/index.d.ts +0 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
import plugin from "tailwindcss/plugin";
|
|
5
|
+
import * as fs from "fs";
|
|
6
|
+
import * as path from "path";
|
|
7
|
+
import path__default from "path";
|
|
8
|
+
import { replaceInFileSync } from "replace-in-file";
|
|
9
|
+
import * as console from "node:console";
|
|
10
|
+
import { PluginAbstract, FontPlugin, PluginImplAbstract } from "@udixio/theme";
|
|
11
|
+
const defaultConfig = {
|
|
12
|
+
statePrefix: "state",
|
|
13
|
+
disabledStyles: {
|
|
14
|
+
textOpacity: 0.38,
|
|
15
|
+
backgroundOpacity: 0.12
|
|
16
|
+
},
|
|
17
|
+
transition: {
|
|
18
|
+
duration: 150
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const state = plugin.withOptions(({ colorKeys }) => {
|
|
22
|
+
const resolved = {
|
|
23
|
+
...defaultConfig,
|
|
24
|
+
disabledStyles: {
|
|
25
|
+
...defaultConfig.disabledStyles,
|
|
26
|
+
...{}
|
|
27
|
+
},
|
|
28
|
+
transition: {
|
|
29
|
+
...defaultConfig.transition,
|
|
30
|
+
...{}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
return ({ addComponents }) => {
|
|
34
|
+
const newComponents = {};
|
|
35
|
+
for (const isGroup of [false, true]) {
|
|
36
|
+
const group = isGroup ? "group-" : "";
|
|
37
|
+
for (const colorName of colorKeys) {
|
|
38
|
+
const className = `.${group}${resolved.statePrefix}-${colorName}`;
|
|
39
|
+
newComponents[className] = {
|
|
40
|
+
[`@apply ${group}hover:bg-${colorName}/[0.08]`]: {},
|
|
41
|
+
[`@apply ${group}active:bg-${colorName}/[0.12]`]: {},
|
|
42
|
+
[`@apply ${group}focus-visible:bg-${colorName}/[0.12]`]: {},
|
|
43
|
+
[`@apply transition-colors`]: {},
|
|
44
|
+
[`@apply duration-${resolved.transition.duration}`]: {},
|
|
45
|
+
[`@apply ${group}disabled:text-on-surface/[${resolved.disabledStyles.textOpacity}]`]: {},
|
|
46
|
+
[`@apply ${group}disabled:bg-on-surface/[${resolved.disabledStyles.backgroundOpacity}]`]: {}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
for (const colorName of colorKeys) {
|
|
51
|
+
for (const stateName of ["hover", "active", "focus", "disabled"]) {
|
|
52
|
+
const className = `.${stateName}-${resolved.statePrefix}-${colorName}`;
|
|
53
|
+
if (stateName === "disabled") {
|
|
54
|
+
newComponents[className] = {
|
|
55
|
+
[`@apply text-on-surface/[${resolved.disabledStyles.textOpacity}]`]: {},
|
|
56
|
+
[`@apply bg-on-surface/[${resolved.disabledStyles.backgroundOpacity}]`]: {}
|
|
57
|
+
};
|
|
58
|
+
} else {
|
|
59
|
+
const opacity = stateName === "hover" ? 0.08 : 0.12;
|
|
60
|
+
newComponents[className] = {
|
|
61
|
+
[`@apply bg-${colorName}/[${opacity}]`]: {}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
addComponents(newComponents);
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
const font = plugin.withOptions((options) => {
|
|
70
|
+
return ({
|
|
71
|
+
addUtilities,
|
|
72
|
+
theme
|
|
73
|
+
}) => {
|
|
74
|
+
const { fontStyles, responsiveBreakPoints } = options;
|
|
75
|
+
const pixelUnit = "rem";
|
|
76
|
+
const newUtilities = {};
|
|
77
|
+
const baseTextStyle = (sizeValue) => ({
|
|
78
|
+
fontSize: sizeValue.fontSize + pixelUnit,
|
|
79
|
+
fontWeight: sizeValue.fontWeight,
|
|
80
|
+
lineHeight: sizeValue.lineHeight + pixelUnit,
|
|
81
|
+
letterSpacing: sizeValue.letterSpacing ? sizeValue.letterSpacing + pixelUnit : null,
|
|
82
|
+
fontFamily: theme("fontFamily." + sizeValue.fontFamily)
|
|
83
|
+
});
|
|
84
|
+
const responsiveTextStyle = (sizeValue, breakPointName, breakPointRatio) => ({
|
|
85
|
+
[`@media (min-width: ${theme("screens." + breakPointName, {})})`]: {
|
|
86
|
+
fontSize: sizeValue.fontSize * breakPointRatio + pixelUnit,
|
|
87
|
+
lineHeight: sizeValue.lineHeight * breakPointRatio + pixelUnit
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
for (const [roleName, roleValue] of Object.entries(fontStyles)) {
|
|
91
|
+
for (const [sizeName, sizeValue] of Object.entries(roleValue)) {
|
|
92
|
+
newUtilities[`.text-${roleName}-${sizeName}`] = {
|
|
93
|
+
...baseTextStyle(sizeValue),
|
|
94
|
+
...Object.entries(responsiveBreakPoints).reduce(
|
|
95
|
+
(acc, [breakPointName, breakPointRatio]) => ({
|
|
96
|
+
...acc,
|
|
97
|
+
...responsiveTextStyle(
|
|
98
|
+
sizeValue,
|
|
99
|
+
breakPointName,
|
|
100
|
+
breakPointRatio
|
|
101
|
+
)
|
|
102
|
+
}),
|
|
103
|
+
{}
|
|
104
|
+
)
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
addUtilities(newUtilities);
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
const main = plugin.withOptions((args) => {
|
|
112
|
+
const configCss = args;
|
|
113
|
+
const fontStyles = {};
|
|
114
|
+
configCss.fontStyles.forEach((line) => {
|
|
115
|
+
const [styleToken, ...properties] = line.split(" ");
|
|
116
|
+
const [roleToken, sizeToken] = styleToken.split("-");
|
|
117
|
+
fontStyles[roleToken] ?? (fontStyles[roleToken] = {});
|
|
118
|
+
properties.forEach((properties2) => {
|
|
119
|
+
var _a;
|
|
120
|
+
(_a = fontStyles[roleToken])[sizeToken] ?? (_a[sizeToken] = {});
|
|
121
|
+
const [key, value] = properties2.slice(0, -1).split("[");
|
|
122
|
+
fontStyles[roleToken][sizeToken][key] = value;
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
let breakPointsCss = configCss.responsiveBreakPoints;
|
|
126
|
+
if (!Array.isArray(breakPointsCss)) {
|
|
127
|
+
breakPointsCss = [breakPointsCss];
|
|
128
|
+
}
|
|
129
|
+
const responsiveBreakPoints = {};
|
|
130
|
+
breakPointsCss.forEach(([key, value]) => {
|
|
131
|
+
responsiveBreakPoints[key] = value;
|
|
132
|
+
});
|
|
133
|
+
const options = {
|
|
134
|
+
colorKeys: configCss.colorKeys,
|
|
135
|
+
fontStyles,
|
|
136
|
+
responsiveBreakPoints
|
|
137
|
+
};
|
|
138
|
+
return (api) => {
|
|
139
|
+
font(options).handler(api);
|
|
140
|
+
state(options).handler(api);
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
const createOrUpdateFile = (filePath, content) => {
|
|
144
|
+
try {
|
|
145
|
+
if (!fs.existsSync(filePath)) {
|
|
146
|
+
const dirPath = path.dirname(filePath);
|
|
147
|
+
if (!fs.existsSync(dirPath)) {
|
|
148
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
149
|
+
}
|
|
150
|
+
fs.writeFileSync(filePath, content);
|
|
151
|
+
console.log(`✅ File successfully created: ${filePath}`);
|
|
152
|
+
} else {
|
|
153
|
+
console.log(`⚠️ File already exists: ${filePath}`);
|
|
154
|
+
replaceFileContent(filePath, /[\s\S]*/, content);
|
|
155
|
+
}
|
|
156
|
+
} catch (error) {
|
|
157
|
+
console.error("❌ Error while creating the file:", error);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
const getFileContent = (filePath, searchPattern) => {
|
|
161
|
+
try {
|
|
162
|
+
if (!fs.existsSync(filePath)) {
|
|
163
|
+
console.error(`❌ The specified file does not exist: ${filePath}`);
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
const fileContent = fs.readFileSync(filePath, "utf8");
|
|
167
|
+
if (searchPattern) {
|
|
168
|
+
if (typeof searchPattern === "string") {
|
|
169
|
+
const found = fileContent.includes(searchPattern) ? searchPattern : false;
|
|
170
|
+
console.log(
|
|
171
|
+
found ? `✅ The file contains the specified string: "${searchPattern}"` : `⚠️ The file does NOT contain the specified string: "${searchPattern}"`
|
|
172
|
+
);
|
|
173
|
+
return found;
|
|
174
|
+
} else {
|
|
175
|
+
const match = fileContent.match(searchPattern);
|
|
176
|
+
if (match) {
|
|
177
|
+
console.log(`✅ Found match: "${match[0]}"`);
|
|
178
|
+
return match[0];
|
|
179
|
+
} else {
|
|
180
|
+
console.log(
|
|
181
|
+
`⚠️ No match found for the pattern: "${searchPattern.toString()}"`
|
|
182
|
+
);
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
console.log(`✅ File content successfully retrieved.`);
|
|
188
|
+
return fileContent;
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.error("❌ An error occurred while processing the file:", error);
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
const replaceFileContent = (filePath, searchPattern, replacement) => {
|
|
195
|
+
try {
|
|
196
|
+
const results = replaceInFileSync({
|
|
197
|
+
files: filePath,
|
|
198
|
+
from: searchPattern,
|
|
199
|
+
to: replacement
|
|
200
|
+
});
|
|
201
|
+
if (results.length > 0 && results[0].hasChanged) {
|
|
202
|
+
console.log(`✅ Content successfully replaced in the file: ${filePath}`);
|
|
203
|
+
} else {
|
|
204
|
+
console.log(
|
|
205
|
+
`⚠️ No replacement made. Here are some possible reasons:
|
|
206
|
+
- The pattern ${searchPattern} was not found.
|
|
207
|
+
- The file might already contain the expected content.`
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
} catch (error) {
|
|
211
|
+
console.error("❌ Error while replacing the file content:", error);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
const findTailwindCssFile = (startDir, searchPattern) => {
|
|
215
|
+
console.log("Recherche du fichier contenant le motif...", startDir);
|
|
216
|
+
const stack = [startDir];
|
|
217
|
+
while (stack.length > 0) {
|
|
218
|
+
const currentDir = stack.pop();
|
|
219
|
+
const files = fs.readdirSync(currentDir);
|
|
220
|
+
for (const file of files) {
|
|
221
|
+
const filePath = path.join(currentDir, file);
|
|
222
|
+
let stats;
|
|
223
|
+
try {
|
|
224
|
+
stats = fs.statSync(filePath);
|
|
225
|
+
} catch (error) {
|
|
226
|
+
console.error(`Erreur lors de l'accès à ${filePath}:`, error);
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (stats.isDirectory()) {
|
|
230
|
+
if (file !== "node_modules") stack.push(filePath);
|
|
231
|
+
} else if (stats.isFile() && (file.endsWith(".css") || file.endsWith(".scss") || file.endsWith(".sass"))) {
|
|
232
|
+
try {
|
|
233
|
+
console.log(`Analyse du fichier : ${filePath}`);
|
|
234
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
235
|
+
if (content.match(searchPattern)) {
|
|
236
|
+
console.log("Fichier trouvé :", filePath);
|
|
237
|
+
return filePath;
|
|
238
|
+
}
|
|
239
|
+
} catch (readError) {
|
|
240
|
+
console.error(`Erreur lors de la lecture de ${filePath}:`, readError);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
throw new Error(
|
|
246
|
+
`Impossible de trouver un fichier contenant "${searchPattern}" dans "${startDir}".`
|
|
247
|
+
);
|
|
248
|
+
};
|
|
249
|
+
function findProjectRoot(startPath) {
|
|
250
|
+
let currentPath = startPath;
|
|
251
|
+
while (!fs.existsSync(path.join(currentPath, "package.json"))) {
|
|
252
|
+
const parentPath = path.dirname(currentPath);
|
|
253
|
+
if (currentPath === parentPath) {
|
|
254
|
+
throw new Error("Impossible de localiser la racine du projet.");
|
|
255
|
+
}
|
|
256
|
+
currentPath = parentPath;
|
|
257
|
+
}
|
|
258
|
+
return currentPath;
|
|
259
|
+
}
|
|
260
|
+
class TailwindPlugin extends PluginAbstract {
|
|
261
|
+
constructor() {
|
|
262
|
+
super(...arguments);
|
|
263
|
+
__publicField(this, "dependencies", [FontPlugin]);
|
|
264
|
+
__publicField(this, "name", "tailwind");
|
|
265
|
+
__publicField(this, "pluginClass", TailwindImplPlugin);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
class TailwindImplPlugin extends PluginImplAbstract {
|
|
269
|
+
onInit() {
|
|
270
|
+
var _a;
|
|
271
|
+
(_a = this.options).responsiveBreakPoints ?? (_a.responsiveBreakPoints = {
|
|
272
|
+
lg: 1.125
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
onLoad() {
|
|
276
|
+
let udixioCssPath = this.options.styleFilePath;
|
|
277
|
+
const projectRoot = findProjectRoot(path__default.resolve());
|
|
278
|
+
if (!udixioCssPath) {
|
|
279
|
+
const searchPattern = /@import ["']tailwindcss["'];/;
|
|
280
|
+
const replacement = `@import 'tailwindcss';
|
|
281
|
+
@import "./udixio.css";`;
|
|
282
|
+
const tailwindCssPath = findTailwindCssFile(projectRoot, searchPattern);
|
|
283
|
+
udixioCssPath = path__default.join(tailwindCssPath, "../udixio.css");
|
|
284
|
+
console.log("rrgfgt", tailwindCssPath, udixioCssPath);
|
|
285
|
+
if (!getFileContent(tailwindCssPath, /@import\s+"\.\/udixio\.css";/)) {
|
|
286
|
+
replaceFileContent(tailwindCssPath, searchPattern, replacement);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const colors = {};
|
|
290
|
+
for (const isDark of [false, true]) {
|
|
291
|
+
this.api.themes.update({ isDark });
|
|
292
|
+
for (const [key, value] of this.api.colors.getColors().entries()) {
|
|
293
|
+
const newKey = key.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").toLowerCase();
|
|
294
|
+
colors[newKey] ?? (colors[newKey] = { light: "", dark: "" });
|
|
295
|
+
colors[newKey][isDark ? "dark" : "light"] = value.getHex();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
const { fontStyles, fontFamily } = this.api.plugins.getPlugin(FontPlugin).getInstance().getFonts();
|
|
299
|
+
const configCss = {
|
|
300
|
+
colorKeys: Object.keys(colors).join(", "),
|
|
301
|
+
fontStyles: Object.entries(fontStyles).map(
|
|
302
|
+
([fontRole, fontStyle]) => Object.entries(fontStyle).map(
|
|
303
|
+
([fontSize, fontStyle2]) => `${fontRole}-${fontSize} ${Object.entries(fontStyle2).map(([name, value]) => `${name}[${value}]`).join(" ")}`
|
|
304
|
+
).join(", ")
|
|
305
|
+
).join(", "),
|
|
306
|
+
responsiveBreakPoints: Object.entries(
|
|
307
|
+
this.options.responsiveBreakPoints ?? {}
|
|
308
|
+
).map(([key, value]) => `${key} ${value}`).join(", ")
|
|
309
|
+
};
|
|
310
|
+
createOrUpdateFile(
|
|
311
|
+
udixioCssPath,
|
|
312
|
+
`
|
|
313
|
+
@plugin "@udixio/tailwind" {
|
|
314
|
+
colorKeys: ${configCss.colorKeys};
|
|
315
|
+
fontStyles: ${configCss.fontStyles};
|
|
316
|
+
responsiveBreakPoints: ${configCss.responsiveBreakPoints};
|
|
317
|
+
}
|
|
318
|
+
@custom-variant dark (&:where(.dark, .dark *));
|
|
319
|
+
@theme {
|
|
320
|
+
--color-*: initial;
|
|
321
|
+
${Object.entries(colors).map(([key, value]) => `--color-${key}: ${value.light};`).join("\n ")}
|
|
322
|
+
}
|
|
323
|
+
@layer theme {
|
|
324
|
+
.dark {
|
|
325
|
+
${Object.entries(colors).map(([key, value]) => `--color-${key}: ${value.dark};`).join("\n ")}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
@theme {
|
|
329
|
+
${Object.entries(fontFamily).map(
|
|
330
|
+
([key, values]) => `--font-${key}: ${values.map((value) => `"${value}"`).join(", ")};`
|
|
331
|
+
).join("\n ")}
|
|
332
|
+
}
|
|
333
|
+
`
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
export {
|
|
338
|
+
TailwindPlugin,
|
|
339
|
+
main as default,
|
|
340
|
+
font,
|
|
341
|
+
state
|
|
342
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugins-tailwind/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { default as plugin } from 'tailwindcss/plugin';
|
|
2
1
|
import { FontPlugin, PluginAbstract, PluginImplAbstract } from '@udixio/theme';
|
|
3
2
|
interface TailwindPluginOptions {
|
|
4
3
|
responsiveBreakPoints?: Record<string, number>;
|
|
@@ -11,7 +10,7 @@ export declare class TailwindPlugin extends PluginAbstract<TailwindImplPlugin, T
|
|
|
11
10
|
}
|
|
12
11
|
declare class TailwindImplPlugin extends PluginImplAbstract<TailwindPluginOptions> {
|
|
13
12
|
onInit(): void;
|
|
14
|
-
|
|
13
|
+
onLoad(): void;
|
|
15
14
|
}
|
|
16
15
|
export {};
|
|
17
16
|
//# sourceMappingURL=tailwind.plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tailwind.plugin.d.ts","sourceRoot":"","sources":["../src/tailwind.plugin.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAI/E,UAAU,qBAAqB;IAE7B,qBAAqB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,aAAa,CAAC,EAAE,MAAM,CAAC;CAExB;AAED,qBAAa,cAAe,SAAQ,cAAc,CAChD,kBAAkB,EAClB,qBAAqB,CACtB;IACQ,YAAY,wBAAgB;IAC5B,IAAI,SAAc;IACzB,WAAW,4BAAsB;CAClC;AAED,cAAM,kBAAmB,SAAQ,kBAAkB,CAAC,qBAAqB,CAAC;IACxE,MAAM;IAMN,MAAM;CAiGP"}
|
package/package.json
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@udixio/tailwind",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"main": "./
|
|
6
|
-
"
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
7
8
|
"exports": {
|
|
9
|
+
"./package.json": "./package.json",
|
|
8
10
|
".": {
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
11
|
+
"development": "./src/index.ts",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/index.cjs",
|
|
15
|
+
"default": "./dist/index.js"
|
|
12
16
|
}
|
|
13
17
|
},
|
|
14
18
|
"dependencies": {
|
|
15
19
|
"tslib": "^2.3.0",
|
|
16
|
-
"@udixio/theme": "0.
|
|
20
|
+
"@udixio/theme": "1.0.0"
|
|
17
21
|
},
|
|
18
22
|
"repository": {
|
|
19
23
|
"type": "git",
|
package/src/file.ts
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { replaceInFileSync } from 'replace-in-file';
|
|
4
|
+
import * as console from 'node:console';
|
|
5
|
+
|
|
6
|
+
export const createOrUpdateFile = (filePath: string, content: string): void => {
|
|
7
|
+
try {
|
|
8
|
+
if (!fs.existsSync(filePath)) {
|
|
9
|
+
// Create the folder if necessary.
|
|
10
|
+
const dirPath = path.dirname(filePath);
|
|
11
|
+
if (!fs.existsSync(dirPath)) {
|
|
12
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Create the file with the provided content.
|
|
16
|
+
fs.writeFileSync(filePath, content);
|
|
17
|
+
console.log(`✅ File successfully created: ${filePath}`);
|
|
18
|
+
} else {
|
|
19
|
+
console.log(`⚠️ File already exists: ${filePath}`);
|
|
20
|
+
replaceFileContent(filePath, /[\s\S]*/, content);
|
|
21
|
+
}
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error('❌ Error while creating the file:', error);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const getFileContent = (
|
|
28
|
+
filePath: string,
|
|
29
|
+
searchPattern?: RegExp | string,
|
|
30
|
+
): string | false | null => {
|
|
31
|
+
try {
|
|
32
|
+
// Vérifier si le fichier existe
|
|
33
|
+
if (!fs.existsSync(filePath)) {
|
|
34
|
+
console.error(`❌ The specified file does not exist: ${filePath}`);
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Lire le contenu du fichier entier
|
|
39
|
+
const fileContent = fs.readFileSync(filePath, 'utf8');
|
|
40
|
+
|
|
41
|
+
// Si un motif est fourni, chercher le texte correspondant
|
|
42
|
+
if (searchPattern) {
|
|
43
|
+
if (typeof searchPattern === 'string') {
|
|
44
|
+
const found = fileContent.includes(searchPattern)
|
|
45
|
+
? searchPattern
|
|
46
|
+
: false;
|
|
47
|
+
console.log(
|
|
48
|
+
found
|
|
49
|
+
? `✅ The file contains the specified string: "${searchPattern}"`
|
|
50
|
+
: `⚠️ The file does NOT contain the specified string: "${searchPattern}"`,
|
|
51
|
+
);
|
|
52
|
+
return found;
|
|
53
|
+
} else {
|
|
54
|
+
const match = fileContent.match(searchPattern);
|
|
55
|
+
if (match) {
|
|
56
|
+
console.log(`✅ Found match: "${match[0]}"`);
|
|
57
|
+
return match[0]; // Retourner le texte trouvé
|
|
58
|
+
} else {
|
|
59
|
+
console.log(
|
|
60
|
+
`⚠️ No match found for the pattern: "${searchPattern.toString()}"`,
|
|
61
|
+
);
|
|
62
|
+
return false; // Aucune correspondance trouvée
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Si aucun motif n'est fourni, retourner tout le contenu
|
|
68
|
+
console.log(`✅ File content successfully retrieved.`);
|
|
69
|
+
return fileContent;
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error('❌ An error occurred while processing the file:', error);
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const replaceFileContent = (
|
|
77
|
+
filePath: string,
|
|
78
|
+
searchPattern: RegExp | string,
|
|
79
|
+
replacement: string,
|
|
80
|
+
): void => {
|
|
81
|
+
try {
|
|
82
|
+
const results = replaceInFileSync({
|
|
83
|
+
files: filePath,
|
|
84
|
+
from: searchPattern,
|
|
85
|
+
to: replacement,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
if (results.length > 0 && results[0].hasChanged) {
|
|
89
|
+
console.log(`✅ Content successfully replaced in the file: ${filePath}`);
|
|
90
|
+
} else {
|
|
91
|
+
console.log(
|
|
92
|
+
`⚠️ No replacement made. Here are some possible reasons:\n- The pattern ${searchPattern} was not found.\n- The file might already contain the expected content.`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error('❌ Error while replacing the file content:', error);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
export const findTailwindCssFile = (
|
|
100
|
+
startDir: string,
|
|
101
|
+
searchPattern: RegExp | string,
|
|
102
|
+
): string | never => {
|
|
103
|
+
console.log('Recherche du fichier contenant le motif...', startDir);
|
|
104
|
+
|
|
105
|
+
const stack = [startDir]; // Pile pour éviter une récursion implicite.
|
|
106
|
+
|
|
107
|
+
while (stack.length > 0) {
|
|
108
|
+
const currentDir = stack.pop()!; // Récupérer un répertoire de la pile.
|
|
109
|
+
const files = fs.readdirSync(currentDir);
|
|
110
|
+
|
|
111
|
+
for (const file of files) {
|
|
112
|
+
const filePath = path.join(currentDir, file);
|
|
113
|
+
|
|
114
|
+
let stats: fs.Stats;
|
|
115
|
+
try {
|
|
116
|
+
stats = fs.statSync(filePath);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.error(`Erreur lors de l'accès à ${filePath}:`, error);
|
|
119
|
+
continue; // Ignorer toute erreur d'accès.
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Ignorer le dossier `node_modules` et autres fichiers inutiles.
|
|
123
|
+
if (stats.isDirectory()) {
|
|
124
|
+
if (file !== 'node_modules') stack.push(filePath); // Empiler seulement les dossiers valides.
|
|
125
|
+
} else if (
|
|
126
|
+
stats.isFile() &&
|
|
127
|
+
(file.endsWith('.css') ||
|
|
128
|
+
file.endsWith('.scss') ||
|
|
129
|
+
file.endsWith('.sass'))
|
|
130
|
+
) {
|
|
131
|
+
try {
|
|
132
|
+
console.log(`Analyse du fichier : ${filePath}`);
|
|
133
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
134
|
+
if (content.match(searchPattern)) {
|
|
135
|
+
console.log('Fichier trouvé :', filePath);
|
|
136
|
+
return filePath; // Retour dès qu'un fichier valide est identifié.
|
|
137
|
+
}
|
|
138
|
+
} catch (readError) {
|
|
139
|
+
console.error(`Erreur lors de la lecture de ${filePath}:`, readError);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
throw new Error(
|
|
146
|
+
`Impossible de trouver un fichier contenant "${searchPattern}" dans "${startDir}".`,
|
|
147
|
+
);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export function findProjectRoot(startPath) {
|
|
151
|
+
let currentPath = startPath;
|
|
152
|
+
|
|
153
|
+
// Boucle jusqu'à trouver un package.json ou jusqu'à arriver à la racine du système
|
|
154
|
+
while (!fs.existsSync(path.join(currentPath, 'package.json'))) {
|
|
155
|
+
const parentPath = path.dirname(currentPath);
|
|
156
|
+
if (currentPath === parentPath) {
|
|
157
|
+
throw new Error('Impossible de localiser la racine du projet.');
|
|
158
|
+
}
|
|
159
|
+
currentPath = parentPath;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return currentPath;
|
|
163
|
+
}
|
package/src/index.ts
ADDED
package/src/main.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import plugin, { PluginAPI } from 'tailwindcss/plugin';
|
|
2
|
+
import {
|
|
3
|
+
font,
|
|
4
|
+
FontPluginOptions,
|
|
5
|
+
state,
|
|
6
|
+
StateOptions,
|
|
7
|
+
} from './plugins-tailwind';
|
|
8
|
+
|
|
9
|
+
export type ConfigJs = FontPluginOptions & StateOptions;
|
|
10
|
+
export type ConfigCss = {
|
|
11
|
+
colorKeys: string[];
|
|
12
|
+
fontStyles: string[];
|
|
13
|
+
responsiveBreakPoints: string[];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const main = plugin.withOptions<ConfigJs>((args) => {
|
|
17
|
+
const configCss = args as unknown as ConfigCss;
|
|
18
|
+
|
|
19
|
+
const fontStyles: any = {};
|
|
20
|
+
|
|
21
|
+
configCss.fontStyles.forEach((line) => {
|
|
22
|
+
const [styleToken, ...properties] = line.split(' ');
|
|
23
|
+
const [roleToken, sizeToken] = styleToken.split('-');
|
|
24
|
+
|
|
25
|
+
fontStyles[roleToken] ??= {};
|
|
26
|
+
properties.forEach((properties) => {
|
|
27
|
+
fontStyles[roleToken][sizeToken] ??= {};
|
|
28
|
+
const [key, value] = properties.slice(0, -1).split('[');
|
|
29
|
+
fontStyles[roleToken][sizeToken][key] = value;
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
let breakPointsCss = configCss.responsiveBreakPoints;
|
|
34
|
+
if (!Array.isArray(breakPointsCss)) {
|
|
35
|
+
breakPointsCss = [breakPointsCss];
|
|
36
|
+
}
|
|
37
|
+
const responsiveBreakPoints: any = {};
|
|
38
|
+
breakPointsCss.forEach(([key, value]) => {
|
|
39
|
+
responsiveBreakPoints[key] = value;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const options: ConfigJs = {
|
|
43
|
+
colorKeys: configCss.colorKeys,
|
|
44
|
+
fontStyles: fontStyles,
|
|
45
|
+
responsiveBreakPoints,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return (api: PluginAPI) => {
|
|
49
|
+
font(options).handler(api);
|
|
50
|
+
state(options).handler(api);
|
|
51
|
+
};
|
|
52
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { FontRole, FontSize, FontStyle } from '@udixio/theme';
|
|
2
|
+
import plugin, { PluginAPI } from 'tailwindcss/plugin';
|
|
3
|
+
|
|
4
|
+
export interface FontPluginOptions {
|
|
5
|
+
fontStyles: Record<FontRole, Record<FontSize, FontStyle>>;
|
|
6
|
+
responsiveBreakPoints: Record<string, number>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const font = plugin.withOptions((options: FontPluginOptions) => {
|
|
10
|
+
return ({
|
|
11
|
+
addUtilities,
|
|
12
|
+
theme,
|
|
13
|
+
}: Pick<PluginAPI, 'addUtilities' | 'theme'>) => {
|
|
14
|
+
const { fontStyles, responsiveBreakPoints } = options;
|
|
15
|
+
|
|
16
|
+
const pixelUnit = 'rem';
|
|
17
|
+
const newUtilities: Record<string, any> = {};
|
|
18
|
+
|
|
19
|
+
const baseTextStyle = (sizeValue: FontStyle) => ({
|
|
20
|
+
fontSize: sizeValue.fontSize + pixelUnit,
|
|
21
|
+
fontWeight: sizeValue.fontWeight as unknown as any,
|
|
22
|
+
lineHeight: sizeValue.lineHeight + pixelUnit,
|
|
23
|
+
letterSpacing: sizeValue.letterSpacing
|
|
24
|
+
? sizeValue.letterSpacing + pixelUnit
|
|
25
|
+
: null,
|
|
26
|
+
fontFamily: theme('fontFamily.' + sizeValue.fontFamily),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const responsiveTextStyle = (
|
|
30
|
+
sizeValue: FontStyle,
|
|
31
|
+
breakPointName: string,
|
|
32
|
+
breakPointRatio: number,
|
|
33
|
+
) => ({
|
|
34
|
+
[`@media (min-width: ${theme('screens.' + breakPointName, {})})`]: {
|
|
35
|
+
fontSize: sizeValue.fontSize * breakPointRatio + pixelUnit,
|
|
36
|
+
lineHeight: sizeValue.lineHeight * breakPointRatio + pixelUnit,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
for (const [roleName, roleValue] of Object.entries(fontStyles)) {
|
|
41
|
+
for (const [sizeName, sizeValue] of Object.entries(roleValue)) {
|
|
42
|
+
newUtilities[`.text-${roleName}-${sizeName}`] = {
|
|
43
|
+
...baseTextStyle(sizeValue),
|
|
44
|
+
...Object.entries(responsiveBreakPoints).reduce(
|
|
45
|
+
(acc, [breakPointName, breakPointRatio]) => ({
|
|
46
|
+
...acc,
|
|
47
|
+
...responsiveTextStyle(
|
|
48
|
+
sizeValue,
|
|
49
|
+
breakPointName,
|
|
50
|
+
breakPointRatio,
|
|
51
|
+
),
|
|
52
|
+
}),
|
|
53
|
+
{},
|
|
54
|
+
),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
addUtilities(newUtilities);
|
|
60
|
+
};
|
|
61
|
+
});
|