@shohojdhara/atomix 0.5.2 → 0.5.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/atomix.config.ts +33 -33
- package/dist/config.d.ts +187 -112
- package/dist/config.js +7 -49
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +1958 -900
- package/dist/index.esm.js +2275 -383
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +2327 -417
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/theme.d.ts +1390 -276
- package/dist/theme.js +2129 -621
- package/dist/theme.js.map +1 -1
- package/package.json +1 -1
- package/scripts/cli/internal/config-loader.js +30 -20
- package/src/lib/config/index.ts +38 -362
- package/src/lib/config/loader.ts +419 -0
- package/src/lib/config/public-api.ts +43 -0
- package/src/lib/config/types.ts +389 -0
- package/src/lib/config/validator.ts +305 -0
- package/src/lib/theme/adapters/index.ts +1 -1
- package/src/lib/theme/adapters/themeAdapter.ts +358 -229
- package/src/lib/theme/components/ThemeToggle.tsx +276 -0
- package/src/lib/theme/config/configLoader.ts +351 -0
- package/src/lib/theme/config/loader.ts +221 -0
- package/src/lib/theme/core/createTheme.ts +126 -50
- package/src/lib/theme/core/createThemeObject.ts +7 -4
- package/src/lib/theme/hooks/useThemeSwitcher.ts +164 -0
- package/src/lib/theme/index.ts +322 -38
- package/src/lib/theme/runtime/ThemeProvider.tsx +44 -10
- package/src/lib/theme/runtime/__tests__/ThemeProvider.test.tsx +44 -393
- package/src/lib/theme/runtime/useTheme.ts +1 -0
- package/src/lib/theme/tokens/tokens.ts +101 -1
- package/src/lib/theme/types.ts +91 -0
- package/src/lib/theme/utils/performanceMonitor.ts +315 -0
- package/src/lib/theme/utils/responsive.ts +280 -0
- package/src/lib/theme/utils/themeUtils.ts +531 -117
- package/src/styles/05-objects/_objects.masonry-grid.scss +3 -3
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Responsive Utility for Atomix Theme System
|
|
3
|
+
*
|
|
4
|
+
* Provides responsive breakpoint detection and device-aware parameter scaling
|
|
5
|
+
* based on configuration from the advanced optimization features.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from 'react';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Breakpoint definitions
|
|
12
|
+
*/
|
|
13
|
+
export interface Breakpoints {
|
|
14
|
+
mobile: string;
|
|
15
|
+
tablet: string;
|
|
16
|
+
desktop: string;
|
|
17
|
+
wide: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Device scaling factors
|
|
22
|
+
*/
|
|
23
|
+
export interface DeviceScaling {
|
|
24
|
+
mobile: number;
|
|
25
|
+
tablet: number;
|
|
26
|
+
desktop: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Responsive configuration
|
|
31
|
+
*/
|
|
32
|
+
export interface ResponsiveConfig {
|
|
33
|
+
breakpoints: Breakpoints;
|
|
34
|
+
deviceScaling: DeviceScaling;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Current device type
|
|
39
|
+
*/
|
|
40
|
+
export type DeviceType = 'mobile' | 'tablet' | 'desktop' | 'wide';
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Responsive utility class
|
|
44
|
+
*/
|
|
45
|
+
export class ResponsiveUtil {
|
|
46
|
+
private config: ResponsiveConfig;
|
|
47
|
+
private currentDevice: DeviceType = 'desktop'; // Default
|
|
48
|
+
private resizeHandler: (() => void) | null = null;
|
|
49
|
+
private observer: ResizeObserver | null = null;
|
|
50
|
+
|
|
51
|
+
constructor(config: ResponsiveConfig) {
|
|
52
|
+
this.config = config;
|
|
53
|
+
this.currentDevice = this.getCurrentDeviceType();
|
|
54
|
+
|
|
55
|
+
// Set up resize listener
|
|
56
|
+
this.setupResizeListener();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Get the current device type based on viewport width
|
|
61
|
+
*/
|
|
62
|
+
public getCurrentDeviceType(): DeviceType {
|
|
63
|
+
if (typeof window === 'undefined') return 'desktop'; // SSR fallback
|
|
64
|
+
|
|
65
|
+
const width = window.innerWidth;
|
|
66
|
+
|
|
67
|
+
// Parse breakpoint values to numbers
|
|
68
|
+
const mobileWidth = this.parsePxValue(this.config.breakpoints.mobile);
|
|
69
|
+
const tabletWidth = this.parsePxValue(this.config.breakpoints.tablet);
|
|
70
|
+
const desktopWidth = this.parsePxValue(this.config.breakpoints.desktop);
|
|
71
|
+
const wideWidth = this.parsePxValue(this.config.breakpoints.wide);
|
|
72
|
+
|
|
73
|
+
if (width < tabletWidth) {
|
|
74
|
+
return 'mobile';
|
|
75
|
+
} else if (width < desktopWidth) {
|
|
76
|
+
return 'tablet';
|
|
77
|
+
} else if (width < wideWidth) {
|
|
78
|
+
return 'desktop';
|
|
79
|
+
} else {
|
|
80
|
+
return 'wide';
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Get the scaling factor for the current device
|
|
86
|
+
*/
|
|
87
|
+
public getCurrentScalingFactor(): number {
|
|
88
|
+
// 'wide' devices use the same scaling as 'desktop'
|
|
89
|
+
const scalingKey = this.currentDevice === 'wide' ? 'desktop' : this.currentDevice;
|
|
90
|
+
return this.config.deviceScaling[scalingKey] || 1.0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Scale a value based on the current device's scaling factor
|
|
95
|
+
*/
|
|
96
|
+
public scaleValue(value: number): number {
|
|
97
|
+
return value * this.getCurrentScalingFactor();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Check if the current device matches a specific type
|
|
102
|
+
*/
|
|
103
|
+
public isDevice(device: DeviceType): boolean {
|
|
104
|
+
return this.currentDevice === device;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Check if the current device is mobile or smaller
|
|
109
|
+
*/
|
|
110
|
+
public isMobileOrSmaller(): boolean {
|
|
111
|
+
return this.currentDevice === 'mobile';
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Check if the current device is tablet or smaller
|
|
116
|
+
*/
|
|
117
|
+
public isTabletOrSmaller(): boolean {
|
|
118
|
+
return this.currentDevice === 'mobile' || this.currentDevice === 'tablet';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Check if the current device is desktop or larger
|
|
123
|
+
*/
|
|
124
|
+
public isDesktopOrLarger(): boolean {
|
|
125
|
+
return this.currentDevice === 'desktop' || this.currentDevice === 'wide';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Update the responsive configuration
|
|
130
|
+
*/
|
|
131
|
+
public updateConfig(config: ResponsiveConfig): void {
|
|
132
|
+
this.config = config;
|
|
133
|
+
this.currentDevice = this.getCurrentDeviceType();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Destroy the responsive utility and clean up listeners
|
|
138
|
+
*/
|
|
139
|
+
public destroy(): void {
|
|
140
|
+
if (this.resizeHandler) {
|
|
141
|
+
window.removeEventListener('resize', this.resizeHandler);
|
|
142
|
+
this.resizeHandler = null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (this.observer) {
|
|
146
|
+
this.observer.disconnect();
|
|
147
|
+
this.observer = null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Parse a CSS value to pixels
|
|
153
|
+
*/
|
|
154
|
+
private parsePxValue(value: string): number {
|
|
155
|
+
if (value.endsWith('px')) {
|
|
156
|
+
return parseFloat(value.slice(0, -2));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// For other units, we'll use a rough conversion assuming 16px base
|
|
160
|
+
if (value.endsWith('rem')) {
|
|
161
|
+
return parseFloat(value.slice(0, -3)) * 16;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (value.endsWith('em')) {
|
|
165
|
+
return parseFloat(value.slice(0, -2)) * 16;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Default to parsing as a raw number
|
|
169
|
+
return parseFloat(value) || 0;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Set up the resize listener
|
|
174
|
+
*/
|
|
175
|
+
private setupResizeListener(): void {
|
|
176
|
+
if (typeof window === 'undefined') return;
|
|
177
|
+
|
|
178
|
+
// Throttled resize handler
|
|
179
|
+
let resizeTimeout: number | null = null;
|
|
180
|
+
|
|
181
|
+
const handleResize = () => {
|
|
182
|
+
if (resizeTimeout) {
|
|
183
|
+
window.clearTimeout(resizeTimeout);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
resizeTimeout = window.setTimeout(() => {
|
|
187
|
+
const newDeviceType = this.getCurrentDeviceType();
|
|
188
|
+
|
|
189
|
+
if (newDeviceType !== this.currentDevice) {
|
|
190
|
+
this.currentDevice = newDeviceType;
|
|
191
|
+
// Optionally trigger a callback here if needed
|
|
192
|
+
}
|
|
193
|
+
}, 150); // Throttle to 150ms
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
this.resizeHandler = handleResize;
|
|
197
|
+
window.addEventListener('resize', handleResize);
|
|
198
|
+
|
|
199
|
+
// Also observe the document body for size changes
|
|
200
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
201
|
+
this.observer = new ResizeObserver(handleResize);
|
|
202
|
+
this.observer.observe(document.body);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Create a responsive utility instance
|
|
209
|
+
*
|
|
210
|
+
* @param config Responsive configuration
|
|
211
|
+
* @returns ResponsiveUtil instance
|
|
212
|
+
*/
|
|
213
|
+
export function createResponsiveUtil(config: ResponsiveConfig): ResponsiveUtil {
|
|
214
|
+
return new ResponsiveUtil(config);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Hook for React components to use responsive features
|
|
219
|
+
*
|
|
220
|
+
* @param config Responsive configuration
|
|
221
|
+
* @returns Current device type and utility functions
|
|
222
|
+
*/
|
|
223
|
+
export function useResponsive(config: ResponsiveConfig) {
|
|
224
|
+
const [util] = React.useState(() => createResponsiveUtil(config));
|
|
225
|
+
const [deviceType, setDeviceType] = React.useState<DeviceType>(() =>
|
|
226
|
+
typeof window !== 'undefined' ? util.getCurrentDeviceType() : 'desktop'
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
React.useEffect(() => {
|
|
230
|
+
if (typeof window === 'undefined') return;
|
|
231
|
+
|
|
232
|
+
const handleResize = () => {
|
|
233
|
+
const newDeviceType = util.getCurrentDeviceType();
|
|
234
|
+
if (newDeviceType !== deviceType) {
|
|
235
|
+
setDeviceType(newDeviceType);
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
// Update device type on mount
|
|
240
|
+
setDeviceType(util.getCurrentDeviceType());
|
|
241
|
+
|
|
242
|
+
// Listen for resize events
|
|
243
|
+
window.addEventListener('resize', handleResize);
|
|
244
|
+
|
|
245
|
+
return () => {
|
|
246
|
+
window.removeEventListener('resize', handleResize);
|
|
247
|
+
util.destroy();
|
|
248
|
+
};
|
|
249
|
+
}, [util, deviceType]);
|
|
250
|
+
|
|
251
|
+
if (typeof window === 'undefined') {
|
|
252
|
+
return {
|
|
253
|
+
deviceType: 'desktop' as DeviceType,
|
|
254
|
+
isMobile: false,
|
|
255
|
+
isTablet: false,
|
|
256
|
+
isDesktop: true,
|
|
257
|
+
isWide: false,
|
|
258
|
+
scaleValue: (value: number) => value,
|
|
259
|
+
getCurrentDeviceType: (): DeviceType => 'desktop',
|
|
260
|
+
getCurrentScalingFactor: (): number => 1,
|
|
261
|
+
isMobileOrSmaller: (): boolean => false,
|
|
262
|
+
isTabletOrSmaller: (): boolean => true,
|
|
263
|
+
isDesktopOrLarger: (): boolean => true,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return {
|
|
268
|
+
deviceType,
|
|
269
|
+
isMobile: deviceType === 'mobile',
|
|
270
|
+
isTablet: deviceType === 'tablet',
|
|
271
|
+
isDesktop: deviceType === 'desktop',
|
|
272
|
+
isWide: deviceType === 'wide',
|
|
273
|
+
scaleValue: (value: number) => util.scaleValue(value),
|
|
274
|
+
getCurrentDeviceType: () => util.getCurrentDeviceType(),
|
|
275
|
+
getCurrentScalingFactor: () => util.getCurrentScalingFactor(),
|
|
276
|
+
isMobileOrSmaller: () => util.isMobileOrSmaller(),
|
|
277
|
+
isTabletOrSmaller: () => util.isTabletOrSmaller(),
|
|
278
|
+
isDesktopOrLarger: () => util.isDesktopOrLarger(),
|
|
279
|
+
};
|
|
280
|
+
}
|