@shohojdhara/atomix 0.5.2 → 0.5.5

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 (61) hide show
  1. package/atomix.config.ts +33 -33
  2. package/dist/atomix.css +3213 -159
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +5 -5
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/config.d.ts +187 -112
  7. package/dist/config.js +2 -47
  8. package/dist/config.js.map +1 -1
  9. package/dist/index.d.ts +1958 -900
  10. package/dist/index.esm.js +2279 -382
  11. package/dist/index.esm.js.map +1 -1
  12. package/dist/index.js +2332 -413
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.min.js +1 -1
  15. package/dist/index.min.js.map +1 -1
  16. package/dist/theme.d.ts +1390 -276
  17. package/dist/theme.js +2125 -621
  18. package/dist/theme.js.map +1 -1
  19. package/package.json +1 -1
  20. package/scripts/cli/internal/config-loader.js +30 -20
  21. package/src/lib/config/index.ts +38 -362
  22. package/src/lib/config/loader.ts +422 -0
  23. package/src/lib/config/public-api.ts +43 -0
  24. package/src/lib/config/types.ts +389 -0
  25. package/src/lib/config/validator.ts +305 -0
  26. package/src/lib/theme/adapters/index.ts +1 -1
  27. package/src/lib/theme/adapters/themeAdapter.ts +358 -229
  28. package/src/lib/theme/components/ThemeToggle.tsx +276 -0
  29. package/src/lib/theme/config/configLoader.ts +351 -0
  30. package/src/lib/theme/config/loader.ts +221 -0
  31. package/src/lib/theme/core/createTheme.ts +126 -50
  32. package/src/lib/theme/core/createThemeObject.ts +7 -4
  33. package/src/lib/theme/hooks/useThemeSwitcher.ts +164 -0
  34. package/src/lib/theme/index.ts +322 -38
  35. package/src/lib/theme/runtime/ThemeProvider.tsx +44 -10
  36. package/src/lib/theme/runtime/__tests__/ThemeProvider.test.tsx +44 -393
  37. package/src/lib/theme/runtime/useTheme.ts +1 -0
  38. package/src/lib/theme/tokens/tokens.ts +101 -1
  39. package/src/lib/theme/types.ts +91 -0
  40. package/src/lib/theme/utils/performanceMonitor.ts +315 -0
  41. package/src/lib/theme/utils/responsive.ts +280 -0
  42. package/src/lib/theme/utils/themeUtils.ts +531 -117
  43. package/src/styles/01-settings/_settings.background.scss +34 -5
  44. package/src/styles/02-tools/_tools.background.scss +330 -52
  45. package/src/styles/05-objects/_objects.masonry-grid.scss +3 -3
  46. package/src/styles/06-components/_components.accordion.scss +2 -2
  47. package/src/styles/06-components/_components.badge.scss +1 -1
  48. package/src/styles/06-components/_components.button.scss +2 -2
  49. package/src/styles/06-components/_components.callout.scss +2 -2
  50. package/src/styles/06-components/_components.card.scss +1 -1
  51. package/src/styles/06-components/_components.dropdown.scss +1 -1
  52. package/src/styles/06-components/_components.dynamic-background.scss +69 -0
  53. package/src/styles/06-components/_components.edge-panel.scss +2 -2
  54. package/src/styles/06-components/_components.input.scss +3 -3
  55. package/src/styles/06-components/_components.messages.scss +6 -6
  56. package/src/styles/06-components/_components.modal.scss +1 -1
  57. package/src/styles/06-components/_components.navbar.scss +1 -1
  58. package/src/styles/06-components/_components.popover.scss +1 -1
  59. package/src/styles/06-components/_components.toggle.scss +1 -1
  60. package/src/styles/06-components/_components.tooltip.scss +3 -3
  61. package/src/styles/06-components/_index.scss +1 -0
