@shohojdhara/atomix 0.3.2 ā 0.3.4
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 +58 -21
- package/dist/atomix.css +96 -121
- package/dist/atomix.min.css +3 -3
- package/dist/index.d.ts +7937 -7765
- package/dist/index.esm.js +3677 -4031
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +3648 -3952
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/package.json +44 -16
- package/scripts/atomix-cli.js +1764 -0
- package/scripts/build-themes.js +208 -0
- package/scripts/cli/interactive-init.js +520 -0
- package/scripts/cli/migration-tools.js +603 -0
- package/scripts/cli/theme-bridge.js +129 -0
- package/scripts/cli/token-manager.js +519 -0
- package/scripts/sync-theme-config.js +309 -0
- package/src/components/Button/Button.tsx +36 -1
- package/src/components/List/ListGroup.tsx +1 -2
- package/src/components/Popover/Popover.tsx +2 -2
- package/src/components/Tooltip/Tooltip.stories.tsx +49 -12
- package/src/components/Tooltip/Tooltip.tsx +32 -58
- package/src/lib/composables/useTooltip.ts +285 -0
- package/src/lib/config/index.ts +275 -0
- package/src/lib/config/loader.ts +105 -0
- package/src/lib/constants/cssVariables.ts +390 -0
- package/src/lib/hooks/__tests__/useComponentCustomization.test.ts +151 -0
- package/src/lib/hooks/index.ts +19 -0
- package/src/lib/hooks/useComponentCustomization.ts +175 -0
- package/src/lib/index.ts +14 -1
- package/src/lib/patterns/__tests__/slots.test.ts +108 -0
- package/src/lib/patterns/index.ts +35 -0
- package/src/lib/patterns/slots.tsx +421 -0
- package/src/lib/theme/composeTheme.ts +0 -5
- package/src/lib/theme/config/index.ts +1 -1
- package/src/lib/theme/config/loader.ts +75 -41
- package/src/lib/theme/config/types.ts +21 -7
- package/src/lib/theme/config/validator.ts +1 -1
- package/src/lib/theme/constants.ts +12 -2
- package/src/lib/theme/createTheme.ts +2 -135
- package/src/lib/theme/createThemeFromConfig.ts +132 -0
- package/src/lib/theme/cssVariableMapper.ts +261 -0
- package/src/lib/theme/devtools/CLI.ts +161 -76
- package/src/lib/theme/devtools/Comparator.tsx +343 -0
- package/src/lib/theme/devtools/IMPROVEMENTS.md +429 -0
- package/src/lib/theme/devtools/Inspector.tsx +21 -6
- package/src/lib/theme/devtools/LiveEditor.tsx +393 -0
- package/src/lib/theme/devtools/README.md +433 -0
- package/src/lib/theme/devtools/index.ts +12 -11
- package/src/lib/theme/generateCSSVariables.ts +79 -38
- package/src/lib/theme/index.ts +45 -246
- package/src/lib/theme/runtime/ThemeApplicator.ts +252 -0
- package/src/lib/theme/runtime/ThemeManager.test.ts +17 -1
- package/src/lib/theme/runtime/ThemeManager.ts +7 -7
- package/src/lib/theme/themeUtils.ts +27 -5
- package/src/lib/theme/types.ts +59 -1
- package/src/lib/theme-tools.ts +125 -0
- package/src/lib/types/components.ts +260 -72
- package/src/lib/types/partProps.ts +426 -0
- package/src/lib/utils/__tests__/componentUtils.test.ts +144 -0
- package/src/lib/utils/componentUtils.ts +163 -0
- package/src/lib/utils/index.ts +17 -57
- package/src/styles/01-settings/_settings.colors.scss +10 -10
- package/src/styles/01-settings/_settings.navbar.scss +1 -1
- package/src/styles/01-settings/_settings.tooltip.scss +1 -1
- package/src/styles/03-generic/_generated-root.css +5 -0
- package/src/styles/06-components/_components.navbar.scss +12 -5
- package/src/styles/06-components/_components.tooltip.scss +31 -81
- package/src/themes/README.md +442 -0
- package/src/themes/themes.config.js +35 -0
- package/src/lib/theme/errors.test.ts +0 -207
- package/src/lib/theme/generators/CSSGenerator.ts +0 -311
- package/src/lib/theme/generators/ConfigGenerator.ts +0 -287
- package/src/lib/theme/generators/TypeGenerator.ts +0 -228
- package/src/lib/theme/generators/index.ts +0 -21
- package/src/lib/theme/monitoring/ThemeAnalytics.ts +0 -409
- package/src/lib/theme/monitoring/index.ts +0 -17
- package/src/lib/theme/overrides/ComponentOverrides.ts +0 -243
- package/src/lib/theme/overrides/index.ts +0 -15
- package/src/lib/theme/studio/ThemeStudio.tsx +0 -312
- package/src/lib/theme/studio/index.ts +0 -8
- package/src/lib/theme/whitelabel/WhiteLabelManager.ts +0 -364
- package/src/lib/theme/whitelabel/index.ts +0 -13
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration Tools for Atomix Design System
|
|
3
|
+
* Helps migrate from other design systems and CSS frameworks
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readFile, writeFile, readdir, stat } from 'fs/promises';
|
|
7
|
+
import { join, extname, relative } from 'path';
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
import ora from 'ora';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Tailwind to Atomix mapping
|
|
13
|
+
*/
|
|
14
|
+
const tailwindToAtomix = {
|
|
15
|
+
// Colors
|
|
16
|
+
'bg-primary': 'c-bg-primary',
|
|
17
|
+
'text-primary': 'c-text-primary',
|
|
18
|
+
'border-primary': 'c-border-primary',
|
|
19
|
+
|
|
20
|
+
// Spacing
|
|
21
|
+
'p-0': 'u-p-0',
|
|
22
|
+
'p-1': 'u-p-1',
|
|
23
|
+
'p-2': 'u-p-2',
|
|
24
|
+
'p-3': 'u-p-3',
|
|
25
|
+
'p-4': 'u-p-4',
|
|
26
|
+
'p-5': 'u-p-5',
|
|
27
|
+
'p-6': 'u-p-6',
|
|
28
|
+
'p-8': 'u-p-8',
|
|
29
|
+
|
|
30
|
+
'm-0': 'u-m-0',
|
|
31
|
+
'm-1': 'u-m-1',
|
|
32
|
+
'm-2': 'u-m-2',
|
|
33
|
+
'm-3': 'u-m-3',
|
|
34
|
+
'm-4': 'u-m-4',
|
|
35
|
+
'm-auto': 'u-m-auto',
|
|
36
|
+
|
|
37
|
+
// Flexbox
|
|
38
|
+
'flex': 'u-flex',
|
|
39
|
+
'flex-row': 'u-flex-row',
|
|
40
|
+
'flex-col': 'u-flex-column',
|
|
41
|
+
'items-center': 'u-items-center',
|
|
42
|
+
'justify-center': 'u-justify-center',
|
|
43
|
+
'justify-between': 'u-justify-between',
|
|
44
|
+
'gap-1': 'u-gap-1',
|
|
45
|
+
'gap-2': 'u-gap-2',
|
|
46
|
+
'gap-4': 'u-gap-4',
|
|
47
|
+
|
|
48
|
+
// Display
|
|
49
|
+
'hidden': 'u-hidden',
|
|
50
|
+
'block': 'u-block',
|
|
51
|
+
'inline-block': 'u-inline-block',
|
|
52
|
+
'inline': 'u-inline',
|
|
53
|
+
'grid': 'u-grid',
|
|
54
|
+
|
|
55
|
+
// Typography
|
|
56
|
+
'text-xs': 'u-text-xs',
|
|
57
|
+
'text-sm': 'u-text-sm',
|
|
58
|
+
'text-base': 'u-text-base',
|
|
59
|
+
'text-lg': 'u-text-lg',
|
|
60
|
+
'text-xl': 'u-text-xl',
|
|
61
|
+
'text-2xl': 'u-text-2xl',
|
|
62
|
+
'font-bold': 'u-font-bold',
|
|
63
|
+
'font-semibold': 'u-font-semibold',
|
|
64
|
+
'font-normal': 'u-font-normal',
|
|
65
|
+
|
|
66
|
+
// Border
|
|
67
|
+
'border': 'u-border',
|
|
68
|
+
'border-2': 'u-border-2',
|
|
69
|
+
'rounded': 'u-rounded',
|
|
70
|
+
'rounded-md': 'u-rounded-md',
|
|
71
|
+
'rounded-lg': 'u-rounded-lg',
|
|
72
|
+
'rounded-full': 'u-rounded-full',
|
|
73
|
+
|
|
74
|
+
// Components
|
|
75
|
+
'btn': 'c-btn',
|
|
76
|
+
'btn-primary': 'c-btn c-btn-primary',
|
|
77
|
+
'btn-secondary': 'c-btn c-btn-secondary',
|
|
78
|
+
'card': 'c-card',
|
|
79
|
+
'badge': 'c-badge',
|
|
80
|
+
'alert': 'c-alert',
|
|
81
|
+
'input': 'c-input',
|
|
82
|
+
'select': 'c-select',
|
|
83
|
+
'checkbox': 'c-checkbox',
|
|
84
|
+
'radio': 'c-radio',
|
|
85
|
+
|
|
86
|
+
// Responsive prefixes
|
|
87
|
+
'sm:': '@sm:',
|
|
88
|
+
'md:': '@md:',
|
|
89
|
+
'lg:': '@lg:',
|
|
90
|
+
'xl:': '@xl:',
|
|
91
|
+
|
|
92
|
+
// States
|
|
93
|
+
'hover:': ':hover ',
|
|
94
|
+
'focus:': ':focus ',
|
|
95
|
+
'active:': ':active ',
|
|
96
|
+
'disabled:': ':disabled '
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Bootstrap to Atomix mapping
|
|
101
|
+
*/
|
|
102
|
+
const bootstrapToAtomix = {
|
|
103
|
+
// Components
|
|
104
|
+
'btn': 'c-btn',
|
|
105
|
+
'btn-primary': 'c-btn c-btn-primary',
|
|
106
|
+
'btn-secondary': 'c-btn c-btn-secondary',
|
|
107
|
+
'btn-success': 'c-btn c-btn-success',
|
|
108
|
+
'btn-danger': 'c-btn c-btn-error',
|
|
109
|
+
'btn-warning': 'c-btn c-btn-warning',
|
|
110
|
+
'btn-info': 'c-btn c-btn-info',
|
|
111
|
+
'btn-lg': 'c-btn c-btn-lg',
|
|
112
|
+
'btn-sm': 'c-btn c-btn-sm',
|
|
113
|
+
|
|
114
|
+
'card': 'c-card',
|
|
115
|
+
'card-header': 'c-card__header',
|
|
116
|
+
'card-body': 'c-card__body',
|
|
117
|
+
'card-footer': 'c-card__footer',
|
|
118
|
+
'card-title': 'c-card__title',
|
|
119
|
+
'card-text': 'c-card__text',
|
|
120
|
+
|
|
121
|
+
'alert': 'c-alert',
|
|
122
|
+
'alert-primary': 'c-alert c-alert-primary',
|
|
123
|
+
'alert-success': 'c-alert c-alert-success',
|
|
124
|
+
'alert-danger': 'c-alert c-alert-error',
|
|
125
|
+
'alert-warning': 'c-alert c-alert-warning',
|
|
126
|
+
|
|
127
|
+
'badge': 'c-badge',
|
|
128
|
+
'badge-primary': 'c-badge c-badge-primary',
|
|
129
|
+
'badge-secondary': 'c-badge c-badge-secondary',
|
|
130
|
+
|
|
131
|
+
'form-control': 'c-input',
|
|
132
|
+
'form-select': 'c-select',
|
|
133
|
+
'form-check': 'c-form-check',
|
|
134
|
+
'form-check-input': 'c-checkbox',
|
|
135
|
+
'form-label': 'c-label',
|
|
136
|
+
|
|
137
|
+
'modal': 'c-modal',
|
|
138
|
+
'modal-dialog': 'c-modal__dialog',
|
|
139
|
+
'modal-content': 'c-modal__content',
|
|
140
|
+
'modal-header': 'c-modal__header',
|
|
141
|
+
'modal-body': 'c-modal__body',
|
|
142
|
+
'modal-footer': 'c-modal__footer',
|
|
143
|
+
|
|
144
|
+
// Grid
|
|
145
|
+
'container': 'o-container',
|
|
146
|
+
'container-fluid': 'o-container-fluid',
|
|
147
|
+
'row': 'o-row',
|
|
148
|
+
'col': 'o-col',
|
|
149
|
+
'col-sm': 'o-col-sm',
|
|
150
|
+
'col-md': 'o-col-md',
|
|
151
|
+
'col-lg': 'o-col-lg',
|
|
152
|
+
'col-xl': 'o-col-xl',
|
|
153
|
+
|
|
154
|
+
// Utilities
|
|
155
|
+
'd-none': 'u-hidden',
|
|
156
|
+
'd-block': 'u-block',
|
|
157
|
+
'd-inline': 'u-inline',
|
|
158
|
+
'd-inline-block': 'u-inline-block',
|
|
159
|
+
'd-flex': 'u-flex',
|
|
160
|
+
'd-grid': 'u-grid',
|
|
161
|
+
|
|
162
|
+
'text-center': 'u-text-center',
|
|
163
|
+
'text-left': 'u-text-left',
|
|
164
|
+
'text-right': 'u-text-right',
|
|
165
|
+
'text-justify': 'u-text-justify',
|
|
166
|
+
|
|
167
|
+
'text-primary': 'u-text-primary',
|
|
168
|
+
'text-success': 'u-text-success',
|
|
169
|
+
'text-danger': 'u-text-error',
|
|
170
|
+
'text-warning': 'u-text-warning',
|
|
171
|
+
'text-muted': 'u-text-muted',
|
|
172
|
+
|
|
173
|
+
'bg-primary': 'u-bg-primary',
|
|
174
|
+
'bg-success': 'u-bg-success',
|
|
175
|
+
'bg-danger': 'u-bg-error',
|
|
176
|
+
'bg-warning': 'u-bg-warning',
|
|
177
|
+
|
|
178
|
+
'p-0': 'u-p-0',
|
|
179
|
+
'p-1': 'u-p-1',
|
|
180
|
+
'p-2': 'u-p-2',
|
|
181
|
+
'p-3': 'u-p-3',
|
|
182
|
+
'p-4': 'u-p-4',
|
|
183
|
+
'p-5': 'u-p-5',
|
|
184
|
+
|
|
185
|
+
'm-0': 'u-m-0',
|
|
186
|
+
'm-1': 'u-m-1',
|
|
187
|
+
'm-2': 'u-m-2',
|
|
188
|
+
'm-3': 'u-m-3',
|
|
189
|
+
'm-4': 'u-m-4',
|
|
190
|
+
'm-5': 'u-m-5',
|
|
191
|
+
'm-auto': 'u-m-auto',
|
|
192
|
+
|
|
193
|
+
'rounded': 'u-rounded',
|
|
194
|
+
'rounded-circle': 'u-rounded-full',
|
|
195
|
+
'border': 'u-border',
|
|
196
|
+
|
|
197
|
+
'w-25': 'u-w-25',
|
|
198
|
+
'w-50': 'u-w-50',
|
|
199
|
+
'w-75': 'u-w-75',
|
|
200
|
+
'w-100': 'u-w-100',
|
|
201
|
+
'h-25': 'u-h-25',
|
|
202
|
+
'h-50': 'u-h-50',
|
|
203
|
+
'h-75': 'u-h-75',
|
|
204
|
+
'h-100': 'u-h-100'
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* SCSS Variable Migration
|
|
209
|
+
*/
|
|
210
|
+
const scssVariableMigration = {
|
|
211
|
+
// Colors
|
|
212
|
+
'$primary': 'var(--atomix-color-primary)',
|
|
213
|
+
'$secondary': 'var(--atomix-color-secondary)',
|
|
214
|
+
'$success': 'var(--atomix-color-success)',
|
|
215
|
+
'$danger': 'var(--atomix-color-error)',
|
|
216
|
+
'$warning': 'var(--atomix-color-warning)',
|
|
217
|
+
'$info': 'var(--atomix-color-info)',
|
|
218
|
+
'$light': 'var(--atomix-color-light)',
|
|
219
|
+
'$dark': 'var(--atomix-color-dark)',
|
|
220
|
+
|
|
221
|
+
// Spacing
|
|
222
|
+
'$spacer': 'var(--atomix-space-4)',
|
|
223
|
+
'$spacing-xs': 'var(--atomix-space-1)',
|
|
224
|
+
'$spacing-sm': 'var(--atomix-space-2)',
|
|
225
|
+
'$spacing-md': 'var(--atomix-space-4)',
|
|
226
|
+
'$spacing-lg': 'var(--atomix-space-6)',
|
|
227
|
+
'$spacing-xl': 'var(--atomix-space-8)',
|
|
228
|
+
|
|
229
|
+
// Typography
|
|
230
|
+
'$font-family-base': 'var(--atomix-font-family-base)',
|
|
231
|
+
'$font-size-base': 'var(--atomix-font-size-base)',
|
|
232
|
+
'$font-weight-normal': 'var(--atomix-font-weight-normal)',
|
|
233
|
+
'$font-weight-bold': 'var(--atomix-font-weight-bold)',
|
|
234
|
+
'$line-height-base': 'var(--atomix-line-height-base)',
|
|
235
|
+
|
|
236
|
+
// Border
|
|
237
|
+
'$border-radius': 'var(--atomix-radius-md)',
|
|
238
|
+
'$border-width': 'var(--atomix-border-width)',
|
|
239
|
+
'$border-color': 'var(--atomix-color-border)'
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Migrate Tailwind classes to Atomix
|
|
244
|
+
*/
|
|
245
|
+
export async function migrateTailwind(sourcePath, options = {}) {
|
|
246
|
+
const spinner = ora('Migrating from Tailwind CSS...').start();
|
|
247
|
+
const report = {
|
|
248
|
+
filesProcessed: 0,
|
|
249
|
+
classesReplaced: 0,
|
|
250
|
+
warnings: [],
|
|
251
|
+
errors: []
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
try {
|
|
255
|
+
const files = await getAllFiles(sourcePath, ['.jsx', '.tsx', '.js', '.ts', '.html']);
|
|
256
|
+
|
|
257
|
+
for (const file of files) {
|
|
258
|
+
spinner.text = `Processing ${relative(process.cwd(), file)}...`;
|
|
259
|
+
|
|
260
|
+
try {
|
|
261
|
+
let content = await readFile(file, 'utf8');
|
|
262
|
+
const originalContent = content;
|
|
263
|
+
let replacementCount = 0;
|
|
264
|
+
|
|
265
|
+
// Replace className attributes
|
|
266
|
+
content = content.replace(/className=["']([^"']+)["']/g, (match, classes) => {
|
|
267
|
+
const classList = classes.split(' ');
|
|
268
|
+
const newClasses = classList.map(cls => {
|
|
269
|
+
const trimmed = cls.trim();
|
|
270
|
+
if (tailwindToAtomix[trimmed]) {
|
|
271
|
+
replacementCount++;
|
|
272
|
+
return tailwindToAtomix[trimmed];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Check for responsive prefixes
|
|
276
|
+
for (const [prefix, replacement] of Object.entries(tailwindToAtomix)) {
|
|
277
|
+
if (trimmed.startsWith(prefix)) {
|
|
278
|
+
const rest = trimmed.substring(prefix.length);
|
|
279
|
+
if (tailwindToAtomix[rest]) {
|
|
280
|
+
replacementCount++;
|
|
281
|
+
return replacement + tailwindToAtomix[rest];
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// If no mapping found, keep original
|
|
287
|
+
if (trimmed && !trimmed.startsWith('c-') && !trimmed.startsWith('u-') && !trimmed.startsWith('o-')) {
|
|
288
|
+
report.warnings.push({
|
|
289
|
+
file: relative(process.cwd(), file),
|
|
290
|
+
class: trimmed,
|
|
291
|
+
message: 'No Atomix equivalent found'
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return trimmed;
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
return `className="${newClasses.join(' ')}"`;
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
// Replace class attributes in HTML
|
|
302
|
+
content = content.replace(/class=["']([^"']+)["']/g, (match, classes) => {
|
|
303
|
+
const classList = classes.split(' ');
|
|
304
|
+
const newClasses = classList.map(cls => {
|
|
305
|
+
const trimmed = cls.trim();
|
|
306
|
+
if (tailwindToAtomix[trimmed]) {
|
|
307
|
+
replacementCount++;
|
|
308
|
+
return tailwindToAtomix[trimmed];
|
|
309
|
+
}
|
|
310
|
+
return trimmed;
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
return `class="${newClasses.join(' ')}"`;
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
if (content !== originalContent) {
|
|
317
|
+
if (options.dryRun) {
|
|
318
|
+
console.log(chalk.yellow(` Would update: ${file}`));
|
|
319
|
+
} else {
|
|
320
|
+
await writeFile(file, content, 'utf8');
|
|
321
|
+
report.filesProcessed++;
|
|
322
|
+
report.classesReplaced += replacementCount;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
} catch (error) {
|
|
327
|
+
report.errors.push({
|
|
328
|
+
file: relative(process.cwd(), file),
|
|
329
|
+
error: error.message
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
spinner.succeed(chalk.green('Tailwind migration complete!'));
|
|
335
|
+
|
|
336
|
+
return report;
|
|
337
|
+
|
|
338
|
+
} catch (error) {
|
|
339
|
+
spinner.fail(chalk.red('Migration failed'));
|
|
340
|
+
throw error;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Migrate Bootstrap classes to Atomix
|
|
346
|
+
*/
|
|
347
|
+
export async function migrateBootstrap(sourcePath, options = {}) {
|
|
348
|
+
const spinner = ora('Migrating from Bootstrap...').start();
|
|
349
|
+
const report = {
|
|
350
|
+
filesProcessed: 0,
|
|
351
|
+
classesReplaced: 0,
|
|
352
|
+
warnings: [],
|
|
353
|
+
errors: []
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
try {
|
|
357
|
+
const files = await getAllFiles(sourcePath, ['.jsx', '.tsx', '.js', '.ts', '.html']);
|
|
358
|
+
|
|
359
|
+
for (const file of files) {
|
|
360
|
+
spinner.text = `Processing ${relative(process.cwd(), file)}...`;
|
|
361
|
+
|
|
362
|
+
try {
|
|
363
|
+
let content = await readFile(file, 'utf8');
|
|
364
|
+
const originalContent = content;
|
|
365
|
+
let replacementCount = 0;
|
|
366
|
+
|
|
367
|
+
// Replace className/class attributes
|
|
368
|
+
const classPattern = /(className|class)=["']([^"']+)["']/g;
|
|
369
|
+
content = content.replace(classPattern, (match, attr, classes) => {
|
|
370
|
+
const classList = classes.split(' ');
|
|
371
|
+
const newClasses = classList.map(cls => {
|
|
372
|
+
const trimmed = cls.trim();
|
|
373
|
+
|
|
374
|
+
// Check direct mapping
|
|
375
|
+
if (bootstrapToAtomix[trimmed]) {
|
|
376
|
+
replacementCount++;
|
|
377
|
+
return bootstrapToAtomix[trimmed];
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Check for col-{breakpoint}-{size} pattern
|
|
381
|
+
const colPattern = /^col-(sm|md|lg|xl)-(\d+)$/;
|
|
382
|
+
const colMatch = trimmed.match(colPattern);
|
|
383
|
+
if (colMatch) {
|
|
384
|
+
replacementCount++;
|
|
385
|
+
return `o-col-${colMatch[1]}-${colMatch[2]}`;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Check for offset pattern
|
|
389
|
+
const offsetPattern = /^offset-(sm|md|lg|xl)-(\d+)$/;
|
|
390
|
+
const offsetMatch = trimmed.match(offsetPattern);
|
|
391
|
+
if (offsetMatch) {
|
|
392
|
+
replacementCount++;
|
|
393
|
+
return `o-offset-${offsetMatch[1]}-${offsetMatch[2]}`;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// If no mapping found, keep original
|
|
397
|
+
if (trimmed && !trimmed.startsWith('c-') && !trimmed.startsWith('u-') && !trimmed.startsWith('o-')) {
|
|
398
|
+
report.warnings.push({
|
|
399
|
+
file: relative(process.cwd(), file),
|
|
400
|
+
class: trimmed,
|
|
401
|
+
message: 'No Atomix equivalent found'
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return trimmed;
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
return `${attr}="${newClasses.join(' ')}"`;
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
if (content !== originalContent) {
|
|
412
|
+
if (options.dryRun) {
|
|
413
|
+
console.log(chalk.yellow(` Would update: ${file}`));
|
|
414
|
+
} else {
|
|
415
|
+
await writeFile(file, content, 'utf8');
|
|
416
|
+
report.filesProcessed++;
|
|
417
|
+
report.classesReplaced += replacementCount;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
} catch (error) {
|
|
422
|
+
report.errors.push({
|
|
423
|
+
file: relative(process.cwd(), file),
|
|
424
|
+
error: error.message
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
spinner.succeed(chalk.green('Bootstrap migration complete!'));
|
|
430
|
+
|
|
431
|
+
return report;
|
|
432
|
+
|
|
433
|
+
} catch (error) {
|
|
434
|
+
spinner.fail(chalk.red('Migration failed'));
|
|
435
|
+
throw error;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Migrate SCSS variables to CSS custom properties
|
|
441
|
+
*/
|
|
442
|
+
export async function migrateSCSSVariables(sourcePath, options = {}) {
|
|
443
|
+
const spinner = ora('Migrating SCSS variables to design tokens...').start();
|
|
444
|
+
const report = {
|
|
445
|
+
filesProcessed: 0,
|
|
446
|
+
variablesReplaced: 0,
|
|
447
|
+
warnings: [],
|
|
448
|
+
errors: []
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
try {
|
|
452
|
+
const files = await getAllFiles(sourcePath, ['.scss', '.sass', '.css']);
|
|
453
|
+
|
|
454
|
+
for (const file of files) {
|
|
455
|
+
spinner.text = `Processing ${relative(process.cwd(), file)}...`;
|
|
456
|
+
|
|
457
|
+
try {
|
|
458
|
+
let content = await readFile(file, 'utf8');
|
|
459
|
+
const originalContent = content;
|
|
460
|
+
let replacementCount = 0;
|
|
461
|
+
|
|
462
|
+
// Replace SCSS variables with CSS custom properties
|
|
463
|
+
for (const [scssVar, cssVar] of Object.entries(scssVariableMigration)) {
|
|
464
|
+
const regex = new RegExp(`\\${scssVar}(?![a-z-])`, 'g');
|
|
465
|
+
const matches = content.match(regex);
|
|
466
|
+
if (matches) {
|
|
467
|
+
replacementCount += matches.length;
|
|
468
|
+
content = content.replace(regex, cssVar);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Find remaining SCSS variables that weren't migrated
|
|
473
|
+
const remainingVars = content.match(/\$[a-z-]+/gi);
|
|
474
|
+
if (remainingVars) {
|
|
475
|
+
remainingVars.forEach(varName => {
|
|
476
|
+
if (!scssVariableMigration[varName]) {
|
|
477
|
+
report.warnings.push({
|
|
478
|
+
file: relative(process.cwd(), file),
|
|
479
|
+
variable: varName,
|
|
480
|
+
message: 'No design token equivalent found'
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
if (content !== originalContent) {
|
|
487
|
+
if (options.dryRun) {
|
|
488
|
+
console.log(chalk.yellow(` Would update: ${file}`));
|
|
489
|
+
} else {
|
|
490
|
+
await writeFile(file, content, 'utf8');
|
|
491
|
+
report.filesProcessed++;
|
|
492
|
+
report.variablesReplaced += replacementCount;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
} catch (error) {
|
|
497
|
+
report.errors.push({
|
|
498
|
+
file: relative(process.cwd(), file),
|
|
499
|
+
error: error.message
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
spinner.succeed(chalk.green('SCSS variable migration complete!'));
|
|
505
|
+
|
|
506
|
+
return report;
|
|
507
|
+
|
|
508
|
+
} catch (error) {
|
|
509
|
+
spinner.fail(chalk.red('Migration failed'));
|
|
510
|
+
throw error;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Get all files recursively
|
|
516
|
+
*/
|
|
517
|
+
async function getAllFiles(dir, extensions = []) {
|
|
518
|
+
const files = [];
|
|
519
|
+
|
|
520
|
+
async function walk(currentPath) {
|
|
521
|
+
const entries = await readdir(currentPath);
|
|
522
|
+
|
|
523
|
+
for (const entry of entries) {
|
|
524
|
+
const fullPath = join(currentPath, entry);
|
|
525
|
+
const stats = await stat(fullPath);
|
|
526
|
+
|
|
527
|
+
if (stats.isDirectory()) {
|
|
528
|
+
// Skip node_modules and hidden directories
|
|
529
|
+
if (!entry.startsWith('.') && entry !== 'node_modules') {
|
|
530
|
+
await walk(fullPath);
|
|
531
|
+
}
|
|
532
|
+
} else if (stats.isFile()) {
|
|
533
|
+
const ext = extname(fullPath);
|
|
534
|
+
if (extensions.length === 0 || extensions.includes(ext)) {
|
|
535
|
+
files.push(fullPath);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
await walk(dir);
|
|
542
|
+
return files;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Display migration report
|
|
547
|
+
*/
|
|
548
|
+
export function displayMigrationReport(report) {
|
|
549
|
+
console.log(chalk.bold('\nš Migration Report\n'));
|
|
550
|
+
console.log(chalk.gray('=' .repeat(50)));
|
|
551
|
+
|
|
552
|
+
console.log(chalk.cyan(`Files processed: ${report.filesProcessed}`));
|
|
553
|
+
console.log(chalk.cyan(`Classes/Variables replaced: ${report.classesReplaced || report.variablesReplaced}`));
|
|
554
|
+
|
|
555
|
+
if (report.warnings.length > 0) {
|
|
556
|
+
console.log(chalk.yellow(`\nā ļø Warnings (${report.warnings.length}):\n`));
|
|
557
|
+
|
|
558
|
+
// Group warnings by type
|
|
559
|
+
const groupedWarnings = {};
|
|
560
|
+
report.warnings.forEach(warning => {
|
|
561
|
+
const key = warning.class || warning.variable;
|
|
562
|
+
if (!groupedWarnings[key]) {
|
|
563
|
+
groupedWarnings[key] = [];
|
|
564
|
+
}
|
|
565
|
+
groupedWarnings[key].push(warning.file);
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
Object.entries(groupedWarnings).forEach(([key, files]) => {
|
|
569
|
+
console.log(chalk.yellow(` ⢠${key}`));
|
|
570
|
+
console.log(chalk.gray(` Found in ${files.length} file(s)`));
|
|
571
|
+
if (files.length <= 3) {
|
|
572
|
+
files.forEach(file => console.log(chalk.gray(` - ${file}`)));
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
if (report.errors.length > 0) {
|
|
578
|
+
console.log(chalk.red(`\nā Errors (${report.errors.length}):\n`));
|
|
579
|
+
report.errors.forEach(error => {
|
|
580
|
+
console.log(chalk.red(` ⢠${error.file}`));
|
|
581
|
+
console.log(chalk.gray(` ${error.error}`));
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
console.log(chalk.gray('\n' + '=' .repeat(50)));
|
|
586
|
+
|
|
587
|
+
if (report.warnings.length > 0) {
|
|
588
|
+
console.log(chalk.yellow('\nš” Suggestions:'));
|
|
589
|
+
console.log(chalk.gray(' 1. Review unmapped classes/variables'));
|
|
590
|
+
console.log(chalk.gray(' 2. Create custom mappings for your specific needs'));
|
|
591
|
+
console.log(chalk.gray(' 3. Consider using Atomix utilities for better compatibility'));
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
console.log(chalk.green('\nā
Migration complete!'));
|
|
595
|
+
console.log(chalk.gray('Please review the changes and test your application.\n'));
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
export default {
|
|
599
|
+
migrateTailwind,
|
|
600
|
+
migrateBootstrap,
|
|
601
|
+
migrateSCSSVariables,
|
|
602
|
+
displayMigrationReport
|
|
603
|
+
};
|