@rakeyshgidwani/roger-ui-bank-theme-harvey 0.2.51 → 0.3.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.
Files changed (128) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/dist/components/ui/button.d.ts +3 -1
  3. package/dist/components/ui/button.d.ts.map +1 -1
  4. package/dist/components/ui/button.esm.js +3 -2
  5. package/dist/components/ui/button.js +3 -2
  6. package/dist/components/ui/layout/container.d.ts +57 -0
  7. package/dist/components/ui/layout/container.d.ts.map +1 -0
  8. package/dist/components/ui/layout/container.esm.js +173 -0
  9. package/dist/components/ui/layout/container.js +173 -0
  10. package/dist/components/ui/layout/index.d.ts +9 -0
  11. package/dist/components/ui/layout/index.d.ts.map +1 -0
  12. package/dist/components/ui/layout/index.esm.js +6 -0
  13. package/dist/components/ui/layout/index.js +6 -0
  14. package/dist/components/ui/layout/responsive-grid.d.ts +93 -0
  15. package/dist/components/ui/layout/responsive-grid.d.ts.map +1 -0
  16. package/dist/components/ui/layout/responsive-grid.esm.js +124 -0
  17. package/dist/components/ui/layout/responsive-grid.js +124 -0
  18. package/dist/components/ui/navigation/index.d.ts +2 -1
  19. package/dist/components/ui/navigation/index.d.ts.map +1 -1
  20. package/dist/components/ui/navigation/index.esm.js +1 -0
  21. package/dist/components/ui/navigation/index.js +1 -0
  22. package/dist/components/ui/navigation/progressive-navigation.d.ts +37 -0
  23. package/dist/components/ui/navigation/progressive-navigation.d.ts.map +1 -0
  24. package/dist/components/ui/navigation/progressive-navigation.esm.js +145 -0
  25. package/dist/components/ui/navigation/progressive-navigation.js +145 -0
  26. package/dist/components/ui/navigation/types.d.ts +21 -0
  27. package/dist/components/ui/navigation/types.d.ts.map +1 -1
  28. package/dist/components/ui/theme-toggle.esm.js +1 -1
  29. package/dist/components/ui/theme-toggle.js +1 -1
  30. package/dist/hooks/use-adaptive-layout.d.ts +2 -1
  31. package/dist/hooks/use-adaptive-layout.d.ts.map +1 -1
  32. package/dist/hooks/use-adaptive-layout.esm.js +13 -8
  33. package/dist/hooks/use-adaptive-layout.js +13 -8
  34. package/dist/hooks/use-device.d.ts +3 -1
  35. package/dist/hooks/use-device.d.ts.map +1 -1
  36. package/dist/hooks/use-device.esm.js +14 -7
  37. package/dist/hooks/use-device.js +14 -7
  38. package/dist/index.d.ts +19 -4
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.esm.js +9 -4
  41. package/dist/index.js +9 -4
  42. package/dist/plugins/css-purge-optimizer.d.ts +25 -0
  43. package/dist/plugins/css-purge-optimizer.d.ts.map +1 -0
  44. package/dist/plugins/css-purge-optimizer.esm.js +414 -0
  45. package/dist/plugins/css-purge-optimizer.js +414 -0
  46. package/dist/plugins/performance-monitor.d.ts +29 -0
  47. package/dist/plugins/performance-monitor.d.ts.map +1 -0
  48. package/dist/plugins/performance-monitor.esm.js +221 -0
  49. package/dist/plugins/performance-monitor.js +221 -0
  50. package/dist/plugins/progressive-css-loader.d.ts +21 -0
  51. package/dist/plugins/progressive-css-loader.d.ts.map +1 -0
  52. package/dist/plugins/progressive-css-loader.esm.js +227 -0
  53. package/dist/plugins/progressive-css-loader.js +227 -0
  54. package/dist/plugins/theme-css-generator.d.ts.map +1 -1
  55. package/dist/plugins/theme-css-generator.esm.js +19 -6
  56. package/dist/plugins/theme-css-generator.js +19 -6
  57. package/dist/styles.css +1025 -110
  58. package/dist/theme.d.ts.map +1 -1
  59. package/dist/theme.esm.js +4 -1
  60. package/dist/theme.js +4 -1
  61. package/dist/themes/phase1-constants.d.ts +23 -0
  62. package/dist/themes/phase1-constants.d.ts.map +1 -0
  63. package/dist/themes/phase1-constants.esm.js +180 -0
  64. package/dist/themes/phase1-constants.js +180 -0
  65. package/dist/themes/themes/default.d.ts.map +1 -1
  66. package/dist/themes/themes/default.esm.js +4 -1
  67. package/dist/themes/themes/default.js +4 -1
  68. package/dist/themes/themes/harvey.d.ts.map +1 -1
  69. package/dist/themes/themes/harvey.esm.js +4 -1
  70. package/dist/themes/themes/harvey.js +4 -1
  71. package/dist/themes/types.d.ts +62 -0
  72. package/dist/themes/types.d.ts.map +1 -1
  73. package/dist/themes/validation.d.ts +17 -0
  74. package/dist/themes/validation.d.ts.map +1 -1
  75. package/dist/themes/validation.esm.js +218 -0
  76. package/dist/themes/validation.js +218 -0
  77. package/dist/types.d.ts +62 -0
  78. package/dist/types.d.ts.map +1 -1
  79. package/dist/utils/progressive-css-injector.d.ts +80 -0
  80. package/dist/utils/progressive-css-injector.d.ts.map +1 -0
  81. package/dist/utils/progressive-css-injector.esm.js +217 -0
  82. package/dist/utils/progressive-css-injector.js +217 -0
  83. package/package.json +1 -1
  84. package/src/components/ui/button.tsx +9 -6
  85. package/src/components/ui/layout/container.tsx +312 -0
  86. package/src/components/ui/layout/index.ts +10 -0
  87. package/src/components/ui/layout/responsive-grid.tsx +286 -0
  88. package/src/components/ui/navigation/index.ts +2 -0
  89. package/src/components/ui/navigation/progressive-navigation.tsx +453 -0
  90. package/src/components/ui/navigation/types.ts +41 -0
  91. package/src/components/ui/theme-toggle.tsx +4 -4
  92. package/src/hooks/use-adaptive-layout.ts +13 -9
  93. package/src/hooks/use-device.tsx +17 -10
  94. package/src/index.ts +19 -4
  95. package/src/plugins/css-purge-optimizer.ts +491 -0
  96. package/src/plugins/performance-monitor.ts +292 -0
  97. package/src/plugins/progressive-css-loader.ts +269 -0
  98. package/src/plugins/theme-css-generator.ts +22 -6
  99. package/src/styles/components/base/badge.css +2 -2
  100. package/src/styles/components/base/button.css +238 -35
  101. package/src/styles/components/base/card.css +2 -2
  102. package/src/styles/components/base/checkbox.css +3 -3
  103. package/src/styles/components/base/label.css +3 -3
  104. package/src/styles/components/feedback/skeleton.css +1 -1
  105. package/src/styles/components/feedback/toast.css +1 -1
  106. package/src/styles/components/index.css +3 -0
  107. package/src/styles/components/layout/container.css +466 -0
  108. package/src/styles/components/layout/index.css +5 -0
  109. package/src/styles/components/layout/responsive-grid.css +422 -0
  110. package/src/styles/components/navigation/breadcrumb.css +1 -1
  111. package/src/styles/components/navigation/index.css +1 -0
  112. package/src/styles/components/navigation/menu.css +2 -2
  113. package/src/styles/components/navigation/pagination.css +4 -4
  114. package/src/styles/components/navigation/progressive-navigation.css +633 -0
  115. package/src/styles/components/navigation/sidebar.css +4 -4
  116. package/src/styles/components/navigation/stepper.css +2 -2
  117. package/src/styles/components/navigation/tabs.css +1 -1
  118. package/src/styles/progressive.css +17 -0
  119. package/src/styles/themes/harvey.css +103 -19
  120. package/src/styles/utilities/semantic-input-system.css +7 -13
  121. package/src/theme.ts +5 -1
  122. package/src/themes/phase1-constants.ts +189 -0
  123. package/src/themes/themes/default.ts +5 -1
  124. package/src/themes/themes/harvey.ts +5 -1
  125. package/src/themes/types.ts +77 -1
  126. package/src/themes/validation.ts +249 -0
  127. package/src/types.ts +77 -1
  128. package/src/utils/progressive-css-injector.ts +254 -0