package/dist/index.js CHANGED
@@ -3587,7 +3587,7 @@ function useResponsiveGlass({baseParams: baseParams, breakpoints: breakpoints =
3587
3587
  * @param config Monitor configuration
3588
3588
  * @returns Performance metrics and controls
3589
3589
  */
3590
- function usePerformanceMonitor(config = {}) {
3590
+ function usePerformanceMonitor$1(config = {}) {
3591
3591
  const {enabled: enabled = !0, targetFps: targetFps = 60, minFps: minFps = 45, scaleUpThreshold: scaleUpThreshold = 58, lowFpsFrames: lowFpsFrames = 3, highFpsFrames: highFpsFrames = 10, debug: debug = !1, showOverlay: showOverlay = !1} = config, [metrics, setMetrics] = React.useState({
3592
3592
  fps: 0,
3593
3593
  frameTime: 0,
@@ -4143,7 +4143,7 @@ function getDevicePreset(presetName) {
4143
4143
  debug: !1
4144
4144
  });
4145
4145
  // Performance monitoring - tracks FPS, frame time, memory usage
4146
- const {metrics: performanceMetrics, toggleMonitoring: toggleMonitoring} = usePerformanceMonitor({
4146
+ const {metrics: performanceMetrics, toggleMonitoring: toggleMonitoring} = usePerformanceMonitor$1({
4147
4147
  enabled: debugPerformance,
4148
4148
  // Enable when debugPerformance is true
4149
4149
  debug: !1,
@@ -5144,7 +5144,7 @@ const BreadcrumbItem = React.forwardRef((({children: children, href: href, acti
5144
5144
 
5145
5145
  BreadcrumbItem.displayName = "BreadcrumbItem";
5146
5146
 
5147
- const Breadcrumb = React.memo((function({items: items, divider: divider, className: className = "", "aria-label": ariaLabel = "Breadcrumb", linkComponent: linkComponent, style: style, children: children}) {
5147
+ const BreadcrumbComponent = React.memo((function({items: items, divider: divider, className: className = "", "aria-label": ariaLabel = "Breadcrumb", linkComponent: linkComponent, style: style, children: children}) {
5148
5148
  const breadcrumbClasses = [ BREADCRUMB.CLASSES.BASE, className ].filter(Boolean).join(" ");
5149
5149
  let content;
5150
5150
  if (items && items.length > 0)
@@ -5184,7 +5184,7 @@ const Breadcrumb = React.memo((function({items: items, divider: divider, classN
5184
5184
  children: content
5185
5185
  })
5186
5186
  });
5187
- }));
5187
+ })), Breadcrumb = BreadcrumbComponent;
5188
5188
 
5189
5189
  /**
5190
5190
  * Spinner state and functionality
@@ -13506,21 +13506,21 @@ const DEFAULT_ATOMIX_FONTS = [ {
13506
13506
  const [interaction, setInteraction] = React.useState({
13507
13507
  hoveredIndex: null,
13508
13508
  selectedIndex: null
13509
- });
13509
+ }), handlePointHover = React.useCallback((index => {
13510
+ setInteraction((prev => ({
13511
+ ...prev,
13512
+ hoveredIndex: index
13513
+ })));
13514
+ }), []), handlePointClick = React.useCallback((index => {
13515
+ setInteraction((prev => ({
13516
+ ...prev,
13517
+ selectedIndex: prev.selectedIndex === index ? null : index
13518
+ })));
13519
+ }), []);
13510
13520
  return {
13511
13521
  interaction: interaction,
13512
- handlePointHover: React.useCallback((index => {
13513
- setInteraction((prev => ({
13514
- ...prev,
13515
- hoveredIndex: index
13516
- })));
13517
- }), []),
13518
- handlePointClick: React.useCallback((index => {
13519
- setInteraction((prev => ({
13520
- ...prev,
13521
- selectedIndex: prev.selectedIndex === index ? null : index
13522
- })));
13523
- }), []),
13522
+ handlePointHover: handlePointHover,
13523
+ handlePointClick: handlePointClick,
13524
13524
  clearInteraction: React.useCallback((() => {
13525
13525
  setInteraction({
13526
13526
  hoveredIndex: null,
@@ -13563,7 +13563,7 @@ var composablesImport = Object.freeze({
13563
13563
  useNavDropdown: useNavDropdown,
13564
13564
  useNavItem: useNavItem,
13565
13565
  useNavbar: useNavbar,
13566
- usePerformanceMonitor: usePerformanceMonitor,
13566
+ usePerformanceMonitor: usePerformanceMonitor$1,
13567
13567
  usePieChart: usePieChart,
13568
13568
  useRadio: useRadio,
13569
13569
  useResponsiveGlass: useResponsiveGlass,
@@ -20901,7 +20901,51 @@ const defaultTokens = {
20901
20901
  "breakpoint-md": "768px",
20902
20902
  "breakpoint-lg": "992px",
20903
20903
  "breakpoint-xl": "1200px",
20904
- "breakpoint-xxl": "1440px"
20904
+ "breakpoint-xxl": "1440px",
20905
+ // Advanced Features - Interactive Effects (Phase 2)
20906
+ "interactive-vortex-enabled": "false",
20907
+ "interactive-vortex-strength": "0.5",
20908
+ "interactive-vortex-radius": "100",
20909
+ "interactive-vortex-decay": "0.8",
20910
+ "interactive-chromatic-enabled": "false",
20911
+ "interactive-chromatic-mode": "lateral",
20912
+ "interactive-chromatic-red-shift": "0.02",
20913
+ "interactive-chromatic-green-shift": "0",
20914
+ "interactive-chromatic-blue-shift": "-0.02",
20915
+ "interactive-chromatic-edge-only": "false",
20916
+ "interactive-chromatic-edge-threshold": "0.5",
20917
+ "interactive-mouse-sensitivity": "1.0",
20918
+ "interactive-mouse-trail-effect": "false",
20919
+ "interactive-animation-speed-base": "1.0",
20920
+ "interactive-animation-speed-multiplier": "1.0",
20921
+ // Advanced Features - Optimization (Phase 3)
20922
+ "optimization-breakpoint-mobile": "0px",
20923
+ "optimization-breakpoint-tablet": "768px",
20924
+ "optimization-breakpoint-desktop": "1024px",
20925
+ "optimization-breakpoint-wide": "1440px",
20926
+ "optimization-device-scaling-mobile": "0.5",
20927
+ "optimization-device-scaling-tablet": "0.75",
20928
+ "optimization-device-scaling-desktop": "1.0",
20929
+ "optimization-performance-fps-target": "60",
20930
+ "optimization-auto-scaling-enabled": "false",
20931
+ "optimization-auto-scaling-low-end": "0.5",
20932
+ "optimization-auto-scaling-mid-range": "0.75",
20933
+ "optimization-auto-scaling-high-end": "1.0",
20934
+ // Advanced Features - Visual Polish (Phase 4)
20935
+ "visual-polish-border-iridescent-glow": "false",
20936
+ "visual-polish-border-shimmer-effect": "false",
20937
+ "visual-polish-border-beveled-edges": "false",
20938
+ "visual-polish-border-pulsing-glow": "false",
20939
+ "visual-polish-content-aware-blur-enabled": "false",
20940
+ "visual-polish-content-aware-depth-detection": "false",
20941
+ "visual-polish-content-aware-edge-preservation": "false",
20942
+ "visual-polish-content-aware-variable-radius": "false",
20943
+ "visual-polish-holographic-enabled": "false",
20944
+ "visual-polish-holographic-rainbow-diffraction": "false",
20945
+ "visual-polish-holographic-scanline-animation": "false",
20946
+ "visual-polish-holographic-grid-overlay": "false",
20947
+ "visual-polish-holographic-data-stream": "false",
20948
+ "visual-polish-holographic-pulse-rings": "false"
20905
20949
  };
20906
20950
 
20907
20951
  /**
@@ -20981,158 +21025,485 @@ const defaultTokens = {
20981
21025
  }
20982
21026
 
20983
21027
  /**
20984
- * Theme System Error Handling
21028
+ * Theme Adapter
20985
21029
  *
20986
- * Centralized error handling for the Atomix theme system.
20987
- * Provides custom error classes and logging utilities.
21030
+ * Converts between Theme objects and DesignTokens
20988
21031
  */
20989
21032
  /**
20990
- * Theme error codes
20991
- */ var ThemeErrorCode, LogLevel;
20992
-
20993
- !function(ThemeErrorCode) {
20994
- /** Theme not found in registry */
20995
- ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
20996
- /** Theme failed to load */
20997
- ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
20998
- /** Theme validation failed */
20999
- ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
21000
- /** Configuration loading failed */
21001
- ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
21002
- /** Configuration validation failed */
21003
- ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
21004
- /** Circular dependency detected */
21005
- ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
21006
- /** Missing dependency */
21007
- ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
21008
- /** Storage operation failed */
21009
- ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
21010
- /** Invalid theme name */
21011
- ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
21012
- /** CSS injection failed */
21013
- ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
21014
- /** Invalid color format */
21015
- ThemeErrorCode.INVALID_COLOR_FORMAT = "INVALID_COLOR_FORMAT",
21016
- /** Missing required token */
21017
- ThemeErrorCode.MISSING_REQUIRED_TOKEN = "MISSING_REQUIRED_TOKEN",
21018
- /** Accessibility contrast violation */
21019
- ThemeErrorCode.CONTRAST_VIOLATION = "CONTRAST_VIOLATION",
21020
- /** Invalid token type */
21021
- ThemeErrorCode.INVALID_TOKEN_TYPE = "INVALID_TOKEN_TYPE",
21022
- /** Unknown error */
21023
- ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
21024
- }(ThemeErrorCode || (ThemeErrorCode = {}));
21033
+ * Convert a Theme object to DesignTokens
21034
+ */ function themeToDesignTokens(theme) {
21035
+ const tokens = {};
21036
+ // Convert colors
21037
+ if (theme.palette) {
21038
+ // Primary color
21039
+ if (theme.palette.primary) {
21040
+ const primaryMain = theme.palette.primary.main;
21041
+ tokens.primary = primaryMain;
21042
+ const rgb = hexToRgb$2(primaryMain);
21043
+ rgb && (tokens["primary-rgb"] = rgb);
21044
+ }
21045
+ // Secondary color
21046
+ if (theme.palette.secondary) {
21047
+ const secondaryMain = theme.palette.secondary.main;
21048
+ tokens.secondary = secondaryMain;
21049
+ const rgb = hexToRgb$2(secondaryMain);
21050
+ rgb && (tokens["secondary-rgb"] = rgb);
21051
+ }
21052
+ // Other colors
21053
+ const colorKeys = [ "error", "warning", "info", "success" ];
21054
+ for (const key of colorKeys) if (theme.palette[key]) {
21055
+ const colorMain = theme.palette[key].main;
21056
+ tokens[key] = colorMain;
21057
+ const rgb = hexToRgb$2(colorMain);
21058
+ rgb && (tokens[`${key}-rgb`] = rgb);
21059
+ }
21060
+ // Background colors
21061
+ theme.palette.background && (tokens["body-bg"] = theme.palette.background.default),
21062
+ // Text colors
21063
+ theme.palette.text && (tokens["body-color"] = theme.palette.text.primary);
21064
+ }
21065
+ // Convert typography
21066
+ // Convert border radius
21067
+ if (theme.typography && (tokens["body-font-family"] = theme.typography.fontFamily,
21068
+ tokens["body-font-size"] = `${theme.typography.fontSize}px`, tokens["font-weight-normal"] = `${theme.typography.fontWeightRegular}`,
21069
+ tokens["font-weight-bold"] = `${theme.typography.fontWeightBold}`),
21070
+ // Convert spacing
21071
+ "function" == typeof theme.spacing && (
21072
+ // If spacing is a function, call it with some values to get results
21073
+ tokens["spacing-1"] = theme.spacing(1), tokens["spacing-2"] = theme.spacing(2),
21074
+ tokens["spacing-4"] = theme.spacing(4)),
21075
+ // Convert breakpoints
21076
+ theme.breakpoints?.values && (tokens["breakpoint-xs"] = `${theme.breakpoints.values.xs}px`,
21077
+ tokens["breakpoint-sm"] = `${theme.breakpoints.values.sm}px`, tokens["breakpoint-md"] = `${theme.breakpoints.values.md}px`,
21078
+ tokens["breakpoint-lg"] = `${theme.breakpoints.values.lg}px`, tokens["breakpoint-xl"] = `${theme.breakpoints.values.xl}px`),
21079
+ // Convert shadows
21080
+ theme.shadows && (tokens["box-shadow"] = theme.shadows[2], // Use a moderate shadow
21081
+ tokens["box-shadow-sm"] = theme.shadows[1], tokens["box-shadow-lg"] = theme.shadows[3]),
21082
+ // Convert transitions
21083
+ theme.transitions && (tokens["transition-duration-base"] = `${theme.transitions.duration.standard}ms`),
21084
+ // Convert z-index
21085
+ theme.zIndex && (tokens["z-modal"] = `${theme.zIndex.modal}`, tokens["z-popover"] = `${theme.zIndex.popover}`,
21086
+ tokens["z-tooltip"] = `${theme.zIndex.tooltip}`), theme.borderRadius) {
21087
+ const baseRadius = theme.borderRadius.base;
21088
+ tokens["border-radius"] = "number" == typeof baseRadius ? `${baseRadius}px` : baseRadius;
21089
+ }
21090
+ // Add advanced feature tokens if available in theme
21091
+ if (theme.custom) {
21092
+ // Interactive Effects (Phase 2)
21093
+ if (theme.custom.interactiveEffects) {
21094
+ const ie = theme.custom.interactiveEffects;
21095
+ // Vortex effects
21096
+ ie.vortex && (tokens["interactive-vortex-enabled"] = String(ie.vortex.enabled ?? !1),
21097
+ tokens["interactive-vortex-strength"] = String(ie.vortex.strength ?? .5), tokens["interactive-vortex-radius"] = String(ie.vortex.radius ?? 100),
21098
+ tokens["interactive-vortex-decay"] = String(ie.vortex.decay ?? .8)),
21099
+ // Chromatic aberration
21100
+ ie.chromaticAberration && (tokens["interactive-chromatic-enabled"] = String(ie.chromaticAberration.enabled ?? !1),
21101
+ tokens["interactive-chromatic-mode"] = ie.chromaticAberration.mode ?? "lateral",
21102
+ tokens["interactive-chromatic-red-shift"] = String(ie.chromaticAberration.redShift ?? .02),
21103
+ tokens["interactive-chromatic-green-shift"] = String(ie.chromaticAberration.greenShift ?? 0),
21104
+ tokens["interactive-chromatic-blue-shift"] = String(ie.chromaticAberration.blueShift ?? -.02),
21105
+ tokens["interactive-chromatic-edge-only"] = String(ie.chromaticAberration.edgeOnly ?? !1),
21106
+ tokens["interactive-chromatic-edge-threshold"] = String(ie.chromaticAberration.edgeThreshold ?? .5)),
21107
+ // Mouse interaction
21108
+ ie.mouseInteraction && (tokens["interactive-mouse-sensitivity"] = String(ie.mouseInteraction.sensitivity ?? 1),
21109
+ tokens["interactive-mouse-trail-effect"] = String(ie.mouseInteraction.trailEffect ?? !1)),
21110
+ // Animation speed
21111
+ ie.animationSpeed && (tokens["interactive-animation-speed-base"] = String(ie.animationSpeed.base ?? 1),
21112
+ tokens["interactive-animation-speed-multiplier"] = String(ie.animationSpeed.timeMultiplier ?? 1));
21113
+ }
21114
+ // Optimization (Phase 3)
21115
+ if (theme.custom.optimization) {
21116
+ const opt = theme.custom.optimization;
21117
+ // Responsive breakpoints
21118
+ opt.responsive && (opt.responsive.breakpoints && (tokens["optimization-breakpoint-mobile"] = opt.responsive.breakpoints.mobile ?? "0px",
21119
+ tokens["optimization-breakpoint-tablet"] = opt.responsive.breakpoints.tablet ?? "768px",
21120
+ tokens["optimization-breakpoint-desktop"] = opt.responsive.breakpoints.desktop ?? "1024px",
21121
+ tokens["optimization-breakpoint-wide"] = opt.responsive.breakpoints.wide ?? "1440px"),
21122
+ opt.responsive.deviceScaling && (tokens["optimization-device-scaling-mobile"] = String(opt.responsive.deviceScaling.mobile ?? .5),
21123
+ tokens["optimization-device-scaling-tablet"] = String(opt.responsive.deviceScaling.tablet ?? .75),
21124
+ tokens["optimization-device-scaling-desktop"] = String(opt.responsive.deviceScaling.desktop ?? 1))),
21125
+ // Performance settings
21126
+ opt.performance && (tokens["optimization-performance-fps-target"] = String(opt.performance.fpsTarget ?? 60),
21127
+ tokens["optimization-auto-scaling-enabled"] = String(opt.performance.autoScaling ?? !1)),
21128
+ // Auto-scaling settings
21129
+ opt.autoScaling && (tokens["optimization-auto-scaling-enabled"] = String(opt.autoScaling.enabled ?? !1),
21130
+ tokens["optimization-auto-scaling-low-end"] = String(opt.autoScaling.qualityThresholds?.lowEnd ?? .5),
21131
+ tokens["optimization-auto-scaling-mid-range"] = String(opt.autoScaling.qualityThresholds?.midRange ?? .75),
21132
+ tokens["optimization-auto-scaling-high-end"] = String(opt.autoScaling.qualityThresholds?.highEnd ?? 1));
21133
+ }
21134
+ // Visual Polish (Phase 4)
21135
+ if (theme.custom.visualPolish) {
21136
+ const vp = theme.custom.visualPolish;
21137
+ vp.borders && (tokens["visual-polish-border-iridescent-glow"] = String(vp.borders.iridescentGlow ?? !1),
21138
+ tokens["visual-polish-border-shimmer-effect"] = String(vp.borders.shimmerEffect ?? !1),
21139
+ tokens["visual-polish-border-beveled-edges"] = String(vp.borders.beveledEdges ?? !1),
21140
+ tokens["visual-polish-border-pulsing-glow"] = String(vp.borders.pulsingGlow ?? !1)),
21141
+ vp.contentAwareBlur && (tokens["visual-polish-content-aware-blur-enabled"] = String(vp.contentAwareBlur.enabled ?? !1),
21142
+ tokens["visual-polish-content-aware-depth-detection"] = String(vp.contentAwareBlur.depthDetection ?? !1),
21143
+ tokens["visual-polish-content-aware-edge-preservation"] = String(vp.contentAwareBlur.edgePreservation ?? !1),
21144
+ tokens["visual-polish-content-aware-variable-radius"] = String(vp.contentAwareBlur.variableRadius ?? !1)),
21145
+ vp.holographicEffects && (tokens["visual-polish-holographic-enabled"] = String(vp.holographicEffects.enabled ?? !1),
21146
+ tokens["visual-polish-holographic-rainbow-diffraction"] = String(vp.holographicEffects.rainbowDiffraction ?? !1),
21147
+ tokens["visual-polish-holographic-scanline-animation"] = String(vp.holographicEffects.scanlineAnimation ?? !1),
21148
+ tokens["visual-polish-holographic-grid-overlay"] = String(vp.holographicEffects.gridOverlay ?? !1),
21149
+ tokens["visual-polish-holographic-data-stream"] = String(vp.holographicEffects.dataStream ?? !1),
21150
+ tokens["visual-polish-holographic-pulse-rings"] = String(vp.holographicEffects.pulseRings ?? !1));
21151
+ }
21152
+ }
21153
+ // Create full tokens object with defaults
21154
+ return createTokens(tokens);
21155
+ }
21025
21156
 
21026
21157
  /**
21027
- * Custom error class for theme-related errors
21028
- */
21029
- class ThemeError extends Error {
21030
- constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
21031
- super(message), this.name = "ThemeError", this.code = code, this.context = context,
21032
- this.timestamp = Date.now(),
21033
- // Maintains proper stack trace for where our error was thrown (only available on V8)
21034
- Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
21035
- }
21036
- /**
21037
- * Convert error to JSON for logging
21038
- */ toJSON() {
21039
- return {
21040
- name: this.name,
21041
- message: this.message,
21042
- code: this.code,
21043
- context: this.context,
21044
- timestamp: this.timestamp,
21045
- stack: this.stack
21046
- };
21158
+ * Converts an AtomixConfig to DesignTokens
21159
+ *
21160
+ * This function maps the configuration from the user-facing format
21161
+ * to the internal DesignTokens format used by the theme system.
21162
+ *
21163
+ * @param config - The configuration object to convert
21164
+ * @returns DesignTokens object ready for theme generation
21165
+ *
21166
+ * @example
21167
+ * ```typescript
21168
+ * import { configToTokens } from '@shohojdhara/atomix/theme';
21169
+ *
21170
+ * const config = {
21171
+ * prefix: 'myapp',
21172
+ * theme: { extend: { colors: { primary: { main: '#7AFFD7' } } } }
21173
+ * };
21174
+ * const tokens = configToTokens(config);
21175
+ * ```
21176
+ */ function configToTokens(config) {
21177
+ const prefix = config.prefix || "atomix", theme = config.theme || {};
21178
+ // Start with default tokens
21179
+ let tokens = {
21180
+ ...defaultTokens
21181
+ };
21182
+ // Apply theme extensions
21183
+ // Apply advanced features if available in config
21184
+ if (theme.extend &&
21185
+ // Apply extensions to tokens
21186
+ Object.entries(theme.extend).forEach((([category, values]) => {
21187
+ "object" == typeof values && null !== values && Object.entries(values).forEach((([key, value]) => {
21188
+ // Map theme categories to token names
21189
+ const tokenName = `${category}-${key}`;
21190
+ "string" == typeof value || "number" == typeof value ? tokens[tokenName] = String(value) : "object" == typeof value && null !== value &&
21191
+ // Handle nested objects like color scales
21192
+ Object.entries(value).forEach((([nestedKey, nestedValue]) => {
21193
+ "string" != typeof nestedValue && "number" != typeof nestedValue || (tokens[`${tokenName}-${nestedKey}`] = String(nestedValue));
21194
+ }));
21195
+ }));
21196
+ })),
21197
+ // Apply theme tokens if provided (completely replacing defaults)
21198
+ theme.tokens && (tokens = {
21199
+ ...tokens,
21200
+ ...theme.tokens
21201
+ }), config) {
21202
+ // Interactive Effects (Phase 2)
21203
+ if (config.interactiveEffects) {
21204
+ const ie = config.interactiveEffects;
21205
+ // Vortex effects
21206
+ ie.vortex && (tokens["interactive-vortex-enabled"] = String(ie.vortex.enabled ?? !1),
21207
+ tokens["interactive-vortex-strength"] = String(ie.vortex.strength ?? .5), tokens["interactive-vortex-radius"] = String(ie.vortex.radius ?? 100),
21208
+ tokens["interactive-vortex-decay"] = String(ie.vortex.decay ?? .8), tokens["interactive-vortex-curl-noise"] = String(ie.vortex.curlNoise ?? !1),
21209
+ tokens["interactive-vortex-velocity-tracking"] = String(ie.vortex.velocityTracking ?? !1)),
21210
+ // Chromatic aberration
21211
+ ie.chromaticAberration && (tokens["interactive-chromatic-enabled"] = String(ie.chromaticAberration.enabled ?? !1),
21212
+ tokens["interactive-chromatic-mode"] = ie.chromaticAberration.mode ?? "lateral",
21213
+ tokens["interactive-chromatic-red-shift"] = String(ie.chromaticAberration.redShift ?? .02),
21214
+ tokens["interactive-chromatic-green-shift"] = String(ie.chromaticAberration.greenShift ?? 0),
21215
+ tokens["interactive-chromatic-blue-shift"] = String(ie.chromaticAberration.blueShift ?? -.02),
21216
+ tokens["interactive-chromatic-edge-only"] = String(ie.chromaticAberration.edgeOnly ?? !1),
21217
+ tokens["interactive-chromatic-edge-threshold"] = String(ie.chromaticAberration.edgeThreshold ?? .5)),
21218
+ // Mouse interaction
21219
+ ie.mouseInteraction && (tokens["interactive-mouse-sensitivity"] = String(ie.mouseInteraction.sensitivity ?? 1),
21220
+ tokens["interactive-mouse-trail-effect"] = String(ie.mouseInteraction.trailEffect ?? !1),
21221
+ tokens["interactive-mouse-pressure-sensitivity"] = String(ie.mouseInteraction.pressureSensitivity ?? !1)),
21222
+ // Animation speed
21223
+ ie.animationSpeed && (tokens["interactive-animation-speed-base"] = String(ie.animationSpeed.base ?? 1),
21224
+ tokens["interactive-animation-speed-multiplier"] = String(ie.animationSpeed.timeMultiplier ?? 1));
21225
+ }
21226
+ // Optimization (Phase 3)
21227
+ if (config.optimization) {
21228
+ const opt = config.optimization;
21229
+ // Responsive breakpoints
21230
+ opt.responsive && (opt.responsive.breakpoints && (tokens["optimization-breakpoint-mobile"] = opt.responsive.breakpoints.mobile ?? "0px",
21231
+ tokens["optimization-breakpoint-tablet"] = opt.responsive.breakpoints.tablet ?? "768px",
21232
+ tokens["optimization-breakpoint-desktop"] = opt.responsive.breakpoints.desktop ?? "1024px",
21233
+ tokens["optimization-breakpoint-wide"] = opt.responsive.breakpoints.wide ?? "1440px"),
21234
+ opt.responsive.deviceScaling && (tokens["optimization-device-scaling-mobile"] = String(opt.responsive.deviceScaling.mobile ?? .5),
21235
+ tokens["optimization-device-scaling-tablet"] = String(opt.responsive.deviceScaling.tablet ?? .75),
21236
+ tokens["optimization-device-scaling-desktop"] = String(opt.responsive.deviceScaling.desktop ?? 1))),
21237
+ // Performance settings
21238
+ opt.performance && (tokens["optimization-performance-fps-target"] = String(opt.performance.fpsTarget ?? 60),
21239
+ tokens["optimization-auto-scaling-enabled"] = String(opt.performance.autoScaling ?? !1),
21240
+ tokens["optimization-monitor-dashboard-enabled"] = String(opt.performance.monitorDashboard ?? !1)),
21241
+ // Auto-scaling settings
21242
+ opt.autoScaling && (tokens["optimization-auto-scaling-enabled"] = String(opt.autoScaling.enabled ?? !1),
21243
+ tokens["optimization-auto-scaling-low-end"] = String(opt.autoScaling.qualityThresholds?.lowEnd ?? .5),
21244
+ tokens["optimization-auto-scaling-mid-range"] = String(opt.autoScaling.qualityThresholds?.midRange ?? .75),
21245
+ tokens["optimization-auto-scaling-high-end"] = String(opt.autoScaling.qualityThresholds?.highEnd ?? 1));
21246
+ }
21247
+ // Visual Polish (Phase 4)
21248
+ if (config.visualPolish) {
21249
+ const vp = config.visualPolish;
21250
+ vp.borders && (tokens["visual-polish-border-iridescent-glow"] = String(vp.borders.iridescentGlow ?? !1),
21251
+ tokens["visual-polish-border-shimmer-effect"] = String(vp.borders.shimmerEffect ?? !1),
21252
+ tokens["visual-polish-border-beveled-edges"] = String(vp.borders.beveledEdges ?? !1),
21253
+ tokens["visual-polish-border-pulsing-glow"] = String(vp.borders.pulsingGlow ?? !1)),
21254
+ vp.contentAwareBlur && (tokens["visual-polish-content-aware-blur-enabled"] = String(vp.contentAwareBlur.enabled ?? !1),
21255
+ tokens["visual-polish-content-aware-depth-detection"] = String(vp.contentAwareBlur.depthDetection ?? !1),
21256
+ tokens["visual-polish-content-aware-edge-preservation"] = String(vp.contentAwareBlur.edgePreservation ?? !1),
21257
+ tokens["visual-polish-content-aware-variable-radius"] = String(vp.contentAwareBlur.variableRadius ?? !1)),
21258
+ vp.holographicEffects && (tokens["visual-polish-holographic-enabled"] = String(vp.holographicEffects.enabled ?? !1),
21259
+ tokens["visual-polish-holographic-rainbow-diffraction"] = String(vp.holographicEffects.rainbowDiffraction ?? !1),
21260
+ tokens["visual-polish-holographic-scanline-animation"] = String(vp.holographicEffects.scanlineAnimation ?? !1),
21261
+ tokens["visual-polish-holographic-grid-overlay"] = String(vp.holographicEffects.gridOverlay ?? !1),
21262
+ tokens["visual-polish-holographic-data-stream"] = String(vp.holographicEffects.dataStream ?? !1),
21263
+ tokens["visual-polish-holographic-pulse-rings"] = String(vp.holographicEffects.pulseRings ?? !1));
21264
+ }
21047
21265
  }
21266
+ // Apply prefix to all tokens
21267
+ const prefixedTokens = {};
21268
+ return Object.entries(tokens).forEach((([key, value]) => {
21269
+ // If the token key already starts with the prefix, use as-is
21270
+ // Otherwise, add the prefix
21271
+ const prefixedKey = key.startsWith(prefix) ? key : `${prefix}-${key}`;
21272
+ prefixedTokens[prefixedKey] = value;
21273
+ })), prefixedTokens;
21048
21274
  }
21049
21275
 
21050
21276
  /**
21051
- * Log level
21052
- */ !function(LogLevel) {
21053
- LogLevel[LogLevel.ERROR = 0] = "ERROR", LogLevel[LogLevel.WARN = 1] = "WARN", LogLevel[LogLevel.INFO = 2] = "INFO",
21054
- LogLevel[LogLevel.DEBUG = 3] = "DEBUG";
21055
- }(LogLevel || (LogLevel = {}));
21277
+ * Convert hex color to RGB
21278
+ */ function hexToRgb$2(hex) {
21279
+ hex = hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, ((m, r, g, b) => r + r + g + g + b + b));
21280
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
21281
+ return result && result[1] && result[2] && result[3] ? `${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)}` : "0, 0, 0";
21282
+ }
21056
21283
 
21057
21284
  /**
21058
- * Theme Logger
21285
+ * Converts DesignTokens to CSS variables
21059
21286
  *
21060
- * Centralized logging for the theme system.
21061
- * Replaces console statements with structured logging.
21287
+ * @param tokens - The tokens to convert
21288
+ * @returns A record of CSS variable names and values
21289
+ */ function designTokensToCSSVars(tokens) {
21290
+ const cssVars = {};
21291
+ return Object.entries(tokens).forEach((([key, value]) => {
21292
+ void 0 !== value && (cssVars[`--atomix-${key}`] = String(value));
21293
+ })), cssVars;
21294
+ }
21295
+
21296
+ /**
21297
+ * Load theme from config file (synchronous, Node.js only)
21298
+ * @param configPath - Path to config file (default: atomix.config.ts)
21299
+ * @returns DesignTokens from theme configuration
21300
+ * @throws Error if config loading is not available in browser environment
21062
21301
  */
21063
- class ThemeLogger {
21064
- constructor(config = {}) {
21065
- this.config = {
21066
- level: config.level ?? ("undefined" != typeof process && "production" === process.env?.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
21067
- enableConsole: config.enableConsole ?? !0,
21068
- onError: config.onError,
21069
- onWarn: config.onWarn,
21070
- onInfo: config.onInfo,
21071
- onDebug: config.onDebug
21072
- };
21073
- }
21074
- /**
21075
- * Log an error
21076
- */ error(message, error, context) {
21077
- if (this.config.level < LogLevel.ERROR) return;
21078
- const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
21079
- this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
21080
- error: errorObj,
21081
- context: {
21082
- ...context,
21083
- ...themeError.context
21084
- },
21085
- code: themeError.code
21086
- }), this.config.onError?.(themeError, context);
21302
+ /**
21303
+ * Atomix Config Loader
21304
+ *
21305
+ * Helper functions to load atomix.config.ts from external projects.
21306
+ * Now also supports atomix.config.js and atomix.config.json
21307
+ */
21308
+ /**
21309
+ * Validate Atomix configuration structure
21310
+ *
21311
+ * Performs basic validation to catch common configuration errors early.
21312
+ * Returns warnings for potential issues.
21313
+ *
21314
+ * @param config - Configuration object to validate
21315
+ * @returns Array of validation warnings (empty if valid)
21316
+ *
21317
+ * @example
21318
+ * ```typescript
21319
+ * import { loadAtomixConfig, validateConfig } from '@shohojdhara/atomix/config';
21320
+ *
21321
+ * const config = loadAtomixConfig();
21322
+ * const warnings = validateConfig(config);
21323
+ * warnings.forEach(w => console.warn(w));
21324
+ * ```
21325
+ */
21326
+ function validateConfig$1(config) {
21327
+ const warnings = [];
21328
+ // Check prefix format
21329
+ // Check theme structure
21330
+ if (config.prefix && (/^[a-zA-Z][a-zA-Z0-9-]*$/.test(config.prefix) || warnings.push(`Invalid prefix "${config.prefix}". Prefix should start with a letter and contain only letters, numbers, and hyphens.\nExample: "myapp", "brand-ui", "enterprise"`),
21331
+ config.prefix.length < 2 && warnings.push(`Prefix "${config.prefix}" is too short. Use at least 2 characters for clarity.\nExample: "app" instead of "a"`)),
21332
+ config.theme && (
21333
+ // Warn if both extend and tokens are provided
21334
+ config.theme.extend && config.theme.tokens && warnings.push("Both theme.extend and theme.tokens are defined. theme.tokens will take precedence and completely replace the default token system.\nIf you want to extend defaults, remove theme.tokens and use only theme.extend."),
21335
+ config.theme.extend)) {
21336
+ const extend = config.theme.extend, validThemeKeys = [ "colors", "typography", "spacing", "borderRadius", "shadows", "zIndex", "transitions", "breakpoints" ];
21337
+ // Check for common typos in theme properties
21338
+ Object.keys(extend).forEach((key => {
21339
+ _includesInstanceProperty(validThemeKeys).call(validThemeKeys, key) || warnings.push(`Unknown theme property: "${key}"\nValid properties: ${validThemeKeys.join(", ")}\nDid you mean one of these? Check for typos.`);
21340
+ }));
21087
21341
  }
21088
- /**
21089
- * Log a warning
21090
- */ warn(message, context) {
21091
- this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
21092
- this.config.onWarn?.(message, context));
21342
+ // Validate advanced features
21343
+ if (config.interactiveEffects) {
21344
+ const ie = config.interactiveEffects;
21345
+ // Validate vortex settings
21346
+ ie.vortex && (ie.vortex.strength && (ie.vortex.strength < 0 || ie.vortex.strength > 10) && warnings.push("Vortex strength should be between 0 and 10 for optimal performance"),
21347
+ ie.vortex.radius && ie.vortex.radius < 0 && warnings.push("Vortex radius should be a positive number"),
21348
+ ie.vortex.decay && (ie.vortex.decay <= 0 || ie.vortex.decay > 1) && warnings.push("Vortex decay should be between 0 and 1")),
21349
+ // Validate chromatic aberration settings
21350
+ ie.chromaticAberration && (ie.chromaticAberration.redShift && Math.abs(ie.chromaticAberration.redShift) > .1 && warnings.push("Chromatic red shift value seems unusually high (>0.1), verify this is intended"),
21351
+ ie.chromaticAberration.blueShift && Math.abs(ie.chromaticAberration.blueShift) > .1 && warnings.push("Chromatic blue shift value seems unusually high (>0.1), verify this is intended"),
21352
+ ie.chromaticAberration.edgeThreshold && (ie.chromaticAberration.edgeThreshold < 0 || ie.chromaticAberration.edgeThreshold > 1) && warnings.push("Chromatic edge threshold should be between 0 and 1")),
21353
+ // Validate mouse interaction settings
21354
+ ie.mouseInteraction && ie.mouseInteraction.sensitivity && ie.mouseInteraction.sensitivity < 0 && warnings.push("Mouse sensitivity should be a positive number"),
21355
+ // Validate animation speed settings
21356
+ ie.animationSpeed && (ie.animationSpeed.base && ie.animationSpeed.base <= 0 && warnings.push("Animation base speed should be greater than 0"),
21357
+ ie.animationSpeed.timeMultiplier && ie.animationSpeed.timeMultiplier <= 0 && warnings.push("Animation time multiplier should be greater than 0"));
21093
21358
  }
21094
- /**
21095
- * Log an info message
21096
- */ info(message, context) {
21097
- this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
21098
- this.config.onInfo?.(message, context));
21359
+ // Validate optimization settings
21360
+ if (config.optimization) {
21361
+ const opt = config.optimization;
21362
+ // Validate responsive breakpoints
21363
+ if (opt.responsive && opt.responsive.breakpoints) {
21364
+ const breakpoints = opt.responsive.breakpoints;
21365
+ breakpoints.mobile && !isValidCSSLength(breakpoints.mobile) && warnings.push("Mobile breakpoint value is not a valid CSS length"),
21366
+ breakpoints.tablet && !isValidCSSLength(breakpoints.tablet) && warnings.push("Tablet breakpoint value is not a valid CSS length"),
21367
+ breakpoints.desktop && !isValidCSSLength(breakpoints.desktop) && warnings.push("Desktop breakpoint value is not a valid CSS length"),
21368
+ breakpoints.wide && !isValidCSSLength(breakpoints.wide) && warnings.push("Wide breakpoint value is not a valid CSS length");
21369
+ }
21370
+ // Validate device scaling
21371
+ if (opt.responsive && opt.responsive.deviceScaling) {
21372
+ const scaling = opt.responsive.deviceScaling;
21373
+ scaling.mobile && (scaling.mobile <= 0 || scaling.mobile > 1) && warnings.push("Mobile device scaling should be between 0 and 1"),
21374
+ scaling.tablet && (scaling.tablet <= 0 || scaling.tablet > 1) && warnings.push("Tablet device scaling should be between 0 and 1"),
21375
+ scaling.desktop && (scaling.desktop <= 0 || scaling.desktop > 1) && warnings.push("Desktop device scaling should be between 0 and 1");
21376
+ }
21377
+ // Validate performance settings
21378
+ // Validate auto-scaling thresholds
21379
+ if (opt.performance && opt.performance.fpsTarget && (opt.performance.fpsTarget <= 0 || opt.performance.fpsTarget > 240) && warnings.push("FPS target should be a reasonable value (typically 30-120)"),
21380
+ opt.autoScaling && opt.autoScaling.qualityThresholds) {
21381
+ const thresholds = opt.autoScaling.qualityThresholds;
21382
+ thresholds.lowEnd && (thresholds.lowEnd < 0 || thresholds.lowEnd > 1) && warnings.push("Auto-scaling low-end threshold should be between 0 and 1"),
21383
+ thresholds.midRange && (thresholds.midRange < 0 || thresholds.midRange > 1) && warnings.push("Auto-scaling mid-range threshold should be between 0 and 1"),
21384
+ thresholds.highEnd && (thresholds.highEnd < 0 || thresholds.highEnd > 1) && warnings.push("Auto-scaling high-end threshold should be between 0 and 1");
21385
+ }
21099
21386
  }
21100
- /**
21101
- * Log a debug message
21102
- */ debug(message, context) {
21103
- this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
21387
+ // Validate visual polish settings
21388
+ if (config.visualPolish) {
21389
+ const vp = config.visualPolish;
21390
+ // Validate content aware blur settings
21391
+ vp.contentAwareBlur && (void 0 !== vp.contentAwareBlur.edgePreservation && "boolean" != typeof vp.contentAwareBlur.edgePreservation && warnings.push("Content-aware blur edge preservation should be a boolean value"),
21392
+ void 0 !== vp.contentAwareBlur.depthDetection && "boolean" != typeof vp.contentAwareBlur.depthDetection && warnings.push("Content-aware blur depth detection should be a boolean value")),
21393
+ // Validate holographic effects settings
21394
+ vp.holographicEffects && (void 0 !== vp.holographicEffects.enabled && "boolean" != typeof vp.holographicEffects.enabled && warnings.push("Holographic effects enabled should be a boolean value"),
21395
+ void 0 !== vp.holographicEffects.rainbowDiffraction && "boolean" != typeof vp.holographicEffects.rainbowDiffraction && warnings.push("Holographic rainbow diffraction should be a boolean value"));
21104
21396
  }
21397
+ // Validate AI settings
21398
+ var _context;
21399
+ return config.ai && (config.ai.provider && !_includesInstanceProperty(_context = [ "openai", "anthropic" ]).call(_context, config.ai.provider) && warnings.push(`Unknown AI provider: "${config.ai.provider}". Supported: openai, anthropic`),
21400
+ config.ai.temperature && (config.ai.temperature < 0 || config.ai.temperature > 1) && warnings.push("AI temperature should be between 0 and 1"),
21401
+ config.ai.maxTokens && config.ai.maxTokens < 100 && warnings.push("AI maxTokens should typically be 100 or more"),
21402
+ config.ai.rateLimit && (config.ai.rateLimit.requests <= 0 && warnings.push("AI rate limit requests should be greater than 0"),
21403
+ config.ai.rateLimit.windowMs <= 0 && warnings.push("AI rate limit window should be greater than 0"))),
21404
+ // Validate telemetry settings
21405
+ config.telemetry && config.telemetry.path && !config.telemetry.path.endsWith(".json") && warnings.push("Telemetry path should typically end with .json"),
21406
+ warnings;
21105
21407
  }
21106
21408
 
21107
21409
  /**
21108
- * Default logger instance
21109
- */ let defaultLogger = null;
21410
+ * Helper function to validate CSS length values
21411
+ */ function isValidCSSLength(value) {
21412
+ return /^(\d+(\.\d+)?)(px|em|rem|%|vw|vh|vmin|vmax|cm|mm|in|pt|pc|ex|ch)?$/.test(value);
21413
+ }
21110
21414
 
21111
21415
  /**
21112
- * Get or create default logger
21113
- */ function getLogger() {
21114
- return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
21416
+ * Load Atomix configuration from project root
21417
+ *
21418
+ * Attempts to load atomix.config.ts, atomix.config.js, or atomix.config.json from the current working directory.
21419
+ * Falls back to default config if file doesn't exist.
21420
+ *
21421
+ * @param options - Loader options
21422
+ * @returns Loaded configuration or default
21423
+ *
21424
+ * @example
21425
+ * ```typescript
21426
+ * import { loadAtomixConfig } from '@shohojdhara/atomix/config';
21427
+ * import { createTheme } from '@shohojdhara/atomix/theme';
21428
+ *
21429
+ * const config = loadAtomixConfig();
21430
+ * const theme = createTheme(config.theme?.tokens || {});
21431
+ * ```
21432
+ */ function loadAtomixConfig(options = {}) {
21433
+ const {configPath: configPath, required: required = !1} = options, defaultConfig = {
21434
+ prefix: "atomix",
21435
+ theme: {
21436
+ extend: {}
21437
+ }
21438
+ };
21439
+ // Default config
21440
+ // In browser environments, config loading is not supported
21441
+ if ("undefined" != typeof window) {
21442
+ if (required) throw new Error('Config loading requires Node.js file system access.\n\nSolutions:\n1. Provide tokens explicitly to createTheme():\n const css = createTheme({ "--brand-primary": "#6366f1" });\n\n2. Use SSR framework (Next.js, Remix, Astro)\n\n3. Load config on server and pass to client\n\nSee examples/config-examples/browser-only.config.ts');
21443
+ return defaultConfig;
21444
+ }
21445
+ // If a specific config path is provided, try to load it directly
21446
+ if (configPath) return loadConfigAtPath(configPath, required, defaultConfig);
21447
+ // Otherwise, try standard locations in order of preference
21448
+ const possiblePaths = [ "atomix.config.ts", "atomix.config.js", "atomix.config.json" ];
21449
+ for (const path of possiblePaths) {
21450
+ const config = loadConfigAtPath(path, !1, defaultConfig);
21451
+ // If we found a valid config, return it
21452
+ if (JSON.stringify(config) !== JSON.stringify(defaultConfig)) return config;
21453
+ }
21454
+ // If no config file was found or all contained only defaults, return default config
21455
+ if (required) throw new Error('No Atomix configuration file found in project root.\n\nExpected one of:\n - atomix.config.ts (recommended)\n - atomix.config.js\n - atomix.config.json\n\nQuick Fix:\n1. Create a config file in your project root:\n touch atomix.config.ts\n\n2. Add basic configuration:\n import { defineConfig } from "@shohojdhara/atomix/config";\n export default defineConfig({ prefix: "myapp" });\n\n3. Or copy an example:\n cp node_modules/@shohojdhara/atomix/examples/config-examples/standard.config.ts ./atomix.config.ts');
21456
+ return defaultConfig;
21457
+ }
21458
+
21459
+ /**
21460
+ * Helper function to load config from a specific path
21461
+ */ function loadConfigAtPath(path, required, defaultConfig) {
21462
+ try {
21463
+ // Use dynamic import for ESM compatibility
21464
+ const configModule = require(path), config = configModule.default || configModule;
21465
+ // Validate it's an AtomixConfig
21466
+ if (config && "object" == typeof config) return config;
21467
+ throw new Error("Invalid config format");
21468
+ } catch (error) {
21469
+ if (required) throw new Error(`Failed to load config from ${path}: ${error.message}`);
21470
+ // Return default config if not required
21471
+ return defaultConfig;
21472
+ }
21115
21473
  }
21116
21474
 
21475
+ /**
21476
+ * Resolve config path
21477
+ *
21478
+ * Finds atomix.config.ts in the project, checking common locations.
21479
+ * Returns null in browser environments where file system access is not available.
21480
+ *
21481
+ * This function is designed to help tools identify if a config exists without loading it.
21482
+ *
21483
+ * @param configPath - Optional custom path to check
21484
+ * @returns Absolute path to config file or null if not found
21485
+ */
21117
21486
  /**
21118
21487
  * Core Theme Functions
21119
21488
  *
21120
- * Simplified theme system using DesignTokens only.
21489
+ * Unified theme system that handles both DesignTokens and Theme objects.
21121
21490
  * Config-first approach: loads from atomix.config.ts when no input is provided.
21491
+ * Config-first approach: loads advanced features from config when available.
21122
21492
  */
21123
21493
  /**
21124
- * Create theme CSS from DesignTokens
21494
+ * Create theme CSS from tokens or Theme object
21125
21495
  *
21126
21496
  * **Config-First Approach**: If no input is provided, loads from `atomix.config.ts`.
21497
+ * Config file is required for automatic loading.
21127
21498
  *
21128
- * @param input - DesignTokens (partial) or undefined (loads from config)
21499
+ * @param input - DesignTokens (partial), Theme object, or undefined (loads from config)
21129
21500
  * @param options - CSS generation options (prefix is automatically read from config if not provided)
21130
21501
  * @returns CSS string with custom properties
21131
21502
  * @throws Error if config loading fails when no input is provided
21132
21503
  *
21133
21504
  * @example
21134
21505
  * ```typescript
21135
- * // Loads from atomix.config.ts
21506
+ * // Loads from atomix.config.ts (config file required)
21136
21507
  * const css = createTheme();
21137
21508
  *
21138
21509
  * // Using DesignTokens
@@ -21141,42 +21512,151 @@ class ThemeLogger {
21141
21512
  * 'spacing-4': '1rem',
21142
21513
  * });
21143
21514
  *
21515
+ * // Using Theme object
21516
+ * const theme = createThemeObject({ palette: { primary: { main: '#7c3aed' } } });
21517
+ * const css = createTheme(theme);
21518
+ *
21144
21519
  * // With custom options
21145
21520
  * const css = createTheme(undefined, { prefix: 'myapp', selector: ':root' });
21146
21521
  * ```
21147
- */ function createTheme(input, options) {
21148
- // Validate options if provided
21149
- if (options?.prefix) {
21150
- const prefixPattern = /^[a-z][a-z0-9-]*$/;
21151
- if (!prefixPattern.test(options.prefix)) throw new ThemeError(`Invalid CSS variable prefix: "${options.prefix}". Prefix must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens (e.g., "atomix", "my-app").`, ThemeErrorCode.THEME_VALIDATION_FAILED, {
21152
- prefix: options.prefix,
21153
- pattern: prefixPattern.toString()
21154
- });
21155
- }
21156
- // Validate selector if provided
21157
- if (options?.selector && ("string" != typeof options.selector || 0 === options.selector.trim().length)) throw new ThemeError(`Invalid CSS selector: "${options.selector}". Selector must be a non-empty string (e.g., ":root", ".my-theme").`, ThemeErrorCode.THEME_VALIDATION_FAILED, {
21158
- selector: options.selector
21159
- });
21160
- // Determine tokens based on input
21161
- let tokens;
21162
- if (input) {
21163
- // Validate input tokens structure
21164
- if ("object" != typeof input || null === input || Array.isArray(input)) throw new ThemeError(`Invalid tokens input. Expected an object with DesignTokens, but received: ${typeof input}.`, ThemeErrorCode.THEME_VALIDATION_FAILED, {
21165
- inputType: typeof input
21166
- });
21167
- // Use DesignTokens directly
21168
- tokens = input;
21522
+ */
21523
+ function createTheme(input, options) {
21524
+ let tokens, configPrefix;
21525
+ // If no input provided, load from config (required)
21526
+ if (input)
21527
+ // Convert Theme object to DesignTokens
21528
+ tokens = !0 === input.__isJSTheme || input.palette && input.typography ? themeToDesignTokens(input) : input; else {
21529
+ const configTokens = function() {
21530
+ // Check if we're in a browser environment
21531
+ if ("undefined" != typeof window) throw new Error("loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.");
21532
+ // Use dynamic import to load the config loader
21533
+ // This allows bundlers to handle external dependencies properly
21534
+ let loadAtomixConfig;
21535
+ try {
21536
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
21537
+ const {loadAtomixConfig: loader} = require("../../config/loader");
21538
+ loadAtomixConfig = loader;
21539
+ } catch (error) {
21540
+ throw new Error("Config loader module not available");
21541
+ }
21542
+ const config = loadAtomixConfig({
21543
+ configPath: undefined,
21544
+ required: !0
21545
+ });
21546
+ if (!config?.theme) return createTokens({});
21547
+ if ((obj = config.theme) && "object" == typeof obj && (obj.palette || obj.typography || obj.spacing || obj.breakpoints || obj.colors)) return themeToDesignTokens(config.theme);
21548
+ // Handle the config.theme object which has extend/tokens/themes properties
21549
+ // Extract the actual tokens from the theme configuration
21550
+ // Helper type guard function
21551
+ var obj;
21552
+ const themeConfig = config.theme;
21553
+ let tokensToApply = {};
21554
+ return themeConfig.tokens ?
21555
+ // If tokens is provided, use it as the base
21556
+ tokensToApply = themeConfig.tokens : themeConfig.extend && (
21557
+ // If only extend is provided, use it as overrides
21558
+ tokensToApply = themeConfig.extend),
21559
+ // Apply advanced feature configurations as tokens
21560
+ config.interactiveEffects && (
21561
+ // Vortex effects
21562
+ config.interactiveEffects.vortex && (tokensToApply = {
21563
+ ...tokensToApply,
21564
+ "interactive-vortex-enabled": String(config.interactiveEffects.vortex.enabled ?? !1),
21565
+ "interactive-vortex-strength": String(config.interactiveEffects.vortex.strength ?? .5),
21566
+ "interactive-vortex-radius": String(config.interactiveEffects.vortex.radius ?? 100),
21567
+ "interactive-vortex-decay": String(config.interactiveEffects.vortex.decay ?? .8)
21568
+ }),
21569
+ // Chromatic aberration
21570
+ config.interactiveEffects.chromaticAberration && (tokensToApply = {
21571
+ ...tokensToApply,
21572
+ "interactive-chromatic-enabled": String(config.interactiveEffects.chromaticAberration.enabled ?? !1),
21573
+ "interactive-chromatic-mode": config.interactiveEffects.chromaticAberration.mode ?? "lateral",
21574
+ "interactive-chromatic-red-shift": String(config.interactiveEffects.chromaticAberration.redShift ?? .02),
21575
+ "interactive-chromatic-green-shift": String(config.interactiveEffects.chromaticAberration.greenShift ?? 0),
21576
+ "interactive-chromatic-blue-shift": String(config.interactiveEffects.chromaticAberration.blueShift ?? -.02),
21577
+ "interactive-chromatic-edge-only": String(config.interactiveEffects.chromaticAberration.edgeOnly ?? !1),
21578
+ "interactive-chromatic-edge-threshold": String(config.interactiveEffects.chromaticAberration.edgeThreshold ?? .5)
21579
+ }),
21580
+ // Mouse interaction
21581
+ config.interactiveEffects.mouseInteraction && (tokensToApply = {
21582
+ ...tokensToApply,
21583
+ "interactive-mouse-sensitivity": String(config.interactiveEffects.mouseInteraction.sensitivity ?? 1),
21584
+ "interactive-mouse-trail-effect": String(config.interactiveEffects.mouseInteraction.trailEffect ?? !1)
21585
+ }),
21586
+ // Animation speed
21587
+ config.interactiveEffects.animationSpeed && (tokensToApply = {
21588
+ ...tokensToApply,
21589
+ "interactive-animation-speed-base": String(config.interactiveEffects.animationSpeed.base ?? 1),
21590
+ "interactive-animation-speed-multiplier": String(config.interactiveEffects.animationSpeed.timeMultiplier ?? 1)
21591
+ })),
21592
+ // Apply optimization configurations as tokens
21593
+ config.optimization && (
21594
+ // Responsive breakpoints
21595
+ config.optimization.responsive && (config.optimization.responsive.breakpoints && (tokensToApply = {
21596
+ ...tokensToApply,
21597
+ "optimization-breakpoint-mobile": config.optimization.responsive.breakpoints.mobile ?? "0px",
21598
+ "optimization-breakpoint-tablet": config.optimization.responsive.breakpoints.tablet ?? "768px",
21599
+ "optimization-breakpoint-desktop": config.optimization.responsive.breakpoints.desktop ?? "1024px",
21600
+ "optimization-breakpoint-wide": config.optimization.responsive.breakpoints.wide ?? "1440px"
21601
+ }), config.optimization.responsive.deviceScaling && (tokensToApply = {
21602
+ ...tokensToApply,
21603
+ "optimization-device-scaling-mobile": String(config.optimization.responsive.deviceScaling.mobile ?? .5),
21604
+ "optimization-device-scaling-tablet": String(config.optimization.responsive.deviceScaling.tablet ?? .75),
21605
+ "optimization-device-scaling-desktop": String(config.optimization.responsive.deviceScaling.desktop ?? 1)
21606
+ })),
21607
+ // Performance settings
21608
+ config.optimization.performance && (tokensToApply = {
21609
+ ...tokensToApply,
21610
+ "optimization-performance-fps-target": String(config.optimization.performance.fpsTarget ?? 60),
21611
+ "optimization-auto-scaling-enabled": String(config.optimization.performance.autoScaling ?? !1)
21612
+ }),
21613
+ // Auto-scaling settings
21614
+ config.optimization.autoScaling && (tokensToApply = {
21615
+ ...tokensToApply,
21616
+ "optimization-auto-scaling-enabled": String(config.optimization.autoScaling.enabled ?? !1),
21617
+ "optimization-auto-scaling-low-end": String(config.optimization.autoScaling.qualityThresholds?.lowEnd ?? .5),
21618
+ "optimization-auto-scaling-mid-range": String(config.optimization.autoScaling.qualityThresholds?.midRange ?? .75),
21619
+ "optimization-auto-scaling-high-end": String(config.optimization.autoScaling.qualityThresholds?.highEnd ?? 1)
21620
+ })),
21621
+ // Apply visual polish configurations as tokens
21622
+ config.visualPolish && (config.visualPolish.borders && (tokensToApply = {
21623
+ ...tokensToApply,
21624
+ "visual-polish-border-iridescent-glow": String(config.visualPolish.borders.iridescentGlow ?? !1),
21625
+ "visual-polish-border-shimmer-effect": String(config.visualPolish.borders.shimmerEffect ?? !1),
21626
+ "visual-polish-border-beveled-edges": String(config.visualPolish.borders.beveledEdges ?? !1),
21627
+ "visual-polish-border-pulsing-glow": String(config.visualPolish.borders.pulsingGlow ?? !1)
21628
+ }), config.visualPolish.contentAwareBlur && (tokensToApply = {
21629
+ ...tokensToApply,
21630
+ "visual-polish-content-aware-blur-enabled": String(config.visualPolish.contentAwareBlur.enabled ?? !1),
21631
+ "visual-polish-content-aware-depth-detection": String(config.visualPolish.contentAwareBlur.depthDetection ?? !1),
21632
+ "visual-polish-content-aware-edge-preservation": String(config.visualPolish.contentAwareBlur.edgePreservation ?? !1),
21633
+ "visual-polish-content-aware-variable-radius": String(config.visualPolish.contentAwareBlur.variableRadius ?? !1)
21634
+ }), config.visualPolish.holographicEffects && (tokensToApply = {
21635
+ ...tokensToApply,
21636
+ "visual-polish-holographic-enabled": String(config.visualPolish.holographicEffects.enabled ?? !1),
21637
+ "visual-polish-holographic-rainbow-diffraction": String(config.visualPolish.holographicEffects.rainbowDiffraction ?? !1),
21638
+ "visual-polish-holographic-scanline-animation": String(config.visualPolish.holographicEffects.scanlineAnimation ?? !1),
21639
+ "visual-polish-holographic-grid-overlay": String(config.visualPolish.holographicEffects.gridOverlay ?? !1),
21640
+ "visual-polish-holographic-data-stream": String(config.visualPolish.holographicEffects.dataStream ?? !1),
21641
+ "visual-polish-holographic-pulse-rings": String(config.visualPolish.holographicEffects.pulseRings ?? !1)
21642
+ })), createTokens(tokensToApply);
21643
+ }();
21644
+ // Get prefix from config
21645
+ try {
21646
+ // Use the imported function directly instead of require to avoid bundling issues
21647
+ const config = loadAtomixConfig({
21648
+ configPath: "atomix.config.ts",
21649
+ required: !0
21650
+ });
21651
+ configPrefix = config?.prefix;
21652
+ } catch (error) {
21653
+ // Prefix loading failed, but tokens were loaded, so continue
21654
+ }
21655
+ tokens = configTokens;
21169
21656
  }
21170
21657
  // Merge with defaults and generate CSS
21171
- else
21172
- // Auto-loading config from file system is removed for browser compatibility.
21173
- // If no input is provided, we return an empty theme (using defaults only) or user must provide tokens.
21174
- // This allows createTheme to be isomorphic.
21175
- // Warn in development if no input provided
21176
- "production" !== process.env.NODE_ENV && "undefined" != typeof window && console.warn("Atomix: createTheme() called without tokens. Using default tokens only."),
21177
- tokens = {};
21178
- const allTokens = createTokens(tokens), prefix = options?.prefix ?? "atomix";
21179
- // Get prefix from options or use default
21658
+ const allTokens = createTokens(tokens), prefix = options?.prefix ?? configPrefix ?? "atomix";
21659
+ // Get prefix from options, config, or use default
21180
21660
  return generateCSSVariables$1(allTokens, {
21181
21661
  ...options,
21182
21662
  prefix: prefix
@@ -21390,43 +21870,176 @@ class ThemeLogger {
21390
21870
  */
21391
21871
  /**
21392
21872
  * Default storage key for theme persistence
21393
- */ "undefined" != typeof process && process.env;
21394
-
21873
+ */
21395
21874
  /**
21396
- * Check if code is running in a browser environment
21875
+ * Theme System Error Handling
21876
+ *
21877
+ * Centralized error handling for the Atomix theme system.
21878
+ * Provides custom error classes and logging utilities.
21397
21879
  */
21398
- const isBrowser = () => "undefined" != typeof window && "undefined" != typeof document, isServer = () => !isBrowser(), sanitizePath = path => path.replace(/[<>"']/g, "").replace(/\.\./g, "").replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "") // Trim leading/trailing slashes
21399
- , buildThemePath = (themeName, basePath = "/themes", useMinified = !1, cdnPath = null) => {
21400
- // Validate theme name to prevent path injection
21401
- if (!isValidThemeName(themeName)) throw new ThemeError(`Invalid theme name: "${themeName}". Theme names must be lowercase alphanumeric with hyphens (e.g., "my-theme").`, ThemeErrorCode.INVALID_THEME_NAME, {
21402
- themeName: themeName,
21403
- pattern: /^[a-z0-9]+(-[a-z0-9]+)*$/
21404
- });
21405
- const fileName = `${themeName}${useMinified ? ".min.css" : ".css"}`;
21406
- return cdnPath ? `${sanitizePath(cdnPath)}/${fileName}` : `${sanitizePath(basePath)}/${fileName.replace(/^\//, "")}`;
21407
- // Sanitize basePath to prevent path injection
21408
- }, applyThemeAttributes = (dataAttribute, themeName) => {
21409
- isServer() || (
21410
- // Set data attribute on body (with null check)
21411
- document.body && document.body.setAttribute(dataAttribute, themeName),
21412
- // Also set on documentElement for broader compatibility
21413
- document.documentElement.setAttribute(dataAttribute, themeName));
21414
- }, isValidThemeName = themeName => !(!themeName || "string" != typeof themeName) && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(themeName), createLocalStorageAdapter = () => ({
21415
- getItem: key => {
21416
- if (isServer()) return null;
21417
- try {
21418
- return localStorage.getItem(key);
21419
- } catch {
21420
- return null;
21421
- }
21422
- },
21423
- setItem: (key, value) => {
21424
- if (!isServer()) try {
21425
- localStorage.setItem(key, value);
21426
- } catch {
21427
- // Silently fail if localStorage is not available
21428
- }
21429
- },
21880
+ /**
21881
+ * Theme error codes
21882
+ */
21883
+ var ThemeErrorCode, LogLevel;
21884
+
21885
+ "undefined" != typeof process && process.env, function(ThemeErrorCode) {
21886
+ /** Theme not found in registry */
21887
+ ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
21888
+ /** Theme failed to load */
21889
+ ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
21890
+ /** Theme validation failed */
21891
+ ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
21892
+ /** Configuration loading failed */
21893
+ ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
21894
+ /** Configuration validation failed */
21895
+ ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
21896
+ /** Circular dependency detected */
21897
+ ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
21898
+ /** Missing dependency */
21899
+ ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
21900
+ /** Storage operation failed */
21901
+ ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
21902
+ /** Invalid theme name */
21903
+ ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
21904
+ /** CSS injection failed */
21905
+ ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
21906
+ /** Invalid color format */
21907
+ ThemeErrorCode.INVALID_COLOR_FORMAT = "INVALID_COLOR_FORMAT",
21908
+ /** Missing required token */
21909
+ ThemeErrorCode.MISSING_REQUIRED_TOKEN = "MISSING_REQUIRED_TOKEN",
21910
+ /** Accessibility contrast violation */
21911
+ ThemeErrorCode.CONTRAST_VIOLATION = "CONTRAST_VIOLATION",
21912
+ /** Invalid token type */
21913
+ ThemeErrorCode.INVALID_TOKEN_TYPE = "INVALID_TOKEN_TYPE",
21914
+ /** Unknown error */
21915
+ ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
21916
+ }(ThemeErrorCode || (ThemeErrorCode = {}));
21917
+
21918
+ /**
21919
+ * Custom error class for theme-related errors
21920
+ */
21921
+ class ThemeError extends Error {
21922
+ constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
21923
+ super(message), this.name = "ThemeError", this.code = code, this.context = context,
21924
+ this.timestamp = Date.now(),
21925
+ // Maintains proper stack trace for where our error was thrown (only available on V8)
21926
+ Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
21927
+ }
21928
+ /**
21929
+ * Convert error to JSON for logging
21930
+ */ toJSON() {
21931
+ return {
21932
+ name: this.name,
21933
+ message: this.message,
21934
+ code: this.code,
21935
+ context: this.context,
21936
+ timestamp: this.timestamp,
21937
+ stack: this.stack
21938
+ };
21939
+ }
21940
+ }
21941
+
21942
+ /**
21943
+ * Log level
21944
+ */ !function(LogLevel) {
21945
+ LogLevel[LogLevel.ERROR = 0] = "ERROR", LogLevel[LogLevel.WARN = 1] = "WARN", LogLevel[LogLevel.INFO = 2] = "INFO",
21946
+ LogLevel[LogLevel.DEBUG = 3] = "DEBUG";
21947
+ }(LogLevel || (LogLevel = {}));
21948
+
21949
+ /**
21950
+ * Theme Logger
21951
+ *
21952
+ * Centralized logging for the theme system.
21953
+ * Replaces console statements with structured logging.
21954
+ */
21955
+ class ThemeLogger {
21956
+ constructor(config = {}) {
21957
+ this.config = {
21958
+ level: config.level ?? ("undefined" != typeof process && "production" === process.env?.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
21959
+ enableConsole: config.enableConsole ?? !0,
21960
+ onError: config.onError,
21961
+ onWarn: config.onWarn,
21962
+ onInfo: config.onInfo,
21963
+ onDebug: config.onDebug
21964
+ };
21965
+ }
21966
+ /**
21967
+ * Log an error
21968
+ */ error(message, error, context) {
21969
+ if (this.config.level < LogLevel.ERROR) return;
21970
+ const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
21971
+ this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
21972
+ error: errorObj,
21973
+ context: {
21974
+ ...context,
21975
+ ...themeError.context
21976
+ },
21977
+ code: themeError.code
21978
+ }), this.config.onError?.(themeError, context);
21979
+ }
21980
+ /**
21981
+ * Log a warning
21982
+ */ warn(message, context) {
21983
+ this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
21984
+ this.config.onWarn?.(message, context));
21985
+ }
21986
+ /**
21987
+ * Log an info message
21988
+ */ info(message, context) {
21989
+ this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
21990
+ this.config.onInfo?.(message, context));
21991
+ }
21992
+ /**
21993
+ * Log a debug message
21994
+ */ debug(message, context) {
21995
+ this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
21996
+ }
21997
+ }
21998
+
21999
+ /**
22000
+ * Default logger instance
22001
+ */ let defaultLogger = null;
22002
+
22003
+ /**
22004
+ * Get or create default logger
22005
+ */ function getLogger() {
22006
+ return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
22007
+ }
22008
+
22009
+ /**
22010
+ * Check if code is running in a browser environment
22011
+ */ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof document, isServer = () => !isBrowser(), sanitizePath = path => path.replace(/[<>"']/g, "").replace(/\.\./g, "").replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "") // Trim leading/trailing slashes
22012
+ , buildThemePath = (themeName, basePath = "/themes", useMinified = !1, cdnPath = null) => {
22013
+ // Validate theme name to prevent path injection
22014
+ if (!isValidThemeName(themeName)) throw new ThemeError(`Invalid theme name: "${themeName}". Theme names must be lowercase alphanumeric with hyphens (e.g., "my-theme").`, ThemeErrorCode.INVALID_THEME_NAME, {
22015
+ themeName: themeName,
22016
+ pattern: /^[a-z0-9]+(-[a-z0-9]+)*$/
22017
+ });
22018
+ const fileName = `${themeName}${useMinified ? ".min.css" : ".css"}`;
22019
+ return cdnPath ? `${sanitizePath(cdnPath)}/${fileName}` : `${sanitizePath(basePath)}/${fileName.replace(/^\//, "")}`;
22020
+ // Sanitize basePath to prevent path injection
22021
+ }, applyThemeAttributes = (dataAttribute, themeName) => {
22022
+ isServer() || (
22023
+ // Set data attribute on body (with null check)
22024
+ document.body && document.body.setAttribute(dataAttribute, themeName),
22025
+ // Also set on documentElement for broader compatibility
22026
+ document.documentElement.setAttribute(dataAttribute, themeName));
22027
+ }, isValidThemeName = themeName => !(!themeName || "string" != typeof themeName) && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(themeName), createLocalStorageAdapter = () => ({
22028
+ getItem: key => {
22029
+ if (isServer()) return null;
22030
+ try {
22031
+ return localStorage.getItem(key);
22032
+ } catch {
22033
+ return null;
22034
+ }
22035
+ },
22036
+ setItem: (key, value) => {
22037
+ if (!isServer()) try {
22038
+ localStorage.setItem(key, value);
22039
+ } catch {
22040
+ // Silently fail if localStorage is not available
22041
+ }
22042
+ },
21430
22043
  removeItem: key => {
21431
22044
  if (!isServer()) try {
21432
22045
  localStorage.removeItem(key);
@@ -21479,105 +22092,427 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
21479
22092
  }))
21480
22093
  });
21481
22094
 
22095
+ // ============================================================================
22096
+ // Theme Mode Switching
22097
+ // ============================================================================
21482
22098
  /**
21483
- * Theme Utilities
22099
+ * Switch between light and dark themes
21484
22100
  *
21485
- * Helper utilities for working with themes, including color manipulation,
21486
- * spacing helpers, and theme value accessors.
21487
- */
22101
+ * Automatically toggles a class on the root element and persists the choice.
22102
+ *
22103
+ * @param mode - Theme mode ('light', 'dark', or 'system')
22104
+ * @param options - Configuration options
22105
+ *
22106
+ * @example
22107
+ * ```typescript
22108
+ * import { switchTheme } from '@shohojdhara/atomix/theme/utils';
22109
+ *
22110
+ * // Switch to dark mode
22111
+ * switchTheme('dark');
22112
+ *
22113
+ * // Toggle between light/dark
22114
+ * const current = getCurrentTheme();
22115
+ * switchTheme(current === 'dark' ? 'light' : 'dark');
22116
+ * ```
22117
+ */ function switchTheme(mode, options = {}) {
22118
+ const {selector: selector = ":root", storageKey: storageKey = "atomix-theme", enableTransition: enableTransition = !0, transitionDuration: transitionDuration = 300} = options, resolvedMode = "system" === mode ? getSystemTheme() : mode, root = ":root" === selector ? document.documentElement : document.querySelector(selector);
22119
+ // Determine actual mode (resolve 'system')
22120
+ if (root) {
22121
+ // Add transition class if enabled
22122
+ if (enableTransition) {
22123
+ const htmlRoot = root;
22124
+ htmlRoot.style.transition = `all ${transitionDuration}ms ease-in-out`,
22125
+ // Remove transition after it completes
22126
+ setTimeout((() => {
22127
+ htmlRoot.style.transition = "";
22128
+ }), transitionDuration);
22129
+ }
22130
+ // Apply theme class
22131
+ root.classList.remove("atomix-theme-light", "atomix-theme-dark"), root.classList.add(`atomix-theme-${resolvedMode}`),
22132
+ // Set data attribute for CSS selectors
22133
+ root.setAttribute("data-theme", resolvedMode),
22134
+ // Persist choice
22135
+ persistTheme(resolvedMode, {
22136
+ storageKey: storageKey
22137
+ }),
22138
+ // Dispatch custom event for listeners
22139
+ window.dispatchEvent(new CustomEvent("atomix-theme-change", {
22140
+ detail: {
22141
+ mode: resolvedMode
22142
+ }
22143
+ }));
22144
+ }
22145
+ }
22146
+
22147
+ /**
22148
+ * Toggle between light and dark themes
22149
+ *
22150
+ * @param options - Configuration options
22151
+ * @returns The new theme mode
22152
+ *
22153
+ * @example
22154
+ * ```typescript
22155
+ * const newMode = toggleTheme();
22156
+ * console.log('Switched to:', newMode);
22157
+ * ```
22158
+ */ function toggleTheme(options = {}) {
22159
+ const next = "dark" === getCurrentTheme(options.storageKey) ? "light" : "dark";
22160
+ return switchTheme(next, options), next;
22161
+ }
22162
+
22163
+ /**
22164
+ * Get current theme mode
22165
+ *
22166
+ * @param storageKey - Storage key (default: 'atomix-theme')
22167
+ * @returns Current theme mode or 'light' if not set
22168
+ */ function getCurrentTheme(storageKey = "atomix-theme") {
22169
+ return "undefined" == typeof window ? "light" : localStorage.getItem(storageKey) || "light";
22170
+ }
22171
+
22172
+ /**
22173
+ * Get system theme preference
22174
+ *
22175
+ * @returns 'dark' if system prefers dark mode, 'light' otherwise
22176
+ */ function getSystemTheme() {
22177
+ return "undefined" == typeof window ? "light" : window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
22178
+ }
22179
+
22180
+ /**
22181
+ * Initialize theme based on saved preference or system preference
22182
+ *
22183
+ * Call this once at app startup.
22184
+ *
22185
+ * @param options - Configuration options
22186
+ * @returns The initialized theme mode
22187
+ *
22188
+ * @example
22189
+ * ```typescript
22190
+ * // In your app entry point
22191
+ * import { initializeTheme } from '@shohojdhara/atomix/theme/utils';
22192
+ *
22193
+ * const theme = initializeTheme();
22194
+ * console.log('Theme initialized:', theme);
22195
+ * ```
22196
+ */ function initializeTheme(options = {}) {
22197
+ const saved = getCurrentTheme(options.storageKey);
22198
+ // If no saved preference, use system preference
22199
+ if (!saved || "system" === saved) {
22200
+ const system = getSystemTheme();
22201
+ return switchTheme(system, options), system;
22202
+ }
22203
+ // Use saved preference
22204
+ return switchTheme(saved, options), saved;
22205
+ }
22206
+
22207
+ /**
22208
+ * Listen for system theme changes
22209
+ *
22210
+ * @param callback - Function to call when system theme changes
22211
+ * @returns Cleanup function to stop listening
22212
+ *
22213
+ * @example
22214
+ * ```typescript
22215
+ * const cleanup = listenToSystemTheme((mode) => {
22216
+ * console.log('System theme changed to:', mode);
22217
+ * switchTheme(mode);
22218
+ * });
22219
+ *
22220
+ * // Later, when component unmounts
22221
+ * cleanup();
22222
+ * ```
22223
+ */ function listenToSystemTheme(callback) {
22224
+ if ("undefined" == typeof window) return () => {};
22225
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"), handler = e => {
22226
+ callback(e.matches ? "dark" : "light");
22227
+ };
22228
+ // Modern browsers
22229
+ return mediaQuery.addEventListener ? (mediaQuery.addEventListener("change", handler),
22230
+ () => mediaQuery.removeEventListener("change", handler)) : (
22231
+ // Fallback for older browsers
22232
+ mediaQuery.addListener(handler), () => mediaQuery.removeListener(handler));
22233
+ }
22234
+
21488
22235
  // ============================================================================
21489
- // Color Manipulation Utilities
22236
+ // Theme Persistence
21490
22237
  // ============================================================================
21491
22238
  /**
21492
- * Convert hex color to RGB object
22239
+ * Save theme preference to storage
22240
+ *
22241
+ * @param mode - Theme mode to save
22242
+ * @param options - Persistence options
22243
+ */ function persistTheme(mode, options = {}) {
22244
+ if ("undefined" == typeof window) return;
22245
+ const {storageKey: storageKey = "atomix-theme", storageType: storageType = "localStorage"} = options;
22246
+ ("localStorage" === storageType ? localStorage : sessionStorage).setItem(storageKey, mode);
22247
+ }
22248
+
22249
+ /**
22250
+ * Clear saved theme preference
22251
+ *
22252
+ * @param options - Persistence options
22253
+ */ function clearThemePreference(options = {}) {
22254
+ if ("undefined" == typeof window) return;
22255
+ const {storageKey: storageKey = "atomix-theme", storageType: storageType = "localStorage"} = options;
22256
+ ("localStorage" === storageType ? localStorage : sessionStorage).removeItem(storageKey);
22257
+ }
22258
+
22259
+ // ============================================================================
22260
+ // Theme Tokens Manipulation
22261
+ // ============================================================================
22262
+ /**
22263
+ * Merge multiple token sets
22264
+ *
22265
+ * Deep merges token objects, with later tokens overriding earlier ones.
22266
+ *
22267
+ * @param tokens - Token objects to merge
22268
+ * @returns Merged tokens
22269
+ *
22270
+ * @example
22271
+ * ```typescript
22272
+ * const merged = mergeTokens(
22273
+ * baseTokens,
22274
+ * { colors: { primary: { main: '#custom' } } }
22275
+ * );
22276
+ * ```
22277
+ */ function mergeTokens(...tokens) {
22278
+ return _reduceInstanceProperty(tokens).call(tokens, ((acc, current) => deepMerge(acc, current)), {});
22279
+ }
22280
+
22281
+ /**
22282
+ * Override specific tokens
22283
+ *
22284
+ * Creates a new token object with specific overrides.
22285
+ *
22286
+ * @param base - Base tokens
22287
+ * @param overrides - Tokens to override
22288
+ * @returns New tokens with overrides applied
22289
+ *
22290
+ * @example
22291
+ * ```typescript
22292
+ * const customized = overrideTokens(defaultTokens, {
22293
+ * colors: {
22294
+ * primary: { main: '#ff0000' }
22295
+ * }
22296
+ * });
22297
+ * ```
22298
+ */ function overrideTokens(base, overrides) {
22299
+ return deepMerge({
22300
+ ...base
22301
+ }, overrides);
22302
+ }
22303
+
22304
+ /**
22305
+ * Pick specific token categories
22306
+ *
22307
+ * Extracts only the specified categories from tokens.
22308
+ *
22309
+ * @param tokens - Source tokens
22310
+ * @param categories - Categories to pick
22311
+ * @returns Tokens with only selected categories
22312
+ *
22313
+ * @example
22314
+ * ```typescript
22315
+ * const colorTokens = pickTokens(allTokens, ['colors']);
22316
+ * ```
22317
+ */ function pickTokens(tokens, categories) {
22318
+ const result = {};
22319
+ return categories.forEach((category => {
22320
+ tokens[category] && (result[category] = tokens[category]);
22321
+ })), result;
22322
+ }
22323
+
22324
+ /**
22325
+ * Omit specific token categories
22326
+ *
22327
+ * Removes specified categories from tokens.
22328
+ *
22329
+ * @param tokens - Source tokens
22330
+ * @param categories - Categories to omit
22331
+ * @returns Tokens without omitted categories
22332
+ *
22333
+ * @example
22334
+ * ```typescript
22335
+ * const withoutColors = omitTokens(allTokens, ['colors']);
22336
+ * ```
22337
+ */ function omitTokens(tokens, categories) {
22338
+ const result = {
22339
+ ...tokens
22340
+ };
22341
+ return categories.forEach((category => {
22342
+ delete result[category];
22343
+ })), result;
22344
+ }
22345
+
22346
+ // ============================================================================
22347
+ // Color Utilities
22348
+ // ============================================================================
22349
+ /**
22350
+ * Convert hex color to RGB
22351
+ *
22352
+ * @param hex - Hex color (with or without #)
22353
+ * @returns RGB object { r, g, b }
21493
22354
  */ function hexToRgb$1(hex) {
21494
- const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
21495
- return result ? {
21496
- r: parseInt(result[1], 16),
21497
- g: parseInt(result[2], 16),
21498
- b: parseInt(result[3], 16)
21499
- } : null;
22355
+ // Validate
22356
+ if (
22357
+ // Remove # if present
22358
+ // Handle shorthand hex
22359
+ 3 === (hex = hex.replace(/^#/, "")).length && (hex = hex.split("").map((c => c + c)).join("")),
22360
+ 6 !== hex.length) return null;
22361
+ const num = parseInt(hex, 16);
22362
+ return {
22363
+ r: num >> 16 & 255,
22364
+ g: num >> 8 & 255,
22365
+ b: 255 & num
22366
+ };
21500
22367
  }
21501
22368
 
21502
22369
  /**
21503
- * Convert RGB to hex color
22370
+ * Convert RGB to hex
22371
+ *
22372
+ * @param r - Red (0-255)
22373
+ * @param g - Green (0-255)
22374
+ * @param b - Blue (0-255)
22375
+ * @returns Hex color with #
21504
22376
  */ function rgbToHex(r, g, b) {
21505
- const toHex = val => Math.round(Math.max(0, Math.min(255, val))).toString(16).padStart(2, "0");
21506
- return `#${toHex(r ?? 0)}${toHex(g ?? 0)}${toHex(b ?? 0)}`;
22377
+ return "#" + [ r, g, b ].map((x => {
22378
+ const hex = x.toString(16);
22379
+ return 1 === hex.length ? "0" + hex : hex;
22380
+ })).join("");
21507
22381
  }
21508
22382
 
21509
22383
  /**
21510
- * Calculate relative luminance of a color
21511
- * Used for determining contrast ratios
21512
- */ function getLuminance(color) {
21513
- const rgb = hexToRgb$1(color);
22384
+ * Calculate luminance of a color
22385
+ *
22386
+ * Used for determining contrast ratios.
22387
+ *
22388
+ * @param hex - Hex color
22389
+ * @returns Luminance value (0-1)
22390
+ */ function getLuminance(hex) {
22391
+ const rgb = hexToRgb$1(hex);
21514
22392
  if (!rgb) return 0;
21515
- const {r: r, g: g, b: b} = rgb, [rs, gs, bs] = [ r ?? 0, g ?? 0, b ?? 0 ].map((c => {
21516
- const val = c / 255;
21517
- return val <= .03928 ? val / 12.92 : Math.pow((val + .055) / 1.055, 2.4);
21518
- }));
21519
- return .2126 * (rs ?? 0) + .7152 * (gs ?? 0) + .0722 * (bs ?? 0);
22393
+ const [r, g, b] = [ rgb.r, rgb.g, rgb.b ].map((v => (v /= 255) <= .03928 ? v / 12.92 : Math.pow((v + .055) / 1.055, 2.4)));
22394
+ return .2126 * (r ?? 0) + .7152 * (g ?? 0) + .0722 * (b ?? 0);
21520
22395
  }
21521
22396
 
21522
22397
  /**
21523
22398
  * Calculate contrast ratio between two colors
21524
- */ function getContrastRatio(foreground, background) {
21525
- const lumA = getLuminance(foreground), lumB = getLuminance(background);
21526
- return (Math.max(lumA, lumB) + .05) / (Math.min(lumA, lumB) + .05);
22399
+ *
22400
+ * @param hex1 - First hex color
22401
+ * @param hex2 - Second hex color
22402
+ * @returns Contrast ratio (1-21)
22403
+ */ function getContrastRatio(hex1, hex2) {
22404
+ const lum1 = getLuminance(hex1), lum2 = getLuminance(hex2);
22405
+ return (Math.max(lum1, lum2) + .05) / (Math.min(lum1, lum2) + .05);
21527
22406
  }
21528
22407
 
21529
22408
  /**
21530
- * Get appropriate contrast text color (black or white) for a background color
21531
- */ function getContrastText(background, threshold = 3) {
21532
- const contrastWithWhite = getContrastRatio("#FFFFFF", background), contrastWithBlack = getContrastRatio("#000000", background);
21533
- return contrastWithWhite >= threshold ? "#FFFFFF" : contrastWithBlack >= threshold ? "#000000" : contrastWithWhite > contrastWithBlack ? "#FFFFFF" : "#000000";
22409
+ * Check if text color passes WCAG AA standard
22410
+ *
22411
+ * @param textColor - Text color hex
22412
+ * @param backgroundColor - Background color hex
22413
+ * @param size - Font size ('small' or 'large')
22414
+ * @returns true if passes WCAG AA
22415
+ */ function isAccessible(textColor, backgroundColor, size = "small") {
22416
+ return getContrastRatio(textColor, backgroundColor) >= ("large" === size ? 3 : 4.5);
21534
22417
  }
21535
22418
 
21536
22419
  /**
21537
- * Lighten a color by a given amount
22420
+ * Get appropriate text color (black or white) for a background
21538
22421
  *
21539
- * @param color - Hex color string
21540
- * @param amount - Amount to lighten (0-1), default 0.2
22422
+ * @param backgroundColor - Background hex color
22423
+ * @param threshold - Contrast threshold (default: 3)
22424
+ * @returns '#000000' or '#FFFFFF'
22425
+ */ function getContrastText(backgroundColor, threshold = 3) {
22426
+ return getContrastRatio(backgroundColor, "#FFFFFF") >= threshold ? "#FFFFFF" : "#000000";
22427
+ }
22428
+
22429
+ /**
22430
+ * Lighten a color
22431
+ *
22432
+ * @param hex - Base hex color
22433
+ * @param amount - Amount to lighten (0-1)
21541
22434
  * @returns Lightened hex color
21542
- */ function lighten(color, amount = .2) {
21543
- const rgb = hexToRgb$1(color);
21544
- if (!rgb) return color;
21545
- const {r: r, g: g, b: b} = rgb, lightenValue = val => Math.min(255, Math.round(val + (255 - val) * amount));
21546
- return rgbToHex(lightenValue(r), lightenValue(g), lightenValue(b));
22435
+ */ function lighten(hex, amount = 0) {
22436
+ const rgb = hexToRgb$1(hex);
22437
+ if (!rgb) return hex;
22438
+ // Use amount directly as factor (0-1)
22439
+ const factor = Math.max(0, Math.min(1, amount)), r = Math.round(rgb.r + (255 - rgb.r) * factor), g = Math.round(rgb.g + (255 - rgb.g) * factor), b = Math.round(rgb.b + (255 - rgb.b) * factor);
22440
+ return rgbToHex(Math.min(255, r), Math.min(255, g), Math.min(255, b));
21547
22441
  }
21548
22442
 
21549
22443
  /**
21550
- * Darken a color by a given amount
22444
+ * Darken a color
21551
22445
  *
21552
- * @param color - Hex color string
21553
- * @param amount - Amount to darken (0-1), default 0.2
22446
+ * @param hex - Base hex color
22447
+ * @param amount - Amount to darken (0-1)
21554
22448
  * @returns Darkened hex color
21555
- */ function darken(color, amount = .2) {
21556
- const rgb = hexToRgb$1(color);
21557
- if (!rgb) return color;
21558
- const {r: r, g: g, b: b} = rgb, darkenValue = val => Math.max(0, Math.round(val * (1 - amount)));
21559
- return rgbToHex(darkenValue(r), darkenValue(g), darkenValue(b));
22449
+ */ function darken(hex, amount = 0) {
22450
+ const rgb = hexToRgb$1(hex);
22451
+ if (!rgb) return hex;
22452
+ // Use amount directly as factor (0-1)
22453
+ const factor = Math.max(0, Math.min(1, amount)), r = Math.round(rgb.r * (1 - factor)), g = Math.round(rgb.g * (1 - factor)), b = Math.round(rgb.b * (1 - factor));
22454
+ return rgbToHex(Math.max(0, r), Math.max(0, g), Math.max(0, b));
21560
22455
  }
21561
22456
 
21562
22457
  /**
21563
- * Add alpha (opacity) to a color
22458
+ * Add alpha to a color
21564
22459
  *
21565
- * @param color - Hex color string
22460
+ * @param hex - Hex color
21566
22461
  * @param opacity - Opacity value (0-1)
21567
22462
  * @returns RGBA color string
21568
- */ function alpha(color, opacity) {
21569
- const rgb = hexToRgb$1(color);
21570
- if (!rgb) return color;
21571
- const {r: r, g: g, b: b} = rgb;
21572
- return `rgba(${r}, ${g}, ${b}, ${Math.max(0, Math.min(1, opacity))})`;
22463
+ */ function alpha(hex, opacity) {
22464
+ const rgb = hexToRgb$1(hex);
22465
+ if (!rgb) return hex;
22466
+ const validOpacity = Math.max(0, Math.min(1, opacity));
22467
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${validOpacity})`;
21573
22468
  }
21574
22469
 
21575
22470
  /**
21576
22471
  * Emphasize a color (lighten if dark, darken if light)
21577
22472
  *
21578
- * @param color - Hex color string
21579
- * @param coefficient - Amount to emphasize (0-1), default 0.15
22473
+ * @param hex - Hex color
22474
+ * @param amount - Amount to emphasize (0-1)
21580
22475
  * @returns Emphasized hex color
22476
+ */ function emphasize(hex, amount = .15) {
22477
+ return getLuminance(hex) > .5 ? darken(hex, amount) : lighten(hex, amount);
22478
+ }
22479
+
22480
+ /**
22481
+ * Create a spacing utility
22482
+ *
22483
+ * @param spacingInput - Spacing configuration
22484
+ * @returns Spacing function
22485
+ */ function createSpacing(spacingInput = 4) {
22486
+ return (...values) => 0 === values.length ? "0px" : "function" == typeof spacingInput ? spacingInput(...values) : values.map((value => {
22487
+ if ("number" == typeof spacingInput) return value * spacingInput + "px";
22488
+ if (Array.isArray(spacingInput)) {
22489
+ const scaled = spacingInput[value];
22490
+ return "number" == typeof scaled ? `${scaled}px` : `${value}px`;
22491
+ }
22492
+ return `${value}px`;
22493
+ })).join(" ");
22494
+ }
22495
+
22496
+ /**
22497
+ * CSS Variable Generator
22498
+ *
22499
+ * Generates CSS custom properties from theme objects and injects them into the DOM.
22500
+ *
22501
+ * **Token Naming Alignment:**
22502
+ * This generator produces CSS variables that match the SCSS token naming pattern exactly:
22503
+ * - Colors: --atomix-primary, --atomix-primary-1 through --atomix-primary-10
22504
+ * - Spacing: --atomix-spacing-1, --atomix-spacing-4, etc.
22505
+ * - Typography: --atomix-font-size-base, --atomix-font-weight-normal, etc.
22506
+ * - Shadows: --atomix-box-shadow, --atomix-box-shadow-sm, etc.
22507
+ *
22508
+ * All tokens follow the flat structure pattern used in SCSS (not nested like --atomix-palette-primary-main).
22509
+ * This ensures compatibility between SCSS themes and JavaScript themes.
22510
+ *
22511
+ * @see src/styles/03-generic/_generic.root.scss for SCSS token definitions
22512
+ */
22513
+ /**
22514
+ * Convert a nested object to flat CSS variable declarations
22515
+ * Uses iterative approach for better performance with large objects
21581
22516
  */
21582
22517
  /**
21583
22518
  * Generate a color scale from a base color (1-10 steps)
@@ -21645,18 +22580,7 @@ function generateCSSVariables(theme, options = {}) {
21645
22580
  color.dark && (vars[`${prefix}-${key}-hover`] = color.dark),
21646
22581
  // Generate semantic color variants (matches SCSS patterns)
21647
22582
  // Text emphasis: emphasized version of the color for text (--atomix-primary-text-emphasis)
21648
- vars[`${prefix}-${key}-text-emphasis`] = function(color, coefficient = .15) {
21649
- return getLuminance(color) > .5 ? darken(color, coefficient) : lighten(color, coefficient);
21650
- }
21651
- // ============================================================================
21652
- // Spacing Utilities
21653
- // ============================================================================
21654
- /**
21655
- * Create a spacing function from various input types
21656
- *
21657
- * @param spacingInput - Spacing configuration (number, array, or function), default 4
21658
- * @returns Spacing function
21659
- */ (color.main, .15),
22583
+ vars[`${prefix}-${key}-text-emphasis`] = emphasize(color.main, .15),
21660
22584
  // Background subtle: very light version for backgrounds (--atomix-primary-bg-subtle)
21661
22585
  vars[`${prefix}-${key}-bg-subtle`] = alpha(color.main, .1),
21662
22586
  // Border subtle: light version for borders (--atomix-primary-border-subtle)
@@ -22001,29 +22925,7 @@ function generateCSSVariables(theme, options = {}) {
22001
22925
  return vars[`${prefix}-focus-ring-width`] = "3px", vars[`${prefix}-focus-ring-offset`] = "2px",
22002
22926
  vars[`${prefix}-focus-ring-opacity`] = "0.25", vars;
22003
22927
  }(theme.palette, prefix)), theme.custom && Object.keys(theme.custom).length > 0) {
22004
- const customVars =
22005
- /**
22006
- * CSS Variable Generator
22007
- *
22008
- * Generates CSS custom properties from theme objects and injects them into the DOM.
22009
- *
22010
- * **Token Naming Alignment:**
22011
- * This generator produces CSS variables that match the SCSS token naming pattern exactly:
22012
- * - Colors: --atomix-primary, --atomix-primary-1 through --atomix-primary-10
22013
- * - Spacing: --atomix-spacing-1, --atomix-spacing-4, etc.
22014
- * - Typography: --atomix-font-size-base, --atomix-font-weight-normal, etc.
22015
- * - Shadows: --atomix-box-shadow, --atomix-box-shadow-sm, etc.
22016
- *
22017
- * All tokens follow the flat structure pattern used in SCSS (not nested like --atomix-palette-primary-main).
22018
- * This ensures compatibility between SCSS themes and JavaScript themes.
22019
- *
22020
- * @see src/styles/03-generic/_generic.root.scss for SCSS token definitions
22021
- */
22022
- /**
22023
- * Convert a nested object to flat CSS variable declarations
22024
- * Uses iterative approach for better performance with large objects
22025
- */
22026
- function(obj, prefix = "", result = {}) {
22928
+ const customVars = function(obj, prefix = "", result = {}) {
22027
22929
  // Use iterative approach with stack to avoid deep recursion
22028
22930
  const stack = [ {
22029
22931
  obj: obj,
@@ -22477,19 +23379,29 @@ const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme:
22477
23379
  // Check storage first
22478
23380
  if (enablePersistence && storageAdapter.isAvailable()) {
22479
23381
  const stored = storageAdapter.getItem(storageKey);
22480
- if (stored) return stored;
23382
+ if (stored) {
23383
+ // If it looks like a JSON object, parse it
23384
+ if (stored.trim().startsWith("{")) try {
23385
+ return JSON.parse(stored);
23386
+ } catch (e) {
23387
+ return logger.error("Failed to parse stored theme tokens", e), stored;
23388
+ }
23389
+ return stored;
23390
+ }
22481
23391
  }
22482
23392
  // If defaultTheme is provided, use it
22483
23393
  return null != defaultTheme ? defaultTheme : "default";
22484
23394
  // Default fallback
22485
23395
  }), [ defaultTheme, enablePersistence, storageKey, storageAdapter ]), [currentTheme, setCurrentTheme] = React.useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : "tokens-theme")), [activeTokens, setActiveTokens] = React.useState((() => {
22486
- // If defaultTheme is DesignTokens, validate and store them
22487
- if (defaultTheme && "string" != typeof defaultTheme) {
23396
+ // 1. Check if initialDefaultTheme (from storage) is an object
23397
+ if (initialDefaultTheme && "string" != typeof initialDefaultTheme) {
23398
+ const {tokens: tokens, validation: validation} = validateAndMergeTokens(initialDefaultTheme);
23399
+ if (validation.valid) return tokens;
23400
+ }
23401
+ // 2. Check if defaultTheme prop is an object
23402
+ if (defaultTheme && "string" != typeof defaultTheme) {
22488
23403
  const {tokens: tokens, validation: validation} = validateAndMergeTokens(defaultTheme);
22489
- return validation.valid ? tokens : (logger.warn("Invalid default theme tokens, using defaults", {
22490
- errors: validation.errors,
22491
- warnings: validation.warnings
22492
- }), createTokens({}));
23404
+ if (validation.valid) return tokens;
22493
23405
  }
22494
23406
  return null;
22495
23407
  })), [isLoading, setIsLoading] = React.useState(!1), [error, setError] = React.useState(null), loadedThemesRef = React.useRef(new Set), themePromisesRef = React.useRef({}), abortControllerRef = React.useRef(null);
@@ -22501,10 +23413,14 @@ const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme:
22501
23413
  React.useEffect((() => {
22502
23414
  isServer() || applyThemeAttributes(String(currentTheme), dataAttribute);
22503
23415
  }), [ currentTheme, dataAttribute ]),
22504
- // Handle theme persistence
23416
+ // Handle persistence
22505
23417
  React.useEffect((() => {
22506
- enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, String(currentTheme));
22507
- }), [ currentTheme, storageKey, enablePersistence, storageAdapter ]),
23418
+ enablePersistence && storageAdapter.isAvailable() && ("tokens-theme" === currentTheme ?
23419
+ // Only persist if we have actual tokens to store
23420
+ activeTokens && storageAdapter.setItem(storageKey, JSON.stringify(activeTokens)) :
23421
+ // Persist named theme string
23422
+ storageAdapter.setItem(storageKey, String(currentTheme)));
23423
+ }), [ currentTheme, activeTokens, enablePersistence, storageKey, storageAdapter ]),
22508
23424
  // Cleanup: Remove completed promises and abort controllers on unmount
22509
23425
  React.useEffect((() => () => {
22510
23426
  // Cancel any in-flight theme loads
@@ -22645,20 +23561,21 @@ const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme:
22645
23561
  setIsLoading(!1);
22646
23562
  }
22647
23563
  }
22648
- }), [ themes, isThemeLoaded, handleError, basePath, useMinified, cdnPath ]), themeManager = React.useMemo((() => ({})), []), availableThemes = React.useMemo((() => Object.entries(themes).map((([name, metadata]) => ({
23564
+ }), [ themes, isThemeLoaded, handleError, basePath, useMinified, cdnPath ]), updateTheme = React.useCallback((async (sectionOrTokens, values) => setTheme("string" == typeof sectionOrTokens && values ? values : sectionOrTokens)), [ setTheme ]), themeManager = React.useMemo((() => ({})), []), availableThemes = React.useMemo((() => Object.entries(themes).map((([name, metadata]) => ({
22649
23565
  ...metadata,
22650
23566
  name: name
22651
23567
  })))), [ themes ]), contextValue = React.useMemo((() => ({
22652
23568
  theme: currentTheme,
22653
23569
  activeTokens: activeTokens,
22654
23570
  setTheme: setTheme,
23571
+ updateTheme: updateTheme,
22655
23572
  availableThemes: availableThemes,
22656
23573
  isLoading: isLoading,
22657
23574
  error: error,
22658
23575
  isThemeLoaded: isThemeLoaded,
22659
23576
  preloadTheme: preloadTheme,
22660
23577
  themeManager: themeManager
22661
- })), [ currentTheme, activeTokens, setTheme, availableThemes,
23578
+ })), [ currentTheme, activeTokens, setTheme, updateTheme, availableThemes,
22662
23579
  // Use memoized value
22663
23580
  isLoading, error, isThemeLoaded, preloadTheme, themeManager ]);
22664
23581
  // Check if theme is loaded
@@ -22712,6 +23629,7 @@ function useTheme() {
22712
23629
  theme: context.theme,
22713
23630
  activeTokens: context.activeTokens,
22714
23631
  setTheme: context.setTheme,
23632
+ updateTheme: context.updateTheme,
22715
23633
  availableThemes: context.availableThemes,
22716
23634
  isLoading: context.isLoading,
22717
23635
  error: context.error,
@@ -22947,6 +23865,389 @@ function useThemeTokens() {
22947
23865
  }
22948
23866
  }
22949
23867
 
23868
+ /**
23869
+ * useThemeSwitcher Hook
23870
+ *
23871
+ * React hook for managing theme switching with persistence and system preference detection.
23872
+ * Provides an easy-to-use API for dark/light mode toggling.
23873
+ *
23874
+ * @example
23875
+ * ```tsx
23876
+ * import { useThemeSwitcher } from '@shohojdhara/atomix/theme';
23877
+ *
23878
+ * function ThemeToggle() {
23879
+ * const { mode, toggle, setMode, isDark } = useThemeSwitcher();
23880
+ *
23881
+ * return (
23882
+ * <button onClick={toggle}>
23883
+ * {isDark ? '☀️ Light' : '🌙 Dark'}
23884
+ * </button>
23885
+ * );
23886
+ * }
23887
+ * ```
23888
+ */
23889
+ /**
23890
+ * Hook for managing theme switching
23891
+ *
23892
+ * @param options - Configuration options
23893
+ * @returns Theme switcher controls
23894
+ */ function useThemeSwitcher(options = {}) {
23895
+ const {initialMode: initialMode = "system", syncWithSystem: syncWithSystem = !1, storageKey: storageKey = "atomix-theme", enableTransition: enableTransition = !0, transitionDuration: transitionDuration = 300} = options, [mode, setModeState] = React.useState((() => {
23896
+ if ("undefined" == typeof window) return initialMode;
23897
+ // Check for saved preference first
23898
+ const saved = getCurrentTheme(storageKey);
23899
+ return saved && "system" !== saved ? saved : "system" === initialMode ? getSystemTheme() : initialMode;
23900
+ // Fall back to initial mode or system
23901
+ }));
23902
+ // State for current mode
23903
+ // Initialize theme on mount
23904
+ return React.useEffect((() => {
23905
+ "undefined" != typeof window && (
23906
+ // Initialize with proper theme application
23907
+ initializeTheme({
23908
+ storageKey: storageKey,
23909
+ enableTransition: enableTransition,
23910
+ transitionDuration: transitionDuration
23911
+ }),
23912
+ // Update state to match initialized theme
23913
+ setModeState(getCurrentTheme(storageKey)));
23914
+ }), [ storageKey, enableTransition, transitionDuration ]),
23915
+ // Listen for system theme changes if enabled
23916
+ React.useEffect((() => {
23917
+ if (syncWithSystem) return listenToSystemTheme((newMode => {
23918
+ setModeState(newMode), switchTheme(newMode, {
23919
+ storageKey: storageKey,
23920
+ enableTransition: enableTransition,
23921
+ transitionDuration: transitionDuration
23922
+ });
23923
+ }));
23924
+ }), [ syncWithSystem, storageKey, enableTransition, transitionDuration ]), {
23925
+ mode: mode,
23926
+ isDark: "dark" === mode,
23927
+ isLight: "light" === mode,
23928
+ toggle: React.useCallback((() => {
23929
+ const newMode = toggleTheme({
23930
+ storageKey: storageKey,
23931
+ enableTransition: enableTransition,
23932
+ transitionDuration: transitionDuration
23933
+ });
23934
+ return setModeState(newMode), newMode;
23935
+ }), [ storageKey, enableTransition, transitionDuration ]),
23936
+ setMode: React.useCallback((newMode => {
23937
+ switchTheme(newMode, {
23938
+ storageKey: storageKey,
23939
+ enableTransition: enableTransition,
23940
+ transitionDuration: transitionDuration
23941
+ }), setModeState(newMode);
23942
+ }), [ storageKey, enableTransition, transitionDuration ]),
23943
+ resetToSystem: React.useCallback((() => {
23944
+ const systemMode = getSystemTheme();
23945
+ switchTheme(systemMode, {
23946
+ storageKey: storageKey,
23947
+ enableTransition: enableTransition,
23948
+ transitionDuration: transitionDuration
23949
+ }), setModeState(systemMode);
23950
+ }), [ storageKey, enableTransition, transitionDuration ]),
23951
+ clearPreference: React.useCallback((() => {
23952
+ "undefined" != typeof window && localStorage.removeItem(storageKey);
23953
+ }), [ storageKey ])
23954
+ };
23955
+ }
23956
+
23957
+ /**
23958
+ * ThemeToggle component with multiple variants
23959
+ */ const ThemeToggle = ({className: className = "", showLabel: showLabel = !1, lightLabel: lightLabel = "Light", darkLabel: darkLabel = "Dark", iconSize: iconSize = 20, variant: variant = "icon", render: render, ariaLabel: ariaLabel = "Toggle theme", ...hookOptions}) => {
23960
+ const {mode: mode, isDark: isDark, toggle: toggle} = useThemeSwitcher(hookOptions);
23961
+ // Custom render
23962
+ return render ? jsxRuntime.jsx(jsxRuntime.Fragment, {
23963
+ children: render({
23964
+ isDark: isDark,
23965
+ toggle: toggle,
23966
+ mode: mode
23967
+ })
23968
+ }) :
23969
+ // Icon-only variant (default)
23970
+ "icon" === variant ? jsxRuntime.jsx("button", {
23971
+ onClick: toggle,
23972
+ className: `theme-toggle theme-toggle-icon ${className}`,
23973
+ "aria-label": ariaLabel,
23974
+ title: isDark ? darkLabel : lightLabel,
23975
+ style: {
23976
+ background: "none",
23977
+ border: "none",
23978
+ cursor: "pointer",
23979
+ padding: "8px",
23980
+ borderRadius: "50%",
23981
+ display: "flex",
23982
+ alignItems: "center",
23983
+ justifyContent: "center",
23984
+ transition: "all 0.3s ease-in-out"
23985
+ },
23986
+ children: isDark ? jsxRuntime.jsxs("svg", {
23987
+ width: iconSize,
23988
+ height: iconSize,
23989
+ viewBox: "0 0 24 24",
23990
+ fill: "none",
23991
+ stroke: "currentColor",
23992
+ strokeWidth: "2",
23993
+ strokeLinecap: "round",
23994
+ strokeLinejoin: "round",
23995
+ children: [ jsxRuntime.jsx("circle", {
23996
+ cx: "12",
23997
+ cy: "12",
23998
+ r: "5"
23999
+ }), jsxRuntime.jsx("line", {
24000
+ x1: "12",
24001
+ y1: "1",
24002
+ x2: "12",
24003
+ y2: "3"
24004
+ }), jsxRuntime.jsx("line", {
24005
+ x1: "12",
24006
+ y1: "21",
24007
+ x2: "12",
24008
+ y2: "23"
24009
+ }), jsxRuntime.jsx("line", {
24010
+ x1: "4.22",
24011
+ y1: "4.22",
24012
+ x2: "5.64",
24013
+ y2: "5.64"
24014
+ }), jsxRuntime.jsx("line", {
24015
+ x1: "18.36",
24016
+ y1: "18.36",
24017
+ x2: "19.78",
24018
+ y2: "19.78"
24019
+ }), jsxRuntime.jsx("line", {
24020
+ x1: "1",
24021
+ y1: "12",
24022
+ x2: "3",
24023
+ y2: "12"
24024
+ }), jsxRuntime.jsx("line", {
24025
+ x1: "21",
24026
+ y1: "12",
24027
+ x2: "23",
24028
+ y2: "12"
24029
+ }), jsxRuntime.jsx("line", {
24030
+ x1: "4.22",
24031
+ y1: "19.78",
24032
+ x2: "5.64",
24033
+ y2: "18.36"
24034
+ }), jsxRuntime.jsx("line", {
24035
+ x1: "18.36",
24036
+ y1: "5.64",
24037
+ x2: "19.78",
24038
+ y2: "4.22"
24039
+ }) ]
24040
+ }) : jsxRuntime.jsx("svg", {
24041
+ width: iconSize,
24042
+ height: iconSize,
24043
+ viewBox: "0 0 24 24",
24044
+ fill: "none",
24045
+ stroke: "currentColor",
24046
+ strokeWidth: "2",
24047
+ strokeLinecap: "round",
24048
+ strokeLinejoin: "round",
24049
+ children: jsxRuntime.jsx("path", {
24050
+ d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
24051
+ })
24052
+ })
24053
+ }) :
24054
+ // Button variant with text
24055
+ "button" === variant ? jsxRuntime.jsxs("button", {
24056
+ onClick: toggle,
24057
+ className: `theme-toggle theme-toggle-button ${className}`,
24058
+ "aria-label": ariaLabel,
24059
+ style: {
24060
+ display: "flex",
24061
+ alignItems: "center",
24062
+ gap: "8px",
24063
+ padding: "8px 16px",
24064
+ borderRadius: "8px",
24065
+ border: "1px solid currentColor",
24066
+ background: "transparent",
24067
+ color: "inherit",
24068
+ cursor: "pointer",
24069
+ fontSize: "14px",
24070
+ fontWeight: "500",
24071
+ transition: "all 0.3s ease-in-out"
24072
+ },
24073
+ children: [ isDark ? jsxRuntime.jsxs("svg", {
24074
+ width: iconSize,
24075
+ height: iconSize,
24076
+ viewBox: "0 0 24 24",
24077
+ fill: "none",
24078
+ stroke: "currentColor",
24079
+ strokeWidth: "2",
24080
+ strokeLinecap: "round",
24081
+ strokeLinejoin: "round",
24082
+ children: [ jsxRuntime.jsx("circle", {
24083
+ cx: "12",
24084
+ cy: "12",
24085
+ r: "5"
24086
+ }), jsxRuntime.jsx("line", {
24087
+ x1: "12",
24088
+ y1: "1",
24089
+ x2: "12",
24090
+ y2: "3"
24091
+ }), jsxRuntime.jsx("line", {
24092
+ x1: "12",
24093
+ y1: "21",
24094
+ x2: "12",
24095
+ y2: "23"
24096
+ }), jsxRuntime.jsx("line", {
24097
+ x1: "4.22",
24098
+ y1: "4.22",
24099
+ x2: "5.64",
24100
+ y2: "5.64"
24101
+ }), jsxRuntime.jsx("line", {
24102
+ x1: "18.36",
24103
+ y1: "18.36",
24104
+ x2: "19.78",
24105
+ y2: "19.78"
24106
+ }), jsxRuntime.jsx("line", {
24107
+ x1: "1",
24108
+ y1: "12",
24109
+ x2: "3",
24110
+ y2: "12"
24111
+ }), jsxRuntime.jsx("line", {
24112
+ x1: "21",
24113
+ y1: "12",
24114
+ x2: "23",
24115
+ y2: "12"
24116
+ }), jsxRuntime.jsx("line", {
24117
+ x1: "4.22",
24118
+ y1: "19.78",
24119
+ x2: "5.64",
24120
+ y2: "18.36"
24121
+ }), jsxRuntime.jsx("line", {
24122
+ x1: "18.36",
24123
+ y1: "5.64",
24124
+ x2: "19.78",
24125
+ y2: "4.22"
24126
+ }) ]
24127
+ }) : jsxRuntime.jsx("svg", {
24128
+ width: iconSize,
24129
+ height: iconSize,
24130
+ viewBox: "0 0 24 24",
24131
+ fill: "none",
24132
+ stroke: "currentColor",
24133
+ strokeWidth: "2",
24134
+ strokeLinecap: "round",
24135
+ strokeLinejoin: "round",
24136
+ children: jsxRuntime.jsx("path", {
24137
+ d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
24138
+ })
24139
+ }), showLabel && jsxRuntime.jsx("span", {
24140
+ children: isDark ? darkLabel : lightLabel
24141
+ }) ]
24142
+ }) :
24143
+ // Switch/toggle variant
24144
+ "switch" === variant ? jsxRuntime.jsx("div", {
24145
+ className: `theme-toggle theme-toggle-switch ${className}`,
24146
+ role: "button",
24147
+ tabIndex: 0,
24148
+ onClick: toggle,
24149
+ onKeyDown: e => "Enter" === e.key && toggle(),
24150
+ "aria-label": ariaLabel,
24151
+ style: {
24152
+ position: "relative",
24153
+ width: "56px",
24154
+ height: "28px",
24155
+ borderRadius: "14px",
24156
+ background: isDark ? "#4b5563" : "#d1d5db",
24157
+ cursor: "pointer",
24158
+ transition: "background 0.3s ease-in-out",
24159
+ display: "flex",
24160
+ alignItems: "center",
24161
+ padding: "2px"
24162
+ },
24163
+ children: jsxRuntime.jsx("div", {
24164
+ style: {
24165
+ position: "absolute",
24166
+ left: isDark ? "auto" : "2px",
24167
+ right: isDark ? "2px" : "auto",
24168
+ width: "24px",
24169
+ height: "24px",
24170
+ borderRadius: "50%",
24171
+ background: "white",
24172
+ boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)",
24173
+ transition: "all 0.3s ease-in-out",
24174
+ display: "flex",
24175
+ alignItems: "center",
24176
+ justifyContent: "center"
24177
+ },
24178
+ children: isDark ? jsxRuntime.jsx("svg", {
24179
+ width: "14",
24180
+ height: "14",
24181
+ viewBox: "0 0 24 24",
24182
+ fill: "none",
24183
+ stroke: "#4b5563",
24184
+ strokeWidth: "2",
24185
+ strokeLinecap: "round",
24186
+ strokeLinejoin: "round",
24187
+ children: jsxRuntime.jsx("path", {
24188
+ d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
24189
+ })
24190
+ }) : jsxRuntime.jsxs("svg", {
24191
+ width: "14",
24192
+ height: "14",
24193
+ viewBox: "0 0 24 24",
24194
+ fill: "none",
24195
+ stroke: "#f59e0b",
24196
+ strokeWidth: "2",
24197
+ strokeLinecap: "round",
24198
+ strokeLinejoin: "round",
24199
+ children: [ jsxRuntime.jsx("circle", {
24200
+ cx: "12",
24201
+ cy: "12",
24202
+ r: "5"
24203
+ }), jsxRuntime.jsx("line", {
24204
+ x1: "12",
24205
+ y1: "1",
24206
+ x2: "12",
24207
+ y2: "3"
24208
+ }), jsxRuntime.jsx("line", {
24209
+ x1: "12",
24210
+ y1: "21",
24211
+ x2: "12",
24212
+ y2: "23"
24213
+ }), jsxRuntime.jsx("line", {
24214
+ x1: "4.22",
24215
+ y1: "4.22",
24216
+ x2: "5.64",
24217
+ y2: "5.64"
24218
+ }), jsxRuntime.jsx("line", {
24219
+ x1: "18.36",
24220
+ y1: "18.36",
24221
+ x2: "19.78",
24222
+ y2: "19.78"
24223
+ }), jsxRuntime.jsx("line", {
24224
+ x1: "1",
24225
+ y1: "12",
24226
+ x2: "3",
24227
+ y2: "12"
24228
+ }), jsxRuntime.jsx("line", {
24229
+ x1: "21",
24230
+ y1: "12",
24231
+ x2: "23",
24232
+ y2: "12"
24233
+ }), jsxRuntime.jsx("line", {
24234
+ x1: "4.22",
24235
+ y1: "19.78",
24236
+ x2: "5.64",
24237
+ y2: "18.36"
24238
+ }), jsxRuntime.jsx("line", {
24239
+ x1: "18.36",
24240
+ y1: "5.64",
24241
+ x2: "19.78",
24242
+ y2: "4.22"
24243
+ }) ]
24244
+ })
24245
+ })
24246
+ }) : null;
24247
+ };
24248
+
24249
+ ThemeToggle.displayName = "ThemeToggle";
24250
+
22950
24251
  /**
22951
24252
  * Theme Applicator
22952
24253
  *
@@ -22959,7 +24260,8 @@ function useThemeTokens() {
22959
24260
  * Theme applicator class for runtime theme application
22960
24261
  *
22961
24262
  * Uses the unified theme system for efficient CSS variable generation and injection.
22962
- */ class ThemeApplicator {
24263
+ */
24264
+ class ThemeApplicator {
22963
24265
  constructor(root = document.documentElement) {
22964
24266
  this.styleId = "atomix-theme-applicator", this.root = root;
22965
24267
  }
@@ -24698,13 +26000,13 @@ class ThemeValidator {
24698
26000
  function createPaletteColor(color) {
24699
26001
  return "string" == typeof color ? {
24700
26002
  main: color,
24701
- light: lighten(color),
24702
- dark: darken(color),
26003
+ light: lighten(color, .15),
26004
+ dark: darken(color, .15),
24703
26005
  contrastText: getContrastText(color)
24704
26006
  } : {
24705
26007
  main: color.main || "#000000",
24706
- light: color.light || lighten(color.main || "#000000"),
24707
- dark: color.dark || darken(color.main || "#000000"),
26008
+ light: color.light || lighten(color.main || "#000000", .15),
26009
+ dark: color.dark || darken(color.main || "#000000", .15),
24708
26010
  contrastText: color.contrastText || getContrastText(color.main || "#000000")
24709
26011
  };
24710
26012
  }
@@ -24739,23 +26041,19 @@ function createThemeObject(...options) {
24739
26041
  },
24740
26042
  background: {
24741
26043
  default: mergedOptions.palette?.background?.default || DEFAULT_PALETTE.background.default,
26044
+ paper: mergedOptions.palette?.background?.paper || DEFAULT_PALETTE.background.paper,
24742
26045
  subtle: mergedOptions.palette?.background?.subtle || DEFAULT_PALETTE.background.subtle
24743
26046
  },
24744
26047
  text: {
24745
26048
  primary: mergedOptions.palette?.text?.primary || DEFAULT_PALETTE.text.primary,
24746
26049
  secondary: mergedOptions.palette?.text?.secondary || DEFAULT_PALETTE.text.secondary,
24747
26050
  disabled: mergedOptions.palette?.text?.disabled || DEFAULT_PALETTE.text.disabled
24748
- }
26051
+ },
26052
+ // Spread other palette properties
26053
+ ...mergedOptions.palette
24749
26054
  }, typography = deepMerge({
24750
26055
  ...DEFAULT_TYPOGRAPHY
24751
- }, mergedOptions.typography || {}), spacing = function(spacingInput = 4) {
24752
- // If it's already a function, return it
24753
- return "function" == typeof spacingInput ? spacingInput :
24754
- // If it's a number, create a function that multiplies by that number
24755
- "number" == typeof spacingInput ? (...values) => 0 === values.length ? "0px" : values.map((value => value * spacingInput + "px")).join(" ") :
24756
- // If it's an array, use it as a scale
24757
- Array.isArray(spacingInput) ? (...values) => 0 === values.length ? "0px" : values.map((value => `${spacingInput[value] || value}px`)).join(" ") : (...values) => 0 === values.length ? "0px" : values.map((value => 4 * value + "px")).join(" ");
24758
- }(mergedOptions.spacing), breakpoints = function(breakpointsInput) {
26056
+ }, mergedOptions.typography || {}), spacing = createSpacing(mergedOptions.spacing), breakpoints = function(breakpointsInput) {
24759
26057
  const values = {
24760
26058
  xs: 0,
24761
26059
  sm: 576,
@@ -25577,25 +26875,7 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
25577
26875
 
25578
26876
  /**
25579
26877
  * Design Tokens Customizer Component
25580
- */
25581
- /**
25582
- * Theme Adapter
25583
- *
25584
- * Converts between Theme objects and DesignTokens.
25585
- */
25586
- /**
25587
- * Convert DesignTokens to Theme-compatible CSS variables
25588
- *
25589
- * @param tokens - DesignTokens object
25590
- * @returns CSS variables object compatible with Theme.cssVars
25591
- */
25592
- function designTokensToCSSVars(tokens) {
25593
- const cssVars = {};
25594
- return Object.entries(tokens).forEach((([key, value]) => {
25595
- void 0 !== value && (cssVars[`--atomix-${key}`] = String(value));
25596
- })), cssVars;
25597
- }
25598
-
26878
+ */
25599
26879
  /**
25600
26880
  * Theme Helper Functions
25601
26881
  *
@@ -25608,7 +26888,8 @@ function designTokensToCSSVars(tokens) {
25608
26888
  *
25609
26889
  * @param value - Value to check
25610
26890
  * @returns True if value is DesignTokens
25611
- */ function isDesignTokens(value) {
26891
+ */
26892
+ function isDesignTokens(value) {
25612
26893
  if (!value || "object" != typeof value) return !1;
25613
26894
  // DesignTokens is a flat object with string keys, no nested structures
25614
26895
  const obj = value;
@@ -25620,6 +26901,335 @@ function designTokensToCSSVars(tokens) {
25620
26901
  // Check if keys look like DesignTokens (kebab-case, no nesting)
25621
26902
  }
25622
26903
 
26904
+ /**
26905
+ * Performance monitor class
26906
+ */ class PerformanceMonitor {
26907
+ /**
26908
+ * Create a new performance monitor
26909
+ *
26910
+ * @param config Configuration options
26911
+ */
26912
+ constructor(config) {
26913
+ this.frameCount = 0, this.lastSampleTime = 0, this.lastFpsUpdate = 0, this.frameTimes = [],
26914
+ this.animationFrameId = null, this.isActive = !1, this.startTime = 0, this.config = {
26915
+ fpsTarget: config?.fpsTarget ?? 60,
26916
+ sampleInterval: config?.sampleInterval ?? 500,
26917
+ onUpdate: config?.onUpdate ?? (() => {}),
26918
+ onDegraded: config?.onDegraded ?? (() => {}),
26919
+ enableMemoryMonitoring: config?.enableMemoryMonitoring ?? ("undefined" != typeof window && window.performance && window.performance.memory)
26920
+ };
26921
+ }
26922
+ /**
26923
+ * Start monitoring performance
26924
+ */ start() {
26925
+ this.isActive || (this.isActive = !0, this.frameCount = 0, this.lastSampleTime = performance.now(),
26926
+ this.lastFpsUpdate = this.lastSampleTime, this.frameTimes = [], this.startTime = this.lastSampleTime,
26927
+ this.animationFrameId = requestAnimationFrame(this.onFrame.bind(this)));
26928
+ }
26929
+ /**
26930
+ * Stop monitoring performance
26931
+ */ stop() {
26932
+ this.animationFrameId && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null),
26933
+ this.isActive = !1;
26934
+ }
26935
+ /**
26936
+ * Get current performance metrics
26937
+ */ getMetrics() {
26938
+ var _context;
26939
+ const now = performance.now(), elapsed = now - this.lastFpsUpdate, fps = elapsed > 0 ? Math.round(this.frameCount / elapsed * 1e3) : 0, avgFrameTime = this.frameTimes.length > 0 ? _reduceInstanceProperty(_context = this.frameTimes).call(_context, ((a, b) => a + b), 0) / this.frameTimes.length : 0, peakFrameTime = this.frameTimes.length > 0 ? Math.max(...this.frameTimes) : 0;
26940
+ // Get memory stats if available
26941
+ let memory;
26942
+ if (this.config.enableMemoryMonitoring) {
26943
+ const perf = window.performance;
26944
+ perf && perf.memory && (memory = {
26945
+ usedJSHeapSize: perf.memory.usedJSHeapSize,
26946
+ totalJSHeapSize: perf.memory.totalJSHeapSize,
26947
+ jsHeapSizeLimit: perf.memory.jsHeapSizeLimit
26948
+ });
26949
+ }
26950
+ return {
26951
+ fps: fps,
26952
+ frameTime: avgFrameTime,
26953
+ peakFrameTime: peakFrameTime,
26954
+ memory: memory,
26955
+ timestamp: now,
26956
+ isDegraded: fps < .7 * this.config.fpsTarget
26957
+ };
26958
+ }
26959
+ /**
26960
+ * Get the current FPS
26961
+ */ getFps() {
26962
+ return this.getMetrics().fps;
26963
+ }
26964
+ /**
26965
+ * Check if performance is degraded
26966
+ */ isPerformanceDegraded() {
26967
+ return this.getMetrics().isDegraded;
26968
+ }
26969
+ /**
26970
+ * Private method called on each animation frame
26971
+ */ onFrame(timestamp) {
26972
+ if (!this.isActive) return;
26973
+ // Calculate frame time
26974
+ const frameTime = timestamp - this.lastSampleTime;
26975
+ // Check if we need to update metrics
26976
+ if (this.frameTimes.push(frameTime),
26977
+ // Keep only the last 60 frame times for averaging
26978
+ this.frameTimes.length > 60 && this.frameTimes.shift(), this.frameCount++, this.lastSampleTime = timestamp,
26979
+ timestamp - this.lastFpsUpdate >= this.config.sampleInterval) {
26980
+ const metrics = this.getMetrics();
26981
+ // Call update callback
26982
+ this.config.onUpdate(metrics),
26983
+ // Check for degradation
26984
+ metrics.isDegraded && this.config.onDegraded(metrics),
26985
+ // Reset counters
26986
+ this.frameCount = 0, this.lastFpsUpdate = timestamp;
26987
+ }
26988
+ this.animationFrameId = requestAnimationFrame(this.onFrame.bind(this));
26989
+ }
26990
+ /**
26991
+ * Run a performance test for a specific function
26992
+ *
26993
+ * @param fn Function to test
26994
+ * @param iterations Number of iterations (default: 100)
26995
+ * @returns Average execution time in ms
26996
+ */ async testFunctionPerformance(fn, iterations = 100) {
26997
+ const times = [];
26998
+ for (let i = 0; i < iterations; i++) {
26999
+ const start = performance.now();
27000
+ fn();
27001
+ const end = performance.now();
27002
+ times.push(end - start);
27003
+ }
27004
+ return _reduceInstanceProperty(times).call(times, ((a, b) => a + b), 0) / times.length;
27005
+ }
27006
+ }
27007
+
27008
+ /**
27009
+ * Create a performance monitor instance
27010
+ *
27011
+ * @param config Configuration options
27012
+ * @returns PerformanceMonitor instance
27013
+ *
27014
+ * @example
27015
+ * ```typescript
27016
+ * import { createPerformanceMonitor } from '@shohojdhara/atomix/theme';
27017
+ *
27018
+ * const monitor = createPerformanceMonitor({
27019
+ * fpsTarget: 60,
27020
+ * onUpdate: (metrics) => console.log('FPS:', metrics.fps),
27021
+ * onDegraded: (metrics) => console.warn('Performance degraded!', metrics),
27022
+ * });
27023
+ *
27024
+ * monitor.start();
27025
+ *
27026
+ * // Later...
27027
+ * monitor.stop();
27028
+ * ```
27029
+ */ function createPerformanceMonitor(config) {
27030
+ return new PerformanceMonitor(config);
27031
+ }
27032
+
27033
+ /**
27034
+ * Hook for React components to monitor performance
27035
+ *
27036
+ * @param config Configuration options
27037
+ * @returns Performance metrics and monitor controls
27038
+ *
27039
+ * @example
27040
+ * ```typescript
27041
+ * import { usePerformanceMonitor } from '@shohojdhara/atomix/theme';
27042
+ *
27043
+ * function MyComponent() {
27044
+ * const { metrics, start, stop } = usePerformanceMonitor({ fpsTarget: 60 });
27045
+ *
27046
+ * useEffect(() => {
27047
+ * start();
27048
+ * return () => stop();
27049
+ * }, []);
27050
+ *
27051
+ * return <div>FPS: {metrics.fps}</div>;
27052
+ * }
27053
+ * ```
27054
+ */ function usePerformanceMonitor(config) {
27055
+ const [monitor] = React__default.default.useState((() => createPerformanceMonitor(config))), [metrics, setMetrics] = React__default.default.useState((() => "undefined" != typeof window ? monitor.getMetrics() : {
27056
+ fps: 0,
27057
+ frameTime: 0,
27058
+ peakFrameTime: 0,
27059
+ timestamp: 0,
27060
+ isDegraded: !1
27061
+ })), start = React__default.default.useCallback((() => {
27062
+ "undefined" != typeof window && monitor.start();
27063
+ }), [ monitor ]), stop = React__default.default.useCallback((() => {
27064
+ "undefined" != typeof window && monitor.stop();
27065
+ }), [ monitor ]);
27066
+ return React__default.default.useEffect((() => {
27067
+ if ("undefined" == typeof window) return;
27068
+ // Update metrics when monitor callbacks fire
27069
+ const originalOnUpdate = config?.onUpdate;
27070
+ return monitor.config.onUpdate = newMetrics => {
27071
+ setMetrics(newMetrics), originalOnUpdate?.(newMetrics);
27072
+ }, () => {
27073
+ monitor.stop();
27074
+ };
27075
+ }), [ monitor, config?.onUpdate ]), {
27076
+ metrics: metrics,
27077
+ start: start,
27078
+ stop: stop
27079
+ };
27080
+ }
27081
+
27082
+ /**
27083
+ * Responsive Utility for Atomix Theme System
27084
+ *
27085
+ * Provides responsive breakpoint detection and device-aware parameter scaling
27086
+ * based on configuration from the advanced optimization features.
27087
+ */
27088
+ /**
27089
+ * Responsive utility class
27090
+ */ class ResponsiveUtil {
27091
+ constructor(config) {
27092
+ this.currentDevice = "desktop", // Default
27093
+ this.resizeHandler = null, this.observer = null, this.config = config, this.currentDevice = this.getCurrentDeviceType(),
27094
+ // Set up resize listener
27095
+ this.setupResizeListener();
27096
+ }
27097
+ /**
27098
+ * Get the current device type based on viewport width
27099
+ */ getCurrentDeviceType() {
27100
+ if ("undefined" == typeof window) return "desktop";
27101
+ // SSR fallback
27102
+ const width = window.innerWidth;
27103
+ // Parse breakpoint values to numbers
27104
+ this.parsePxValue(this.config.breakpoints.mobile);
27105
+ const tabletWidth = this.parsePxValue(this.config.breakpoints.tablet), desktopWidth = this.parsePxValue(this.config.breakpoints.desktop), wideWidth = this.parsePxValue(this.config.breakpoints.wide);
27106
+ return width < tabletWidth ? "mobile" : width < desktopWidth ? "tablet" : width < wideWidth ? "desktop" : "wide";
27107
+ }
27108
+ /**
27109
+ * Get the scaling factor for the current device
27110
+ */ getCurrentScalingFactor() {
27111
+ // 'wide' devices use the same scaling as 'desktop'
27112
+ const scalingKey = "wide" === this.currentDevice ? "desktop" : this.currentDevice;
27113
+ return this.config.deviceScaling[scalingKey] || 1;
27114
+ }
27115
+ /**
27116
+ * Scale a value based on the current device's scaling factor
27117
+ */ scaleValue(value) {
27118
+ return value * this.getCurrentScalingFactor();
27119
+ }
27120
+ /**
27121
+ * Check if the current device matches a specific type
27122
+ */ isDevice(device) {
27123
+ return this.currentDevice === device;
27124
+ }
27125
+ /**
27126
+ * Check if the current device is mobile or smaller
27127
+ */ isMobileOrSmaller() {
27128
+ return "mobile" === this.currentDevice;
27129
+ }
27130
+ /**
27131
+ * Check if the current device is tablet or smaller
27132
+ */ isTabletOrSmaller() {
27133
+ return "mobile" === this.currentDevice || "tablet" === this.currentDevice;
27134
+ }
27135
+ /**
27136
+ * Check if the current device is desktop or larger
27137
+ */ isDesktopOrLarger() {
27138
+ return "desktop" === this.currentDevice || "wide" === this.currentDevice;
27139
+ }
27140
+ /**
27141
+ * Update the responsive configuration
27142
+ */ updateConfig(config) {
27143
+ this.config = config, this.currentDevice = this.getCurrentDeviceType();
27144
+ }
27145
+ /**
27146
+ * Destroy the responsive utility and clean up listeners
27147
+ */ destroy() {
27148
+ this.resizeHandler && (window.removeEventListener("resize", this.resizeHandler),
27149
+ this.resizeHandler = null), this.observer && (this.observer.disconnect(), this.observer = null);
27150
+ }
27151
+ /**
27152
+ * Parse a CSS value to pixels
27153
+ */ parsePxValue(value) {
27154
+ return value.endsWith("px") ? parseFloat(value.slice(0, -2)) :
27155
+ // For other units, we'll use a rough conversion assuming 16px base
27156
+ value.endsWith("rem") ? 16 * parseFloat(value.slice(0, -3)) : value.endsWith("em") ? 16 * parseFloat(value.slice(0, -2)) : parseFloat(value) || 0;
27157
+ }
27158
+ /**
27159
+ * Set up the resize listener
27160
+ */ setupResizeListener() {
27161
+ if ("undefined" == typeof window) return;
27162
+ // Throttled resize handler
27163
+ let resizeTimeout = null;
27164
+ const handleResize = () => {
27165
+ resizeTimeout && window.clearTimeout(resizeTimeout), resizeTimeout = window.setTimeout((() => {
27166
+ const newDeviceType = this.getCurrentDeviceType();
27167
+ newDeviceType !== this.currentDevice && (this.currentDevice = newDeviceType);
27168
+ }), 150);
27169
+ } // Throttle to 150ms
27170
+ ;
27171
+ this.resizeHandler = handleResize, window.addEventListener("resize", handleResize),
27172
+ // Also observe the document body for size changes
27173
+ "undefined" != typeof ResizeObserver && (this.observer = new ResizeObserver(handleResize),
27174
+ this.observer.observe(document.body));
27175
+ }
27176
+ }
27177
+
27178
+ /**
27179
+ * Create a responsive utility instance
27180
+ *
27181
+ * @param config Responsive configuration
27182
+ * @returns ResponsiveUtil instance
27183
+ */ function createResponsiveUtil(config) {
27184
+ return new ResponsiveUtil(config);
27185
+ }
27186
+
27187
+ /**
27188
+ * Hook for React components to use responsive features
27189
+ *
27190
+ * @param config Responsive configuration
27191
+ * @returns Current device type and utility functions
27192
+ */ function useResponsive(config) {
27193
+ const [util] = React__default.default.useState((() => createResponsiveUtil(config))), [deviceType, setDeviceType] = React__default.default.useState((() => "undefined" != typeof window ? util.getCurrentDeviceType() : "desktop"));
27194
+ return React__default.default.useEffect((() => {
27195
+ if ("undefined" == typeof window) return;
27196
+ const handleResize = () => {
27197
+ const newDeviceType = util.getCurrentDeviceType();
27198
+ newDeviceType !== deviceType && setDeviceType(newDeviceType);
27199
+ };
27200
+ // Update device type on mount
27201
+ return setDeviceType(util.getCurrentDeviceType()),
27202
+ // Listen for resize events
27203
+ window.addEventListener("resize", handleResize), () => {
27204
+ window.removeEventListener("resize", handleResize), util.destroy();
27205
+ };
27206
+ }), [ util, deviceType ]), "undefined" == typeof window ? {
27207
+ deviceType: "desktop",
27208
+ isMobile: !1,
27209
+ isTablet: !1,
27210
+ isDesktop: !0,
27211
+ isWide: !1,
27212
+ scaleValue: value => value,
27213
+ getCurrentDeviceType: () => "desktop",
27214
+ getCurrentScalingFactor: () => 1,
27215
+ isMobileOrSmaller: () => !1,
27216
+ isTabletOrSmaller: () => !0,
27217
+ isDesktopOrLarger: () => !0
27218
+ } : {
27219
+ deviceType: deviceType,
27220
+ isMobile: "mobile" === deviceType,
27221
+ isTablet: "tablet" === deviceType,
27222
+ isDesktop: "desktop" === deviceType,
27223
+ isWide: "wide" === deviceType,
27224
+ scaleValue: value => util.scaleValue(value),
27225
+ getCurrentDeviceType: () => util.getCurrentDeviceType(),
27226
+ getCurrentScalingFactor: () => util.getCurrentScalingFactor(),
27227
+ isMobileOrSmaller: () => util.isMobileOrSmaller(),
27228
+ isTabletOrSmaller: () => util.isTabletOrSmaller(),
27229
+ isDesktopOrLarger: () => util.isDesktopOrLarger()
27230
+ };
27231
+ }
27232
+
25623
27233
  /**
25624
27234
  * RTL (Right-to-Left) Support Utilities
25625
27235
  *
@@ -25805,6 +27415,32 @@ class RTLManager {
25805
27415
  }
25806
27416
  }
25807
27417
 
27418
+ /**
27419
+ * Create RTL manager instance
27420
+ */ function createRTLManager(config) {
27421
+ return new RTLManager(config);
27422
+ }
27423
+
27424
+ /**
27425
+ * Check if locale is RTL
27426
+ */ function isRTLLocale(locale) {
27427
+ return RTL_LOCALES.has(locale.toLowerCase());
27428
+ }
27429
+
27430
+ /**
27431
+ * Get direction from locale
27432
+ */ function getDirectionFromLocale(locale) {
27433
+ return isRTLLocale(locale) ? "rtl" : "ltr";
27434
+ }
27435
+
27436
+ /**
27437
+ * RTL-aware CSS helper
27438
+ *
27439
+ * Returns appropriate CSS based on direction
27440
+ */ function rtlCSS(ltrCSS, rtlCSS, direction = "ltr") {
27441
+ return "rtl" === direction ? rtlCSS : ltrCSS;
27442
+ }
27443
+
25808
27444
  /**
25809
27445
  * Theme System Exports
25810
27446
  *
@@ -25827,8 +27463,6 @@ class RTLManager {
25827
27463
  // ============================================================================
25828
27464
  // Core Theme Functions
25829
27465
  // ============================================================================
25830
- // Create theme CSS from DesignTokens
25831
- // File saving utilities removed to prevent bundling Node.js modules in browser
25832
27466
  /**
25833
27467
  * Inject theme CSS into DOM
25834
27468
  */ function injectTheme(css, id = "atomix-theme") {
@@ -25841,6 +27475,115 @@ class RTLManager {
25841
27475
  removeCSS(id);
25842
27476
  }
25843
27477
 
27478
+ /**
27479
+ * Main theme module interface
27480
+ */ var index = {
27481
+ // Core
27482
+ createTheme: createTheme,
27483
+ injectTheme: injectTheme,
27484
+ removeTheme: removeTheme,
27485
+ // Context and Provider
27486
+ ThemeProvider: ThemeProvider,
27487
+ useTheme: useTheme,
27488
+ useThemeTokens: useThemeTokens,
27489
+ ThemeContext: ThemeContext,
27490
+ ThemeErrorBoundary: ThemeErrorBoundary,
27491
+ // Adapters
27492
+ configToTokens: configToTokens,
27493
+ designTokensToCSSVars: designTokensToCSSVars,
27494
+ // Theme Utils
27495
+ switchTheme: switchTheme,
27496
+ toggleTheme: toggleTheme,
27497
+ getCurrentTheme: getCurrentTheme,
27498
+ getSystemTheme: getSystemTheme,
27499
+ initializeTheme: initializeTheme,
27500
+ listenToSystemTheme: listenToSystemTheme,
27501
+ persistTheme: persistTheme,
27502
+ clearThemePreference: clearThemePreference,
27503
+ // Token Manipulation
27504
+ mergeTokens: mergeTokens,
27505
+ overrideTokens: overrideTokens,
27506
+ pickTokens: pickTokens,
27507
+ omitTokens: omitTokens,
27508
+ // Color Utilities
27509
+ hexToRgb: hexToRgb$1,
27510
+ rgbToHex: rgbToHex,
27511
+ getLuminance: getLuminance,
27512
+ getContrastRatio: getContrastRatio,
27513
+ isAccessible: isAccessible,
27514
+ getContrastText: getContrastText,
27515
+ lighten: lighten,
27516
+ darken: darken,
27517
+ alpha: alpha,
27518
+ emphasize: emphasize,
27519
+ createSpacing: createSpacing,
27520
+ // Performance utilities
27521
+ createPerformanceMonitor: createPerformanceMonitor,
27522
+ usePerformanceMonitor: usePerformanceMonitor,
27523
+ // Responsive utilities
27524
+ createResponsiveUtil: createResponsiveUtil,
27525
+ useResponsive: useResponsive,
27526
+ // Components
27527
+ ThemeToggle: ThemeToggle,
27528
+ ThemeApplicator: ThemeApplicator,
27529
+ applyTheme: applyTheme,
27530
+ getThemeApplicator: getThemeApplicator,
27531
+ // Registry
27532
+ createThemeRegistry: createThemeRegistry,
27533
+ registerTheme: registerTheme,
27534
+ unregisterTheme: unregisterTheme,
27535
+ hasTheme: hasTheme,
27536
+ getTheme: getTheme,
27537
+ getAllThemes: getAllThemes,
27538
+ getThemeIds: getThemeIds,
27539
+ clearThemes: clearThemes,
27540
+ getThemeCount: getThemeCount,
27541
+ // Composition
27542
+ deepMerge: deepMerge,
27543
+ mergeTheme: mergeTheme,
27544
+ extendTheme: extendTheme,
27545
+ // Tokens
27546
+ createTokens: createTokens,
27547
+ defaultTokens: defaultTokens,
27548
+ // Generators
27549
+ generateCSSVariables: generateCSSVariables$1,
27550
+ generateCSSVariablesForSelector: generateCSSVariablesForSelector,
27551
+ // Naming
27552
+ generateClassName: generateClassName,
27553
+ generateCSSVariableName: generateCSSVariableName,
27554
+ normalizeThemeTokens: normalizeThemeTokens,
27555
+ camelToKebab: camelToKebab,
27556
+ themePropertyToCSSVar: themePropertyToCSSVar,
27557
+ // Component Theming
27558
+ getComponentThemeValue: getComponentThemeValue,
27559
+ generateComponentCSSVars: generateComponentCSSVars,
27560
+ applyComponentTheme: applyComponentTheme,
27561
+ useComponentTheme: useComponentTheme,
27562
+ // Hooks
27563
+ useThemeSwitcher: useThemeSwitcher,
27564
+ // Helpers
27565
+ isDesignTokens: isDesignTokens,
27566
+ // CSS Variable Mapper
27567
+ mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
27568
+ applyCSSVariables: applyCSSVariables,
27569
+ removeCSSVariables: removeCSSVariables,
27570
+ getCSSVariable: getCSSVariable,
27571
+ cssVarsToStyle: cssVarsToStyle,
27572
+ mergeCSSVars: mergeCSSVars,
27573
+ isValidCSSVariableName: isValidCSSVariableName,
27574
+ extractComponentName: extractComponentName,
27575
+ // Injection Utils
27576
+ injectCSS: injectCSS$1,
27577
+ removeCSS: removeCSS,
27578
+ isCSSInjected: isCSSInjected,
27579
+ // I18n
27580
+ RTLManager: RTLManager,
27581
+ createRTLManager: createRTLManager,
27582
+ isRTLLocale: isRTLLocale,
27583
+ getDirectionFromLocale: getDirectionFromLocale,
27584
+ rtlCSS: rtlCSS
27585
+ };
27586
+
25844
27587
  /**
25845
27588
  * CSS Variables Constants
25846
27589
  *
@@ -26147,6 +27890,122 @@ function mergePartStyles(base, override) {
26147
27890
  * );
26148
27891
  * }
26149
27892
  */
27893
+ /**
27894
+ * Configuration Validator
27895
+ *
27896
+ * Provides detailed validation and feedback for Atomix configurations,
27897
+ * especially for advanced features (Phases 2, 3, and 4).
27898
+ */
27899
+ /**
27900
+ * Validate an Atomix configuration with detailed feedback
27901
+ *
27902
+ * @param config - The configuration to validate
27903
+ * @param options - Validation options
27904
+ * @returns Detailed validation result
27905
+ *
27906
+ * @example
27907
+ * ```typescript
27908
+ * import { validateConfiguration } from '@shohojdhara/atomix/config';
27909
+ *
27910
+ * const config = { /* your config *\/ };
27911
+ * const result = validateConfiguration(config);
27912
+ *
27913
+ * if (!result.isValid) {
27914
+ * console.warn('Warnings:', result.warnings);
27915
+ * console.info('Suggestions:', result.suggestions);
27916
+ * }
27917
+ * ```
27918
+ */
27919
+ function validateConfiguration(config, options) {
27920
+ const {performanceAnalysis: performanceAnalysis = !0, compatibilityReport: compatibilityReport = !0} = options || {}, warnings = [], suggestions = [];
27921
+ let performanceImpact = "low";
27922
+ // Use the existing validation
27923
+ const baseWarnings = validateConfig$1(config);
27924
+ warnings.push(...baseWarnings),
27925
+ // Analyze advanced features for performance impact
27926
+ performanceAnalysis && (performanceImpact =
27927
+ /**
27928
+ * Analyze the performance impact of a configuration
27929
+ */
27930
+ function(config) {
27931
+ let impactScore = 0;
27932
+ // Analyze interactive effects
27933
+ if (config.interactiveEffects) {
27934
+ const ie = config.interactiveEffects;
27935
+ ie.vortex?.enabled && (impactScore += 2), ie.chromaticAberration?.enabled && (impactScore += 1),
27936
+ ie.mouseInteraction?.trailEffect && (impactScore += 1), ie.mouseInteraction?.pressureSensitivity && (impactScore += 1);
27937
+ }
27938
+ // Analyze visual polish effects
27939
+ if (config.visualPolish) {
27940
+ const vp = config.visualPolish;
27941
+ vp.borders?.iridescentGlow && (impactScore += 1), vp.borders?.shimmerEffect && (impactScore += 1),
27942
+ vp.contentAwareBlur?.enabled && (impactScore += 2), vp.holographicEffects?.enabled && (impactScore += 2),
27943
+ vp.holographicEffects?.scanlineAnimation && (impactScore += 1), vp.holographicEffects?.dataStream && (impactScore += 1),
27944
+ vp.holographicEffects?.pulseRings && (impactScore += 1);
27945
+ }
27946
+ // Analyze optimization settings
27947
+ return config.optimization?.autoScaling?.enabled && (impactScore -= 1),
27948
+ impactScore >= 6 ? "high" : impactScore >= 3 ? "medium" : "low";
27949
+ }
27950
+ /**
27951
+ * Generate suggestions based on the configuration
27952
+ */ (config)),
27953
+ // Generate suggestions based on configuration
27954
+ function(config, suggestions) {
27955
+ // Suggest enabling performance optimizations if heavy effects are used
27956
+ (config.interactiveEffects || config.visualPolish?.holographicEffects?.enabled) && (config.optimization?.autoScaling?.enabled || suggestions.push("Consider enabling auto-scaling in optimization settings to adjust effects based on device performance: optimization.autoScaling.enabled = true"),
27957
+ config.optimization?.performance?.fpsTarget || suggestions.push("Set a target FPS in optimization.performance.fpsTarget to ensure smooth performance when using interactive effects")),
27958
+ // Suggest responsive breakpoints if optimization is partially configured
27959
+ config.optimization && !config.optimization.responsive && suggestions.push("Consider adding responsive breakpoints in optimization.responsive.breakpoints to adapt advanced effects based on device type"),
27960
+ // Suggest disabling heavy effects on lower-end devices
27961
+ config.visualPolish?.holographicEffects?.enabled && suggestions.push("For better performance on lower-end devices, consider conditionally disabling holographic effects based on device capabilities"),
27962
+ // Suggest using content-aware blur with performance considerations
27963
+ config.visualPolish?.contentAwareBlur?.enabled && suggestions.push("Content-aware blur can be expensive; consider setting a maximum blur radius or using simpler blur techniques for mobile devices"),
27964
+ // Suggest using chromatic aberration适度
27965
+ config.interactiveEffects?.chromaticAberration?.enabled && (config.interactiveEffects.chromaticAberration.redShift && Math.abs(config.interactiveEffects.chromaticAberration.redShift) > .05 && suggestions.push("High chromatic aberration red shift values (>0.05) may cause discomfort for some users; consider reducing to improve accessibility"),
27966
+ config.interactiveEffects.chromaticAberration.blueShift && Math.abs(config.interactiveEffects.chromaticAberration.blueShift) > .05 && suggestions.push("High chromatic aberration blue shift values (>0.05) may cause discomfort for some users; consider reducing to improve accessibility"));
27967
+ }
27968
+ /**
27969
+ * Generate a compatibility report for the configuration
27970
+ */ (config, suggestions);
27971
+ // Determine overall validity
27972
+ const isValid = 0 === warnings.length, compatibility = compatibilityReport ? function(config) {
27973
+ return {
27974
+ browsers: !(config.visualPolish?.holographicEffects?.enabled || config.visualPolish?.contentAwareBlur?.enabled || config.interactiveEffects?.vortex?.enabled || config.interactiveEffects?.chromaticAberration?.enabled),
27975
+ // May have issues on older browsers
27976
+ ssr: !0,
27977
+ // Works fine with SSR
27978
+ frameworks: [ "react", "vue", "angular", "svelte", "vanillajs" ]
27979
+ };
27980
+ }
27981
+ /**
27982
+ * Print a detailed configuration report to the console
27983
+ *
27984
+ * @param config - The configuration to analyze
27985
+ * @param title - Optional title for the report
27986
+ *
27987
+ * @example
27988
+ * ```typescript
27989
+ * import { printConfigReport } from '@shohojdhara/atomix/config';
27990
+ *
27991
+ * const config = { /* your config *\/ };
27992
+ * printConfigReport(config, 'My Application Config');
27993
+ * ```
27994
+ */ (config) : {
27995
+ browsers: !0,
27996
+ ssr: !0,
27997
+ frameworks: [ "react", "vue", "angular", "svelte", "vanillajs" ]
27998
+ };
27999
+ // Generate compatibility report
28000
+ return {
28001
+ isValid: isValid,
28002
+ warnings: warnings,
28003
+ suggestions: suggestions,
28004
+ performanceImpact: performanceImpact,
28005
+ compatibility: compatibility
28006
+ };
28007
+ }
28008
+
26150
28009
  // Import and re-export as namespaces with proper typing
26151
28010
  // Export as namespaces with explicit typing
26152
28011
  const composables = composablesImport, utils = utilsImport, types = typesImport, constants = constantsImport, theme = Object.freeze({
@@ -26161,19 +28020,30 @@ const composables = composablesImport, utils = utilsImport, types = typesImport,
26161
28020
  ThemeLiveEditor: ThemeLiveEditor,
26162
28021
  ThemePreview: ThemePreview,
26163
28022
  ThemeProvider: ThemeProvider,
28023
+ ThemeToggle: ThemeToggle,
26164
28024
  ThemeValidator: ThemeValidator,
28025
+ alpha: alpha,
26165
28026
  applyCSSVariables: applyCSSVariables,
26166
28027
  applyComponentTheme: applyComponentTheme,
26167
28028
  applyTheme: applyTheme,
26168
28029
  camelToKebab: camelToKebab,
28030
+ clearThemePreference: clearThemePreference,
26169
28031
  clearThemes: clearThemes,
28032
+ configToTokens: configToTokens,
28033
+ createPerformanceMonitor: createPerformanceMonitor,
28034
+ createRTLManager: createRTLManager,
28035
+ createResponsiveUtil: createResponsiveUtil,
28036
+ createSpacing: createSpacing,
26170
28037
  createTheme: createTheme,
26171
28038
  createThemeRegistry: createThemeRegistry,
26172
28039
  createTokens: createTokens,
26173
28040
  cssVarsToStyle: cssVarsToStyle,
28041
+ darken: darken,
26174
28042
  deepMerge: deepMerge,
28043
+ default: index,
26175
28044
  defaultTokens: defaultTokens,
26176
28045
  designTokensToCSSVars: designTokensToCSSVars,
28046
+ emphasize: emphasize,
26177
28047
  extendTheme: extendTheme,
26178
28048
  extractComponentName: extractComponentName,
26179
28049
  generateCSSVariableName: generateCSSVariableName,
@@ -26184,29 +28054,53 @@ const composables = composablesImport, utils = utilsImport, types = typesImport,
26184
28054
  getAllThemes: getAllThemes,
26185
28055
  getCSSVariable: getCSSVariable,
26186
28056
  getComponentThemeValue: getComponentThemeValue,
28057
+ getContrastRatio: getContrastRatio,
28058
+ getContrastText: getContrastText,
28059
+ getCurrentTheme: getCurrentTheme,
28060
+ getDirectionFromLocale: getDirectionFromLocale,
28061
+ getLuminance: getLuminance,
28062
+ getSystemTheme: getSystemTheme,
26187
28063
  getTheme: getTheme,
26188
28064
  getThemeApplicator: getThemeApplicator,
26189
28065
  getThemeCount: getThemeCount,
26190
28066
  getThemeIds: getThemeIds,
26191
28067
  hasTheme: hasTheme,
28068
+ hexToRgb: hexToRgb$1,
28069
+ initializeTheme: initializeTheme,
26192
28070
  injectCSS: injectCSS$1,
26193
28071
  injectTheme: injectTheme,
28072
+ isAccessible: isAccessible,
26194
28073
  isCSSInjected: isCSSInjected,
26195
28074
  isDesignTokens: isDesignTokens,
28075
+ isRTLLocale: isRTLLocale,
26196
28076
  isValidCSSVariableName: isValidCSSVariableName,
28077
+ lighten: lighten,
28078
+ listenToSystemTheme: listenToSystemTheme,
26197
28079
  mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
26198
28080
  mergeCSSVars: mergeCSSVars,
26199
28081
  mergeTheme: mergeTheme,
28082
+ mergeTokens: mergeTokens,
26200
28083
  normalizeThemeTokens: normalizeThemeTokens,
28084
+ omitTokens: omitTokens,
28085
+ overrideTokens: overrideTokens,
28086
+ persistTheme: persistTheme,
28087
+ pickTokens: pickTokens,
26201
28088
  registerTheme: registerTheme,
26202
28089
  removeCSS: removeCSS,
26203
28090
  removeCSSVariables: removeCSSVariables,
26204
28091
  removeTheme: removeTheme,
28092
+ rgbToHex: rgbToHex,
28093
+ rtlCSS: rtlCSS,
28094
+ switchTheme: switchTheme,
26205
28095
  themePropertyToCSSVar: themePropertyToCSSVar,
28096
+ toggleTheme: toggleTheme,
26206
28097
  unregisterTheme: unregisterTheme,
26207
28098
  useComponentTheme: useComponentTheme,
26208
28099
  useHistory: useHistory,
28100
+ usePerformanceMonitor: usePerformanceMonitor,
28101
+ useResponsive: useResponsive,
26209
28102
  useTheme: useTheme,
28103
+ useThemeSwitcher: useThemeSwitcher,
26210
28104
  useThemeTokens: useThemeTokens
26211
28105
  }), atomix = {
26212
28106
  // Re-export all components and utilities
@@ -26274,10 +28168,11 @@ exports.TYPEDBUTTON = TYPEDBUTTON, exports.Tabs = Tabs, exports.Testimonial = Te
26274
28168
  exports.Textarea = Textarea, exports.ThemeApplicator = ThemeApplicator, exports.ThemeComparator = ThemeComparator,
26275
28169
  exports.ThemeContext = ThemeContext, exports.ThemeErrorBoundary = ThemeErrorBoundary,
26276
28170
  exports.ThemeInspector = ThemeInspector, exports.ThemeLiveEditor = ThemeLiveEditor,
26277
- exports.ThemePreview = ThemePreview, exports.ThemeProvider = ThemeProvider, exports.ThemeValidator = ThemeValidator,
26278
- exports.Todo = Todo, exports.Toggle = Toggle, exports.Tooltip = Tooltip, exports.TreemapChart = TreemapChart,
26279
- exports.UPLOAD = UPLOAD, exports.Upload = Upload, exports.VIDEO_PLAYER = VIDEO_PLAYER,
26280
- exports.VideoPlayer = VideoPlayer, exports.WaterfallChart = WaterfallChart, exports.applyCSSVariables = applyCSSVariables,
28171
+ exports.ThemePreview = ThemePreview, exports.ThemeProvider = ThemeProvider, exports.ThemeToggle = ThemeToggle,
28172
+ exports.ThemeValidator = ThemeValidator, exports.Todo = Todo, exports.Toggle = Toggle,
28173
+ exports.Tooltip = Tooltip, exports.TreemapChart = TreemapChart, exports.UPLOAD = UPLOAD,
28174
+ exports.Upload = Upload, exports.VIDEO_PLAYER = VIDEO_PLAYER, exports.VideoPlayer = VideoPlayer,
28175
+ exports.WaterfallChart = WaterfallChart, exports.alpha = alpha, exports.applyCSSVariables = applyCSSVariables,
26281
28176
  exports.applyCSSVarsToStyle =
26282
28177
  /**
26283
28178
  * Utility to apply CSS variables to style object
@@ -26291,60 +28186,16 @@ function(cssVars, baseStyle) {
26291
28186
  };
26292
28187
  }
26293
28188
  /**
26294
- * Atomix Configuration System
26295
- *
26296
- * Tailwind-like configuration for customizing the Atomix Design System.
26297
- *
26298
- * External developers can create `atomix.config.ts` in their project root
26299
- * to customize design tokens, similar to Tailwind's tailwind.config.js
26300
- *
26301
- * @example
26302
- * ```typescript
26303
- * // atomix.config.ts (in your project)
26304
- * import { defineConfig } from '@shohojdhara/atomix/config';
26305
- *
26306
- * export default defineConfig({
26307
- * theme: {
26308
- * extend: {
26309
- * colors: {
26310
- * primary: { main: '#7AFFD7' },
26311
- * },
26312
- * },
26313
- * },
26314
- * });
26315
- * ```
26316
- */
26317
- /**
26318
- * Helper function to define Atomix configuration with type safety
28189
+ * Configuration Types
26319
28190
  *
26320
- * @param config - Atomix configuration object
26321
- * @returns The configuration object
28191
+ * Type definitions for the Atomix configuration system.
26322
28192
  */
26323
28193
  /**
26324
28194
  * Helper function to define Atomix configuration with type safety
26325
- *
26326
- * Similar to Tailwind's defineConfig, provides autocomplete and type checking.
26327
- *
26328
- * @param config - Atomix configuration object
26329
- * @returns The configuration object
26330
- *
26331
- * @example
26332
- * ```typescript
26333
- * import { defineConfig } from '@shohojdhara/atomix/config';
26334
- *
26335
- * export default defineConfig({
26336
- * theme: {
26337
- * extend: {
26338
- * colors: {
26339
- * primary: { main: '#7AFFD7' },
26340
- * },
26341
- * },
26342
- * },
26343
- * });
26344
- * ```
26345
28195
  */ , exports.applyComponentTheme = applyComponentTheme, exports.applyPartStyles = applyPartStyles,
26346
- exports.applyTheme = applyTheme, exports.camelToKebab = camelToKebab, exports.clearThemes = clearThemes,
26347
- exports.composables = composables, exports.constants = constants, exports.createBreakpoints = createBreakpoints$1,
28196
+ exports.applyTheme = applyTheme, exports.camelToKebab = camelToKebab, exports.clearThemePreference = clearThemePreference,
28197
+ exports.clearThemes = clearThemes, exports.composables = composables, exports.configToTokens = configToTokens,
28198
+ exports.constants = constants, exports.createBreakpoints = createBreakpoints$1,
26348
28199
  exports.createCSSVarStyle = createCSSVarStyle, exports.createDarkVariant =
26349
28200
  /**
26350
28201
  * Create a dark theme variant from a light theme
@@ -26401,7 +28252,9 @@ function(lightTheme) {
26401
28252
  /**
26402
28253
  * Validate theme structure
26403
28254
  */ , exports.createDebugAttrs = createDebugAttrs, exports.createFontPreloadLink = createFontPreloadLink,
26404
- exports.createPartProps = createPartProps, exports.createSlotComponent =
28255
+ exports.createPartProps = createPartProps, exports.createPerformanceMonitor = createPerformanceMonitor,
28256
+ exports.createRTLManager = createRTLManager, exports.createResponsiveUtil = createResponsiveUtil,
28257
+ exports.createSlotComponent =
26405
28258
  /**
26406
28259
  * Create a slot wrapper component
26407
28260
  *
@@ -26439,11 +28292,13 @@ function(defaultElement = "div") {
26439
28292
  }
26440
28293
  /**
26441
28294
  * Hook to manage slot rendering
26442
- */ , exports.createTheme = createTheme, exports.createThemeRegistry = createThemeRegistry,
26443
- exports.createTokens = createTokens, exports.cssVarsToStyle = cssVarsToStyle, exports.deepMerge = deepMerge,
28295
+ */ , exports.createSpacing = createSpacing, exports.createTheme = createTheme,
28296
+ exports.createThemeRegistry = createThemeRegistry, exports.createTokens = createTokens,
28297
+ exports.cssVarsToStyle = cssVarsToStyle, exports.darken = darken, exports.deepMerge = deepMerge,
26444
28298
  exports.default = atomix, exports.defaultTokens = defaultTokens, exports.defineConfig = function(config) {
26445
28299
  return config;
26446
- }, exports.designTokensToCSSVars = designTokensToCSSVars, exports.exportTheme =
28300
+ }, exports.designTokensToCSSVars = designTokensToCSSVars, exports.emphasize = emphasize,
28301
+ exports.exportTheme =
26447
28302
  /**
26448
28303
  * Export theme as JSON
26449
28304
  */
@@ -26463,9 +28318,12 @@ exports.getAllThemes = getAllThemes, exports.getCSSVariable = getCSSVariable, ex
26463
28318
  */
26464
28319
  function(component) {
26465
28320
  return COMPONENT_CSS_VARS[component];
26466
- }, exports.getComponentThemeValue = getComponentThemeValue, exports.getDefaultBreakpoints = getDefaultBreakpoints,
26467
- exports.getDevicePreset = getDevicePreset, exports.getMobileOptimizedParams = getMobileOptimizedParams,
26468
- exports.getPartStyles = getPartStyles, exports.getQualityMultipliers = getQualityMultipliers,
28321
+ }, exports.getComponentThemeValue = getComponentThemeValue, exports.getContrastRatio = getContrastRatio,
28322
+ exports.getContrastText = getContrastText, exports.getCurrentTheme = getCurrentTheme,
28323
+ exports.getDefaultBreakpoints = getDefaultBreakpoints, exports.getDevicePreset = getDevicePreset,
28324
+ exports.getDirectionFromLocale = getDirectionFromLocale, exports.getLuminance = getLuminance,
28325
+ exports.getMobileOptimizedParams = getMobileOptimizedParams, exports.getPartStyles = getPartStyles,
28326
+ exports.getQualityMultipliers = getQualityMultipliers, exports.getSystemTheme = getSystemTheme,
26469
28327
  exports.getTheme = getTheme, exports.getThemeApplicator = getThemeApplicator, exports.getThemeCount = getThemeCount,
26470
28328
  exports.getThemeIds = getThemeIds, exports.getThemeMetadata =
26471
28329
  /**
@@ -26486,7 +28344,7 @@ function(theme) {
26486
28344
  /**
26487
28345
  * Check if theme supports dark mode
26488
28346
  */ , exports.hasCustomization = hasCustomization, exports.hasTheme = hasTheme,
26489
- exports.importTheme = function(json) {
28347
+ exports.hexToRgb = hexToRgb$1, exports.importTheme = function(json) {
26490
28348
  try {
26491
28349
  return JSON.parse(json);
26492
28350
  } catch (error) {
@@ -26497,15 +28355,49 @@ exports.importTheme = function(json) {
26497
28355
  // are already exported from './theme' module. Import them directly from there.
26498
28356
  // This file only exports theme-tools specific utilities.
26499
28357
  // Export all components individually for better tree-shaking
26500
- , exports.injectCSS = injectCSS$1, exports.injectTheme = injectTheme, exports.isCSSInjected = isCSSInjected,
26501
- exports.isDesignTokens = isDesignTokens, exports.isSlot = function(value) {
28358
+ , exports.initializeTheme = initializeTheme, exports.injectCSS = injectCSS$1, exports.injectTheme = injectTheme,
28359
+ exports.isAccessible = isAccessible, exports.isCSSInjected = isCSSInjected, exports.isDesignTokens = isDesignTokens,
28360
+ exports.isRTLLocale = isRTLLocale, exports.isSlot = function(value) {
26502
28361
  return "object" == typeof value && null !== value && ("render" in value || "component" in value || "children" in value);
26503
28362
  }
26504
28363
  /**
26505
28364
  * Merge multiple slot configurations
26506
28365
  * Later slots override earlier ones
26507
28366
  */ , exports.isValidCSSVariableName = isValidCSSVariableName, exports.isYouTubeUrl = isYouTubeUrl,
26508
- exports.mapSCSSTokensToCSSVars = mapSCSSTokensToCSSVars, exports.mergeCSSVars = mergeCSSVars,
28367
+ exports.lighten = lighten, exports.listenToSystemTheme = listenToSystemTheme, exports.loadAtomixConfig = loadAtomixConfig,
28368
+ exports.loadConfig =
28369
+ /**
28370
+ * Public API for loading and managing Atomix configuration
28371
+ *
28372
+ * This module provides the public-facing API for configuration loading
28373
+ * in external projects.
28374
+ */
28375
+ /**
28376
+ * Load Atomix configuration from an external project.
28377
+ *
28378
+ * @param options - Loading options
28379
+ * @returns The loaded configuration
28380
+ *
28381
+ * @example
28382
+ * ```typescript
28383
+ * import { loadConfig } from '@shohojdhara/atomix/config';
28384
+ *
28385
+ * const config = loadConfig();
28386
+ * console.log(config.prefix); // 'atomix' or user's custom prefix
28387
+ * ```
28388
+ */
28389
+ function(options) {
28390
+ return loadAtomixConfig({
28391
+ configPath: options?.configPath,
28392
+ required: options?.required ?? !1
28393
+ });
28394
+ }
28395
+ /**
28396
+ * Validate Atomix configuration structure.
28397
+ *
28398
+ * @param config - Configuration object to validate
28399
+ * @returns Array of validation warnings (empty if valid)
28400
+ */ , exports.mapSCSSTokensToCSSVars = mapSCSSTokensToCSSVars, exports.mergeCSSVars = mergeCSSVars,
26509
28401
  exports.mergeClassNames = mergeClassNames, exports.mergeComponentProps = mergeComponentProps,
26510
28402
  exports.mergePartStyles = mergePartStyles, exports.mergeSlots = function(...slots) {
26511
28403
  const filtered = slots.filter((s => void 0 !== s));
@@ -26513,8 +28405,17 @@ exports.mergePartStyles = mergePartStyles, exports.mergeSlots = function(...slot
26513
28405
  ...acc,
26514
28406
  ...slot
26515
28407
  })));
26516
- }, exports.mergeTheme = mergeTheme, exports.normalizeThemeTokens = normalizeThemeTokens,
26517
- exports.preloadFonts = preloadFonts, exports.quickTheme =
28408
+ }, exports.mergeTheme = mergeTheme, exports.mergeTokens = mergeTokens, exports.normalizeThemeTokens = normalizeThemeTokens,
28409
+ exports.omitTokens = omitTokens, exports.overrideTokens = overrideTokens, exports.persistTheme = persistTheme,
28410
+ exports.pickTokens = pickTokens, exports.preloadFonts = preloadFonts, exports.printConfigReport = function(config, title) {
28411
+ const result = validateConfiguration(config);
28412
+ result.warnings.length > 0 && result.warnings.forEach((warning => {})), result.suggestions.length > 0 && result.suggestions.forEach((suggestion => {}));
28413
+ const featuresDetected = [];
28414
+ config.interactiveEffects && featuresDetected.push("Interactive Effects"), config.optimization && featuresDetected.push("Optimization"),
28415
+ config.visualPolish && featuresDetected.push("Visual Polish"), config.ai && featuresDetected.push("AI Integration"),
28416
+ config.tokenEngine && featuresDetected.push("Token Engine"), config.generator && featuresDetected.push("Component Generator"),
28417
+ featuresDetected.length > 0 && featuresDetected.forEach((feature => {}));
28418
+ }, exports.quickTheme =
26518
28419
  /**
26519
28420
  * Quick theme creator with sensible defaults
26520
28421
  */
@@ -26531,11 +28432,26 @@ function(name, primaryColor, secondaryColor) {
26531
28432
  }
26532
28433
  });
26533
28434
  }, exports.registerTheme = registerTheme, exports.removeCSS = removeCSS, exports.removeCSSVariables = removeCSSVariables,
26534
- exports.removeTheme = removeTheme, exports.renderSlot = renderSlot, exports.sliderConstants = sliderConstants,
28435
+ exports.removeTheme = removeTheme, exports.renderSlot = renderSlot, exports.resolveConfigPath = function(configPath) {
28436
+ // In browser environments, config resolution is not possible
28437
+ if ("undefined" != typeof window) return null;
28438
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
28439
+ const {existsSync: existsSync} = require("fs"), {join: join} = require("path");
28440
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
28441
+ // If a specific config path is provided, check if it exists
28442
+ if (configPath) {
28443
+ const absPath = join(process.cwd(), configPath);
28444
+ return existsSync(absPath) ? absPath : null;
28445
+ }
28446
+ // Otherwise, check standard locations
28447
+ const possiblePaths = [ join(process.cwd(), "atomix.config.ts"), join(process.cwd(), "atomix.config.js"), join(process.cwd(), "atomix.config.json") ];
28448
+ for (const path of possiblePaths) if (existsSync(path)) return path;
28449
+ return null;
28450
+ }, exports.rgbToHex = rgbToHex, exports.rtlCSS = rtlCSS, exports.sliderConstants = sliderConstants,
26535
28451
  exports.supportsDarkMode = function(theme) {
26536
28452
  var _context;
26537
28453
  return "dark" === theme.palette?.mode || !0 === theme.supportsDarkMode || Boolean((null == (_context = theme.a11y?.modes) ? void 0 : Function.call.bind(_includesInstanceProperty(_context), _context))?.("dark"));
26538
- }, exports.theme = theme, exports.themePropertyToCSSVar = themePropertyToCSSVar,
28454
+ }, exports.switchTheme = switchTheme, exports.theme = theme, exports.themePropertyToCSSVar = themePropertyToCSSVar,
26539
28455
  exports.themeToCSS =
26540
28456
  /**
26541
28457
  * Generate CSS string from theme
@@ -26545,10 +28461,11 @@ function(theme, selector = ":root") {
26545
28461
  selector: selector,
26546
28462
  prefix: "atomix"
26547
28463
  });
26548
- }, exports.types = types, exports.unregisterTheme = unregisterTheme, exports.useAccordion = useAccordion,
26549
- exports.useAtomixGlass = useAtomixGlass, exports.useBadge = useBadge, exports.useBarChart = useBarChart,
26550
- exports.useBlock = useBlock, exports.useChartData = useChartData, exports.useChartInteraction = useChartInteraction,
26551
- exports.useChartScale = useChartScale, exports.useComponentCustomization = function(component, props) {
28464
+ }, exports.toggleTheme = toggleTheme, exports.types = types, exports.unregisterTheme = unregisterTheme,
28465
+ exports.useAccordion = useAccordion, exports.useAtomixGlass = useAtomixGlass, exports.useBadge = useBadge,
28466
+ exports.useBarChart = useBarChart, exports.useBlock = useBlock, exports.useChartData = useChartData,
28467
+ exports.useChartInteraction = useChartInteraction, exports.useChartScale = useChartScale,
28468
+ exports.useComponentCustomization = function(component, props) {
26552
28469
  const {theme: theme} = useTheme(), cssVars = React.useMemo((() => mergeCSSVars(theme?.components?.[component]?.cssVars || {}, props.cssVars || {})), [ theme, component, props.cssVars ]), parts = React.useMemo((() => {
26553
28470
  const themeParts = theme?.components?.[component]?.parts || {}, propParts = props.parts || {}, merged = {};
26554
28471
  return new Set([ ...Object.keys(themeParts), ...Object.keys(propParts) ]).forEach((partName => {
@@ -26587,14 +28504,16 @@ exports.useMergedProps = function(defaultProps, props) {
26587
28504
  ...props
26588
28505
  })), [ defaultProps, props ]);
26589
28506
  }, exports.useNav = useNav, exports.useNavDropdown = useNavDropdown, exports.useNavItem = useNavItem,
26590
- exports.useNavbar = useNavbar, exports.usePerformanceMonitor = usePerformanceMonitor,
26591
- exports.usePieChart = usePieChart, exports.useRadio = useRadio, exports.useResponsiveGlass = useResponsiveGlass,
28507
+ exports.useNavbar = useNavbar, exports.usePieChart = usePieChart, exports.useRadio = useRadio,
28508
+ exports.useResponsive = useResponsive, exports.useResponsiveGlass = useResponsiveGlass,
26592
28509
  exports.useRiver = useRiver, exports.useSelect = useSelect, exports.useSideMenu = useSideMenu,
26593
28510
  exports.useSideMenuItem = useSideMenuItem, exports.useSlot = function(slot, props, fallback) {
26594
28511
  return React__default.default.useMemo((() => renderSlot(slot, props, fallback)), [ slot, props, fallback ]);
26595
28512
  }, exports.useSpinner = useSpinner, exports.useTextarea = useTextarea, exports.useTheme = useTheme,
26596
- exports.useThemeTokens = useThemeTokens, exports.useTodo = useTodo, exports.utils = utils,
26597
- exports.validateTheme = function(theme) {
28513
+ exports.useThemeSwitcher = useThemeSwitcher, exports.useThemeTokens = useThemeTokens,
28514
+ exports.useTodo = useTodo, exports.utils = utils, exports.validateConfig = function(config) {
28515
+ return validateConfig$1(config);
28516
+ }, exports.validateConfiguration = validateConfiguration, exports.validateTheme = function(theme) {
26598
28517
  const errors = [];
26599
28518
  return theme.name || errors.push("Theme must have a name"), theme.palette || errors.push("Theme must have a palette"),
26600
28519
  theme.palette && !theme.palette.primary && errors.push("Theme palette must have a primary color"),