@shohojdhara/atomix 0.3.2 → 0.3.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.
Files changed (84) hide show
  1. package/README.md +58 -21
  2. package/dist/atomix.css +96 -121
  3. package/dist/atomix.min.css +3 -3
  4. package/dist/index.d.ts +7937 -7765
  5. package/dist/index.esm.js +3677 -4031
  6. package/dist/index.esm.js.map +1 -1
  7. package/dist/index.js +3648 -3952
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.min.js +1 -1
  10. package/dist/index.min.js.map +1 -1
  11. package/package.json +44 -16
  12. package/scripts/atomix-cli.js +1764 -0
  13. package/scripts/build-themes.js +208 -0
  14. package/scripts/cli/interactive-init.js +520 -0
  15. package/scripts/cli/migration-tools.js +603 -0
  16. package/scripts/cli/theme-bridge.js +129 -0
  17. package/scripts/cli/token-manager.js +519 -0
  18. package/scripts/sync-theme-config.js +309 -0
  19. package/src/components/Button/Button.tsx +36 -1
  20. package/src/components/List/ListGroup.tsx +1 -2
  21. package/src/components/Popover/Popover.tsx +2 -2
  22. package/src/components/Tooltip/Tooltip.stories.tsx +49 -12
  23. package/src/components/Tooltip/Tooltip.tsx +32 -58
  24. package/src/lib/composables/useTooltip.ts +285 -0
  25. package/src/lib/config/index.ts +275 -0
  26. package/src/lib/config/loader.ts +105 -0
  27. package/src/lib/constants/cssVariables.ts +390 -0
  28. package/src/lib/hooks/__tests__/useComponentCustomization.test.ts +151 -0
  29. package/src/lib/hooks/index.ts +19 -0
  30. package/src/lib/hooks/useComponentCustomization.ts +175 -0
  31. package/src/lib/index.ts +14 -1
  32. package/src/lib/patterns/__tests__/slots.test.ts +108 -0
  33. package/src/lib/patterns/index.ts +35 -0
  34. package/src/lib/patterns/slots.tsx +421 -0
  35. package/src/lib/theme/composeTheme.ts +0 -5
  36. package/src/lib/theme/config/index.ts +1 -1
  37. package/src/lib/theme/config/loader.ts +75 -41
  38. package/src/lib/theme/config/types.ts +21 -7
  39. package/src/lib/theme/config/validator.ts +1 -1
  40. package/src/lib/theme/constants.ts +12 -2
  41. package/src/lib/theme/createTheme.ts +2 -135
  42. package/src/lib/theme/createThemeFromConfig.ts +132 -0
  43. package/src/lib/theme/cssVariableMapper.ts +261 -0
  44. package/src/lib/theme/devtools/CLI.ts +161 -76
  45. package/src/lib/theme/devtools/Comparator.tsx +343 -0
  46. package/src/lib/theme/devtools/IMPROVEMENTS.md +429 -0
  47. package/src/lib/theme/devtools/Inspector.tsx +21 -6
  48. package/src/lib/theme/devtools/LiveEditor.tsx +393 -0
  49. package/src/lib/theme/devtools/README.md +433 -0
  50. package/src/lib/theme/devtools/index.ts +12 -11
  51. package/src/lib/theme/generateCSSVariables.ts +79 -38
  52. package/src/lib/theme/index.ts +45 -246
  53. package/src/lib/theme/runtime/ThemeApplicator.ts +252 -0
  54. package/src/lib/theme/runtime/ThemeManager.test.ts +17 -1
  55. package/src/lib/theme/runtime/ThemeManager.ts +7 -7
  56. package/src/lib/theme/themeUtils.ts +27 -5
  57. package/src/lib/theme/types.ts +59 -1
  58. package/src/lib/theme-tools.ts +125 -0
  59. package/src/lib/types/components.ts +260 -72
  60. package/src/lib/types/partProps.ts +426 -0
  61. package/src/lib/utils/__tests__/componentUtils.test.ts +144 -0
  62. package/src/lib/utils/componentUtils.ts +163 -0
  63. package/src/lib/utils/index.ts +17 -57
  64. package/src/styles/01-settings/_settings.colors.scss +10 -10
  65. package/src/styles/01-settings/_settings.navbar.scss +1 -1
  66. package/src/styles/01-settings/_settings.tooltip.scss +1 -1
  67. package/src/styles/03-generic/_generated-root.css +5 -0
  68. package/src/styles/06-components/_components.navbar.scss +12 -5
  69. package/src/styles/06-components/_components.tooltip.scss +31 -81
  70. package/src/themes/README.md +442 -0
  71. package/src/themes/themes.config.js +35 -0
  72. package/src/lib/theme/errors.test.ts +0 -207
  73. package/src/lib/theme/generators/CSSGenerator.ts +0 -311
  74. package/src/lib/theme/generators/ConfigGenerator.ts +0 -287
  75. package/src/lib/theme/generators/TypeGenerator.ts +0 -228
  76. package/src/lib/theme/generators/index.ts +0 -21
  77. package/src/lib/theme/monitoring/ThemeAnalytics.ts +0 -409
  78. package/src/lib/theme/monitoring/index.ts +0 -17
  79. package/src/lib/theme/overrides/ComponentOverrides.ts +0 -243
  80. package/src/lib/theme/overrides/index.ts +0 -15
  81. package/src/lib/theme/studio/ThemeStudio.tsx +0 -312
  82. package/src/lib/theme/studio/index.ts +0 -8
  83. package/src/lib/theme/whitelabel/WhiteLabelManager.ts +0 -364
  84. package/src/lib/theme/whitelabel/index.ts +0 -13
