@shohojdhara/atomix 0.4.7 → 0.4.9

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 (176) hide show
  1. package/atomix.config.ts +58 -1
  2. package/dist/atomix.css +172 -157
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +4 -4
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/charts.d.ts +33 -0
  7. package/dist/charts.js +1274 -164
  8. package/dist/charts.js.map +1 -1
  9. package/dist/core.d.ts +33 -10
  10. package/dist/core.js +1099 -83
  11. package/dist/core.js.map +1 -1
  12. package/dist/forms.d.ts +33 -0
  13. package/dist/forms.js +2106 -1050
  14. package/dist/forms.js.map +1 -1
  15. package/dist/heavy.d.ts +42 -1
  16. package/dist/heavy.js +1663 -638
  17. package/dist/heavy.js.map +1 -1
  18. package/dist/index.d.ts +442 -270
  19. package/dist/index.esm.js +1947 -680
  20. package/dist/index.esm.js.map +1 -1
  21. package/dist/index.js +1982 -712
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.min.js +1 -1
  24. package/dist/index.min.js.map +1 -1
  25. package/package.json +6 -3
  26. package/scripts/atomix-cli.js +136 -1827
  27. package/scripts/cli/__tests__/basic.test.js +3 -2
  28. package/scripts/cli/__tests__/clean.test.js +278 -0
  29. package/scripts/cli/__tests__/component-validator.test.js +433 -0
  30. package/scripts/cli/__tests__/generator.test.js +613 -0
  31. package/scripts/cli/__tests__/glass-motion.test.js +256 -0
  32. package/scripts/cli/__tests__/integration.test.js +719 -108
  33. package/scripts/cli/__tests__/migrate.test.js +74 -0
  34. package/scripts/cli/__tests__/security.test.js +206 -0
  35. package/scripts/cli/__tests__/test-setup.js +3 -1
  36. package/scripts/cli/__tests__/theme-bridge.test.js +507 -0
  37. package/scripts/cli/__tests__/token-provider.test.js +361 -0
  38. package/scripts/cli/__tests__/utils.test.js +5 -5
  39. package/scripts/cli/commands/benchmark.js +105 -0
  40. package/scripts/cli/commands/build-theme.js +115 -0
  41. package/scripts/cli/commands/clean.js +109 -0
  42. package/scripts/cli/commands/doctor.js +88 -0
  43. package/scripts/cli/commands/generate.js +218 -0
  44. package/scripts/cli/commands/init.js +73 -0
  45. package/scripts/cli/commands/migrate.js +106 -0
  46. package/scripts/cli/commands/sync-tokens.js +206 -0
  47. package/scripts/cli/commands/theme-bridge.js +248 -0
  48. package/scripts/cli/commands/tokens.js +157 -0
  49. package/scripts/cli/commands/validate.js +194 -0
  50. package/scripts/cli/internal/ai-engine.js +156 -0
  51. package/scripts/cli/internal/compiler.js +114 -0
  52. package/scripts/cli/internal/component-validator.js +443 -0
  53. package/scripts/cli/internal/config-loader.js +162 -0
  54. package/scripts/cli/internal/filesystem.js +158 -0
  55. package/scripts/cli/internal/generator.js +430 -0
  56. package/scripts/cli/internal/glass-generator.js +398 -0
  57. package/scripts/cli/internal/hook-generator.js +369 -0
  58. package/scripts/cli/internal/hooks.js +61 -0
  59. package/scripts/cli/internal/itcss-generator.js +565 -0
  60. package/scripts/cli/internal/motion-generator.js +679 -0
  61. package/scripts/cli/internal/template-engine.js +301 -0
  62. package/scripts/cli/internal/theme-bridge.js +664 -0
  63. package/scripts/cli/internal/tokens/engine.js +122 -0
  64. package/scripts/cli/internal/tokens/provider.js +34 -0
  65. package/scripts/cli/internal/tokens/providers/figma.js +50 -0
  66. package/scripts/cli/internal/tokens/providers/style-dictionary.js +48 -0
  67. package/scripts/cli/internal/tokens/providers/w3c.js +48 -0
  68. package/scripts/cli/internal/tokens/token-provider.js +443 -0
  69. package/scripts/cli/internal/tokens/token-validator.js +513 -0
  70. package/scripts/cli/internal/validator.js +276 -0
  71. package/scripts/cli/internal/wizard.js +115 -0
  72. package/scripts/cli/mappings.js +23 -0
  73. package/scripts/cli/migration-tools.js +164 -94
  74. package/scripts/cli/plugins/style-dictionary.js +46 -0
  75. package/scripts/cli/templates/README.md +525 -95
  76. package/scripts/cli/templates/common-templates.js +40 -14
  77. package/scripts/cli/templates/components/react-component.ts +282 -0
  78. package/scripts/cli/templates/config/project-config.ts +112 -0
  79. package/scripts/cli/templates/hooks/use-component.ts +477 -0
  80. package/scripts/cli/templates/index.js +19 -4
  81. package/scripts/cli/templates/index.ts +171 -0
  82. package/scripts/cli/templates/next-templates.js +72 -0
  83. package/scripts/cli/templates/react-templates.js +70 -126
  84. package/scripts/cli/templates/scss-templates.js +35 -35
  85. package/scripts/cli/templates/stories/storybook-story.ts +241 -0
  86. package/scripts/cli/templates/styles/scss-component.ts +255 -0
  87. package/scripts/cli/templates/tests/vitest-test.ts +229 -0
  88. package/scripts/cli/templates/token-templates.js +337 -1
  89. package/scripts/cli/templates/tokens/token-generators.ts +1088 -0
  90. package/scripts/cli/templates/types/component-types.ts +145 -0
  91. package/scripts/cli/templates/utils/testing-utils.ts +144 -0
  92. package/scripts/cli/templates/vanilla-templates.js +39 -0
  93. package/scripts/cli/token-manager.js +8 -2
  94. package/scripts/cli/utils/cache-manager.js +240 -0
  95. package/scripts/cli/utils/detector.js +46 -0
  96. package/scripts/cli/utils/diagnostics.js +289 -0
  97. package/scripts/cli/utils/error.js +89 -0
  98. package/scripts/cli/utils/helpers.js +67 -0
  99. package/scripts/cli/utils/logger.js +75 -0
  100. package/scripts/cli/utils/security.js +302 -0
  101. package/scripts/cli/utils/telemetry.js +115 -0
  102. package/scripts/cli/utils/validation.js +37 -0
  103. package/scripts/cli/utils.js +28 -341
  104. package/src/components/Accordion/Accordion.stories.tsx +0 -18
  105. package/src/components/Accordion/Accordion.test.tsx +0 -17
  106. package/src/components/Accordion/Accordion.tsx +0 -4
  107. package/src/components/AtomixGlass/AtomixGlass.test.tsx +37 -3
  108. package/src/components/AtomixGlass/AtomixGlass.tsx +143 -31
  109. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +129 -31
  110. package/src/components/AtomixGlass/PerformanceDashboard.tsx +219 -0
  111. package/src/components/AtomixGlass/README.md +25 -10
  112. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +216 -0
  113. package/src/components/AtomixGlass/animation-system.ts +578 -0
  114. package/src/components/AtomixGlass/shader-utils.ts +4 -1
  115. package/src/components/AtomixGlass/stories/Overview.stories.tsx +157 -6
  116. package/src/components/AtomixGlass/stories/Phase1-Animation.stories.tsx +653 -0
  117. package/src/components/AtomixGlass/stories/Phase1-Test.stories.tsx +95 -0
  118. package/src/components/AtomixGlass/stories/Playground.stories.tsx +51 -51
  119. package/src/components/AtomixGlass/stories/shared-components.tsx +6 -0
  120. package/src/components/Avatar/Avatar.tsx +1 -1
  121. package/src/components/Button/Button.stories.disabled-link.tsx +10 -0
  122. package/src/components/Button/Button.stories.tsx +10 -0
  123. package/src/components/Button/Button.test.tsx +16 -11
  124. package/src/components/Button/Button.tsx +4 -4
  125. package/src/components/Card/Card.tsx +1 -1
  126. package/src/components/Dropdown/Dropdown.tsx +12 -12
  127. package/src/components/Form/Select.tsx +62 -3
  128. package/src/components/Modal/Modal.tsx +14 -3
  129. package/src/components/Navigation/Navbar/Navbar.tsx +44 -0
  130. package/src/components/Slider/Slider.stories.tsx +3 -3
  131. package/src/components/Slider/Slider.tsx +38 -0
  132. package/src/components/Steps/Steps.tsx +3 -3
  133. package/src/components/Tabs/Tabs.tsx +77 -8
  134. package/src/components/Testimonial/Testimonial.tsx +1 -1
  135. package/src/components/TypedButton/TypedButton.stories.tsx +59 -0
  136. package/src/components/TypedButton/TypedButton.tsx +39 -0
  137. package/src/components/TypedButton/index.ts +2 -0
  138. package/src/components/VideoPlayer/VideoPlayer.tsx +11 -4
  139. package/src/lib/composables/index.ts +4 -7
  140. package/src/lib/composables/types.ts +45 -0
  141. package/src/lib/composables/useAccordion.ts +0 -7
  142. package/src/lib/composables/useAtomixGlass.ts +148 -6
  143. package/src/lib/composables/useAtomixGlassStyles.ts +9 -7
  144. package/src/lib/composables/useChartExport.ts +3 -13
  145. package/src/lib/composables/useDropdown.ts +66 -0
  146. package/src/lib/composables/useFocusTrap.ts +80 -0
  147. package/src/lib/composables/usePerformanceMonitor.ts +448 -0
  148. package/src/lib/composables/useResponsiveGlass.presets.ts +192 -0
  149. package/src/lib/composables/useResponsiveGlass.ts +441 -0
  150. package/src/lib/composables/useTooltip.ts +16 -0
  151. package/src/lib/composables/useTypedButton.ts +66 -0
  152. package/src/lib/config/index.ts +62 -5
  153. package/src/lib/constants/components.ts +62 -7
  154. package/src/lib/theme/devtools/__tests__/useHistory.test.tsx +150 -0
  155. package/src/lib/theme/tokens/centralized-tokens.ts +120 -0
  156. package/src/lib/theme/utils/__tests__/domUtils.test.ts +101 -0
  157. package/src/lib/types/components.ts +37 -11
  158. package/src/lib/types/glass.ts +35 -0
  159. package/src/lib/types/index.ts +1 -0
  160. package/src/lib/utils/displacement-generator.ts +1 -1
  161. package/src/styles/01-settings/_settings.testtypecheck.scss +53 -0
  162. package/src/styles/01-settings/_settings.typedbutton.scss +53 -0
  163. package/src/styles/06-components/_components.atomix-glass.scss +17 -21
  164. package/src/styles/06-components/_components.edge-panel.scss +1 -5
  165. package/src/styles/06-components/_components.modal.scss +1 -4
  166. package/src/styles/06-components/_components.navbar.scss +1 -1
  167. package/src/styles/06-components/_components.testbutton.scss +212 -0
  168. package/src/styles/06-components/_components.testtypecheck.scss +212 -0
  169. package/src/styles/06-components/_components.tooltip.scss +9 -5
  170. package/src/styles/06-components/_components.typedbutton.scss +212 -0
  171. package/src/styles/99-utilities/_index.scss +1 -0
  172. package/src/styles/99-utilities/_utilities.text.scss +1 -1
  173. package/src/styles/99-utilities/_utilities.touch-target.scss +36 -0
  174. package/scripts/cli/component-generator.js +0 -564
  175. package/scripts/cli/interactive-init.js +0 -357
  176. package/src/styles/06-components/old.chart.styles.scss +0 -2788