@@ -0,0 +1,414 @@
1
+ /**
2
+ * CSS Purge Optimizer Plugin
3
+ * Implements Phase 3 Performance Optimization: CSS Bundle Optimization
4
+ *
5
+ * Optimizations:
6
+ * - Removes unused responsive breakpoint styles
7
+ * - Purges unused CSS custom properties
8
+ * - Optimizes CSS layer ordering
9
+ * - Minifies and compresses output
10
+ */
11
+ import postcss from 'postcss';
12
+ const DEFAULT_CONFIG = {
13
+ breakpoints: ['xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl'],
14
+ preserveCustomProperties: [
15
+ // Core design system variables
16
+ '--cs-*',
17
+ '--tw-*', // Preserve all Tailwind CSS variables
18
+ // Component design tokens (critical for responsive system)
19
+ '--button-*',
20
+ '--badge-*',
21
+ '--card-*',
22
+ '--input-*',
23
+ '--label-*',
24
+ '--checkbox-*',
25
+ '--menu-*',
26
+ '--sidebar-*',
27
+ '--breadcrumb-*',
28
+ '--pagination-*',
29
+ '--stepper-*',
30
+ '--tabs-*',
31
+ '--progressive-nav-*',
32
+ '--skeleton-*',
33
+ '--toast-*',
34
+ '--popover-*',
35
+ '--tooltip-*',
36
+ '--enterprise-*',
37
+ '--font-*',
38
+ '--user-menu-*',
39
+ '--subscription-*',
40
+ '--list-*',
41
+ '--tree-*',
42
+ // Layout and utility tokens
43
+ '--container-*',
44
+ '--grid-*',
45
+ '--spacing-*',
46
+ '--breakpoint-*'
47
+ ],
48
+ preserveSelectors: [
49
+ '.sr-only',
50
+ '.focus\\:*',
51
+ '.hover\\:*',
52
+ '.active\\:*',
53
+ '[data-*]'
54
+ ],
55
+ aggressive: false,
56
+ minify: true
57
+ };
58
+ export default function cssPurgeOptimizer(config = {}) {
59
+ const finalConfig = { ...DEFAULT_CONFIG, ...config };
60
+ return {
61
+ name: 'css-purge-optimizer',
62
+ apply: 'build',
63
+ generateBundle(_options, bundle) {
64
+ // Find CSS assets in bundle
65
+ const cssAssets = Object.keys(bundle).filter(key => key.endsWith('.css'));
66
+ cssAssets.forEach(assetKey => {
67
+ const asset = bundle[assetKey];
68
+ if (asset.type === 'asset' && typeof asset.source === 'string') {
69
+ const optimizedCSS = optimizeCSS(asset.source, finalConfig);
70
+ // Calculate optimization savings
71
+ const originalSize = Buffer.byteLength(asset.source, 'utf8');
72
+ const optimizedSize = Buffer.byteLength(optimizedCSS, 'utf8');
73
+ const savings = originalSize - optimizedSize;
74
+ const savingsPercent = Math.round((savings / originalSize) * 100);
75
+ console.log(`🔧 CSS Optimization: ${assetKey}`);
76
+ console.log(` Original: ${Math.round(originalSize / 1024 * 100) / 100}KB`);
77
+ console.log(` Optimized: ${Math.round(optimizedSize / 1024 * 100) / 100}KB`);
78
+ console.log(` Savings: ${Math.round(savings / 1024 * 100) / 100}KB (${savingsPercent}%)`);
79
+ // Update the asset with optimized CSS
80
+ asset.source = optimizedCSS;
81
+ }
82
+ });
83
+ }
84
+ };
85
+ }
86
+ /**
87
+ * Main CSS optimization function
88
+ */
89
+ function optimizeCSS(cssContent, config) {
90
+ let optimizedCSS = cssContent;
91
+ // Step 1: Analyze usage patterns
92
+ const usage = analyzeUsage(cssContent, config);
93
+ // Step 2: Remove unused responsive breakpoint styles
94
+ optimizedCSS = removeUnusedBreakpoints(optimizedCSS, usage, config);
95
+ // Step 3: Remove unused custom properties
96
+ optimizedCSS = removeUnusedCustomProperties(optimizedCSS, usage, config);
97
+ // Step 4: Optimize CSS layers and ordering
98
+ optimizedCSS = optimizeCSSLayers(optimizedCSS);
99
+ // Step 5: Remove duplicate rules
100
+ optimizedCSS = removeDuplicateRules(optimizedCSS);
101
+ // Step 6: Minify if enabled
102
+ if (config.minify) {
103
+ optimizedCSS = minifyCSS(optimizedCSS);
104
+ }
105
+ return optimizedCSS;
106
+ }
107
+ /**
108
+ * Analyzes CSS usage patterns using PostCSS
109
+ */
110
+ function analyzeUsage(cssContent, config) {
111
+ const usage = {
112
+ usedBreakpoints: new Set(),
113
+ usedCustomProperties: new Set(),
114
+ usedSelectors: new Set(),
115
+ unusedRules: []
116
+ };
117
+ try {
118
+ const root = postcss.parse(cssContent);
119
+ // Walk through all nodes to analyze usage
120
+ root.walkAtRules('media', (rule) => {
121
+ // Analyze media query breakpoints
122
+ const mediaQuery = rule.params;
123
+ config.breakpoints.forEach((breakpoint) => {
124
+ const breakpointPixels = getBreakpointPixels(breakpoint);
125
+ // Check for pixel-based media queries
126
+ if (mediaQuery.includes(`${breakpointPixels}px`)) {
127
+ usage.usedBreakpoints.add(breakpoint);
128
+ }
129
+ // Check for CSS variable usage
130
+ if (mediaQuery.includes(`--cs-breakpoints-${breakpoint}`)) {
131
+ usage.usedBreakpoints.add(breakpoint);
132
+ }
133
+ });
134
+ });
135
+ // Analyze custom property declarations and usage
136
+ root.walkDecls((decl) => {
137
+ // Find custom property definitions
138
+ if (decl.prop.startsWith('--')) {
139
+ // Check if this property is used elsewhere in the CSS
140
+ const propertyUsage = cssContent.includes(`var(${decl.prop})`);
141
+ if (propertyUsage) {
142
+ usage.usedCustomProperties.add(decl.prop);
143
+ }
144
+ }
145
+ // Find custom property usage in values
146
+ const varMatches = decl.value.match(/var\(--[^)]+\)/g);
147
+ if (varMatches) {
148
+ varMatches.forEach(match => {
149
+ const propertyName = match.match(/--[^)]+/)?.[0];
150
+ if (propertyName) {
151
+ usage.usedCustomProperties.add(propertyName);
152
+ }
153
+ });
154
+ }
155
+ });
156
+ // Analyze selectors
157
+ root.walkRules((rule) => {
158
+ const selectors = rule.selector.split(',');
159
+ selectors.forEach(selector => {
160
+ const trimmedSelector = selector.trim();
161
+ usage.usedSelectors.add(trimmedSelector);
162
+ // Extract class names
163
+ const classMatches = trimmedSelector.match(/\.[a-zA-Z0-9_-]+/g);
164
+ if (classMatches) {
165
+ classMatches.forEach(className => {
166
+ usage.usedSelectors.add(className);
167
+ });
168
+ }
169
+ });
170
+ });
171
+ // For safety, always mark critical breakpoints as used
172
+ const criticalBreakpoints = ['xs', 'sm', 'md'];
173
+ criticalBreakpoints.forEach((bp) => usage.usedBreakpoints.add(bp));
174
+ }
175
+ catch (error) {
176
+ console.warn('PostCSS parsing failed in usage analysis, falling back to regex:', error);
177
+ // Fallback to basic regex analysis
178
+ return analyzeUsageFallback(cssContent, config);
179
+ }
180
+ return usage;
181
+ }
182
+ /**
183
+ * Fallback regex-based usage analysis
184
+ */
185
+ function analyzeUsageFallback(cssContent, config) {
186
+ const usage = {
187
+ usedBreakpoints: new Set(),
188
+ usedCustomProperties: new Set(),
189
+ usedSelectors: new Set(),
190
+ unusedRules: []
191
+ };
192
+ // Analyze breakpoint usage in media queries
193
+ config.breakpoints.forEach((breakpoint) => {
194
+ const varPattern = new RegExp(`var\\(--cs-breakpoints-${breakpoint}\\)`, 'g');
195
+ const breakpointPixels = getBreakpointPixels(breakpoint);
196
+ const pixelPattern = new RegExp(`(min-width|max-width):\\s*${breakpointPixels}px`, 'g');
197
+ const literalPattern = new RegExp(`\\b${breakpoint}\\b`, 'g');
198
+ if (varPattern.test(cssContent) ||
199
+ pixelPattern.test(cssContent) ||
200
+ literalPattern.test(cssContent)) {
201
+ usage.usedBreakpoints.add(breakpoint);
202
+ }
203
+ });
204
+ // For safety, always mark critical breakpoints as used
205
+ const criticalBreakpoints = ['xs', 'sm', 'md'];
206
+ criticalBreakpoints.forEach((bp) => usage.usedBreakpoints.add(bp));
207
+ // Analyze custom property usage
208
+ const customPropertyMatches = cssContent.match(/var\(--[^)]+\)/g) || [];
209
+ customPropertyMatches.forEach(match => {
210
+ const propertyName = match.match(/--[^)]+/)?.[0];
211
+ if (propertyName) {
212
+ usage.usedCustomProperties.add(propertyName);
213
+ }
214
+ });
215
+ // Analyze selector usage
216
+ const selectorMatches = cssContent.match(/\.[a-zA-Z0-9_-]+/g) || [];
217
+ selectorMatches.forEach(selector => {
218
+ usage.usedSelectors.add(selector);
219
+ });
220
+ return usage;
221
+ }
222
+ /**
223
+ * Maps breakpoint names to their pixel values
224
+ */
225
+ function getBreakpointPixels(breakpoint) {
226
+ const breakpointMap = {
227
+ xs: 0, // mobile-first, no min-width
228
+ sm: 640,
229
+ md: 768,
230
+ lg: 1024,
231
+ xl: 1280,
232
+ '2xl': 1536,
233
+ '3xl': 1792
234
+ };
235
+ return breakpointMap[breakpoint] || 0;
236
+ }
237
+ /**
238
+ * Removes unused responsive breakpoint styles using PostCSS
239
+ */
240
+ function removeUnusedBreakpoints(cssContent, usage, config) {
241
+ if (!config.aggressive) {
242
+ console.log(` Skipping breakpoint removal (non-aggressive mode)`);
243
+ return cssContent;
244
+ }
245
+ try {
246
+ const root = postcss.parse(cssContent);
247
+ let removedCount = 0;
248
+ root.walkAtRules('media', (rule) => {
249
+ const mediaQuery = rule.params;
250
+ // Check if this media query uses an unused breakpoint
251
+ const usesUnusedBreakpoint = config.breakpoints.some(breakpoint => {
252
+ // Skip critical breakpoints
253
+ if (['xs', 'sm', 'md'].includes(breakpoint)) {
254
+ return false;
255
+ }
256
+ // Check if breakpoint is unused and referenced in this media query
257
+ if (!usage.usedBreakpoints.has(breakpoint)) {
258
+ const breakpointPixels = getBreakpointPixels(breakpoint);
259
+ return mediaQuery.includes(`${breakpointPixels}px`) ||
260
+ mediaQuery.includes(`--cs-breakpoints-${breakpoint}`);
261
+ }
262
+ return false;
263
+ });
264
+ if (usesUnusedBreakpoint) {
265
+ console.log(` Removed unused breakpoint media query: ${mediaQuery}`);
266
+ rule.remove();
267
+ removedCount++;
268
+ }
269
+ });
270
+ return root.toString();
271
+ }
272
+ catch (error) {
273
+ console.warn('PostCSS parsing failed in breakpoint removal, using original CSS:', error);
274
+ return cssContent;
275
+ }
276
+ }
277
+ /**
278
+ * Removes unused CSS custom properties using PostCSS
279
+ */
280
+ function removeUnusedCustomProperties(cssContent, usage, config) {
281
+ try {
282
+ const root = postcss.parse(cssContent);
283
+ let removedCount = 0;
284
+ root.walkDecls((decl) => {
285
+ // Only process custom property declarations
286
+ if (decl.prop.startsWith('--')) {
287
+ // Check if property should be preserved (check this first for Tailwind variables)
288
+ const shouldPreserve = config.preserveCustomProperties.some(pattern => {
289
+ const regex = new RegExp(pattern.replace('*', '.*'));
290
+ return regex.test(decl.prop);
291
+ });
292
+ // Always preserve whitelisted properties (like --tw-*), otherwise check usage
293
+ if (!shouldPreserve && !usage.usedCustomProperties.has(decl.prop)) {
294
+ console.log(` Removed unused custom property: ${decl.prop}`);
295
+ decl.remove();
296
+ removedCount++;
297
+ }
298
+ }
299
+ });
300
+ return root.toString();
301
+ }
302
+ catch (error) {
303
+ console.warn('PostCSS parsing failed in custom property removal, using original CSS:', error);
304
+ return cssContent;
305
+ }
306
+ }
307
+ /**
308
+ * Optimizes CSS layer ordering using PostCSS
309
+ */
310
+ function optimizeCSSLayers(cssContent) {
311
+ try {
312
+ const root = postcss.parse(cssContent);
313
+ const layerOrder = ['reset', 'base', 'themes', 'components', 'utilities'];
314
+ let hasLayers = false;
315
+ // Remove existing @layer declarations
316
+ root.walkAtRules('layer', (rule) => {
317
+ if (!rule.nodes || rule.nodes.length === 0) {
318
+ // This is a layer order declaration, not a layer block
319
+ hasLayers = true;
320
+ rule.remove();
321
+ }
322
+ });
323
+ // Add optimized layer order at the beginning if we found layers
324
+ if (hasLayers) {
325
+ const layerDeclaration = postcss.atRule({
326
+ name: 'layer',
327
+ params: layerOrder.join(', ')
328
+ });
329
+ root.prepend(layerDeclaration);
330
+ root.prepend(postcss.comment({ text: ' Optimized CSS layer order ' }));
331
+ }
332
+ return root.toString();
333
+ }
334
+ catch (error) {
335
+ console.warn('PostCSS parsing failed in layer optimization, using original CSS:', error);
336
+ return cssContent;
337
+ }
338
+ }
339
+ /**
340
+ * Removes duplicate CSS rules using PostCSS
341
+ */
342
+ function removeDuplicateRules(cssContent) {
343
+ try {
344
+ const root = postcss.parse(cssContent);
345
+ const ruleMap = new Map();
346
+ let removedCount = 0;
347
+ root.walkRules((rule) => {
348
+ const selector = rule.selector;
349
+ const declarations = rule.nodes?.map(node => {
350
+ if (node.type === 'decl') {
351
+ return `${node.prop}: ${node.value}`;
352
+ }
353
+ return '';
354
+ }).filter(Boolean).sort().join('; ');
355
+ const ruleKey = `${selector}|${declarations}`;
356
+ if (ruleMap.has(ruleKey)) {
357
+ console.log(` Removed duplicate rule: ${selector}`);
358
+ rule.remove();
359
+ removedCount++;
360
+ }
361
+ else {
362
+ ruleMap.set(ruleKey, selector);
363
+ }
364
+ });
365
+ return root.toString();
366
+ }
367
+ catch (error) {
368
+ console.warn('PostCSS parsing failed in duplicate rule removal, using original CSS:', error);
369
+ return cssContent;
370
+ }
371
+ }
372
+ /**
373
+ * Basic CSS minification
374
+ */
375
+ function minifyCSS(cssContent) {
376
+ return cssContent
377
+ // Remove comments
378
+ .replace(/\/\*[\s\S]*?\*\//g, '')
379
+ // Remove unnecessary whitespace
380
+ .replace(/\s+/g, ' ')
381
+ // Remove whitespace around braces and semicolons
382
+ .replace(/\s*{\s*/g, '{')
383
+ .replace(/\s*}\s*/g, '}')
384
+ .replace(/\s*;\s*/g, ';')
385
+ .replace(/\s*:\s*/g, ':')
386
+ .replace(/\s*,\s*/g, ',')
387
+ // Remove trailing semicolons
388
+ .replace(/;}/g, '}')
389
+ // Remove leading/trailing whitespace
390
+ .trim();
391
+ }
392
+ /**
393
+ * Generates optimization report
394
+ */
395
+ export function generateOptimizationReport(originalCSS, optimizedCSS) {
396
+ const originalSize = Buffer.byteLength(originalCSS, 'utf8');
397
+ const optimizedSize = Buffer.byteLength(optimizedCSS, 'utf8');
398
+ const savings = originalSize - optimizedSize;
399
+ const savingsPercent = Math.round((savings / originalSize) * 100);
400
+ return `
401
+ CSS Optimization Report
402
+ ======================
403
+ Original Size: ${Math.round(originalSize / 1024 * 100) / 100}KB
404
+ Optimized Size: ${Math.round(optimizedSize / 1024 * 100) / 100}KB
405
+ Savings: ${Math.round(savings / 1024 * 100) / 100}KB (${savingsPercent}%)
406
+
407
+ Optimizations Applied:
408
+ - Removed unused responsive breakpoint styles
409
+ - Purged unused CSS custom properties
410
+ - Optimized CSS layer ordering
411
+ - Removed duplicate rules
412
+ - Applied minification
413
+ `;
414
+ }