@shohojdhara/atomix 0.3.10 → 0.3.12

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 (47) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/dist/atomix.css +9 -6
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +9 -6
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/charts.js +82 -60
  7. package/dist/charts.js.map +1 -1
  8. package/dist/core.js +82 -60
  9. package/dist/core.js.map +1 -1
  10. package/dist/forms.js +82 -60
  11. package/dist/forms.js.map +1 -1
  12. package/dist/heavy.js +82 -60
  13. package/dist/heavy.js.map +1 -1
  14. package/dist/index.d.ts +11 -107
  15. package/dist/index.esm.js +165 -407
  16. package/dist/index.esm.js.map +1 -1
  17. package/dist/index.js +169 -412
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.min.js +1 -1
  20. package/dist/index.min.js.map +1 -1
  21. package/dist/theme.d.ts +1 -32
  22. package/dist/theme.js +12 -207
  23. package/dist/theme.js.map +1 -1
  24. package/package.json +1 -1
  25. package/src/components/AtomixGlass/AtomixGlass.tsx +124 -127
  26. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +28 -32
  27. package/src/components/AtomixGlass/GlassFilter.tsx +15 -4
  28. package/src/components/EdgePanel/EdgePanel.stories.tsx +2 -7
  29. package/src/components/EdgePanel/EdgePanel.tsx +0 -10
  30. package/src/components/Form/Radio.stories.tsx +235 -103
  31. package/src/components/Navigation/Nav/NavDropdown.tsx +8 -4
  32. package/src/components/Navigation/SideMenu/SideMenu.tsx +2 -22
  33. package/src/components/Navigation/SideMenu/SideMenuItem.tsx +11 -15
  34. package/src/lib/config/index.ts +5 -5
  35. package/src/lib/theme/config/index.ts +1 -1
  36. package/src/lib/theme/core/createTheme.ts +11 -40
  37. package/src/lib/theme/generators/index.ts +1 -4
  38. package/src/lib/theme/index.ts +4 -16
  39. package/src/lib/theme/runtime/ThemeProvider.tsx +1 -16
  40. package/src/lib/types/components.ts +2 -26
  41. package/src/styles/06-components/_components.edge-panel.scss +4 -4
  42. package/src/styles/06-components/_components.nav.scss +3 -0
  43. package/src/lib/config/loader.ts +0 -147
  44. package/src/lib/theme/config/__tests__/configLoader.test.ts +0 -207
  45. package/src/lib/theme/config/configLoader.ts +0 -113
  46. package/src/lib/theme/config/loader.ts +0 -293
  47. package/src/lib/theme/generators/cssFile.ts +0 -79
@@ -29,7 +29,7 @@ export { createTheme } from './core';
29
29
  export { deepMerge, mergeTheme, extendTheme } from './core';
30
30
 
31
31
  // Simplified Theme Registry