@@ -1,359 +1,46 @@
1
1
  /**
2
- * CLI Utility Functions
3
- * Provides common utilities for the Atomix CLI including security, validation, and helpers
2
+ * Atomix CLI Utils Barrel
3
+ * Re-exports for tests and backward compatibility. Prefer importing from utils/*.js in command code.
4
4
  */
5
5
 
6
- import { resolve, relative, isAbsolute, normalize } from 'path';
7
- import { access } from 'fs/promises';
6
+ import { validateSecurePath, validateComponentNameSecure } from './utils/security.js';
7
+ import { validateThemeName } from './utils/validation.js';
8
+ import { sanitizeInput, fileExists } from './utils/helpers.js';
9
+ import { AtomixCLIError, ErrorCategory } from './utils/error.js';
10
+ import { resolve, normalize } from 'path';
8
11
 
9
12
  /**
10
- * Enhanced Error Class for CLI
13
+ * Validates path: security check and sensitive file check.
14
+ * @param {string} inputPath - Path to validate
15
+ * @param {string} basePath - Base directory (defaults to process.cwd())
16
+ * @returns {{ isValid: boolean, error?: string, safePath?: string }}
11
17
  */
12
- export class AtomixCLIError extends Error {
13
- constructor(message, code, suggestions = []) {
14
- super(message);
15
- this.name = 'AtomixCLIError';
16
- this.code = code;
17
- this.suggestions = suggestions;
18
+ function validatePath(inputPath, basePath = process.cwd()) {
19
+ const normalized = normalize(resolve(basePath, inputPath));
20
+ const sensitive = ['.env', '.npmrc', '.env.local', '.env.production', 'id_rsa', '.ssh'];
21
+ if (sensitive.some(s => normalized.includes(s))) {
22
+ return { isValid: false, error: 'Path targets a sensitive path and is not allowed.' };
18
23
  }
19
- }
20
-
21
- /**
22
- * Validates and sanitizes file paths to prevent directory traversal attacks
23
- * @param {string} inputPath - The path to validate
24
- * @param {string} basePath - The base directory (defaults to process.cwd())
25
- * @returns {Object} { isValid: boolean, safePath: string, error?: string }
26
- */
27
- export function validatePath(inputPath, basePath = process.cwd()) {
28
- try {
29
- // Normalize the paths to remove any '..' or '.' segments
30
- const normalizedBase = normalize(resolve(basePath));
31
- const normalizedInput = normalize(isAbsolute(inputPath)
32
- ? inputPath
33
- : resolve(basePath, inputPath));
34
-
35
- // Check if the resolved path is within the base directory
36
- const relativePath = relative(normalizedBase, normalizedInput);
37
-
38
- // If the relative path starts with '..', it's outside the base directory
39
- if (relativePath.startsWith('..')) {
40
- return {
41
- isValid: false,
42
- safePath: null,
43
- error: 'Path is outside the project directory'
44
- };
45
- }
46
-
47
- // Additional checks for sensitive paths
48
- const sensitivePatterns = [
49
- /^\.git/,
50
- /node_modules/,
51
- /^\.env/,
52
- /\.pem$/,
53
- /\.key$/,
54
- /private/i,
55
- /secret/i
56
- ];
57
-
58
- for (const pattern of sensitivePatterns) {
59
- if (pattern.test(relativePath)) {
60
- return {
61
- isValid: false,
62
- safePath: null,
63
- error: `Access to sensitive path is restricted: ${pattern}`
64
- };
65
- }
66
- }
67
-
68
- return {
69
- isValid: true,
70
- safePath: normalizedInput,
71
- error: null
72
- };
73
- } catch (error) {
74
- return {
75
- isValid: false,
76
- safePath: null,
77
- error: `Invalid path: ${error.message}`
78
- };
79
- }
80
- }
81
-
82
- /**
83
- * Validates component names according to PascalCase convention
84
- * @param {string} name - The component name to validate
85
- * @returns {Object} { isValid: boolean, error?: string }
86
- */
87
- export function validateComponentName(name) {
88
- if (!name || typeof name !== 'string') {
89
- return {
90
- isValid: false,
91
- error: 'Component name must be a non-empty string'
92
- };
93
- }
94
-
95
- // Check PascalCase: starts with uppercase, only contains letters and numbers
96
- if (!/^[A-Z][a-zA-Z0-9]*$/.test(name)) {
97
- return {
98
- isValid: false,
99
- error: 'Component name must be in PascalCase (e.g., Button, CardHeader)'
100
- };
101
- }
102
-
103
- // Check for reserved words
104
- const reservedWords = [
105
- 'Component', 'React', 'Fragment', 'Suspense', 'StrictMode',
106
- 'Error', 'Loading', 'App', 'Root', 'Document', 'Html'
107
- ];
108
-
109
- if (reservedWords.includes(name)) {
110
- return {
111
- isValid: false,
112
- error: `"${name}" is a reserved word. Please choose a different name.`
113
- };
114
- }
115
-
116
- // Check minimum length
117
- if (name.length < 2) {
118
- return {
119
- isValid: false,
120
- error: 'Component name must be at least 2 characters long'
121
- };
122
- }
123
-
124
- return { isValid: true };
125
- }
126
-
127
- /**
128
- * Validates theme names according to kebab-case convention
129
- * @param {string} name - The theme name to validate
130
- * @returns {Object} { isValid: boolean, error?: string }
131
- */
132
- export function validateThemeName(name) {
133
- if (!name || typeof name !== 'string') {
134
- return {
135
- isValid: false,
136
- error: 'Theme name must be a non-empty string'
137
- };
138
- }
139
-
140
- // Check kebab-case: lowercase letters, numbers, and hyphens
141
- if (!/^[a-z][a-z0-9-]*$/.test(name)) {
142
- return {
143
- isValid: false,
144
- error: 'Theme name must be lowercase and use hyphens (e.g., dark-theme)'
145
- };
146
- }
147
-
148
- // Check for consecutive hyphens
149
- if (/--/.test(name)) {
150
- return {
151
- isValid: false,
152
- error: 'Theme name cannot contain consecutive hyphens'
153
- };
154
- }
155
-
156
- // Check for trailing hyphen
157
- if (name.endsWith('-')) {
158
- return {
159
- isValid: false,
160
- error: 'Theme name cannot end with a hyphen'
161
- };
162
- }
163
-
164
- return { isValid: true };
165
- }
166
-
167
- /**
168
- * Sanitizes user input to prevent injection attacks
169
- * @param {string} input - The user input to sanitize
170
- * @returns {string} Sanitized input
171
- */
172
- export function sanitizeInput(input) {
173
- if (typeof input !== 'string') {
174
- return String(input);
175
- }
176
-
177
- // Remove any shell metacharacters that could be dangerous
178
- // Added single and double quotes to the blacklist to prevent shell injection
179
- return input
180
- .replace(/[;&|`$<>\\"']/g, '')
181
- .replace(/\0/g, '') // Remove null bytes
182
- .trim();
183
- }
184
-
185
- /**
186
- * Checks if a file exists and is accessible
187
- * @param {string} filePath - Path to check
188
- * @returns {Promise<boolean>}
189
- */
190
- export async function fileExists(filePath) {
191
- try {
192
- await access(filePath);
193
- return true;
194
- } catch {
195
- return false;
196
- }
197
- }
198
-
199
- /**
200
- * Checks if running in CI environment
201
- * @returns {boolean}
202
- */
203
- export function isCI() {
204
- return !!(
205
- process.env.CI ||
206
- process.env.CONTINUOUS_INTEGRATION ||
207
- process.env.GITHUB_ACTIONS ||
208
- process.env.GITLAB_CI ||
209
- process.env.CIRCLECI ||
210
- process.env.TRAVIS ||
211
- process.env.JENKINS_URL
212
- );
213
- }
214
-
215
- /**
216
- * Checks if running in debug mode
217
- * @returns {boolean}
218
- */
219
- export function isDebug() {
220
- return process.env.ATOMIX_DEBUG === 'true' ||
221
- process.argv.includes('--debug') ||
222
- process.argv.includes('-d');
223
- }
224
-
225
- /**
226
- * Formats file size in human readable format
227
- * @param {number} bytes - File size in bytes
228
- * @returns {string} Formatted size
229
- */
230
- export function formatFileSize(bytes) {
231
- const sizes = ['B', 'KB', 'MB', 'GB'];
232
- if (bytes === 0) return '0 B';
233
- const i = Math.floor(Math.log(bytes) / Math.log(1024));
234
- return `${(bytes / Math.pow(1024, i)).toFixed(2)} ${sizes[i]}`;
235
- }
236
-
237
- /**
238
- * Debounce function for watch mode
239
- * @param {Function} func - Function to debounce
240
- * @param {number} wait - Wait time in milliseconds
241
- * @returns {Function} Debounced function
242
- */
243
- export function debounce(func, wait) {
244
- let timeout;
245
- return function executedFunction(...args) {
246
- const later = () => {
247
- clearTimeout(timeout);
248
- func(...args);
249
- };
250
- clearTimeout(timeout);
251
- timeout = setTimeout(later, wait);
252
- };
253
- }
254
-
255
- /**
256
- * Creates a safe file path for cross-platform compatibility
257
- * @param {...string} segments - Path segments
258
- * @returns {string} Safe file path
259
- */
260
- export function safePath(...segments) {
261
- // Filter out empty segments and join with proper separator
262
- return segments
263
- .filter(Boolean)
264
- .join('/')
265
- .replace(/\/+/g, '/') // Remove duplicate slashes
266
- .replace(/\\/g, '/'); // Convert Windows backslashes
267
- }
268
-
269
- /**
270
- * Validates SCSS/CSS color values
271
- * @param {string} color - Color value to validate
272
- * @returns {boolean}
273
- */
274
- export function isValidColor(color) {
275
- const patterns = [
276
- /^#[0-9A-F]{3}$/i, // #RGB
277
- /^#[0-9A-F]{4}$/i, // #RGBA
278
- /^#[0-9A-F]{6}$/i, // #RRGGBB
279
- /^#[0-9A-F]{8}$/i, // #RRGGBBAA
280
- /^rgb\(/i, // rgb()
281
- /^rgba\(/i, // rgba()
282
- /^hsl\(/i, // hsl()
283
- /^hsla\(/i, // hsla()
284
- /^var\(--/ // CSS custom property
285
- ];
286
-
287
- return patterns.some(pattern => pattern.test(color));
288
- }
289
-
290
- /**
291
- * Extracts and validates npm scripts from package.json
292
- * @param {Object} packageJson - Parsed package.json content
293
- * @param {Array<string>} requiredScripts - List of required script names
294
- * @returns {Object} { valid: boolean, missing: Array<string> }
295
- */
296
- export function validateNpmScripts(packageJson, requiredScripts = []) {
297
- const scripts = packageJson.scripts || {};
298
- const missing = requiredScripts.filter(script => !scripts[script]);
299
-
24
+ const result = validateSecurePath(inputPath, basePath);
25
+ const error = result.error === 'Path traversal attempt detected'
26
+ ? 'Path is outside the project directory.'
27
+ : (result.error || null);
300
28
  return {
301
- valid: missing.length === 0,
302
- missing
29
+ isValid: result.isValid,
30
+ error,
31
+ safePath: result.safePath || null
303
32
  };
304
33
  }
305
34
 
306
- /**
307
- * Generates a unique ID for components/themes
308
- * @param {string} prefix - Prefix for the ID
309
- * @returns {string} Unique ID
310
- */
311
- export function generateId(prefix = 'atomix') {
312
- const timestamp = Date.now().toString(36);
313
- const random = Math.random().toString(36).substring(2, 7);
314
- return `${prefix}-${timestamp}-${random}`;
315
- }
316
-
317
- /**
318
- * Checks Node.js version compatibility
319
- * @param {string} requiredVersion - Minimum required version (e.g., '18.0.0')
320
- * @returns {Object} { compatible: boolean, current: string, required: string }
321
- */
322
- export function checkNodeVersion(requiredVersion = '18.0.0') {
323
- const currentVersion = process.version.substring(1); // Remove 'v' prefix
324
- const current = currentVersion.split('.').map(Number);
325
- const required = requiredVersion.split('.').map(Number);
326
-
327
- let compatible = true;
328
- for (let i = 0; i < required.length; i++) {
329
- if (current[i] < required[i]) {
330
- compatible = false;
331
- break;
332
- } else if (current[i] > required[i]) {
333
- break;
334
- }
335
- }
336
-
337
- return {
338
- compatible,
339
- current: currentVersion,
340
- required: requiredVersion
341
- };
342
- }
35
+ /** Sync component name validation (PascalCase, reserved words). Use validation.validateComponentName for async. */
36
+ const validateComponentName = validateComponentNameSecure;
343
37
 
344
- export default {
38
+ export {
345
39
  validatePath,
346
40
  validateComponentName,
347
41
  validateThemeName,
348
42
  sanitizeInput,
349
43
  fileExists,
350
- isCI,
351
- isDebug,
352
- formatFileSize,
353
- debounce,
354
- safePath,
355
- isValidColor,
356
- validateNpmScripts,
357
- generateId,
358
- checkNodeVersion
44
+ AtomixCLIError,
45
+ ErrorCategory
359
46
  };
@@ -22,8 +22,6 @@ const IS_DISABLED_CLASS = ACCORDION.CLASSES.IS_DISABLED;
22
22
 
23
23
  const mockHandlers = {
24
24
  onOpenChange: fn(() => {}),
25
- onOpen: fn(() => {}),
26
- onClose: fn(() => {}),
27
25
  };
28
26
 
29
27
  // Sample content for stories
@@ -222,20 +220,6 @@ const meta = {
222
220
  type: { summary: '(open: boolean) => void' },
223
221
  },
224
222
  },
225
- onOpen: {
226
- action: 'onOpen',
227
- description: 'Callback when accordion opens',
228
- table: {
229
- type: { summary: '() => void' },
230
- },
231
- },
232
- onClose: {
233
- action: 'onClose',
234
- description: 'Callback when accordion closes',
235
- table: {
236
- type: { summary: '() => void' },
237
- },
238
- },
239
223
  },
240
224
  } satisfies Meta<typeof Accordion>;
241
225
 
@@ -268,8 +252,6 @@ export const WithAllProps: Story = {
268
252
  iconPosition: 'left',
269
253
  disabled: false,
270
254
  onOpenChange: mockHandlers.onOpenChange,
271
- onOpen: mockHandlers.onOpen,
272
- onClose: mockHandlers.onClose,
273
255
  },
274
256
  parameters: {
275
257
  docs: {
@@ -28,23 +28,6 @@ describe('Accordion Component', () => {
28
28
  expect(button).toHaveAttribute('aria-expanded', 'false');
29
29
  });
30
30
 
31
- it('calls legacy onOpen/onClose handlers', () => {
32
- const onOpen = vi.fn();
33
- const onClose = vi.fn();
34
- render(
35
- <Accordion title="Test" onOpen={onOpen} onClose={onClose}>
36
- Content
37
- </Accordion>
38
- );
39
- const button = screen.getByRole('button');
40
-
41
- fireEvent.click(button);
42
- expect(onOpen).toHaveBeenCalled();
43
-
44
- fireEvent.click(button);
45
- expect(onClose).toHaveBeenCalled();
46
- });
47
-
48
31
  it('handles controlled state', () => {
49
32
  const onOpenChange = vi.fn();
50
33
  const { rerender } = render(
@@ -114,8 +114,6 @@ const AccordionImpl = memo(
114
114
  defaultOpen = false,
115
115
  isOpen: controlledOpen,
116
116
  onOpenChange,
117
- onOpen,
118
- onClose,
119
117
  disabled = false,
120
118
  iconPosition = 'right',
121
119
  icon,
@@ -143,8 +141,6 @@ const AccordionImpl = memo(
143
141
  iconPosition,
144
142
  isOpen: controlledOpen,
145
143
  onOpenChange,
146
- onOpen,
147
- onClose,
148
144
  });
149
145
 
150
146
  const headerClassNames = generateHeaderClassNames();
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { render, screen } from '@testing-library/react';
2
+ import { render, screen, waitFor } from '@testing-library/react';
3
3
  import userEvent from '@testing-library/user-event';
4
4
  import { vi } from 'vitest';
5
5
  import AtomixGlass from './AtomixGlass';
@@ -158,18 +158,52 @@ describe('AtomixGlass Component', () => {
158
158
  expect(container.querySelector('.c-atomix-glass__container')).toBeInTheDocument();
159
159
  });
160
160
 
161
- test('applies custom style', () => {
162
- const customStyle = { backgroundColor: 'red' };
161
+ test('applies custom style to root/container layout', () => {
162
+ const customStyle: React.CSSProperties = { backgroundColor: 'red', position: 'fixed', top: 0, left: 0 };
163
163
  const { container } = render(
164
164
  <AtomixGlass style={customStyle}>
165
165
  <div>Content</div>
166
166
  </AtomixGlass>
167
167
  );
168
168
 
169
+ const root = container.querySelector('.c-atomix-glass');
169
170
  const glassContainer = container.querySelector('.c-atomix-glass__container');
171
+ expect(root).toHaveStyle('position: fixed');
170
172
  expect(glassContainer).toHaveStyle('background-color: rgb(255, 0, 0)');
171
173
  });
172
174
 
175
+ test('sets 100% width/height for fixed/sticky positioning', async () => {
176
+ const { container } = render(
177
+ <AtomixGlass style={{ position: 'fixed' }}>
178
+ <div>Content</div>
179
+ </AtomixGlass>
180
+ );
181
+
182
+ const glassContainer = container.querySelector('.c-atomix-glass__container');
183
+
184
+ // Use waitFor because updateAtomixGlassStyles is called imperatively inside a requestAnimationFrame loop
185
+ await waitFor(() => {
186
+ // With the new logic, fixed/sticky elements use measured sizes,
187
+ // not 100% (which is for standard flow)
188
+ expect(glassContainer).not.toHaveStyle('--atomix-glass-container-width: 100%');
189
+ });
190
+ });
191
+
192
+ test('sets 100% width/height for standard flow (not fixed/sticky)', async () => {
193
+ const { container } = render(
194
+ <AtomixGlass>
195
+ <div>Content</div>
196
+ </AtomixGlass>
197
+ );
198
+
199
+ const glassContainer = container.querySelector('.c-atomix-glass__container');
200
+
201
+ await waitFor(() => {
202
+ expect(glassContainer).toHaveStyle('--atomix-glass-container-width: 100%');
203
+ expect(glassContainer).toHaveStyle('--atomix-glass-container-height: 100%');
204
+ });
205
+ });
206
+
173
207
  test('uses standard mode by default', () => {
174
208
  const { container } = render(
175
209
  <AtomixGlass>