@rakeyshgidwani/roger-ui-bank-theme-harvey 0.2.52 → 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.
- package/CHANGELOG.md +1 -1
- package/dist/components/ui/button.d.ts +3 -1
- package/dist/components/ui/button.d.ts.map +1 -1
- package/dist/components/ui/button.esm.js +3 -2
- package/dist/components/ui/button.js +3 -2
- package/dist/components/ui/layout/container.d.ts +57 -0
- package/dist/components/ui/layout/container.d.ts.map +1 -0
- package/dist/components/ui/layout/container.esm.js +173 -0
- package/dist/components/ui/layout/container.js +173 -0
- package/dist/components/ui/layout/index.d.ts +9 -0
- package/dist/components/ui/layout/index.d.ts.map +1 -0
- package/dist/components/ui/layout/index.esm.js +6 -0
- package/dist/components/ui/layout/index.js +6 -0
- package/dist/components/ui/layout/responsive-grid.d.ts +93 -0
- package/dist/components/ui/layout/responsive-grid.d.ts.map +1 -0
- package/dist/components/ui/layout/responsive-grid.esm.js +124 -0
- package/dist/components/ui/layout/responsive-grid.js +124 -0
- package/dist/components/ui/navigation/index.d.ts +2 -1
- package/dist/components/ui/navigation/index.d.ts.map +1 -1
- package/dist/components/ui/navigation/index.esm.js +1 -0
- package/dist/components/ui/navigation/index.js +1 -0
- package/dist/components/ui/navigation/progressive-navigation.d.ts +37 -0
- package/dist/components/ui/navigation/progressive-navigation.d.ts.map +1 -0
- package/dist/components/ui/navigation/progressive-navigation.esm.js +145 -0
- package/dist/components/ui/navigation/progressive-navigation.js +145 -0
- package/dist/components/ui/navigation/types.d.ts +21 -0
- package/dist/components/ui/navigation/types.d.ts.map +1 -1
- package/dist/hooks/use-adaptive-layout.d.ts +2 -1
- package/dist/hooks/use-adaptive-layout.d.ts.map +1 -1
- package/dist/hooks/use-adaptive-layout.esm.js +13 -8
- package/dist/hooks/use-adaptive-layout.js +13 -8
- package/dist/hooks/use-device.d.ts +3 -1
- package/dist/hooks/use-device.d.ts.map +1 -1
- package/dist/hooks/use-device.esm.js +14 -7
- package/dist/hooks/use-device.js +14 -7
- package/dist/index.d.ts +19 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +9 -4
- package/dist/index.js +9 -4
- package/dist/plugins/css-purge-optimizer.d.ts +25 -0
- package/dist/plugins/css-purge-optimizer.d.ts.map +1 -0
- package/dist/plugins/css-purge-optimizer.esm.js +414 -0
- package/dist/plugins/css-purge-optimizer.js +414 -0
- package/dist/plugins/performance-monitor.d.ts +29 -0
- package/dist/plugins/performance-monitor.d.ts.map +1 -0
- package/dist/plugins/performance-monitor.esm.js +221 -0
- package/dist/plugins/performance-monitor.js +221 -0
- package/dist/plugins/progressive-css-loader.d.ts +21 -0
- package/dist/plugins/progressive-css-loader.d.ts.map +1 -0
- package/dist/plugins/progressive-css-loader.esm.js +227 -0
- package/dist/plugins/progressive-css-loader.js +227 -0
- package/dist/plugins/theme-css-generator.d.ts.map +1 -1
- package/dist/plugins/theme-css-generator.esm.js +19 -6
- package/dist/plugins/theme-css-generator.js +19 -6
- package/dist/styles.css +1025 -110
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.esm.js +4 -1
- package/dist/theme.js +4 -1
- package/dist/themes/phase1-constants.d.ts +23 -0
- package/dist/themes/phase1-constants.d.ts.map +1 -0
- package/dist/themes/phase1-constants.esm.js +180 -0
- package/dist/themes/phase1-constants.js +180 -0
- package/dist/themes/themes/default.d.ts.map +1 -1
- package/dist/themes/themes/default.esm.js +4 -1
- package/dist/themes/themes/default.js +4 -1
- package/dist/themes/themes/harvey.d.ts.map +1 -1
- package/dist/themes/themes/harvey.esm.js +4 -1
- package/dist/themes/themes/harvey.js +4 -1
- package/dist/themes/types.d.ts +62 -0
- package/dist/themes/types.d.ts.map +1 -1
- package/dist/themes/validation.d.ts +17 -0
- package/dist/themes/validation.d.ts.map +1 -1
- package/dist/themes/validation.esm.js +218 -0
- package/dist/themes/validation.js +218 -0
- package/dist/types.d.ts +62 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/progressive-css-injector.d.ts +80 -0
- package/dist/utils/progressive-css-injector.d.ts.map +1 -0
- package/dist/utils/progressive-css-injector.esm.js +217 -0
- package/dist/utils/progressive-css-injector.js +217 -0
- package/package.json +1 -1
- package/src/components/ui/button.tsx +9 -6
- package/src/components/ui/layout/container.tsx +312 -0
- package/src/components/ui/layout/index.ts +10 -0
- package/src/components/ui/layout/responsive-grid.tsx +286 -0
- package/src/components/ui/navigation/index.ts +2 -0
- package/src/components/ui/navigation/progressive-navigation.tsx +453 -0
- package/src/components/ui/navigation/types.ts +41 -0
- package/src/hooks/use-adaptive-layout.ts +13 -9
- package/src/hooks/use-device.tsx +17 -10
- package/src/index.ts +19 -4
- package/src/plugins/css-purge-optimizer.ts +491 -0
- package/src/plugins/performance-monitor.ts +292 -0
- package/src/plugins/progressive-css-loader.ts +269 -0
- package/src/plugins/theme-css-generator.ts +22 -6
- package/src/styles/components/base/badge.css +2 -2
- package/src/styles/components/base/button.css +238 -35
- package/src/styles/components/base/card.css +2 -2
- package/src/styles/components/base/checkbox.css +3 -3
- package/src/styles/components/base/label.css +3 -3
- package/src/styles/components/feedback/skeleton.css +1 -1
- package/src/styles/components/feedback/toast.css +1 -1
- package/src/styles/components/index.css +3 -0
- package/src/styles/components/layout/container.css +466 -0
- package/src/styles/components/layout/index.css +5 -0
- package/src/styles/components/layout/responsive-grid.css +422 -0
- package/src/styles/components/navigation/breadcrumb.css +1 -1
- package/src/styles/components/navigation/index.css +1 -0
- package/src/styles/components/navigation/menu.css +2 -2
- package/src/styles/components/navigation/pagination.css +4 -4
- package/src/styles/components/navigation/progressive-navigation.css +633 -0
- package/src/styles/components/navigation/sidebar.css +4 -4
- package/src/styles/components/navigation/stepper.css +2 -2
- package/src/styles/components/navigation/tabs.css +1 -1
- package/src/styles/progressive.css +17 -0
- package/src/styles/themes/harvey.css +103 -19
- package/src/styles/utilities/semantic-input-system.css +7 -13
- package/src/theme.ts +5 -1
- package/src/themes/phase1-constants.ts +189 -0
- package/src/themes/themes/default.ts +5 -1
- package/src/themes/themes/harvey.ts +5 -1
- package/src/themes/types.ts +77 -1
- package/src/themes/validation.ts +249 -0
- package/src/types.ts +77 -1
- package/src/utils/progressive-css-injector.ts +254 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progressive CSS Injector
|
|
3
|
+
* Runtime utility to load progressive CSS for desktop enhancement
|
|
4
|
+
*
|
|
5
|
+
* This is a simplified, production-ready approach that:
|
|
6
|
+
* 1. Detects desktop viewport (>= 1024px)
|
|
7
|
+
* 2. Dynamically loads progressive.css
|
|
8
|
+
* 3. Handles viewport changes and preloading
|
|
9
|
+
*/
|
|
10
|
+
const DEFAULT_CONFIG = {
|
|
11
|
+
desktopBreakpoint: 1024, // lg breakpoint
|
|
12
|
+
progressiveCSSPath: '/progressive.css',
|
|
13
|
+
enablePreload: true,
|
|
14
|
+
enableViewportDetection: true
|
|
15
|
+
};
|
|
16
|
+
class ProgressiveCSSInjector {
|
|
17
|
+
constructor(config = {}) {
|
|
18
|
+
this.isLoaded = false;
|
|
19
|
+
this.linkElement = null;
|
|
20
|
+
this.preloadElement = null;
|
|
21
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Initialize the progressive CSS loader
|
|
25
|
+
*/
|
|
26
|
+
init() {
|
|
27
|
+
if (typeof window === 'undefined')
|
|
28
|
+
return; // SSR safety
|
|
29
|
+
// Only run in production or when explicitly enabled
|
|
30
|
+
// In development, progressive.css likely doesn't exist
|
|
31
|
+
const isProduction = typeof import.meta !== 'undefined' && import.meta.env?.PROD === true;
|
|
32
|
+
const isDevelopment = typeof import.meta !== 'undefined' && import.meta.env?.DEV === true;
|
|
33
|
+
if (isDevelopment && !this.config.enableViewportDetection) {
|
|
34
|
+
console.log('Progressive CSS: Skipping in development (set enableViewportDetection: true to override)');
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// In production, check if progressive CSS file exists
|
|
38
|
+
if (isProduction) {
|
|
39
|
+
this.checkFileExists()
|
|
40
|
+
.then(exists => {
|
|
41
|
+
if (!exists) {
|
|
42
|
+
console.log('Progressive CSS file not found, skipping enhancement');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.initializeFeatures();
|
|
46
|
+
})
|
|
47
|
+
.catch(error => {
|
|
48
|
+
console.warn('Progressive CSS loader initialization failed:', error);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// In development with explicit enablement, skip file check
|
|
53
|
+
this.initializeFeatures();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Initialize progressive CSS features
|
|
58
|
+
*/
|
|
59
|
+
initializeFeatures() {
|
|
60
|
+
// Initial viewport check
|
|
61
|
+
this.checkAndLoadProgressiveCSS();
|
|
62
|
+
// Setup viewport change listener if enabled
|
|
63
|
+
if (this.config.enableViewportDetection) {
|
|
64
|
+
this.setupViewportListener();
|
|
65
|
+
}
|
|
66
|
+
// Setup preloading if enabled
|
|
67
|
+
if (this.config.enablePreload) {
|
|
68
|
+
this.setupPreloading();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Check if the progressive CSS file exists
|
|
73
|
+
*/
|
|
74
|
+
async checkFileExists() {
|
|
75
|
+
try {
|
|
76
|
+
const response = await fetch(this.config.progressiveCSSPath, { method: 'HEAD' });
|
|
77
|
+
return response.ok;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Check viewport and load progressive CSS if needed
|
|
85
|
+
*/
|
|
86
|
+
checkAndLoadProgressiveCSS() {
|
|
87
|
+
const isDesktop = window.innerWidth >= this.config.desktopBreakpoint;
|
|
88
|
+
if (isDesktop && !this.isLoaded) {
|
|
89
|
+
this.loadProgressiveCSS();
|
|
90
|
+
}
|
|
91
|
+
else if (!isDesktop && this.isLoaded) {
|
|
92
|
+
this.unloadProgressiveCSS();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Load progressive CSS
|
|
97
|
+
*/
|
|
98
|
+
loadProgressiveCSS() {
|
|
99
|
+
if (this.isLoaded || this.linkElement)
|
|
100
|
+
return;
|
|
101
|
+
this.linkElement = document.createElement('link');
|
|
102
|
+
this.linkElement.rel = 'stylesheet';
|
|
103
|
+
this.linkElement.href = this.config.progressiveCSSPath;
|
|
104
|
+
this.linkElement.media = `screen and (min-width: ${this.config.desktopBreakpoint}px)`;
|
|
105
|
+
this.linkElement.onload = () => {
|
|
106
|
+
this.isLoaded = true;
|
|
107
|
+
console.log(`Progressive CSS loaded for viewport >= ${this.config.desktopBreakpoint}px`);
|
|
108
|
+
};
|
|
109
|
+
this.linkElement.onerror = () => {
|
|
110
|
+
console.warn('Failed to load progressive CSS');
|
|
111
|
+
this.cleanup();
|
|
112
|
+
};
|
|
113
|
+
document.head.appendChild(this.linkElement);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Unload progressive CSS (for mobile/tablet)
|
|
117
|
+
*/
|
|
118
|
+
unloadProgressiveCSS() {
|
|
119
|
+
if (this.linkElement) {
|
|
120
|
+
document.head.removeChild(this.linkElement);
|
|
121
|
+
this.linkElement = null;
|
|
122
|
+
this.isLoaded = false;
|
|
123
|
+
console.log('Progressive CSS unloaded for mobile/tablet viewport');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Setup viewport change listener
|
|
128
|
+
*/
|
|
129
|
+
setupViewportListener() {
|
|
130
|
+
let resizeTimeout;
|
|
131
|
+
const handleResize = () => {
|
|
132
|
+
clearTimeout(resizeTimeout);
|
|
133
|
+
resizeTimeout = window.setTimeout(() => {
|
|
134
|
+
this.checkAndLoadProgressiveCSS();
|
|
135
|
+
}, 150); // Debounce resize events
|
|
136
|
+
};
|
|
137
|
+
window.addEventListener('resize', handleResize);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Setup preloading for fast desktop switches
|
|
141
|
+
*/
|
|
142
|
+
setupPreloading() {
|
|
143
|
+
// Only preload on tablet+ to avoid mobile data usage
|
|
144
|
+
if (window.innerWidth >= 768) {
|
|
145
|
+
this.preloadElement = document.createElement('link');
|
|
146
|
+
this.preloadElement.rel = 'preload';
|
|
147
|
+
this.preloadElement.href = this.config.progressiveCSSPath;
|
|
148
|
+
this.preloadElement.as = 'style';
|
|
149
|
+
document.head.appendChild(this.preloadElement);
|
|
150
|
+
console.log('Progressive CSS preloaded for fast desktop enhancement');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Cleanup resources
|
|
155
|
+
*/
|
|
156
|
+
cleanup() {
|
|
157
|
+
if (this.linkElement) {
|
|
158
|
+
this.linkElement = null;
|
|
159
|
+
}
|
|
160
|
+
if (this.preloadElement) {
|
|
161
|
+
document.head.removeChild(this.preloadElement);
|
|
162
|
+
this.preloadElement = null;
|
|
163
|
+
}
|
|
164
|
+
this.isLoaded = false;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Force load progressive CSS (for testing/debugging)
|
|
168
|
+
*/
|
|
169
|
+
forceLoad() {
|
|
170
|
+
this.loadProgressiveCSS();
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Force unload progressive CSS (for testing/debugging)
|
|
174
|
+
*/
|
|
175
|
+
forceUnload() {
|
|
176
|
+
this.unloadProgressiveCSS();
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Get current load status
|
|
180
|
+
*/
|
|
181
|
+
getStatus() {
|
|
182
|
+
return {
|
|
183
|
+
isLoaded: this.isLoaded,
|
|
184
|
+
hasLinkElement: !!this.linkElement,
|
|
185
|
+
hasPreloadElement: !!this.preloadElement,
|
|
186
|
+
currentViewport: window.innerWidth,
|
|
187
|
+
isDesktopViewport: window.innerWidth >= this.config.desktopBreakpoint
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Export singleton instance for easy use
|
|
192
|
+
export const progressiveLoader = new ProgressiveCSSInjector();
|
|
193
|
+
// Export class for custom instances
|
|
194
|
+
export { ProgressiveCSSInjector };
|
|
195
|
+
// Export initialization function for manual control
|
|
196
|
+
export function initializeProgressiveCSS(config) {
|
|
197
|
+
// Only initialize in browser environment
|
|
198
|
+
if (typeof window === 'undefined') {
|
|
199
|
+
console.log('Progressive CSS: Skipping initialization (non-browser environment)');
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
// Respect production gating by default
|
|
203
|
+
const isProduction = typeof import.meta !== 'undefined' && import.meta.env?.PROD === true;
|
|
204
|
+
const isDevelopment = typeof import.meta !== 'undefined' && import.meta.env?.DEV === true;
|
|
205
|
+
if (isDevelopment && !config?.enableViewportDetection) {
|
|
206
|
+
console.log('Progressive CSS: Skipping in development (pass enableViewportDetection: true to override)');
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
void isProduction; // Use the variable to avoid unused warning
|
|
210
|
+
if (config) {
|
|
211
|
+
const customLoader = new ProgressiveCSSInjector(config);
|
|
212
|
+
customLoader.init();
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
progressiveLoader.init();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progressive CSS Injector
|
|
3
|
+
* Runtime utility to load progressive CSS for desktop enhancement
|
|
4
|
+
*
|
|
5
|
+
* This is a simplified, production-ready approach that:
|
|
6
|
+
* 1. Detects desktop viewport (>= 1024px)
|
|
7
|
+
* 2. Dynamically loads progressive.css
|
|
8
|
+
* 3. Handles viewport changes and preloading
|
|
9
|
+
*/
|
|
10
|
+
const DEFAULT_CONFIG = {
|
|
11
|
+
desktopBreakpoint: 1024, // lg breakpoint
|
|
12
|
+
progressiveCSSPath: '/progressive.css',
|
|
13
|
+
enablePreload: true,
|
|
14
|
+
enableViewportDetection: true
|
|
15
|
+
};
|
|
16
|
+
class ProgressiveCSSInjector {
|
|
17
|
+
constructor(config = {}) {
|
|
18
|
+
this.isLoaded = false;
|
|
19
|
+
this.linkElement = null;
|
|
20
|
+
this.preloadElement = null;
|
|
21
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Initialize the progressive CSS loader
|
|
25
|
+
*/
|
|
26
|
+
init() {
|
|
27
|
+
if (typeof window === 'undefined')
|
|
28
|
+
return; // SSR safety
|
|
29
|
+
// Only run in production or when explicitly enabled
|
|
30
|
+
// In development, progressive.css likely doesn't exist
|
|
31
|
+
const isProduction = typeof import.meta !== 'undefined' && import.meta.env?.PROD === true;
|
|
32
|
+
const isDevelopment = typeof import.meta !== 'undefined' && import.meta.env?.DEV === true;
|
|
33
|
+
if (isDevelopment && !this.config.enableViewportDetection) {
|
|
34
|
+
console.log('Progressive CSS: Skipping in development (set enableViewportDetection: true to override)');
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// In production, check if progressive CSS file exists
|
|
38
|
+
if (isProduction) {
|
|
39
|
+
this.checkFileExists()
|
|
40
|
+
.then(exists => {
|
|
41
|
+
if (!exists) {
|
|
42
|
+
console.log('Progressive CSS file not found, skipping enhancement');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.initializeFeatures();
|
|
46
|
+
})
|
|
47
|
+
.catch(error => {
|
|
48
|
+
console.warn('Progressive CSS loader initialization failed:', error);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// In development with explicit enablement, skip file check
|
|
53
|
+
this.initializeFeatures();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Initialize progressive CSS features
|
|
58
|
+
*/
|
|
59
|
+
initializeFeatures() {
|
|
60
|
+
// Initial viewport check
|
|
61
|
+
this.checkAndLoadProgressiveCSS();
|
|
62
|
+
// Setup viewport change listener if enabled
|
|
63
|
+
if (this.config.enableViewportDetection) {
|
|
64
|
+
this.setupViewportListener();
|
|
65
|
+
}
|
|
66
|
+
// Setup preloading if enabled
|
|
67
|
+
if (this.config.enablePreload) {
|
|
68
|
+
this.setupPreloading();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Check if the progressive CSS file exists
|
|
73
|
+
*/
|
|
74
|
+
async checkFileExists() {
|
|
75
|
+
try {
|
|
76
|
+
const response = await fetch(this.config.progressiveCSSPath, { method: 'HEAD' });
|
|
77
|
+
return response.ok;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Check viewport and load progressive CSS if needed
|
|
85
|
+
*/
|
|
86
|
+
checkAndLoadProgressiveCSS() {
|
|
87
|
+
const isDesktop = window.innerWidth >= this.config.desktopBreakpoint;
|
|
88
|
+
if (isDesktop && !this.isLoaded) {
|
|
89
|
+
this.loadProgressiveCSS();
|
|
90
|
+
}
|
|
91
|
+
else if (!isDesktop && this.isLoaded) {
|
|
92
|
+
this.unloadProgressiveCSS();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Load progressive CSS
|
|
97
|
+
*/
|
|
98
|
+
loadProgressiveCSS() {
|
|
99
|
+
if (this.isLoaded || this.linkElement)
|
|
100
|
+
return;
|
|
101
|
+
this.linkElement = document.createElement('link');
|
|
102
|
+
this.linkElement.rel = 'stylesheet';
|
|
103
|
+
this.linkElement.href = this.config.progressiveCSSPath;
|
|
104
|
+
this.linkElement.media = `screen and (min-width: ${this.config.desktopBreakpoint}px)`;
|
|
105
|
+
this.linkElement.onload = () => {
|
|
106
|
+
this.isLoaded = true;
|
|
107
|
+
console.log(`Progressive CSS loaded for viewport >= ${this.config.desktopBreakpoint}px`);
|
|
108
|
+
};
|
|
109
|
+
this.linkElement.onerror = () => {
|
|
110
|
+
console.warn('Failed to load progressive CSS');
|
|
111
|
+
this.cleanup();
|
|
112
|
+
};
|
|
113
|
+
document.head.appendChild(this.linkElement);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Unload progressive CSS (for mobile/tablet)
|
|
117
|
+
*/
|
|
118
|
+
unloadProgressiveCSS() {
|
|
119
|
+
if (this.linkElement) {
|
|
120
|
+
document.head.removeChild(this.linkElement);
|
|
121
|
+
this.linkElement = null;
|
|
122
|
+
this.isLoaded = false;
|
|
123
|
+
console.log('Progressive CSS unloaded for mobile/tablet viewport');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Setup viewport change listener
|
|
128
|
+
*/
|
|
129
|
+
setupViewportListener() {
|
|
130
|
+
let resizeTimeout;
|
|
131
|
+
const handleResize = () => {
|
|
132
|
+
clearTimeout(resizeTimeout);
|
|
133
|
+
resizeTimeout = window.setTimeout(() => {
|
|
134
|
+
this.checkAndLoadProgressiveCSS();
|
|
135
|
+
}, 150); // Debounce resize events
|
|
136
|
+
};
|
|
137
|
+
window.addEventListener('resize', handleResize);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Setup preloading for fast desktop switches
|
|
141
|
+
*/
|
|
142
|
+
setupPreloading() {
|
|
143
|
+
// Only preload on tablet+ to avoid mobile data usage
|
|
144
|
+
if (window.innerWidth >= 768) {
|
|
145
|
+
this.preloadElement = document.createElement('link');
|
|
146
|
+
this.preloadElement.rel = 'preload';
|
|
147
|
+
this.preloadElement.href = this.config.progressiveCSSPath;
|
|
148
|
+
this.preloadElement.as = 'style';
|
|
149
|
+
document.head.appendChild(this.preloadElement);
|
|
150
|
+
console.log('Progressive CSS preloaded for fast desktop enhancement');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Cleanup resources
|
|
155
|
+
*/
|
|
156
|
+
cleanup() {
|
|
157
|
+
if (this.linkElement) {
|
|
158
|
+
this.linkElement = null;
|
|
159
|
+
}
|
|
160
|
+
if (this.preloadElement) {
|
|
161
|
+
document.head.removeChild(this.preloadElement);
|
|
162
|
+
this.preloadElement = null;
|
|
163
|
+
}
|
|
164
|
+
this.isLoaded = false;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Force load progressive CSS (for testing/debugging)
|
|
168
|
+
*/
|
|
169
|
+
forceLoad() {
|
|
170
|
+
this.loadProgressiveCSS();
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Force unload progressive CSS (for testing/debugging)
|
|
174
|
+
*/
|
|
175
|
+
forceUnload() {
|
|
176
|
+
this.unloadProgressiveCSS();
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Get current load status
|
|
180
|
+
*/
|
|
181
|
+
getStatus() {
|
|
182
|
+
return {
|
|
183
|
+
isLoaded: this.isLoaded,
|
|
184
|
+
hasLinkElement: !!this.linkElement,
|
|
185
|
+
hasPreloadElement: !!this.preloadElement,
|
|
186
|
+
currentViewport: window.innerWidth,
|
|
187
|
+
isDesktopViewport: window.innerWidth >= this.config.desktopBreakpoint
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Export singleton instance for easy use
|
|
192
|
+
export const progressiveLoader = new ProgressiveCSSInjector();
|
|
193
|
+
// Export class for custom instances
|
|
194
|
+
export { ProgressiveCSSInjector };
|
|
195
|
+
// Export initialization function for manual control
|
|
196
|
+
export function initializeProgressiveCSS(config) {
|
|
197
|
+
// Only initialize in browser environment
|
|
198
|
+
if (typeof window === 'undefined') {
|
|
199
|
+
console.log('Progressive CSS: Skipping initialization (non-browser environment)');
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
// Respect production gating by default
|
|
203
|
+
const isProduction = typeof import.meta !== 'undefined' && import.meta.env?.PROD === true;
|
|
204
|
+
const isDevelopment = typeof import.meta !== 'undefined' && import.meta.env?.DEV === true;
|
|
205
|
+
if (isDevelopment && !config?.enableViewportDetection) {
|
|
206
|
+
console.log('Progressive CSS: Skipping in development (pass enableViewportDetection: true to override)');
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
void isProduction; // Use the variable to avoid unused warning
|
|
210
|
+
if (config) {
|
|
211
|
+
const customLoader = new ProgressiveCSSInjector(config);
|
|
212
|
+
customLoader.init();
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
progressiveLoader.init();
|
|
216
|
+
}
|
|
217
|
+
}
|
package/package.json
CHANGED
|
@@ -6,24 +6,27 @@ import { Slot } from "@radix-ui/react-slot"
|
|
|
6
6
|
export interface ButtonProps
|
|
7
7
|
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
8
8
|
variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'
|
|
9
|
-
size?: '
|
|
9
|
+
size?: 'xs' | 'sm' | 'default' | 'lg' | 'xl' | 'icon' | 'mobile'
|
|
10
|
+
/** Phase 2 Enhancement: Content density support for responsive design */
|
|
11
|
+
density?: 'compact' | 'comfortable' | 'spacious'
|
|
10
12
|
asChild?: boolean
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
14
|
-
({ className, variant = 'default', size = 'default', asChild = false, ...props }, ref) => {
|
|
16
|
+
({ className, variant = 'default', size = 'default', density, asChild = false, ...props }, ref) => {
|
|
15
17
|
const Comp = asChild ? Slot : "button"
|
|
16
|
-
|
|
18
|
+
|
|
17
19
|
// Build semantic CSS classes using BEM methodology
|
|
18
20
|
const baseClass = 'button'
|
|
19
21
|
const variantClass = `button--variant-${variant}`
|
|
20
22
|
const sizeClass = `button--size-${size}`
|
|
21
|
-
|
|
23
|
+
const densityClass = density ? `button--density-${density}` : null
|
|
24
|
+
|
|
22
25
|
// Combine classes
|
|
23
|
-
const buttonClasses = [baseClass, variantClass, sizeClass, className]
|
|
26
|
+
const buttonClasses = [baseClass, variantClass, sizeClass, densityClass, className]
|
|
24
27
|
.filter(Boolean)
|
|
25
28
|
.join(' ')
|
|
26
|
-
|
|
29
|
+
|
|
27
30
|
return (
|
|
28
31
|
<Comp
|
|
29
32
|
className={buttonClasses}
|