@@ -0,0 +1,285 @@
1
+ import { useState, useRef, useEffect, RefObject, useCallback } from 'react';
2
+
3
+ export type TooltipPosition =
4
+ | 'top'
5
+ | 'bottom'
6
+ | 'left'
7
+ | 'right'
8
+ | 'top-left'
9
+ | 'top-right'
10
+ | 'bottom-left'
11
+ | 'bottom-right';
12
+
13
+ export type TooltipTrigger = 'click' | 'hover';
14
+
15
+ interface UseTooltipProps {
16
+ position?: TooltipPosition;
17
+ trigger?: TooltipTrigger;
18
+ offset?: number;
19
+ delay?: number;
20
+ }
21
+
22
+ interface TooltipStyles {
23
+ tooltip: React.CSSProperties;
24
+ arrow: React.CSSProperties;
25
+ }
26
+
27
+ interface UseTooltipResult {
28
+ isVisible: boolean;
29
+ isPositioned: boolean;
30
+ tooltipId: string;
31
+ triggerRef: RefObject<HTMLDivElement>;
32
+ tooltipRef: RefObject<HTMLDivElement>;
33
+ tooltipStyle: React.CSSProperties;
34
+ arrowStyle: React.CSSProperties;
35
+ showTooltip: () => void;
36
+ hideTooltip: () => void;
37
+ toggleTooltip: () => void;
38
+ triggerProps: React.HTMLAttributes<HTMLDivElement>;
39
+ wrapperProps: React.HTMLAttributes<HTMLDivElement>;
40
+ }
41
+
42
+ /**
43
+ * Calculate tooltip and arrow positions based on trigger and tooltip dimensions
44
+ */
45
+ const calculateTooltipPosition = (
46
+ position: TooltipPosition,
47
+ triggerRect: DOMRect,
48
+ tooltipRect: DOMRect,
49
+ wrapperRect: DOMRect,
50
+ offset: number,
51
+ arrowSize: number
52
+ ): TooltipStyles => {
53
+ const tooltipWidth = tooltipRect.width || 0;
54
+ const tooltipHeight = tooltipRect.height || 0;
55
+ const triggerWidth = triggerRect.width;
56
+ const triggerHeight = triggerRect.height;
57
+
58
+ const tooltipStyle: React.CSSProperties = {
59
+ '--atomix-tooltip-offset': `${offset}px`,
60
+ } as React.CSSProperties;
61
+
62
+ const arrowStyle: React.CSSProperties = {};
63
+
64
+ switch (position) {
65
+ case 'top':
66
+ tooltipStyle.top = `${triggerRect.top - wrapperRect.top - tooltipHeight - offset}px`;
67
+ tooltipStyle.left = `${triggerRect.left - wrapperRect.left + triggerWidth / 2 - tooltipWidth / 2}px`;
68
+ arrowStyle.bottom = `${arrowSize / -2}px`;
69
+ arrowStyle.left = `${tooltipWidth / 2 - arrowSize / 2}px`;
70
+ break;
71
+
72
+ case 'bottom':
73
+ tooltipStyle.top = `${triggerRect.bottom - wrapperRect.top + offset}px`;
74
+ tooltipStyle.left = `${triggerRect.left - wrapperRect.left + triggerWidth / 2 - tooltipWidth / 2}px`;
75
+ arrowStyle.top = `${arrowSize / -2}px`;
76
+ arrowStyle.left = `${tooltipWidth / 2 - arrowSize / 2}px`;
77
+ break;
78
+
79
+ case 'left':
80
+ tooltipStyle.right = `${wrapperRect.right - triggerRect.left + offset}px`;
81
+ tooltipStyle.top = `${triggerRect.top - wrapperRect.top + triggerHeight / 2 - tooltipHeight / 2}px`;
82
+ arrowStyle.right = `${arrowSize / -2}px`;
83
+ arrowStyle.top = `${tooltipHeight / 2 - arrowSize / 2}px`;
84
+ break;
85
+
86
+ case 'right':
87
+ tooltipStyle.left = `${triggerRect.right - wrapperRect.left + offset}px`;
88
+ tooltipStyle.top = `${triggerRect.top - wrapperRect.top + triggerHeight / 2 - tooltipHeight / 2}px`;
89
+ arrowStyle.left = `${arrowSize / -2}px`;
90
+ arrowStyle.top = `${tooltipHeight / 2 - arrowSize / 2}px`;
91
+ break;
92
+
93
+ case 'top-left':
94
+ tooltipStyle.bottom = `${wrapperRect.bottom - triggerRect.top + offset}px`;
95
+ tooltipStyle.left = `${triggerRect.left - wrapperRect.left}px`;
96
+ arrowStyle.bottom = `${arrowSize / -2}px`;
97
+ arrowStyle.left = `${arrowSize}px`;
98
+ break;
99
+
100
+ case 'top-right':
101
+ tooltipStyle.bottom = `${wrapperRect.bottom - triggerRect.top + offset}px`;
102
+ tooltipStyle.right = `${wrapperRect.right - triggerRect.right}px`;
103
+ arrowStyle.bottom = `${arrowSize / -2}px`;
104
+ arrowStyle.right = `${arrowSize}px`;
105
+ break;
106
+
107
+ case 'bottom-left':
108
+ tooltipStyle.top = `${triggerRect.bottom - wrapperRect.top + offset}px`;
109
+ tooltipStyle.left = `${triggerRect.left - wrapperRect.left}px`;
110
+ arrowStyle.top = `${arrowSize / -2}px`;
111
+ arrowStyle.left = `${arrowSize}px`;
112
+ break;
113
+
114
+ case 'bottom-right':
115
+ tooltipStyle.top = `${triggerRect.bottom - wrapperRect.top + offset}px`;
116
+ tooltipStyle.right = `${wrapperRect.right - triggerRect.right}px`;
117
+ arrowStyle.top = `${arrowSize / -2}px`;
118
+ arrowStyle.right = `${arrowSize}px`;
119
+ break;
120
+ }
121
+
122
+ return { tooltip: tooltipStyle, arrow: arrowStyle };
123
+ };
124
+
125
+ /**
126
+ * Get arrow size from CSS custom property
127
+ */
128
+ const getArrowSize = (element: HTMLElement): number => {
129
+ const arrowSizeValue = getComputedStyle(element)
130
+ .getPropertyValue('--atomix-tooltip-arrow-size')
131
+ .trim();
132
+
133
+ if (!arrowSizeValue) return 8; // Default fallback
134
+
135
+ // Try to parse as rem (e.g., "0.5rem")
136
+ const remMatch = arrowSizeValue.match(/([\d.]+)rem/);
137
+ if (remMatch?.[1]) {
138
+ return parseFloat(remMatch[1]) * 16; // Convert rem to px
139
+ }
140
+
141
+ // Try to parse as px (e.g., "8px")
142
+ const pxMatch = arrowSizeValue.match(/([\d.]+)px/);
143
+ if (pxMatch?.[1]) {
144
+ return parseFloat(pxMatch[1]);
145
+ }
146
+
147
+ return 8; // Default fallback
148
+ };
149
+
150
+ /**
151
+ * Hook for managing tooltip state and positioning logic
152
+ */
153
+ export const useTooltip = ({
154
+ position = 'top',
155
+ trigger = 'hover',
156
+ offset = 10,
157
+ delay = 200,
158
+ }: UseTooltipProps): UseTooltipResult => {
159
+ const [isVisible, setIsVisible] = useState(false);
160
+ const [isPositioned, setIsPositioned] = useState(false);
161
+ const [tooltipStyle, setTooltipStyle] = useState<React.CSSProperties>({});
162
+ const [arrowStyle, setArrowStyle] = useState<React.CSSProperties>({});
163
+
164
+ const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
165
+ const triggerRef = useRef<HTMLDivElement>(null);
166
+ const tooltipRef = useRef<HTMLDivElement>(null);
167
+ const tooltipId = `tooltip-${Math.random().toString(36).slice(2, 11)}`;
168
+
169
+ const showTooltip = useCallback(() => {
170
+ if (timeoutRef.current) {
171
+ clearTimeout(timeoutRef.current);
172
+ }
173
+
174
+ if (delay > 0) {
175
+ timeoutRef.current = setTimeout(() => {
176
+ setIsVisible(true);
177
+ }, delay);
178
+ } else {
179
+ setIsVisible(true);
180
+ }
181
+ }, [delay]);
182
+
183
+ const hideTooltip = useCallback(() => {
184
+ if (timeoutRef.current) {
185
+ clearTimeout(timeoutRef.current);
186
+ }
187
+ setIsVisible(false);
188
+ setIsPositioned(false);
189
+ }, []);
190
+
191
+ const toggleTooltip = useCallback(() => {
192
+ if (isVisible) {
193
+ hideTooltip();
194
+ } else {
195
+ showTooltip();
196
+ }
197
+ }, [isVisible, showTooltip, hideTooltip]);
198
+
199
+ // Calculate and update tooltip position
200
+ const updatePosition = useCallback(() => {
201
+ if (!triggerRef.current || !tooltipRef.current) return;
202
+
203
+ const triggerRect = triggerRef.current.getBoundingClientRect();
204
+ const tooltipRect = tooltipRef.current.getBoundingClientRect();
205
+ const wrapperElement = triggerRef.current.parentElement;
206
+
207
+ if (!wrapperElement) return;
208
+
209
+ const wrapperRect = wrapperElement.getBoundingClientRect();
210
+ const arrowSize = getArrowSize(tooltipRef.current);
211
+
212
+ const styles = calculateTooltipPosition(
213
+ position,
214
+ triggerRect,
215
+ tooltipRect,
216
+ wrapperRect,
217
+ offset,
218
+ arrowSize
219
+ );
220
+
221
+ setTooltipStyle(styles.tooltip);
222
+ setArrowStyle(styles.arrow);
223
+ setIsPositioned(true);
224
+ }, [position, offset]);
225
+
226
+ // Position tooltip when visible
227
+ useEffect(() => {
228
+ if (!isVisible || !triggerRef.current || !tooltipRef.current) {
229
+ return;
230
+ }
231
+
232
+ // Use single RAF to ensure tooltip is rendered before calculating
233
+ const rafId = requestAnimationFrame(() => {
234
+ updatePosition();
235
+ });
236
+
237
+ // Recalculate on window resize and scroll
238
+ const handleUpdate = () => {
239
+ updatePosition();
240
+ };
241
+
242
+ window.addEventListener('resize', handleUpdate);
243
+ window.addEventListener('scroll', handleUpdate, true);
244
+
245
+ return () => {
246
+ cancelAnimationFrame(rafId);
247
+ window.removeEventListener('resize', handleUpdate);
248
+ window.removeEventListener('scroll', handleUpdate, true);
249
+ };
250
+ }, [isVisible, updatePosition]);
251
+
252
+ // Setup trigger props
253
+ const triggerProps: React.HTMLAttributes<HTMLDivElement> = {
254
+ 'aria-describedby': isVisible ? tooltipId : undefined,
255
+ };
256
+
257
+ const wrapperProps: React.HTMLAttributes<HTMLDivElement> = {};
258
+
259
+ if (trigger === 'hover') {
260
+ wrapperProps.onMouseEnter = showTooltip;
261
+ wrapperProps.onMouseLeave = hideTooltip;
262
+ triggerProps.onFocus = showTooltip;
263
+ triggerProps.onBlur = hideTooltip;
264
+ } else if (trigger === 'click') {
265
+ triggerProps.onClick = toggleTooltip;
266
+ }
267
+
268
+ return {
269
+ isVisible,
270
+ isPositioned,
271
+ tooltipId,
272
+ triggerRef,
273
+ tooltipRef,
274
+ tooltipStyle,
275
+ arrowStyle,
276
+ showTooltip,
277
+ hideTooltip,
278
+ toggleTooltip,
279
+ triggerProps,
280
+ wrapperProps,
281
+ };
282
+ };
283
+
284
+ export default useTooltip;
285
+
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Atomix Configuration System
3
+ *
4
+ * Tailwind-like configuration for customizing the Atomix Design System.
5
+ *
6
+ * External developers can create `atomix.config.ts` in their project root
7
+ * to customize design tokens, similar to Tailwind's tailwind.config.js
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * // atomix.config.ts (in your project)
12
+ * import { defineConfig } from '@shohojdhara/atomix/config';
13
+ *
14
+ * export default defineConfig({
15
+ * theme: {
16
+ * extend: {
17
+ * colors: {
18
+ * primary: { main: '#7AFFD7' },
19
+ * },
20
+ * },
21
+ * },
22
+ * });
23
+ * ```
24
+ */
25
+
26
+ import type { Theme } from '../theme/types';
27
+
28
+ /**
29
+ * Color Scale (1-10)
30
+ */
31
+ export interface ColorScale {
32
+ 1?: string;
33
+ 2?: string;
34
+ 3?: string;
35
+ 4?: string;
36
+ 5?: string;
37
+ 6?: string;
38
+ 7?: string;
39
+ 8?: string;
40
+ 9?: string;
41
+ 10?: string;
42
+ [key: string]: string | undefined;
43
+ }
44
+
45
+ /**
46
+ * Palette Color Options
47
+ */
48
+ export interface PaletteColorOptions {
49
+ main: string;
50
+ light?: string;
51
+ dark?: string;
52
+ contrastText?: string;
53
+ }
54
+
55
+ /**
56
+ * Design Tokens Schema (Tailwind-like)
57
+ */
58
+ export interface ThemeTokens {
59
+ /** Color palette */
60
+ colors?: Record<string, string | PaletteColorOptions | ColorScale | Record<string, string>>;
61
+ /** Spacing scale */
62
+ spacing?: Record<string, string>;
63
+ /** Border radius scale */
64
+ borderRadius?: Record<string, string>;
65
+ /** Typography scale and settings */
66
+ typography?: {
67
+ fontFamilies?: Record<string, string>;
68
+ fontSizes?: Record<string, string>;
69
+ fontWeights?: Record<string, string | number>;
70
+ lineHeights?: Record<string, string | number>;
71
+ letterSpacings?: Record<string, string>;
72
+ };
73
+ /** Shadow scale */
74
+ shadows?: Record<string, string>;
75
+ /** Z-index scale */
76
+ zIndex?: Record<string, string | number>;
77
+ /** Breakpoints scale */
78
+ breakpoints?: Record<string, string | number>;
79
+ /** Transitions settings */
80
+ transitions?: {
81
+ durations?: Record<string, string>;
82
+ easings?: Record<string, string>;
83
+ };
84
+ }
85
+
86
+ /**
87
+ * CSS Theme Definition
88
+ */
89
+ export interface CSSThemeDefinition {
90
+ type: 'css';
91
+ name: string;
92
+ class?: string;
93
+ description?: string;
94
+ author?: string;
95
+ version?: string;
96
+ tags?: string[];
97
+ supportsDarkMode?: boolean;
98
+ status?: 'stable' | 'beta' | 'experimental' | 'deprecated';
99
+ a11y?: {
100
+ contrastTarget?: number;
101
+ modes?: string[];
102
+ };
103
+ color?: string;
104
+ features?: string[];
105
+ dependencies?: string[];
106
+ cssPath?: string;
107
+ }
108
+
109
+ /**
110
+ * JavaScript Theme Definition
111
+ */
112
+ export interface JSThemeDefinition {
113
+ type: 'js';
114
+ name: string;
115
+ class?: string;
116
+ description?: string;
117
+ author?: string;
118
+ version?: string;
119
+ tags?: string[];
120
+ supportsDarkMode?: boolean;
121
+ status?: 'stable' | 'beta' | 'experimental' | 'deprecated';
122
+ a11y?: {
123
+ contrastTarget?: number;
124
+ modes?: string[];
125
+ };
126
+ color?: string;
127
+ features?: string[];
128
+ dependencies?: string[];
129
+ createTheme: () => Theme;
130
+ }
131
+
132
+ /**
133
+ * Theme Definition (CSS or JS)
134
+ */
135
+ export type ThemeDefinition = CSSThemeDefinition | JSThemeDefinition;
136
+
137
+ /**
138
+ * Build configuration (migrated from theme.config.ts)
139
+ */
140
+ export interface BuildConfig {
141
+ output?: {
142
+ directory?: string;
143
+ formats?: {
144
+ expanded?: string;
145
+ compressed?: string;
146
+ };
147
+ };
148
+ sass?: {
149
+ style?: 'expanded' | 'compressed';
150
+ sourceMap?: boolean;
151
+ loadPaths?: string[];
152
+ };
153
+ }
154
+
155
+ /**
156
+ * Runtime configuration (migrated from theme.config.ts)
157
+ */
158
+ export interface RuntimeConfig {
159
+ basePath?: string;
160
+ cdnPath?: string | null;
161
+ preload?: string[];
162
+ lazy?: boolean;
163
+ defaultTheme?: string;
164
+ storageKey?: string;
165
+ dataAttribute?: string;
166
+ enablePersistence?: boolean;
167
+ useMinified?: boolean;
168
+ }
169
+
170
+ /**
171
+ * Integration settings (migrated from theme.config.ts)
172
+ */
173
+ export interface IntegrationConfig {
174
+ cssVariables?: Record<string, string>;
175
+ classNames?: {
176
+ theme?: string;
177
+ colorMode?: string;
178
+ };
179
+ }
180
+
181
+ /**
182
+ * Atomix Configuration Interface
183
+ *
184
+ * Tailwind-like configuration for external developers.
185
+ * Focus on theme customization - build/runtime configs are internal only.
186
+ */
187
+ export interface AtomixConfig {
188
+ /**
189
+ * CSS variable prefix (default: 'atomix')
190
+ *
191
+ * Change this to customize all CSS variable names.
192
+ * Example: prefix: 'myapp' → --myapp-primary instead of --atomix-primary
193
+ */
194
+ prefix?: string;
195
+
196
+ /**
197
+ * Theme customization (Tailwind-like)
198
+ *
199
+ * Use `extend` to add or override design tokens.
200
+ * Use `tokens` to completely replace the default token system (advanced).
201
+ */
202
+ theme?: {
203
+ /**
204
+ * Extend the default design tokens
205
+ *
206
+ * This is the recommended way to customize Atomix.
207
+ * Your values will override or extend the base tokens.
208
+ */
209
+ extend?: ThemeTokens;
210
+
211
+ /**
212
+ * Override the default tokens entirely (advanced)
213
+ *
214
+ * Use with caution - this replaces the entire token system.
215
+ * Most users should use `extend` instead.
216
+ */
217
+ tokens?: ThemeTokens;
218
+
219
+ /**
220
+ * Register custom themes (optional)
221
+ *
222
+ * Define CSS or JavaScript themes that can be loaded dynamically.
223
+ */
224
+ themes?: Record<string, ThemeDefinition>;
225
+ };
226
+
227
+ // Internal configurations (for library development only)
228
+ // These are not needed for external developers
229
+ /** @internal Build configuration (internal use only) */
230
+ build?: BuildConfig;
231
+ /** @internal Runtime configuration (internal use only) */
232
+ runtime?: RuntimeConfig;
233
+ /** @internal Integration settings (internal use only) */
234
+ integration?: IntegrationConfig;
235
+ /** @internal Theme dependencies mapping (internal use only) */
236
+ dependencies?: Record<string, string[]>;
237
+ }
238
+
239
+ /**
240
+ * Helper function to define Atomix configuration with type safety
241
+ *
242
+ * @param config - Atomix configuration object
243
+ * @returns The configuration object
244
+ */
245
+ /**
246
+ * Helper function to define Atomix configuration with type safety
247
+ *
248
+ * Similar to Tailwind's defineConfig, provides autocomplete and type checking.
249
+ *
250
+ * @param config - Atomix configuration object
251
+ * @returns The configuration object
252
+ *
253
+ * @example
254
+ * ```typescript
255
+ * import { defineConfig } from '@shohojdhara/atomix/config';
256
+ *
257
+ * export default defineConfig({
258
+ * theme: {
259
+ * extend: {
260
+ * colors: {
261
+ * primary: { main: '#7AFFD7' },
262
+ * },
263
+ * },
264
+ * },
265
+ * });
266
+ * ```
267
+ */
268
+ export function defineConfig(config: AtomixConfig): AtomixConfig {
269
+ return config;
270
+ }
271
+
272
+ // Export loader functions
273
+ export { loadAtomixConfig, resolveConfigPath } from './loader';
274
+
275
+ export default AtomixConfig;
@@ -0,0 +1,105 @@
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
+ *
23
+ * const config = loadAtomixConfig();
24
+ * const theme = createThemeFromConfig(config);
25
+ * ```
26
+ */
27
+ export function loadAtomixConfig(
28
+ options: {
29
+ /** Custom config path (default: 'atomix.config.ts') */
30
+ configPath?: string;
31
+ /** Whether to throw error if config not found (default: false) */
32
+ required?: boolean;
33
+ } = {}
34
+ ): AtomixConfig {
35
+ const { configPath = 'atomix.config.ts', required = false } = options;
36
+
37
+ // Default config
38
+ const defaultConfig: AtomixConfig = {
39
+ prefix: 'atomix',
40
+ theme: {
41
+ extend: {},
42
+ },
43
+ };
44
+
45
+ // In browser environments, config loading is not supported
46
+ if (typeof window !== 'undefined') {
47
+ if (required) {
48
+ throw new Error('Config loading not supported in browser environment');
49
+ }
50
+ return defaultConfig;
51
+ }
52
+
53
+ // Try to load config file
54
+ try {
55
+ // Use dynamic import for ESM compatibility
56
+ const configModule = require(configPath);
57
+ const config = configModule.default || configModule;
58
+
59
+ // Validate it's an AtomixConfig
60
+ if (config && typeof config === 'object') {
61
+ return config as AtomixConfig;
62
+ }
63
+
64
+ throw new Error('Invalid config format');
65
+ } catch (error: any) {
66
+ if (required) {
67
+ throw new Error(`Failed to load config from ${configPath}: ${error.message}`);
68
+ }
69
+
70
+ // Return default config if not required
71
+ return defaultConfig;
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Resolve config path
77
+ *
78
+ * Finds atomix.config.ts in the project, checking common locations.
79
+ */
80
+ export function resolveConfigPath(): string | null {
81
+ if (typeof process === 'undefined' || !process.cwd) {
82
+ return null;
83
+ }
84
+
85
+ const fs = require('fs');
86
+ const path = require('path');
87
+
88
+ const cwd = process.cwd();
89
+ const possiblePaths = [
90
+ path.join(cwd, 'atomix.config.ts'),
91
+ path.join(cwd, 'atomix.config.js'),
92
+ path.join(cwd, 'atomix.config.mjs'),
93
+ ];
94
+
95
+ for (const configPath of possiblePaths) {
96
+ if (fs.existsSync(configPath)) {
97
+ return configPath;
98
+ }
99
+ }
100
+
101
+ return null;
102
+ }
103
+
104
+ export default loadAtomixConfig;
105
+