32
- export {
32
+ export {
33
33
  createThemeRegistry,
34
34
  registerTheme,
35
35
  unregisterTheme,
@@ -46,7 +46,7 @@ export {
46
46
  // ============================================================================
47
47
 
48
48
  import { injectCSS, removeCSS, isCSSInjected } from './utils/injectCSS';
49
- import { saveCSSFile, saveCSSFileSync } from './generators/cssFile';
49
+ // File saving utilities removed to prevent bundling Node.js modules in browser
50
50
 
51
51
  /**
52
52
  * Inject theme CSS into DOM
@@ -62,12 +62,7 @@ export function removeTheme(id: string = 'atomix-theme'): void {
62
62
  removeCSS(id);
63
63
  }
64
64
 
65
- /**
66
- * Save theme to CSS file
67
- */
68
- export async function saveTheme(css: string, filePath: string): Promise<void> {
69
- await saveCSSFile(css, filePath);
70
- }
65
+
71
66
 
72
67
  // ============================================================================
73
68
  // Token Utilities
@@ -113,14 +108,7 @@ export {
113
108
  export { injectCSS, removeCSS, isCSSInjected } from './utils/injectCSS';
114
109
 
115
110
 
116
- // ============================================================================
117
- // Config Loader
118
- // ============================================================================
119
-
120
- export {
121
- loadThemeFromConfig,
122
- loadThemeFromConfigSync,
123
- } from './config/configLoader';
111
+ // Config loader removed to prevent bundling Node.js modules in browser
124
112
 
125
113
  // ============================================================================
126
114
  // React Integration
@@ -86,22 +86,7 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
86
86
  return defaultTheme;
87
87
  }
88
88
 
89
- // Try to load from atomix.config.ts as fallback, but only in Node.js/SSR environments
90
- if (typeof window === 'undefined') {
91
- try {
92
- // Dynamically import the config loader to avoid bundling issues in browser
93
- // eslint-disable-next-line @typescript-eslint/no-var-requires
94
- const { loadThemeFromConfigSync } = require('../config/configLoader');
95
-
96
- const configTokens = loadThemeFromConfigSync();
97
- if (configTokens && Object.keys(configTokens).length > 0) {
98
- // For simplicity, we'll treat config tokens as a special theme name
99
- return 'config-theme';
100
- }
101
- } catch (error) {
102
- // Failed to load theme from config, using default
103
- }
104
- }
89
+
105
90
 
106
91
  // Default fallback
107
92
  return 'default';
@@ -1418,19 +1418,7 @@ export interface SideMenuProps extends BaseComponentProps {
1418
1418
  * <SideMenu LinkComponent={Link} />
1419
1419
  * ```
1420
1420
  */
1421
- LinkComponent?: React.ComponentType<{
1422
- href?: string;
1423
- to?: string;
1424
- children: React.ReactNode;
1425
- className?: string;
1426
- onClick?: (event: React.MouseEvent) => void;
1427
- target?: string;
1428
- rel?: string;
1429
- 'aria-disabled'?: boolean;
1430
- 'aria-current'?: string;
1431
- tabIndex?: number;
1432
- ref?: React.Ref<HTMLAnchorElement>;
1433
- }>;
1421
+ LinkComponent?: React.ElementType;
1434
1422
 
1435
1423
  /**
1436
1424
  * Menu items
@@ -1524,19 +1512,7 @@ export interface SideMenuItemProps extends BaseComponentProps {
1524
1512
  * <SideMenuItem href="/about" LinkComponent={Link}>About</SideMenuItem>
1525
1513
  * ```
1526
1514
  */
1527
- LinkComponent?: React.ComponentType<{
1528
- href?: string;
1529
- to?: string;
1530
- children: React.ReactNode;
1531
- className?: string;
1532
- onClick?: (event: React.MouseEvent) => void;
1533
- target?: string;
1534
- rel?: string;
1535
- 'aria-disabled'?: boolean;
1536
- 'aria-current'?: string;
1537
- tabIndex?: number;
1538
- ref?: React.Ref<HTMLAnchorElement>;
1539
- }>;
1515
+ LinkComponent?: React.ElementType;
1540
1516
  }
1541
1517
 
1542
1518
  /**
@@ -416,7 +416,7 @@
416
416
  }
417
417
 
418
418
  // Remove borders for glass variant on all positions
419
- &.c-edge-panel--start .c-edge-panel__glass-wrapper {
419
+ &.c-edge-panel--start .c-edge-panel__glass-content {
420
420
  animation: slideInStart 0.3s ease forwards;
421
421
 
422
422
  &.is-animating-out {
@@ -424,7 +424,7 @@
424
424
  }
425
425
  }
426
426
 
427
- &.c-edge-panel--end .c-edge-panel__glass-wrapper {
427
+ &.c-edge-panel--end .c-edge-panel__glass-content {
428
428
  animation: slideInEnd 0.3s ease forwards;
429
429
 
430
430
  &.is-animating-out {
@@ -432,11 +432,11 @@
432
432
  }
433
433
  }
434
434
 
435
- &.c-edge-panel--top .c-edge-panel__glass-wrapper {
435
+ &.c-edge-panel--top .c-edge-panel__glass-content{
436
436
  animation: slideInTop 0.3s ease forwards;
437
437
  }
438
438
 
439
- &.c-edge-panel--bottom .c-edge-panel__glass-wrapper {
439
+ &.c-edge-panel--bottom .c-edge-panel__glass-content {
440
440
  animation: slideInBottom 0.3s ease forwards;
441
441
  }
442
442
 
@@ -92,6 +92,9 @@
92
92
  visibility: hidden;
93
93
  opacity: 0;
94
94
  white-space: nowrap;
95
+ list-style: none;
96
+ padding: 0;
97
+ margin: 0;
95
98
  @include transition.basic-transition();
96
99
 
97
100
  &--center {
@@ -1,147 +0,0 @@
1
- /**
2
- * Atomix Config Loader
3
- *
4
- * Helper functions to load atomix.config.ts from external projects.
5
- * Similar to how Tailwind loads tailwind.config.js
6
- */
7
-
8
- import type { AtomixConfig } from './index';
9
-
10
- /**
11
- * Load Atomix configuration from project root
12
- *
13
- * Attempts to load atomix.config.ts from the current working directory.
14
- * Falls back to default config if file doesn't exist.
15
- *
16
- * @param options - Loader options
17
- * @returns Loaded configuration or default
18
- *
19
- * @example
20
- * ```typescript
21
- * import { loadAtomixConfig } from '@shohojdhara/atomix/config';
22
- * import { createTheme } from '@shohojdhara/atomix/theme';
23
- *
24
- * const config = loadAtomixConfig();
25
- * const theme = createTheme(config.theme?.tokens || {});
26
- * ```
27
- */
28
- export function loadAtomixConfig(
29
- options: {
30
- /** Custom config path (default: 'atomix.config.ts') */
31
- configPath?: string;
32
- /** Whether to throw error if config not found (default: false) */
33
- required?: boolean;
34
- } = {}
35
- ): AtomixConfig {
36
- const { configPath = 'atomix.config.ts', required = false } = options;
37
-
38
- // Default config
39
- const defaultConfig: AtomixConfig = {
40
- prefix: 'atomix',
41
- theme: {
42
- extend: {},
43
- },
44
- };
45
-
46
- // In browser environments, config loading is not supported
47
- if (typeof window !== 'undefined') {
48
- if (required) {
49
- throw new Error('loadAtomixConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.');
50
- }
51
- return defaultConfig;
52
- }
53
-
54
- // Try to load config file
55
- try {
56
- // Use dynamic import for ESM compatibility
57
- const configModule = require(configPath);
58
- const config = configModule.default || configModule;
59
-
60
- // Validate it's an AtomixConfig
61
- if (config && typeof config === 'object') {
62
- return config as AtomixConfig;
63
- }
64
-
65
- throw new Error('Invalid config format');
66
- } catch (error: any) {
67
- if (required) {
68
- throw new Error(`Failed to load config from ${configPath}: ${error.message}`);
69
- }
70
-
71
- // Return default config if not required
72
- return defaultConfig;
73
- }
74
- }
75
-
76
- /**
77
- * Resolve config path
78
- *
79
- * Finds atomix.config.ts in the project, checking common locations.
80
- * Returns null in browser environments where file system access is not available.
81
- *
82
- * This function is designed to work in Node.js environments only.
83
- * In browser builds, it will always return null without attempting to access Node.js modules.
84
- *
85
- * @internal This function uses Node.js modules and should not be called in browser environments.
86
- */
87
- export function resolveConfigPath(): string | null {
88
- // Early return for browser environments - prevents any Node.js module access
89
- // This check happens before any require() calls, preventing bundlers from analyzing them
90
- if (typeof window !== 'undefined' || typeof process === 'undefined' || !process.cwd) {
91
- return null;
92
- }
93
-
94
- // Only attempt to load Node.js modules in Node.js runtime
95
- // Use a lazy-loading pattern that prevents static analysis by bundlers
96
- try {
97
- // Create a function that only executes in Node.js runtime
98
- // Use string-based module names to prevent static analysis by bundlers
99
- const loadNodeModules = () => {
100
- // These requires are only executed at runtime in Node.js environments
101
- // They are marked as external in Rollup config and should not be bundled
102
- // Using string concatenation and computed property access to prevent static analysis
103
- if (typeof require === 'undefined') {
104
- return null;
105
- }
106
-
107
- // Use a try-catch wrapper to safely access require
108
- try {
109
- // Build module names dynamically to prevent static analysis
110
- const moduleNames: [string, string] = ['f' + 's', 'p' + 'a' + 't' + 'h'];
111
- // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
112
- const fs = require(moduleNames[0]);
113
- // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
114
- const path = require(moduleNames[1]);
115
- return { fs, path };
116
- } catch {
117
- return null;
118
- }
119
- };
120
-
121
- const modules = loadNodeModules();
122
- if (!modules) {
123
- return null;
124
- }
125
-
126
- const { fs, path } = modules;
127
- const cwd = process.cwd();
128
- const possiblePaths = [
129
- path.join(cwd, 'atomix.config.ts'),
130
- path.join(cwd, 'atomix.config.js'),
131
- path.join(cwd, 'atomix.config.mjs'),
132
- ];
133
-
134
- for (const configPath of possiblePaths) {
135
- if (fs.existsSync(configPath)) {
136
- return configPath;
137
- }
138
- }
139
- } catch (error) {
140
- // Silently fail in browser environments or when modules are unavailable
141
- return null;
142
- }
143
-
144
- return null;
145
- }
146
-
147
- export default loadAtomixConfig;
@@ -1,207 +0,0 @@
1
- /**
2
- * Config Loader Tests
3
- *
4
- * Tests for automatic config loading from atomix.config.ts
5
- */
6
-
7
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
8
- import { loadThemeFromConfigSync, loadThemeFromConfig } from '../configLoader';
9
- import { createTheme } from '../../core/createTheme';
10
- import type { DesignTokens } from '../../tokens/tokens';
11
-
12
- describe('Config Loader', () => {
13
- beforeEach(() => {
14
- // Clear any cached configs
15
- vi.clearAllMocks();
16
- });
17
-
18
- afterEach(() => {
19
- vi.restoreAllMocks();
20
- });
21
-
22
- describe('loadThemeFromConfigSync', () => {
23
- it('should return empty object in browser environment', () => {
24
- // Mock window object
25
- const originalWindow = global.window;
26
- // @ts-expect-error - intentionally setting window for test
27
- global.window = {};
28
-
29
- const result = loadThemeFromConfigSync();
30
- expect(result).toEqual({});
31
-
32
- // Restore
33
- global.window = originalWindow;
34
- });
35
-
36
- it('should handle missing config file gracefully', () => {
37
- // In Node.js environment, if config doesn't exist, should return empty object
38
- const result = loadThemeFromConfigSync('non-existent-config.ts');
39
- expect(result).toEqual({});
40
- });
41
- });
42
-
43
- describe('loadThemeFromConfig', () => {
44
- it('should return empty object in browser environment', async () => {
45
- // Mock window object
46
- const originalWindow = global.window;
47
- // @ts-expect-error - intentionally setting window for test
48
- global.window = {};
49
-
50
- const result = await loadThemeFromConfig();
51
- expect(result).toEqual({});
52
-
53
- // Restore
54
- global.window = originalWindow;
55
- });
56
-
57
- it('should handle missing config file gracefully', async () => {
58
- const result = await loadThemeFromConfig('non-existent-config.ts');
59
- expect(result).toEqual({});
60
- });
61
- });
62
-
63
- describe('Token Flattening', () => {
64
- it('should correctly map simple color strings', () => {
65
- // This tests the internal flattenConfigTokens function indirectly
66
- // by checking that createTheme can handle config structure
67
- const mockConfig = {
68
- theme: {
69
- extend: {
70
- colors: {
71
- primary: '#7AFFD7',
72
- secondary: '#FF5733',
73
- },
74
- },
75
- },
76
- };
77
-
78
- // Since we can't directly test the private function,
79
- // we test through createTheme which uses it
80
- // This is an integration test
81
- expect(typeof createTheme).toBe('function');
82
- });
83
-
84
- it('should correctly map palette color objects', () => {
85
- const mockConfig = {
86
- theme: {
87
- extend: {
88
- colors: {
89
- primary: {
90
- main: '#7AFFD7',
91
- light: '#B3FFE9',
92
- dark: '#00E6C3',
93
- },
94
- },
95
- },
96
- },
97
- };
98
-
99
- // Integration test through createTheme
100
- expect(typeof createTheme).toBe('function');
101
- });
102
-
103
- it('should correctly map color scales', () => {
104
- const mockConfig = {
105
- theme: {
106
- extend: {
107
- colors: {
108
- primary: {
109
- 1: '#f0f9ff',
110
- 6: '#3b82f6',
111
- 10: '#1e3a8a',
112
- },
113
- },
114
- },
115
- },
116
- };
117
-
118
- // Integration test
119
- expect(typeof createTheme).toBe('function');
120
- });
121
-
122
- it('should correctly map spacing tokens', () => {
123
- const mockConfig = {
124
- theme: {
125
- extend: {
126
- spacing: {
127
- '4': '1rem',
128
- '8': '2rem',
129
- },
130
- },
131
- },
132
- };
133
-
134
- // Integration test
135
- expect(typeof createTheme).toBe('function');
136
- });
137
-
138
- it('should correctly map typography tokens', () => {
139
- const mockConfig = {
140
- theme: {
141
- extend: {
142
- typography: {
143
- fontFamilies: {
144
- sans: ['Inter', 'sans-serif'],
145
- },
146
- fontSizes: {
147
- '2xl': '1.5rem',
148
- },
149
- },
150
- },
151
- },
152
- };
153
-
154
- // Integration test
155
- expect(typeof createTheme).toBe('function');
156
- });
157
- });
158
- });
159
-
160
- describe('createTheme with Config Loading', () => {
161
- it('should work without input (will use defaults if config not available)', () => {
162
- // createTheme() should work even if config is not available
163
- // It will fall back to default tokens
164
- const css = createTheme();
165
-
166
- expect(typeof css).toBe('string');
167
- expect(css).toContain(':root');
168
- expect(css).toContain('--atomix');
169
- });
170
-
171
- it('should accept DesignTokens input', () => {
172
- const tokens: Partial<DesignTokens> = {
173
- 'primary': '#7AFFD7',
174
- 'spacing-4': '1rem',
175
- };
176
-
177
- const css = createTheme(tokens);
178
-
179
- expect(typeof css).toBe('string');
180
- expect(css).toContain('--atomix-primary');
181
- expect(css).toContain('#7AFFD7');
182
- });
183
-
184
- it('should respect prefix option', () => {
185
- const tokens: Partial<DesignTokens> = {
186
- 'primary': '#7AFFD7',
187
- };
188
-
189
- const css = createTheme(tokens, { prefix: 'myapp' });
190
-
191
- expect(css).toContain('--myapp-primary');
192
- expect(css).not.toContain('--atomix-primary');
193
- });
194
-
195
- it('should respect selector option', () => {
196
- const tokens: Partial<DesignTokens> = {
197
- 'primary': '#7AFFD7',
198
- };
199
-
200
- const css = createTheme(tokens, { selector: '[data-theme="dark"]' });
201
-
202
- expect(css).toContain('[data-theme="dark"]');
203
- expect(css).not.toContain(':root');
204
- });
205
- });
206
-
207
-
@@ -1,113 +0,0 @@
1
-
2
- /**
3
- * Theme Configuration Loader
4
- *
5
- * Provides functions to load theme configurations from atomix.config.ts
6
- * Includes both sync and async versions, with automatic fallbacks
7
- */
8
-
9
- import type { DesignTokens } from '../tokens/tokens';
10
- import { createTokens } from '../tokens/tokens';
11
- import { loadAtomixConfig as loadAtomixConfigStatic } from '../../config/loader';
12
-
13
- /**
14
- * Load theme from config file (synchronous, Node.js only)
15
- * @param configPath - Path to config file (default: atomix.config.ts)
16
- * @returns DesignTokens from theme configuration
17
- * @throws Error if config loading is not available in browser environment
18
- */
19
- export function loadThemeFromConfigSync(options?: { configPath?: string; required?: boolean }): DesignTokens {
20
- // Check if we're in a browser environment
21
- if (typeof window !== 'undefined') {
22
- throw new Error('loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.');
23
- }
24
-
25
- // Use static import - the function handles browser environment checks internally
26
- let config;
27
-
28
- try {
29
- config = loadAtomixConfigStatic({
30
- configPath: options?.configPath || 'atomix.config.ts',
31
- required: options?.required !== false,
32
- });
33
- } catch (error) {
34
- if (options?.required !== false) {
35
- throw new Error('Config loader module not available');
36
- }
37
- // Return empty tokens if config is not required
38
- return createTokens({});
39
- }
40
-
41
- if (!config?.theme) {
42
- return createTokens({});
43
- }
44
-
45
- // Extract tokens from config.theme structure
46
- // config.theme can have: { extend?: ThemeTokens, tokens?: ThemeTokens, themes?: ... }
47
- // We need to extract the actual DesignTokens (flat structure)
48
- const themeConfig = config.theme;
49
-
50
- // Check if theme is directly a flat object (DesignTokens format)
51
- // This handles the case where config.theme might be passed as DesignTokens directly
52
- if (themeConfig && typeof themeConfig === 'object' && !('extend' in themeConfig) && !('tokens' in themeConfig) && !('themes' in themeConfig)) {
53
- // It's likely already a flat DesignTokens object
54
- return createTokens(themeConfig as Partial<DesignTokens>);
55
- }
56
-
57
- // If theme has nested structure (extend/tokens/themes), we can't directly use it
58
- // Return empty tokens - the theme system will use defaults
59
- // TODO: Add proper conversion from ThemeTokens to DesignTokens if needed
60
- return createTokens({});
61
- }
62
-
63
- /**
64
- * Load theme from config file (asynchronous)
65
- * @param configPath - Path to config file (default: atomix.config.ts)
66
- * @returns Promise resolving to DesignTokens from theme configuration
67
- */
68
- export async function loadThemeFromConfig(options?: { configPath?: string; required?: boolean }): Promise<DesignTokens> {
69
- // Check if we're in a browser environment
70
- if (typeof window !== 'undefined') {
71
- throw new Error('loadThemeFromConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.');
72
- }
73
-
74
- // Use static import with runtime check
75
- // The function will handle browser environment checks internally
76
- let config;
77
-
78
- try {
79
- // loadAtomixConfig is synchronous, not async
80
- config = loadAtomixConfigStatic({
81
- configPath: options?.configPath || 'atomix.config.ts',
82
- required: options?.required !== false,
83
- });
84
- } catch (error) {
85
- if (options?.required !== false) {
86
- throw new Error('Config loader module not available');
87
- }
88
- // Return empty tokens if config is not required
89
- return createTokens({});
90
- }
91
-
92
- if (!config?.theme) {
93
- return createTokens({});
94
- }
95
-
96
- // Extract tokens from config.theme structure
97
- // config.theme can have: { extend?: ThemeTokens, tokens?: ThemeTokens, themes?: ... }
98
- // We need to extract the actual DesignTokens (flat structure)
99
- const themeConfig = config.theme;
100
-
101
- // Check if theme is directly a flat object (DesignTokens format)
102
- // This handles the case where config.theme might be passed as DesignTokens directly
103
- if (themeConfig && typeof themeConfig === 'object' && !('extend' in themeConfig) && !('tokens' in themeConfig) && !('themes' in themeConfig)) {
104
- // It's likely already a flat DesignTokens object
105
- return createTokens(themeConfig as Partial<DesignTokens>);
106
- }
107
-
108
- // If theme has nested structure (extend/tokens/themes), we can't directly use it
109
- // Return empty tokens - the theme system will use defaults
110
- // TODO: Add proper conversion from ThemeTokens to DesignTokens if needed
111
- return createTokens({});
112
- }
113
-