@shohojdhara/atomix 0.5.2 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/atomix.config.ts +33 -33
  2. package/dist/config.d.ts +187 -112
  3. package/dist/config.js +7 -49
  4. package/dist/config.js.map +1 -1
  5. package/dist/index.d.ts +1958 -900
  6. package/dist/index.esm.js +2275 -383
  7. package/dist/index.esm.js.map +1 -1
  8. package/dist/index.js +2327 -417
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.min.js +1 -1
  11. package/dist/index.min.js.map +1 -1
  12. package/dist/theme.d.ts +1390 -276
  13. package/dist/theme.js +2129 -621
  14. package/dist/theme.js.map +1 -1
  15. package/package.json +1 -1
  16. package/scripts/cli/internal/config-loader.js +30 -20
  17. package/src/lib/config/index.ts +38 -362
  18. package/src/lib/config/loader.ts +419 -0
  19. package/src/lib/config/public-api.ts +43 -0
  20. package/src/lib/config/types.ts +389 -0
  21. package/src/lib/config/validator.ts +305 -0
  22. package/src/lib/theme/adapters/index.ts +1 -1
  23. package/src/lib/theme/adapters/themeAdapter.ts +358 -229
  24. package/src/lib/theme/components/ThemeToggle.tsx +276 -0
  25. package/src/lib/theme/config/configLoader.ts +351 -0
  26. package/src/lib/theme/config/loader.ts +221 -0
  27. package/src/lib/theme/core/createTheme.ts +126 -50
  28. package/src/lib/theme/core/createThemeObject.ts +7 -4
  29. package/src/lib/theme/hooks/useThemeSwitcher.ts +164 -0
  30. package/src/lib/theme/index.ts +322 -38
  31. package/src/lib/theme/runtime/ThemeProvider.tsx +44 -10
  32. package/src/lib/theme/runtime/__tests__/ThemeProvider.test.tsx +44 -393
  33. package/src/lib/theme/runtime/useTheme.ts +1 -0
  34. package/src/lib/theme/tokens/tokens.ts +101 -1
  35. package/src/lib/theme/types.ts +91 -0
  36. package/src/lib/theme/utils/performanceMonitor.ts +315 -0
  37. package/src/lib/theme/utils/responsive.ts +280 -0
  38. package/src/lib/theme/utils/themeUtils.ts +531 -117
  39. package/src/styles/05-objects/_objects.masonry-grid.scss +3 -3
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: !0
5
5
  });
6
6
 
7
- var jsxRuntime = require("react/jsx-runtime"), React = require("react"), PhosphorIcons = require("@phosphor-icons/react"), reactDom = require("react-dom");
7
+ var jsxRuntime = require("react/jsx-runtime"), React = require("react"), PhosphorIcons = require("@phosphor-icons/react"), reactDom = require("react-dom"), fs = require("fs"), path$4 = require("path");
8
8
 
9
9
  function _interopDefaultCompat(e) {
10
10
  return e && "object" == typeof e && "default" in e ? e : {
@@ -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,479 @@ 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
+ * Validate Atomix configuration structure
21304
+ *
21305
+ * Performs basic validation to catch common configuration errors early.
21306
+ * Returns warnings for potential issues.
21307
+ *
21308
+ * @param config - Configuration object to validate
21309
+ * @returns Array of validation warnings (empty if valid)
21310
+ *
21311
+ * @example
21312
+ * ```typescript
21313
+ * import { loadAtomixConfig, validateConfig } from '@shohojdhara/atomix/config';
21314
+ *
21315
+ * const config = loadAtomixConfig();
21316
+ * const warnings = validateConfig(config);
21317
+ * warnings.forEach(w => console.warn(w));
21318
+ * ```
21319
+ */
21320
+ function validateConfig$1(config) {
21321
+ const warnings = [];
21322
+ // Check prefix format
21323
+ // Check theme structure
21324
+ 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"`),
21325
+ config.prefix.length < 2 && warnings.push(`Prefix "${config.prefix}" is too short. Use at least 2 characters for clarity.\nExample: "app" instead of "a"`)),
21326
+ config.theme && (
21327
+ // Warn if both extend and tokens are provided
21328
+ 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."),
21329
+ config.theme.extend)) {
21330
+ const extend = config.theme.extend, validThemeKeys = [ "colors", "typography", "spacing", "borderRadius", "shadows", "zIndex", "transitions", "breakpoints" ];
21331
+ // Check for common typos in theme properties
21332
+ Object.keys(extend).forEach((key => {
21333
+ _includesInstanceProperty(validThemeKeys).call(validThemeKeys, key) || warnings.push(`Unknown theme property: "${key}"\nValid properties: ${validThemeKeys.join(", ")}\nDid you mean one of these? Check for typos.`);
21334
+ }));
21087
21335
  }
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));
21336
+ // Validate advanced features
21337
+ if (config.interactiveEffects) {
21338
+ const ie = config.interactiveEffects;
21339
+ // Validate vortex settings
21340
+ 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"),
21341
+ ie.vortex.radius && ie.vortex.radius < 0 && warnings.push("Vortex radius should be a positive number"),
21342
+ ie.vortex.decay && (ie.vortex.decay <= 0 || ie.vortex.decay > 1) && warnings.push("Vortex decay should be between 0 and 1")),
21343
+ // Validate chromatic aberration settings
21344
+ 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"),
21345
+ ie.chromaticAberration.blueShift && Math.abs(ie.chromaticAberration.blueShift) > .1 && warnings.push("Chromatic blue shift value seems unusually high (>0.1), verify this is intended"),
21346
+ ie.chromaticAberration.edgeThreshold && (ie.chromaticAberration.edgeThreshold < 0 || ie.chromaticAberration.edgeThreshold > 1) && warnings.push("Chromatic edge threshold should be between 0 and 1")),
21347
+ // Validate mouse interaction settings
21348
+ ie.mouseInteraction && ie.mouseInteraction.sensitivity && ie.mouseInteraction.sensitivity < 0 && warnings.push("Mouse sensitivity should be a positive number"),
21349
+ // Validate animation speed settings
21350
+ ie.animationSpeed && (ie.animationSpeed.base && ie.animationSpeed.base <= 0 && warnings.push("Animation base speed should be greater than 0"),
21351
+ ie.animationSpeed.timeMultiplier && ie.animationSpeed.timeMultiplier <= 0 && warnings.push("Animation time multiplier should be greater than 0"));
21093
21352
  }
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));
21353
+ // Validate optimization settings
21354
+ if (config.optimization) {
21355
+ const opt = config.optimization;
21356
+ // Validate responsive breakpoints
21357
+ if (opt.responsive && opt.responsive.breakpoints) {
21358
+ const breakpoints = opt.responsive.breakpoints;
21359
+ breakpoints.mobile && !isValidCSSLength(breakpoints.mobile) && warnings.push("Mobile breakpoint value is not a valid CSS length"),
21360
+ breakpoints.tablet && !isValidCSSLength(breakpoints.tablet) && warnings.push("Tablet breakpoint value is not a valid CSS length"),
21361
+ breakpoints.desktop && !isValidCSSLength(breakpoints.desktop) && warnings.push("Desktop breakpoint value is not a valid CSS length"),
21362
+ breakpoints.wide && !isValidCSSLength(breakpoints.wide) && warnings.push("Wide breakpoint value is not a valid CSS length");
21363
+ }
21364
+ // Validate device scaling
21365
+ if (opt.responsive && opt.responsive.deviceScaling) {
21366
+ const scaling = opt.responsive.deviceScaling;
21367
+ scaling.mobile && (scaling.mobile <= 0 || scaling.mobile > 1) && warnings.push("Mobile device scaling should be between 0 and 1"),
21368
+ scaling.tablet && (scaling.tablet <= 0 || scaling.tablet > 1) && warnings.push("Tablet device scaling should be between 0 and 1"),
21369
+ scaling.desktop && (scaling.desktop <= 0 || scaling.desktop > 1) && warnings.push("Desktop device scaling should be between 0 and 1");
21370
+ }
21371
+ // Validate performance settings
21372
+ // Validate auto-scaling thresholds
21373
+ 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)"),
21374
+ opt.autoScaling && opt.autoScaling.qualityThresholds) {
21375
+ const thresholds = opt.autoScaling.qualityThresholds;
21376
+ thresholds.lowEnd && (thresholds.lowEnd < 0 || thresholds.lowEnd > 1) && warnings.push("Auto-scaling low-end threshold should be between 0 and 1"),
21377
+ thresholds.midRange && (thresholds.midRange < 0 || thresholds.midRange > 1) && warnings.push("Auto-scaling mid-range threshold should be between 0 and 1"),
21378
+ thresholds.highEnd && (thresholds.highEnd < 0 || thresholds.highEnd > 1) && warnings.push("Auto-scaling high-end threshold should be between 0 and 1");
21379
+ }
21099
21380
  }
21100
- /**
21101
- * Log a debug message
21102
- */ debug(message, context) {
21103
- this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
21381
+ // Validate visual polish settings
21382
+ if (config.visualPolish) {
21383
+ const vp = config.visualPolish;
21384
+ // Validate content aware blur settings
21385
+ vp.contentAwareBlur && (void 0 !== vp.contentAwareBlur.edgePreservation && "boolean" != typeof vp.contentAwareBlur.edgePreservation && warnings.push("Content-aware blur edge preservation should be a boolean value"),
21386
+ void 0 !== vp.contentAwareBlur.depthDetection && "boolean" != typeof vp.contentAwareBlur.depthDetection && warnings.push("Content-aware blur depth detection should be a boolean value")),
21387
+ // Validate holographic effects settings
21388
+ vp.holographicEffects && (void 0 !== vp.holographicEffects.enabled && "boolean" != typeof vp.holographicEffects.enabled && warnings.push("Holographic effects enabled should be a boolean value"),
21389
+ void 0 !== vp.holographicEffects.rainbowDiffraction && "boolean" != typeof vp.holographicEffects.rainbowDiffraction && warnings.push("Holographic rainbow diffraction should be a boolean value"));
21104
21390
  }
21391
+ // Validate AI settings
21392
+ var _context;
21393
+ 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`),
21394
+ config.ai.temperature && (config.ai.temperature < 0 || config.ai.temperature > 1) && warnings.push("AI temperature should be between 0 and 1"),
21395
+ config.ai.maxTokens && config.ai.maxTokens < 100 && warnings.push("AI maxTokens should typically be 100 or more"),
21396
+ config.ai.rateLimit && (config.ai.rateLimit.requests <= 0 && warnings.push("AI rate limit requests should be greater than 0"),
21397
+ config.ai.rateLimit.windowMs <= 0 && warnings.push("AI rate limit window should be greater than 0"))),
21398
+ // Validate telemetry settings
21399
+ config.telemetry && config.telemetry.path && !config.telemetry.path.endsWith(".json") && warnings.push("Telemetry path should typically end with .json"),
21400
+ warnings;
21105
21401
  }
21106
21402
 
21107
21403
  /**
21108
- * Default logger instance
21109
- */ let defaultLogger = null;
21404
+ * Helper function to validate CSS length values
21405
+ */ function isValidCSSLength(value) {
21406
+ return /^(\d+(\.\d+)?)(px|em|rem|%|vw|vh|vmin|vmax|cm|mm|in|pt|pc|ex|ch)?$/.test(value);
21407
+ }
21110
21408
 
21111
21409
  /**
21112
- * Get or create default logger
21113
- */ function getLogger() {
21114
- return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
21410
+ * Load Atomix configuration from project root
21411
+ *
21412
+ * Attempts to load atomix.config.ts, atomix.config.js, or atomix.config.json from the current working directory.
21413
+ * Falls back to default config if file doesn't exist.
21414
+ *
21415
+ * @param options - Loader options
21416
+ * @returns Loaded configuration or default
21417
+ *
21418
+ * @example
21419
+ * ```typescript
21420
+ * import { loadAtomixConfig } from '@shohojdhara/atomix/config';
21421
+ * import { createTheme } from '@shohojdhara/atomix/theme';
21422
+ *
21423
+ * const config = loadAtomixConfig();
21424
+ * const theme = createTheme(config.theme?.tokens || {});
21425
+ * ```
21426
+ */ function loadAtomixConfig(options = {}) {
21427
+ const {configPath: configPath, required: required = !1} = options, defaultConfig = {
21428
+ prefix: "atomix",
21429
+ theme: {
21430
+ extend: {}
21431
+ }
21432
+ };
21433
+ // Default config
21434
+ // In browser environments, config loading is not supported
21435
+ if ("undefined" != typeof window) {
21436
+ 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');
21437
+ return defaultConfig;
21438
+ }
21439
+ // If a specific config path is provided, try to load it directly
21440
+ if (configPath) return loadConfigAtPath(configPath, required, defaultConfig);
21441
+ // Otherwise, try standard locations in order of preference
21442
+ const possiblePaths = [ "atomix.config.ts", "atomix.config.js", "atomix.config.json" ];
21443
+ for (const path of possiblePaths) {
21444
+ const config = loadConfigAtPath(path, !1, defaultConfig);
21445
+ // If we found a valid config, return it
21446
+ if (JSON.stringify(config) !== JSON.stringify(defaultConfig)) return config;
21447
+ }
21448
+ // If no config file was found or all contained only defaults, return default config
21449
+ 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');
21450
+ return defaultConfig;
21451
+ }
21452
+
21453
+ /**
21454
+ * Helper function to load config from a specific path
21455
+ */ function loadConfigAtPath(path, required, defaultConfig) {
21456
+ try {
21457
+ // Use dynamic import for ESM compatibility
21458
+ const configModule = require(path), config = configModule.default || configModule;
21459
+ // Validate it's an AtomixConfig
21460
+ if (config && "object" == typeof config) return config;
21461
+ throw new Error("Invalid config format");
21462
+ } catch (error) {
21463
+ if (required) throw new Error(`Failed to load config from ${path}: ${error.message}`);
21464
+ // Return default config if not required
21465
+ return defaultConfig;
21466
+ }
21115
21467
  }
21116
21468
 
21469
+ /**
21470
+ * Resolve config path
21471
+ *
21472
+ * Finds atomix.config.ts in the project, checking common locations.
21473
+ * Returns null in browser environments where file system access is not available.
21474
+ *
21475
+ * This function is designed to help tools identify if a config exists without loading it.
21476
+ *
21477
+ * @param configPath - Optional custom path to check
21478
+ * @returns Absolute path to config file or null if not found
21479
+ */
21117
21480
  /**
21118
21481
  * Core Theme Functions
21119
21482
  *
21120
- * Simplified theme system using DesignTokens only.
21483
+ * Unified theme system that handles both DesignTokens and Theme objects.
21121
21484
  * Config-first approach: loads from atomix.config.ts when no input is provided.
21485
+ * Config-first approach: loads advanced features from config when available.
21122
21486
  */
21123
21487
  /**
21124
- * Create theme CSS from DesignTokens
21488
+ * Create theme CSS from tokens or Theme object
21125
21489
  *
21126
21490
  * **Config-First Approach**: If no input is provided, loads from `atomix.config.ts`.
21491
+ * Config file is required for automatic loading.
21127
21492
  *
21128
- * @param input - DesignTokens (partial) or undefined (loads from config)
21493
+ * @param input - DesignTokens (partial), Theme object, or undefined (loads from config)
21129
21494
  * @param options - CSS generation options (prefix is automatically read from config if not provided)
21130
21495
  * @returns CSS string with custom properties
21131
21496
  * @throws Error if config loading fails when no input is provided
21132
21497
  *
21133
21498
  * @example
21134
21499
  * ```typescript
21135
- * // Loads from atomix.config.ts
21500
+ * // Loads from atomix.config.ts (config file required)
21136
21501
  * const css = createTheme();
21137
21502
  *
21138
21503
  * // Using DesignTokens
@@ -21141,42 +21506,151 @@ class ThemeLogger {
21141
21506
  * 'spacing-4': '1rem',
21142
21507
  * });
21143
21508
  *
21509
+ * // Using Theme object
21510
+ * const theme = createThemeObject({ palette: { primary: { main: '#7c3aed' } } });
21511
+ * const css = createTheme(theme);
21512
+ *
21144
21513
  * // With custom options
21145
21514
  * const css = createTheme(undefined, { prefix: 'myapp', selector: ':root' });
21146
21515
  * ```
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;
21516
+ */
21517
+ function createTheme(input, options) {
21518
+ let tokens, configPrefix;
21519
+ // If no input provided, load from config (required)
21520
+ if (input)
21521
+ // Convert Theme object to DesignTokens
21522
+ tokens = !0 === input.__isJSTheme || input.palette && input.typography ? themeToDesignTokens(input) : input; else {
21523
+ const configTokens = function() {
21524
+ // Check if we're in a browser environment
21525
+ if ("undefined" != typeof window) throw new Error("loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.");
21526
+ // Use dynamic import to load the config loader
21527
+ // This allows bundlers to handle external dependencies properly
21528
+ let loadAtomixConfig;
21529
+ try {
21530
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
21531
+ const {loadAtomixConfig: loader} = require("../../config/loader");
21532
+ loadAtomixConfig = loader;
21533
+ } catch (error) {
21534
+ throw new Error("Config loader module not available");
21535
+ }
21536
+ const config = loadAtomixConfig({
21537
+ configPath: undefined,
21538
+ required: !0
21539
+ });
21540
+ if (!config?.theme) return createTokens({});
21541
+ if ((obj = config.theme) && "object" == typeof obj && (obj.palette || obj.typography || obj.spacing || obj.breakpoints || obj.colors)) return themeToDesignTokens(config.theme);
21542
+ // Handle the config.theme object which has extend/tokens/themes properties
21543
+ // Extract the actual tokens from the theme configuration
21544
+ // Helper type guard function
21545
+ var obj;
21546
+ const themeConfig = config.theme;
21547
+ let tokensToApply = {};
21548
+ return themeConfig.tokens ?
21549
+ // If tokens is provided, use it as the base
21550
+ tokensToApply = themeConfig.tokens : themeConfig.extend && (
21551
+ // If only extend is provided, use it as overrides
21552
+ tokensToApply = themeConfig.extend),
21553
+ // Apply advanced feature configurations as tokens
21554
+ config.interactiveEffects && (
21555
+ // Vortex effects
21556
+ config.interactiveEffects.vortex && (tokensToApply = {
21557
+ ...tokensToApply,
21558
+ "interactive-vortex-enabled": String(config.interactiveEffects.vortex.enabled ?? !1),
21559
+ "interactive-vortex-strength": String(config.interactiveEffects.vortex.strength ?? .5),
21560
+ "interactive-vortex-radius": String(config.interactiveEffects.vortex.radius ?? 100),
21561
+ "interactive-vortex-decay": String(config.interactiveEffects.vortex.decay ?? .8)
21562
+ }),
21563
+ // Chromatic aberration
21564
+ config.interactiveEffects.chromaticAberration && (tokensToApply = {
21565
+ ...tokensToApply,
21566
+ "interactive-chromatic-enabled": String(config.interactiveEffects.chromaticAberration.enabled ?? !1),
21567
+ "interactive-chromatic-mode": config.interactiveEffects.chromaticAberration.mode ?? "lateral",
21568
+ "interactive-chromatic-red-shift": String(config.interactiveEffects.chromaticAberration.redShift ?? .02),
21569
+ "interactive-chromatic-green-shift": String(config.interactiveEffects.chromaticAberration.greenShift ?? 0),
21570
+ "interactive-chromatic-blue-shift": String(config.interactiveEffects.chromaticAberration.blueShift ?? -.02),
21571
+ "interactive-chromatic-edge-only": String(config.interactiveEffects.chromaticAberration.edgeOnly ?? !1),
21572
+ "interactive-chromatic-edge-threshold": String(config.interactiveEffects.chromaticAberration.edgeThreshold ?? .5)
21573
+ }),
21574
+ // Mouse interaction
21575
+ config.interactiveEffects.mouseInteraction && (tokensToApply = {
21576
+ ...tokensToApply,
21577
+ "interactive-mouse-sensitivity": String(config.interactiveEffects.mouseInteraction.sensitivity ?? 1),
21578
+ "interactive-mouse-trail-effect": String(config.interactiveEffects.mouseInteraction.trailEffect ?? !1)
21579
+ }),
21580
+ // Animation speed
21581
+ config.interactiveEffects.animationSpeed && (tokensToApply = {
21582
+ ...tokensToApply,
21583
+ "interactive-animation-speed-base": String(config.interactiveEffects.animationSpeed.base ?? 1),
21584
+ "interactive-animation-speed-multiplier": String(config.interactiveEffects.animationSpeed.timeMultiplier ?? 1)
21585
+ })),
21586
+ // Apply optimization configurations as tokens
21587
+ config.optimization && (
21588
+ // Responsive breakpoints
21589
+ config.optimization.responsive && (config.optimization.responsive.breakpoints && (tokensToApply = {
21590
+ ...tokensToApply,
21591
+ "optimization-breakpoint-mobile": config.optimization.responsive.breakpoints.mobile ?? "0px",
21592
+ "optimization-breakpoint-tablet": config.optimization.responsive.breakpoints.tablet ?? "768px",
21593
+ "optimization-breakpoint-desktop": config.optimization.responsive.breakpoints.desktop ?? "1024px",
21594
+ "optimization-breakpoint-wide": config.optimization.responsive.breakpoints.wide ?? "1440px"
21595
+ }), config.optimization.responsive.deviceScaling && (tokensToApply = {
21596
+ ...tokensToApply,
21597
+ "optimization-device-scaling-mobile": String(config.optimization.responsive.deviceScaling.mobile ?? .5),
21598
+ "optimization-device-scaling-tablet": String(config.optimization.responsive.deviceScaling.tablet ?? .75),
21599
+ "optimization-device-scaling-desktop": String(config.optimization.responsive.deviceScaling.desktop ?? 1)
21600
+ })),
21601
+ // Performance settings
21602
+ config.optimization.performance && (tokensToApply = {
21603
+ ...tokensToApply,
21604
+ "optimization-performance-fps-target": String(config.optimization.performance.fpsTarget ?? 60),
21605
+ "optimization-auto-scaling-enabled": String(config.optimization.performance.autoScaling ?? !1)
21606
+ }),
21607
+ // Auto-scaling settings
21608
+ config.optimization.autoScaling && (tokensToApply = {
21609
+ ...tokensToApply,
21610
+ "optimization-auto-scaling-enabled": String(config.optimization.autoScaling.enabled ?? !1),
21611
+ "optimization-auto-scaling-low-end": String(config.optimization.autoScaling.qualityThresholds?.lowEnd ?? .5),
21612
+ "optimization-auto-scaling-mid-range": String(config.optimization.autoScaling.qualityThresholds?.midRange ?? .75),
21613
+ "optimization-auto-scaling-high-end": String(config.optimization.autoScaling.qualityThresholds?.highEnd ?? 1)
21614
+ })),
21615
+ // Apply visual polish configurations as tokens
21616
+ config.visualPolish && (config.visualPolish.borders && (tokensToApply = {
21617
+ ...tokensToApply,
21618
+ "visual-polish-border-iridescent-glow": String(config.visualPolish.borders.iridescentGlow ?? !1),
21619
+ "visual-polish-border-shimmer-effect": String(config.visualPolish.borders.shimmerEffect ?? !1),
21620
+ "visual-polish-border-beveled-edges": String(config.visualPolish.borders.beveledEdges ?? !1),
21621
+ "visual-polish-border-pulsing-glow": String(config.visualPolish.borders.pulsingGlow ?? !1)
21622
+ }), config.visualPolish.contentAwareBlur && (tokensToApply = {
21623
+ ...tokensToApply,
21624
+ "visual-polish-content-aware-blur-enabled": String(config.visualPolish.contentAwareBlur.enabled ?? !1),
21625
+ "visual-polish-content-aware-depth-detection": String(config.visualPolish.contentAwareBlur.depthDetection ?? !1),
21626
+ "visual-polish-content-aware-edge-preservation": String(config.visualPolish.contentAwareBlur.edgePreservation ?? !1),
21627
+ "visual-polish-content-aware-variable-radius": String(config.visualPolish.contentAwareBlur.variableRadius ?? !1)
21628
+ }), config.visualPolish.holographicEffects && (tokensToApply = {
21629
+ ...tokensToApply,
21630
+ "visual-polish-holographic-enabled": String(config.visualPolish.holographicEffects.enabled ?? !1),
21631
+ "visual-polish-holographic-rainbow-diffraction": String(config.visualPolish.holographicEffects.rainbowDiffraction ?? !1),
21632
+ "visual-polish-holographic-scanline-animation": String(config.visualPolish.holographicEffects.scanlineAnimation ?? !1),
21633
+ "visual-polish-holographic-grid-overlay": String(config.visualPolish.holographicEffects.gridOverlay ?? !1),
21634
+ "visual-polish-holographic-data-stream": String(config.visualPolish.holographicEffects.dataStream ?? !1),
21635
+ "visual-polish-holographic-pulse-rings": String(config.visualPolish.holographicEffects.pulseRings ?? !1)
21636
+ })), createTokens(tokensToApply);
21637
+ }();
21638
+ // Get prefix from config
21639
+ try {
21640
+ // Use the imported function directly instead of require to avoid bundling issues
21641
+ const config = loadAtomixConfig({
21642
+ configPath: "atomix.config.ts",
21643
+ required: !0
21644
+ });
21645
+ configPrefix = config?.prefix;
21646
+ } catch (error) {
21647
+ // Prefix loading failed, but tokens were loaded, so continue
21648
+ }
21649
+ tokens = configTokens;
21169
21650
  }
21170
21651
  // 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
21652
+ const allTokens = createTokens(tokens), prefix = options?.prefix ?? configPrefix ?? "atomix";
21653
+ // Get prefix from options, config, or use default
21180
21654
  return generateCSSVariables$1(allTokens, {
21181
21655
  ...options,
21182
21656
  prefix: prefix
@@ -21390,46 +21864,179 @@ class ThemeLogger {
21390
21864
  */
21391
21865
  /**
21392
21866
  * Default storage key for theme persistence
21393
- */ "undefined" != typeof process && process.env;
21394
-
21867
+ */
21395
21868
  /**
21396
- * Check if code is running in a browser environment
21869
+ * Theme System Error Handling
21870
+ *
21871
+ * Centralized error handling for the Atomix theme system.
21872
+ * Provides custom error classes and logging utilities.
21397
21873
  */
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
- },
21430
- removeItem: key => {
21431
- if (!isServer()) try {
21432
- localStorage.removeItem(key);
21874
+ /**
21875
+ * Theme error codes
21876
+ */
21877
+ var ThemeErrorCode, LogLevel;
21878
+
21879
+ "undefined" != typeof process && process.env, function(ThemeErrorCode) {
21880
+ /** Theme not found in registry */
21881
+ ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
21882
+ /** Theme failed to load */
21883
+ ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
21884
+ /** Theme validation failed */
21885
+ ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
21886
+ /** Configuration loading failed */
21887
+ ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
21888
+ /** Configuration validation failed */
21889
+ ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
21890
+ /** Circular dependency detected */
21891
+ ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
21892
+ /** Missing dependency */
21893
+ ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
21894
+ /** Storage operation failed */
21895
+ ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
21896
+ /** Invalid theme name */
21897
+ ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
21898
+ /** CSS injection failed */
21899
+ ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
21900
+ /** Invalid color format */
21901
+ ThemeErrorCode.INVALID_COLOR_FORMAT = "INVALID_COLOR_FORMAT",
21902
+ /** Missing required token */
21903
+ ThemeErrorCode.MISSING_REQUIRED_TOKEN = "MISSING_REQUIRED_TOKEN",
21904
+ /** Accessibility contrast violation */
21905
+ ThemeErrorCode.CONTRAST_VIOLATION = "CONTRAST_VIOLATION",
21906
+ /** Invalid token type */
21907
+ ThemeErrorCode.INVALID_TOKEN_TYPE = "INVALID_TOKEN_TYPE",
21908
+ /** Unknown error */
21909
+ ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
21910
+ }(ThemeErrorCode || (ThemeErrorCode = {}));
21911
+
21912
+ /**
21913
+ * Custom error class for theme-related errors
21914
+ */
21915
+ class ThemeError extends Error {
21916
+ constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
21917
+ super(message), this.name = "ThemeError", this.code = code, this.context = context,
21918
+ this.timestamp = Date.now(),
21919
+ // Maintains proper stack trace for where our error was thrown (only available on V8)
21920
+ Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
21921
+ }
21922
+ /**
21923
+ * Convert error to JSON for logging
21924
+ */ toJSON() {
21925
+ return {
21926
+ name: this.name,
21927
+ message: this.message,
21928
+ code: this.code,
21929
+ context: this.context,
21930
+ timestamp: this.timestamp,
21931
+ stack: this.stack
21932
+ };
21933
+ }
21934
+ }
21935
+
21936
+ /**
21937
+ * Log level
21938
+ */ !function(LogLevel) {
21939
+ LogLevel[LogLevel.ERROR = 0] = "ERROR", LogLevel[LogLevel.WARN = 1] = "WARN", LogLevel[LogLevel.INFO = 2] = "INFO",
21940
+ LogLevel[LogLevel.DEBUG = 3] = "DEBUG";
21941
+ }(LogLevel || (LogLevel = {}));
21942
+
21943
+ /**
21944
+ * Theme Logger
21945
+ *
21946
+ * Centralized logging for the theme system.
21947
+ * Replaces console statements with structured logging.
21948
+ */
21949
+ class ThemeLogger {
21950
+ constructor(config = {}) {
21951
+ this.config = {
21952
+ level: config.level ?? ("undefined" != typeof process && "production" === process.env?.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
21953
+ enableConsole: config.enableConsole ?? !0,
21954
+ onError: config.onError,
21955
+ onWarn: config.onWarn,
21956
+ onInfo: config.onInfo,
21957
+ onDebug: config.onDebug
21958
+ };
21959
+ }
21960
+ /**
21961
+ * Log an error
21962
+ */ error(message, error, context) {
21963
+ if (this.config.level < LogLevel.ERROR) return;
21964
+ const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
21965
+ this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
21966
+ error: errorObj,
21967
+ context: {
21968
+ ...context,
21969
+ ...themeError.context
21970
+ },
21971
+ code: themeError.code
21972
+ }), this.config.onError?.(themeError, context);
21973
+ }
21974
+ /**
21975
+ * Log a warning
21976
+ */ warn(message, context) {
21977
+ this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
21978
+ this.config.onWarn?.(message, context));
21979
+ }
21980
+ /**
21981
+ * Log an info message
21982
+ */ info(message, context) {
21983
+ this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
21984
+ this.config.onInfo?.(message, context));
21985
+ }
21986
+ /**
21987
+ * Log a debug message
21988
+ */ debug(message, context) {
21989
+ this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
21990
+ }
21991
+ }
21992
+
21993
+ /**
21994
+ * Default logger instance
21995
+ */ let defaultLogger = null;
21996
+
21997
+ /**
21998
+ * Get or create default logger
21999
+ */ function getLogger() {
22000
+ return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
22001
+ }
22002
+
22003
+ /**
22004
+ * Check if code is running in a browser environment
22005
+ */ 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
22006
+ , buildThemePath = (themeName, basePath = "/themes", useMinified = !1, cdnPath = null) => {
22007
+ // Validate theme name to prevent path injection
22008
+ 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, {
22009
+ themeName: themeName,
22010
+ pattern: /^[a-z0-9]+(-[a-z0-9]+)*$/
22011
+ });
22012
+ const fileName = `${themeName}${useMinified ? ".min.css" : ".css"}`;
22013
+ return cdnPath ? `${sanitizePath(cdnPath)}/${fileName}` : `${sanitizePath(basePath)}/${fileName.replace(/^\//, "")}`;
22014
+ // Sanitize basePath to prevent path injection
22015
+ }, applyThemeAttributes = (dataAttribute, themeName) => {
22016
+ isServer() || (
22017
+ // Set data attribute on body (with null check)
22018
+ document.body && document.body.setAttribute(dataAttribute, themeName),
22019
+ // Also set on documentElement for broader compatibility
22020
+ document.documentElement.setAttribute(dataAttribute, themeName));
22021
+ }, isValidThemeName = themeName => !(!themeName || "string" != typeof themeName) && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(themeName), createLocalStorageAdapter = () => ({
22022
+ getItem: key => {
22023
+ if (isServer()) return null;
22024
+ try {
22025
+ return localStorage.getItem(key);
22026
+ } catch {
22027
+ return null;
22028
+ }
22029
+ },
22030
+ setItem: (key, value) => {
22031
+ if (!isServer()) try {
22032
+ localStorage.setItem(key, value);
22033
+ } catch {
22034
+ // Silently fail if localStorage is not available
22035
+ }
22036
+ },
22037
+ removeItem: key => {
22038
+ if (!isServer()) try {
22039
+ localStorage.removeItem(key);
21433
22040
  } catch {
21434
22041
  // Silently fail
21435
22042
  }
@@ -21479,105 +22086,427 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
21479
22086
  }))
21480
22087
  });
21481
22088
 
22089
+ // ============================================================================
22090
+ // Theme Mode Switching
22091
+ // ============================================================================
21482
22092
  /**
21483
- * Theme Utilities
22093
+ * Switch between light and dark themes
21484
22094
  *
21485
- * Helper utilities for working with themes, including color manipulation,
21486
- * spacing helpers, and theme value accessors.
21487
- */
22095
+ * Automatically toggles a class on the root element and persists the choice.
22096
+ *
22097
+ * @param mode - Theme mode ('light', 'dark', or 'system')
22098
+ * @param options - Configuration options
22099
+ *
22100
+ * @example
22101
+ * ```typescript
22102
+ * import { switchTheme } from '@shohojdhara/atomix/theme/utils';
22103
+ *
22104
+ * // Switch to dark mode
22105
+ * switchTheme('dark');
22106
+ *
22107
+ * // Toggle between light/dark
22108
+ * const current = getCurrentTheme();
22109
+ * switchTheme(current === 'dark' ? 'light' : 'dark');
22110
+ * ```
22111
+ */ function switchTheme(mode, options = {}) {
22112
+ 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);
22113
+ // Determine actual mode (resolve 'system')
22114
+ if (root) {
22115
+ // Add transition class if enabled
22116
+ if (enableTransition) {
22117
+ const htmlRoot = root;
22118
+ htmlRoot.style.transition = `all ${transitionDuration}ms ease-in-out`,
22119
+ // Remove transition after it completes
22120
+ setTimeout((() => {
22121
+ htmlRoot.style.transition = "";
22122
+ }), transitionDuration);
22123
+ }
22124
+ // Apply theme class
22125
+ root.classList.remove("atomix-theme-light", "atomix-theme-dark"), root.classList.add(`atomix-theme-${resolvedMode}`),
22126
+ // Set data attribute for CSS selectors
22127
+ root.setAttribute("data-theme", resolvedMode),
22128
+ // Persist choice
22129
+ persistTheme(resolvedMode, {
22130
+ storageKey: storageKey
22131
+ }),
22132
+ // Dispatch custom event for listeners
22133
+ window.dispatchEvent(new CustomEvent("atomix-theme-change", {
22134
+ detail: {
22135
+ mode: resolvedMode
22136
+ }
22137
+ }));
22138
+ }
22139
+ }
22140
+
22141
+ /**
22142
+ * Toggle between light and dark themes
22143
+ *
22144
+ * @param options - Configuration options
22145
+ * @returns The new theme mode
22146
+ *
22147
+ * @example
22148
+ * ```typescript
22149
+ * const newMode = toggleTheme();
22150
+ * console.log('Switched to:', newMode);
22151
+ * ```
22152
+ */ function toggleTheme(options = {}) {
22153
+ const next = "dark" === getCurrentTheme(options.storageKey) ? "light" : "dark";
22154
+ return switchTheme(next, options), next;
22155
+ }
22156
+
22157
+ /**
22158
+ * Get current theme mode
22159
+ *
22160
+ * @param storageKey - Storage key (default: 'atomix-theme')
22161
+ * @returns Current theme mode or 'light' if not set
22162
+ */ function getCurrentTheme(storageKey = "atomix-theme") {
22163
+ return "undefined" == typeof window ? "light" : localStorage.getItem(storageKey) || "light";
22164
+ }
22165
+
22166
+ /**
22167
+ * Get system theme preference
22168
+ *
22169
+ * @returns 'dark' if system prefers dark mode, 'light' otherwise
22170
+ */ function getSystemTheme() {
22171
+ return "undefined" == typeof window ? "light" : window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
22172
+ }
22173
+
22174
+ /**
22175
+ * Initialize theme based on saved preference or system preference
22176
+ *
22177
+ * Call this once at app startup.
22178
+ *
22179
+ * @param options - Configuration options
22180
+ * @returns The initialized theme mode
22181
+ *
22182
+ * @example
22183
+ * ```typescript
22184
+ * // In your app entry point
22185
+ * import { initializeTheme } from '@shohojdhara/atomix/theme/utils';
22186
+ *
22187
+ * const theme = initializeTheme();
22188
+ * console.log('Theme initialized:', theme);
22189
+ * ```
22190
+ */ function initializeTheme(options = {}) {
22191
+ const saved = getCurrentTheme(options.storageKey);
22192
+ // If no saved preference, use system preference
22193
+ if (!saved || "system" === saved) {
22194
+ const system = getSystemTheme();
22195
+ return switchTheme(system, options), system;
22196
+ }
22197
+ // Use saved preference
22198
+ return switchTheme(saved, options), saved;
22199
+ }
22200
+
22201
+ /**
22202
+ * Listen for system theme changes
22203
+ *
22204
+ * @param callback - Function to call when system theme changes
22205
+ * @returns Cleanup function to stop listening
22206
+ *
22207
+ * @example
22208
+ * ```typescript
22209
+ * const cleanup = listenToSystemTheme((mode) => {
22210
+ * console.log('System theme changed to:', mode);
22211
+ * switchTheme(mode);
22212
+ * });
22213
+ *
22214
+ * // Later, when component unmounts
22215
+ * cleanup();
22216
+ * ```
22217
+ */ function listenToSystemTheme(callback) {
22218
+ if ("undefined" == typeof window) return () => {};
22219
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"), handler = e => {
22220
+ callback(e.matches ? "dark" : "light");
22221
+ };
22222
+ // Modern browsers
22223
+ return mediaQuery.addEventListener ? (mediaQuery.addEventListener("change", handler),
22224
+ () => mediaQuery.removeEventListener("change", handler)) : (
22225
+ // Fallback for older browsers
22226
+ mediaQuery.addListener(handler), () => mediaQuery.removeListener(handler));
22227
+ }
22228
+
22229
+ // ============================================================================
22230
+ // Theme Persistence
22231
+ // ============================================================================
22232
+ /**
22233
+ * Save theme preference to storage
22234
+ *
22235
+ * @param mode - Theme mode to save
22236
+ * @param options - Persistence options
22237
+ */ function persistTheme(mode, options = {}) {
22238
+ if ("undefined" == typeof window) return;
22239
+ const {storageKey: storageKey = "atomix-theme", storageType: storageType = "localStorage"} = options;
22240
+ ("localStorage" === storageType ? localStorage : sessionStorage).setItem(storageKey, mode);
22241
+ }
22242
+
22243
+ /**
22244
+ * Clear saved theme preference
22245
+ *
22246
+ * @param options - Persistence options
22247
+ */ function clearThemePreference(options = {}) {
22248
+ if ("undefined" == typeof window) return;
22249
+ const {storageKey: storageKey = "atomix-theme", storageType: storageType = "localStorage"} = options;
22250
+ ("localStorage" === storageType ? localStorage : sessionStorage).removeItem(storageKey);
22251
+ }
22252
+
22253
+ // ============================================================================
22254
+ // Theme Tokens Manipulation
22255
+ // ============================================================================
22256
+ /**
22257
+ * Merge multiple token sets
22258
+ *
22259
+ * Deep merges token objects, with later tokens overriding earlier ones.
22260
+ *
22261
+ * @param tokens - Token objects to merge
22262
+ * @returns Merged tokens
22263
+ *
22264
+ * @example
22265
+ * ```typescript
22266
+ * const merged = mergeTokens(
22267
+ * baseTokens,
22268
+ * { colors: { primary: { main: '#custom' } } }
22269
+ * );
22270
+ * ```
22271
+ */ function mergeTokens(...tokens) {
22272
+ return _reduceInstanceProperty(tokens).call(tokens, ((acc, current) => deepMerge(acc, current)), {});
22273
+ }
22274
+
22275
+ /**
22276
+ * Override specific tokens
22277
+ *
22278
+ * Creates a new token object with specific overrides.
22279
+ *
22280
+ * @param base - Base tokens
22281
+ * @param overrides - Tokens to override
22282
+ * @returns New tokens with overrides applied
22283
+ *
22284
+ * @example
22285
+ * ```typescript
22286
+ * const customized = overrideTokens(defaultTokens, {
22287
+ * colors: {
22288
+ * primary: { main: '#ff0000' }
22289
+ * }
22290
+ * });
22291
+ * ```
22292
+ */ function overrideTokens(base, overrides) {
22293
+ return deepMerge({
22294
+ ...base
22295
+ }, overrides);
22296
+ }
22297
+
22298
+ /**
22299
+ * Pick specific token categories
22300
+ *
22301
+ * Extracts only the specified categories from tokens.
22302
+ *
22303
+ * @param tokens - Source tokens
22304
+ * @param categories - Categories to pick
22305
+ * @returns Tokens with only selected categories
22306
+ *
22307
+ * @example
22308
+ * ```typescript
22309
+ * const colorTokens = pickTokens(allTokens, ['colors']);
22310
+ * ```
22311
+ */ function pickTokens(tokens, categories) {
22312
+ const result = {};
22313
+ return categories.forEach((category => {
22314
+ tokens[category] && (result[category] = tokens[category]);
22315
+ })), result;
22316
+ }
22317
+
22318
+ /**
22319
+ * Omit specific token categories
22320
+ *
22321
+ * Removes specified categories from tokens.
22322
+ *
22323
+ * @param tokens - Source tokens
22324
+ * @param categories - Categories to omit
22325
+ * @returns Tokens without omitted categories
22326
+ *
22327
+ * @example
22328
+ * ```typescript
22329
+ * const withoutColors = omitTokens(allTokens, ['colors']);
22330
+ * ```
22331
+ */ function omitTokens(tokens, categories) {
22332
+ const result = {
22333
+ ...tokens
22334
+ };
22335
+ return categories.forEach((category => {
22336
+ delete result[category];
22337
+ })), result;
22338
+ }
22339
+
21488
22340
  // ============================================================================
21489
- // Color Manipulation Utilities
22341
+ // Color Utilities
21490
22342
  // ============================================================================
21491
22343
  /**
21492
- * Convert hex color to RGB object
22344
+ * Convert hex color to RGB
22345
+ *
22346
+ * @param hex - Hex color (with or without #)
22347
+ * @returns RGB object { r, g, b }
21493
22348
  */ 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;
22349
+ // Validate
22350
+ if (
22351
+ // Remove # if present
22352
+ // Handle shorthand hex
22353
+ 3 === (hex = hex.replace(/^#/, "")).length && (hex = hex.split("").map((c => c + c)).join("")),
22354
+ 6 !== hex.length) return null;
22355
+ const num = parseInt(hex, 16);
22356
+ return {
22357
+ r: num >> 16 & 255,
22358
+ g: num >> 8 & 255,
22359
+ b: 255 & num
22360
+ };
21500
22361
  }
21501
22362
 
21502
22363
  /**
21503
- * Convert RGB to hex color
22364
+ * Convert RGB to hex
22365
+ *
22366
+ * @param r - Red (0-255)
22367
+ * @param g - Green (0-255)
22368
+ * @param b - Blue (0-255)
22369
+ * @returns Hex color with #
21504
22370
  */ 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)}`;
22371
+ return "#" + [ r, g, b ].map((x => {
22372
+ const hex = x.toString(16);
22373
+ return 1 === hex.length ? "0" + hex : hex;
22374
+ })).join("");
21507
22375
  }
21508
22376
 
21509
22377
  /**
21510
- * Calculate relative luminance of a color
21511
- * Used for determining contrast ratios
21512
- */ function getLuminance(color) {
21513
- const rgb = hexToRgb$1(color);
22378
+ * Calculate luminance of a color
22379
+ *
22380
+ * Used for determining contrast ratios.
22381
+ *
22382
+ * @param hex - Hex color
22383
+ * @returns Luminance value (0-1)
22384
+ */ function getLuminance(hex) {
22385
+ const rgb = hexToRgb$1(hex);
21514
22386
  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);
22387
+ 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)));
22388
+ return .2126 * (r ?? 0) + .7152 * (g ?? 0) + .0722 * (b ?? 0);
21520
22389
  }
21521
22390
 
21522
22391
  /**
21523
22392
  * 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);
22393
+ *
22394
+ * @param hex1 - First hex color
22395
+ * @param hex2 - Second hex color
22396
+ * @returns Contrast ratio (1-21)
22397
+ */ function getContrastRatio(hex1, hex2) {
22398
+ const lum1 = getLuminance(hex1), lum2 = getLuminance(hex2);
22399
+ return (Math.max(lum1, lum2) + .05) / (Math.min(lum1, lum2) + .05);
21527
22400
  }
21528
22401
 
21529
22402
  /**
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";
22403
+ * Check if text color passes WCAG AA standard
22404
+ *
22405
+ * @param textColor - Text color hex
22406
+ * @param backgroundColor - Background color hex
22407
+ * @param size - Font size ('small' or 'large')
22408
+ * @returns true if passes WCAG AA
22409
+ */ function isAccessible(textColor, backgroundColor, size = "small") {
22410
+ return getContrastRatio(textColor, backgroundColor) >= ("large" === size ? 3 : 4.5);
21534
22411
  }
21535
22412
 
21536
22413
  /**
21537
- * Lighten a color by a given amount
22414
+ * Get appropriate text color (black or white) for a background
21538
22415
  *
21539
- * @param color - Hex color string
21540
- * @param amount - Amount to lighten (0-1), default 0.2
22416
+ * @param backgroundColor - Background hex color
22417
+ * @param threshold - Contrast threshold (default: 3)
22418
+ * @returns '#000000' or '#FFFFFF'
22419
+ */ function getContrastText(backgroundColor, threshold = 3) {
22420
+ return getContrastRatio(backgroundColor, "#FFFFFF") >= threshold ? "#FFFFFF" : "#000000";
22421
+ }
22422
+
22423
+ /**
22424
+ * Lighten a color
22425
+ *
22426
+ * @param hex - Base hex color
22427
+ * @param amount - Amount to lighten (0-1)
21541
22428
  * @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));
22429
+ */ function lighten(hex, amount = 0) {
22430
+ const rgb = hexToRgb$1(hex);
22431
+ if (!rgb) return hex;
22432
+ // Use amount directly as factor (0-1)
22433
+ 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);
22434
+ return rgbToHex(Math.min(255, r), Math.min(255, g), Math.min(255, b));
21547
22435
  }
21548
22436
 
21549
22437
  /**
21550
- * Darken a color by a given amount
22438
+ * Darken a color
21551
22439
  *
21552
- * @param color - Hex color string
21553
- * @param amount - Amount to darken (0-1), default 0.2
22440
+ * @param hex - Base hex color
22441
+ * @param amount - Amount to darken (0-1)
21554
22442
  * @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));
22443
+ */ function darken(hex, amount = 0) {
22444
+ const rgb = hexToRgb$1(hex);
22445
+ if (!rgb) return hex;
22446
+ // Use amount directly as factor (0-1)
22447
+ 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));
22448
+ return rgbToHex(Math.max(0, r), Math.max(0, g), Math.max(0, b));
21560
22449
  }
21561
22450
 
21562
22451
  /**
21563
- * Add alpha (opacity) to a color
22452
+ * Add alpha to a color
21564
22453
  *
21565
- * @param color - Hex color string
22454
+ * @param hex - Hex color
21566
22455
  * @param opacity - Opacity value (0-1)
21567
22456
  * @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))})`;
22457
+ */ function alpha(hex, opacity) {
22458
+ const rgb = hexToRgb$1(hex);
22459
+ if (!rgb) return hex;
22460
+ const validOpacity = Math.max(0, Math.min(1, opacity));
22461
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${validOpacity})`;
21573
22462
  }
21574
22463
 
21575
22464
  /**
21576
22465
  * Emphasize a color (lighten if dark, darken if light)
21577
22466
  *
21578
- * @param color - Hex color string
21579
- * @param coefficient - Amount to emphasize (0-1), default 0.15
22467
+ * @param hex - Hex color
22468
+ * @param amount - Amount to emphasize (0-1)
21580
22469
  * @returns Emphasized hex color
22470
+ */ function emphasize(hex, amount = .15) {
22471
+ return getLuminance(hex) > .5 ? darken(hex, amount) : lighten(hex, amount);
22472
+ }
22473
+
22474
+ /**
22475
+ * Create a spacing utility
22476
+ *
22477
+ * @param spacingInput - Spacing configuration
22478
+ * @returns Spacing function
22479
+ */ function createSpacing(spacingInput = 4) {
22480
+ return (...values) => 0 === values.length ? "0px" : "function" == typeof spacingInput ? spacingInput(...values) : values.map((value => {
22481
+ if ("number" == typeof spacingInput) return value * spacingInput + "px";
22482
+ if (Array.isArray(spacingInput)) {
22483
+ const scaled = spacingInput[value];
22484
+ return "number" == typeof scaled ? `${scaled}px` : `${value}px`;
22485
+ }
22486
+ return `${value}px`;
22487
+ })).join(" ");
22488
+ }
22489
+
22490
+ /**
22491
+ * CSS Variable Generator
22492
+ *
22493
+ * Generates CSS custom properties from theme objects and injects them into the DOM.
22494
+ *
22495
+ * **Token Naming Alignment:**
22496
+ * This generator produces CSS variables that match the SCSS token naming pattern exactly:
22497
+ * - Colors: --atomix-primary, --atomix-primary-1 through --atomix-primary-10
22498
+ * - Spacing: --atomix-spacing-1, --atomix-spacing-4, etc.
22499
+ * - Typography: --atomix-font-size-base, --atomix-font-weight-normal, etc.
22500
+ * - Shadows: --atomix-box-shadow, --atomix-box-shadow-sm, etc.
22501
+ *
22502
+ * All tokens follow the flat structure pattern used in SCSS (not nested like --atomix-palette-primary-main).
22503
+ * This ensures compatibility between SCSS themes and JavaScript themes.
22504
+ *
22505
+ * @see src/styles/03-generic/_generic.root.scss for SCSS token definitions
22506
+ */
22507
+ /**
22508
+ * Convert a nested object to flat CSS variable declarations
22509
+ * Uses iterative approach for better performance with large objects
21581
22510
  */
21582
22511
  /**
21583
22512
  * Generate a color scale from a base color (1-10 steps)
@@ -21645,18 +22574,7 @@ function generateCSSVariables(theme, options = {}) {
21645
22574
  color.dark && (vars[`${prefix}-${key}-hover`] = color.dark),
21646
22575
  // Generate semantic color variants (matches SCSS patterns)
21647
22576
  // 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),
22577
+ vars[`${prefix}-${key}-text-emphasis`] = emphasize(color.main, .15),
21660
22578
  // Background subtle: very light version for backgrounds (--atomix-primary-bg-subtle)
21661
22579
  vars[`${prefix}-${key}-bg-subtle`] = alpha(color.main, .1),
21662
22580
  // Border subtle: light version for borders (--atomix-primary-border-subtle)
@@ -22001,29 +22919,7 @@ function generateCSSVariables(theme, options = {}) {
22001
22919
  return vars[`${prefix}-focus-ring-width`] = "3px", vars[`${prefix}-focus-ring-offset`] = "2px",
22002
22920
  vars[`${prefix}-focus-ring-opacity`] = "0.25", vars;
22003
22921
  }(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 = {}) {
22922
+ const customVars = function(obj, prefix = "", result = {}) {
22027
22923
  // Use iterative approach with stack to avoid deep recursion
22028
22924
  const stack = [ {
22029
22925
  obj: obj,
@@ -22477,19 +23373,29 @@ const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme:
22477
23373
  // Check storage first
22478
23374
  if (enablePersistence && storageAdapter.isAvailable()) {
22479
23375
  const stored = storageAdapter.getItem(storageKey);
22480
- if (stored) return stored;
23376
+ if (stored) {
23377
+ // If it looks like a JSON object, parse it
23378
+ if (stored.trim().startsWith("{")) try {
23379
+ return JSON.parse(stored);
23380
+ } catch (e) {
23381
+ return logger.error("Failed to parse stored theme tokens", e), stored;
23382
+ }
23383
+ return stored;
23384
+ }
22481
23385
  }
22482
23386
  // If defaultTheme is provided, use it
22483
23387
  return null != defaultTheme ? defaultTheme : "default";
22484
23388
  // Default fallback
22485
23389
  }), [ 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) {
23390
+ // 1. Check if initialDefaultTheme (from storage) is an object
23391
+ if (initialDefaultTheme && "string" != typeof initialDefaultTheme) {
23392
+ const {tokens: tokens, validation: validation} = validateAndMergeTokens(initialDefaultTheme);
23393
+ if (validation.valid) return tokens;
23394
+ }
23395
+ // 2. Check if defaultTheme prop is an object
23396
+ if (defaultTheme && "string" != typeof defaultTheme) {
22488
23397
  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({}));
23398
+ if (validation.valid) return tokens;
22493
23399
  }
22494
23400
  return null;
22495
23401
  })), [isLoading, setIsLoading] = React.useState(!1), [error, setError] = React.useState(null), loadedThemesRef = React.useRef(new Set), themePromisesRef = React.useRef({}), abortControllerRef = React.useRef(null);
@@ -22501,10 +23407,14 @@ const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme:
22501
23407
  React.useEffect((() => {
22502
23408
  isServer() || applyThemeAttributes(String(currentTheme), dataAttribute);
22503
23409
  }), [ currentTheme, dataAttribute ]),
22504
- // Handle theme persistence
23410
+ // Handle persistence
22505
23411
  React.useEffect((() => {
22506
- enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, String(currentTheme));
22507
- }), [ currentTheme, storageKey, enablePersistence, storageAdapter ]),
23412
+ enablePersistence && storageAdapter.isAvailable() && ("tokens-theme" === currentTheme ?
23413
+ // Only persist if we have actual tokens to store
23414
+ activeTokens && storageAdapter.setItem(storageKey, JSON.stringify(activeTokens)) :
23415
+ // Persist named theme string
23416
+ storageAdapter.setItem(storageKey, String(currentTheme)));
23417
+ }), [ currentTheme, activeTokens, enablePersistence, storageKey, storageAdapter ]),
22508
23418
  // Cleanup: Remove completed promises and abort controllers on unmount
22509
23419
  React.useEffect((() => () => {
22510
23420
  // Cancel any in-flight theme loads
@@ -22645,20 +23555,21 @@ const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme:
22645
23555
  setIsLoading(!1);
22646
23556
  }
22647
23557
  }
22648
- }), [ themes, isThemeLoaded, handleError, basePath, useMinified, cdnPath ]), themeManager = React.useMemo((() => ({})), []), availableThemes = React.useMemo((() => Object.entries(themes).map((([name, metadata]) => ({
23558
+ }), [ 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
23559
  ...metadata,
22650
23560
  name: name
22651
23561
  })))), [ themes ]), contextValue = React.useMemo((() => ({
22652
23562
  theme: currentTheme,
22653
23563
  activeTokens: activeTokens,
22654
23564
  setTheme: setTheme,
23565
+ updateTheme: updateTheme,
22655
23566
  availableThemes: availableThemes,
22656
23567
  isLoading: isLoading,
22657
23568
  error: error,
22658
23569
  isThemeLoaded: isThemeLoaded,
22659
23570
  preloadTheme: preloadTheme,
22660
23571
  themeManager: themeManager
22661
- })), [ currentTheme, activeTokens, setTheme, availableThemes,
23572
+ })), [ currentTheme, activeTokens, setTheme, updateTheme, availableThemes,
22662
23573
  // Use memoized value
22663
23574
  isLoading, error, isThemeLoaded, preloadTheme, themeManager ]);
22664
23575
  // Check if theme is loaded
@@ -22712,6 +23623,7 @@ function useTheme() {
22712
23623
  theme: context.theme,
22713
23624
  activeTokens: context.activeTokens,
22714
23625
  setTheme: context.setTheme,
23626
+ updateTheme: context.updateTheme,
22715
23627
  availableThemes: context.availableThemes,
22716
23628
  isLoading: context.isLoading,
22717
23629
  error: context.error,
@@ -22947,6 +23859,389 @@ function useThemeTokens() {
22947
23859
  }
22948
23860
  }
22949
23861
 
23862
+ /**
23863
+ * useThemeSwitcher Hook
23864
+ *
23865
+ * React hook for managing theme switching with persistence and system preference detection.
23866
+ * Provides an easy-to-use API for dark/light mode toggling.
23867
+ *
23868
+ * @example
23869
+ * ```tsx
23870
+ * import { useThemeSwitcher } from '@shohojdhara/atomix/theme';
23871
+ *
23872
+ * function ThemeToggle() {
23873
+ * const { mode, toggle, setMode, isDark } = useThemeSwitcher();
23874
+ *
23875
+ * return (
23876
+ * <button onClick={toggle}>
23877
+ * {isDark ? '☀️ Light' : '🌙 Dark'}
23878
+ * </button>
23879
+ * );
23880
+ * }
23881
+ * ```
23882
+ */
23883
+ /**
23884
+ * Hook for managing theme switching
23885
+ *
23886
+ * @param options - Configuration options
23887
+ * @returns Theme switcher controls
23888
+ */ function useThemeSwitcher(options = {}) {
23889
+ const {initialMode: initialMode = "system", syncWithSystem: syncWithSystem = !1, storageKey: storageKey = "atomix-theme", enableTransition: enableTransition = !0, transitionDuration: transitionDuration = 300} = options, [mode, setModeState] = React.useState((() => {
23890
+ if ("undefined" == typeof window) return initialMode;
23891
+ // Check for saved preference first
23892
+ const saved = getCurrentTheme(storageKey);
23893
+ return saved && "system" !== saved ? saved : "system" === initialMode ? getSystemTheme() : initialMode;
23894
+ // Fall back to initial mode or system
23895
+ }));
23896
+ // State for current mode
23897
+ // Initialize theme on mount
23898
+ return React.useEffect((() => {
23899
+ "undefined" != typeof window && (
23900
+ // Initialize with proper theme application
23901
+ initializeTheme({
23902
+ storageKey: storageKey,
23903
+ enableTransition: enableTransition,
23904
+ transitionDuration: transitionDuration
23905
+ }),
23906
+ // Update state to match initialized theme
23907
+ setModeState(getCurrentTheme(storageKey)));
23908
+ }), [ storageKey, enableTransition, transitionDuration ]),
23909
+ // Listen for system theme changes if enabled
23910
+ React.useEffect((() => {
23911
+ if (syncWithSystem) return listenToSystemTheme((newMode => {
23912
+ setModeState(newMode), switchTheme(newMode, {
23913
+ storageKey: storageKey,
23914
+ enableTransition: enableTransition,
23915
+ transitionDuration: transitionDuration
23916
+ });
23917
+ }));
23918
+ }), [ syncWithSystem, storageKey, enableTransition, transitionDuration ]), {
23919
+ mode: mode,
23920
+ isDark: "dark" === mode,
23921
+ isLight: "light" === mode,
23922
+ toggle: React.useCallback((() => {
23923
+ const newMode = toggleTheme({
23924
+ storageKey: storageKey,
23925
+ enableTransition: enableTransition,
23926
+ transitionDuration: transitionDuration
23927
+ });
23928
+ return setModeState(newMode), newMode;
23929
+ }), [ storageKey, enableTransition, transitionDuration ]),
23930
+ setMode: React.useCallback((newMode => {
23931
+ switchTheme(newMode, {
23932
+ storageKey: storageKey,
23933
+ enableTransition: enableTransition,
23934
+ transitionDuration: transitionDuration
23935
+ }), setModeState(newMode);
23936
+ }), [ storageKey, enableTransition, transitionDuration ]),
23937
+ resetToSystem: React.useCallback((() => {
23938
+ const systemMode = getSystemTheme();
23939
+ switchTheme(systemMode, {
23940
+ storageKey: storageKey,
23941
+ enableTransition: enableTransition,
23942
+ transitionDuration: transitionDuration
23943
+ }), setModeState(systemMode);
23944
+ }), [ storageKey, enableTransition, transitionDuration ]),
23945
+ clearPreference: React.useCallback((() => {
23946
+ "undefined" != typeof window && localStorage.removeItem(storageKey);
23947
+ }), [ storageKey ])
23948
+ };
23949
+ }
23950
+
23951
+ /**
23952
+ * ThemeToggle component with multiple variants
23953
+ */ 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}) => {
23954
+ const {mode: mode, isDark: isDark, toggle: toggle} = useThemeSwitcher(hookOptions);
23955
+ // Custom render
23956
+ return render ? jsxRuntime.jsx(jsxRuntime.Fragment, {
23957
+ children: render({
23958
+ isDark: isDark,
23959
+ toggle: toggle,
23960
+ mode: mode
23961
+ })
23962
+ }) :
23963
+ // Icon-only variant (default)
23964
+ "icon" === variant ? jsxRuntime.jsx("button", {
23965
+ onClick: toggle,
23966
+ className: `theme-toggle theme-toggle-icon ${className}`,
23967
+ "aria-label": ariaLabel,
23968
+ title: isDark ? darkLabel : lightLabel,
23969
+ style: {
23970
+ background: "none",
23971
+ border: "none",
23972
+ cursor: "pointer",
23973
+ padding: "8px",
23974
+ borderRadius: "50%",
23975
+ display: "flex",
23976
+ alignItems: "center",
23977
+ justifyContent: "center",
23978
+ transition: "all 0.3s ease-in-out"
23979
+ },
23980
+ children: isDark ? jsxRuntime.jsxs("svg", {
23981
+ width: iconSize,
23982
+ height: iconSize,
23983
+ viewBox: "0 0 24 24",
23984
+ fill: "none",
23985
+ stroke: "currentColor",
23986
+ strokeWidth: "2",
23987
+ strokeLinecap: "round",
23988
+ strokeLinejoin: "round",
23989
+ children: [ jsxRuntime.jsx("circle", {
23990
+ cx: "12",
23991
+ cy: "12",
23992
+ r: "5"
23993
+ }), jsxRuntime.jsx("line", {
23994
+ x1: "12",
23995
+ y1: "1",
23996
+ x2: "12",
23997
+ y2: "3"
23998
+ }), jsxRuntime.jsx("line", {
23999
+ x1: "12",
24000
+ y1: "21",
24001
+ x2: "12",
24002
+ y2: "23"
24003
+ }), jsxRuntime.jsx("line", {
24004
+ x1: "4.22",
24005
+ y1: "4.22",
24006
+ x2: "5.64",
24007
+ y2: "5.64"
24008
+ }), jsxRuntime.jsx("line", {
24009
+ x1: "18.36",
24010
+ y1: "18.36",
24011
+ x2: "19.78",
24012
+ y2: "19.78"
24013
+ }), jsxRuntime.jsx("line", {
24014
+ x1: "1",
24015
+ y1: "12",
24016
+ x2: "3",
24017
+ y2: "12"
24018
+ }), jsxRuntime.jsx("line", {
24019
+ x1: "21",
24020
+ y1: "12",
24021
+ x2: "23",
24022
+ y2: "12"
24023
+ }), jsxRuntime.jsx("line", {
24024
+ x1: "4.22",
24025
+ y1: "19.78",
24026
+ x2: "5.64",
24027
+ y2: "18.36"
24028
+ }), jsxRuntime.jsx("line", {
24029
+ x1: "18.36",
24030
+ y1: "5.64",
24031
+ x2: "19.78",
24032
+ y2: "4.22"
24033
+ }) ]
24034
+ }) : jsxRuntime.jsx("svg", {
24035
+ width: iconSize,
24036
+ height: iconSize,
24037
+ viewBox: "0 0 24 24",
24038
+ fill: "none",
24039
+ stroke: "currentColor",
24040
+ strokeWidth: "2",
24041
+ strokeLinecap: "round",
24042
+ strokeLinejoin: "round",
24043
+ children: jsxRuntime.jsx("path", {
24044
+ d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
24045
+ })
24046
+ })
24047
+ }) :
24048
+ // Button variant with text
24049
+ "button" === variant ? jsxRuntime.jsxs("button", {
24050
+ onClick: toggle,
24051
+ className: `theme-toggle theme-toggle-button ${className}`,
24052
+ "aria-label": ariaLabel,
24053
+ style: {
24054
+ display: "flex",
24055
+ alignItems: "center",
24056
+ gap: "8px",
24057
+ padding: "8px 16px",
24058
+ borderRadius: "8px",
24059
+ border: "1px solid currentColor",
24060
+ background: "transparent",
24061
+ color: "inherit",
24062
+ cursor: "pointer",
24063
+ fontSize: "14px",
24064
+ fontWeight: "500",
24065
+ transition: "all 0.3s ease-in-out"
24066
+ },
24067
+ children: [ isDark ? jsxRuntime.jsxs("svg", {
24068
+ width: iconSize,
24069
+ height: iconSize,
24070
+ viewBox: "0 0 24 24",
24071
+ fill: "none",
24072
+ stroke: "currentColor",
24073
+ strokeWidth: "2",
24074
+ strokeLinecap: "round",
24075
+ strokeLinejoin: "round",
24076
+ children: [ jsxRuntime.jsx("circle", {
24077
+ cx: "12",
24078
+ cy: "12",
24079
+ r: "5"
24080
+ }), jsxRuntime.jsx("line", {
24081
+ x1: "12",
24082
+ y1: "1",
24083
+ x2: "12",
24084
+ y2: "3"
24085
+ }), jsxRuntime.jsx("line", {
24086
+ x1: "12",
24087
+ y1: "21",
24088
+ x2: "12",
24089
+ y2: "23"
24090
+ }), jsxRuntime.jsx("line", {
24091
+ x1: "4.22",
24092
+ y1: "4.22",
24093
+ x2: "5.64",
24094
+ y2: "5.64"
24095
+ }), jsxRuntime.jsx("line", {
24096
+ x1: "18.36",
24097
+ y1: "18.36",
24098
+ x2: "19.78",
24099
+ y2: "19.78"
24100
+ }), jsxRuntime.jsx("line", {
24101
+ x1: "1",
24102
+ y1: "12",
24103
+ x2: "3",
24104
+ y2: "12"
24105
+ }), jsxRuntime.jsx("line", {
24106
+ x1: "21",
24107
+ y1: "12",
24108
+ x2: "23",
24109
+ y2: "12"
24110
+ }), jsxRuntime.jsx("line", {
24111
+ x1: "4.22",
24112
+ y1: "19.78",
24113
+ x2: "5.64",
24114
+ y2: "18.36"
24115
+ }), jsxRuntime.jsx("line", {
24116
+ x1: "18.36",
24117
+ y1: "5.64",
24118
+ x2: "19.78",
24119
+ y2: "4.22"
24120
+ }) ]
24121
+ }) : jsxRuntime.jsx("svg", {
24122
+ width: iconSize,
24123
+ height: iconSize,
24124
+ viewBox: "0 0 24 24",
24125
+ fill: "none",
24126
+ stroke: "currentColor",
24127
+ strokeWidth: "2",
24128
+ strokeLinecap: "round",
24129
+ strokeLinejoin: "round",
24130
+ children: jsxRuntime.jsx("path", {
24131
+ d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
24132
+ })
24133
+ }), showLabel && jsxRuntime.jsx("span", {
24134
+ children: isDark ? darkLabel : lightLabel
24135
+ }) ]
24136
+ }) :
24137
+ // Switch/toggle variant
24138
+ "switch" === variant ? jsxRuntime.jsx("div", {
24139
+ className: `theme-toggle theme-toggle-switch ${className}`,
24140
+ role: "button",
24141
+ tabIndex: 0,
24142
+ onClick: toggle,
24143
+ onKeyDown: e => "Enter" === e.key && toggle(),
24144
+ "aria-label": ariaLabel,
24145
+ style: {
24146
+ position: "relative",
24147
+ width: "56px",
24148
+ height: "28px",
24149
+ borderRadius: "14px",
24150
+ background: isDark ? "#4b5563" : "#d1d5db",
24151
+ cursor: "pointer",
24152
+ transition: "background 0.3s ease-in-out",
24153
+ display: "flex",
24154
+ alignItems: "center",
24155
+ padding: "2px"
24156
+ },
24157
+ children: jsxRuntime.jsx("div", {
24158
+ style: {
24159
+ position: "absolute",
24160
+ left: isDark ? "auto" : "2px",
24161
+ right: isDark ? "2px" : "auto",
24162
+ width: "24px",
24163
+ height: "24px",
24164
+ borderRadius: "50%",
24165
+ background: "white",
24166
+ boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)",
24167
+ transition: "all 0.3s ease-in-out",
24168
+ display: "flex",
24169
+ alignItems: "center",
24170
+ justifyContent: "center"
24171
+ },
24172
+ children: isDark ? jsxRuntime.jsx("svg", {
24173
+ width: "14",
24174
+ height: "14",
24175
+ viewBox: "0 0 24 24",
24176
+ fill: "none",
24177
+ stroke: "#4b5563",
24178
+ strokeWidth: "2",
24179
+ strokeLinecap: "round",
24180
+ strokeLinejoin: "round",
24181
+ children: jsxRuntime.jsx("path", {
24182
+ d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
24183
+ })
24184
+ }) : jsxRuntime.jsxs("svg", {
24185
+ width: "14",
24186
+ height: "14",
24187
+ viewBox: "0 0 24 24",
24188
+ fill: "none",
24189
+ stroke: "#f59e0b",
24190
+ strokeWidth: "2",
24191
+ strokeLinecap: "round",
24192
+ strokeLinejoin: "round",
24193
+ children: [ jsxRuntime.jsx("circle", {
24194
+ cx: "12",
24195
+ cy: "12",
24196
+ r: "5"
24197
+ }), jsxRuntime.jsx("line", {
24198
+ x1: "12",
24199
+ y1: "1",
24200
+ x2: "12",
24201
+ y2: "3"
24202
+ }), jsxRuntime.jsx("line", {
24203
+ x1: "12",
24204
+ y1: "21",
24205
+ x2: "12",
24206
+ y2: "23"
24207
+ }), jsxRuntime.jsx("line", {
24208
+ x1: "4.22",
24209
+ y1: "4.22",
24210
+ x2: "5.64",
24211
+ y2: "5.64"
24212
+ }), jsxRuntime.jsx("line", {
24213
+ x1: "18.36",
24214
+ y1: "18.36",
24215
+ x2: "19.78",
24216
+ y2: "19.78"
24217
+ }), jsxRuntime.jsx("line", {
24218
+ x1: "1",
24219
+ y1: "12",
24220
+ x2: "3",
24221
+ y2: "12"
24222
+ }), jsxRuntime.jsx("line", {
24223
+ x1: "21",
24224
+ y1: "12",
24225
+ x2: "23",
24226
+ y2: "12"
24227
+ }), jsxRuntime.jsx("line", {
24228
+ x1: "4.22",
24229
+ y1: "19.78",
24230
+ x2: "5.64",
24231
+ y2: "18.36"
24232
+ }), jsxRuntime.jsx("line", {
24233
+ x1: "18.36",
24234
+ y1: "5.64",
24235
+ x2: "19.78",
24236
+ y2: "4.22"
24237
+ }) ]
24238
+ })
24239
+ })
24240
+ }) : null;
24241
+ };
24242
+
24243
+ ThemeToggle.displayName = "ThemeToggle";
24244
+
22950
24245
  /**
22951
24246
  * Theme Applicator
22952
24247
  *
@@ -22959,7 +24254,8 @@ function useThemeTokens() {
22959
24254
  * Theme applicator class for runtime theme application
22960
24255
  *
22961
24256
  * Uses the unified theme system for efficient CSS variable generation and injection.
22962
- */ class ThemeApplicator {
24257
+ */
24258
+ class ThemeApplicator {
22963
24259
  constructor(root = document.documentElement) {
22964
24260
  this.styleId = "atomix-theme-applicator", this.root = root;
22965
24261
  }
@@ -24698,13 +25994,13 @@ class ThemeValidator {
24698
25994
  function createPaletteColor(color) {
24699
25995
  return "string" == typeof color ? {
24700
25996
  main: color,
24701
- light: lighten(color),
24702
- dark: darken(color),
25997
+ light: lighten(color, .15),
25998
+ dark: darken(color, .15),
24703
25999
  contrastText: getContrastText(color)
24704
26000
  } : {
24705
26001
  main: color.main || "#000000",
24706
- light: color.light || lighten(color.main || "#000000"),
24707
- dark: color.dark || darken(color.main || "#000000"),
26002
+ light: color.light || lighten(color.main || "#000000", .15),
26003
+ dark: color.dark || darken(color.main || "#000000", .15),
24708
26004
  contrastText: color.contrastText || getContrastText(color.main || "#000000")
24709
26005
  };
24710
26006
  }
@@ -24739,23 +26035,19 @@ function createThemeObject(...options) {
24739
26035
  },
24740
26036
  background: {
24741
26037
  default: mergedOptions.palette?.background?.default || DEFAULT_PALETTE.background.default,
26038
+ paper: mergedOptions.palette?.background?.paper || DEFAULT_PALETTE.background.paper,
24742
26039
  subtle: mergedOptions.palette?.background?.subtle || DEFAULT_PALETTE.background.subtle
24743
26040
  },
24744
26041
  text: {
24745
26042
  primary: mergedOptions.palette?.text?.primary || DEFAULT_PALETTE.text.primary,
24746
26043
  secondary: mergedOptions.palette?.text?.secondary || DEFAULT_PALETTE.text.secondary,
24747
26044
  disabled: mergedOptions.palette?.text?.disabled || DEFAULT_PALETTE.text.disabled
24748
- }
26045
+ },
26046
+ // Spread other palette properties
26047
+ ...mergedOptions.palette
24749
26048
  }, typography = deepMerge({
24750
26049
  ...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) {
26050
+ }, mergedOptions.typography || {}), spacing = createSpacing(mergedOptions.spacing), breakpoints = function(breakpointsInput) {
24759
26051
  const values = {
24760
26052
  xs: 0,
24761
26053
  sm: 576,
@@ -25577,25 +26869,7 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
25577
26869
 
25578
26870
  /**
25579
26871
  * 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
-
26872
+ */
25599
26873
  /**
25600
26874
  * Theme Helper Functions
25601
26875
  *
@@ -25608,7 +26882,8 @@ function designTokensToCSSVars(tokens) {
25608
26882
  *
25609
26883
  * @param value - Value to check
25610
26884
  * @returns True if value is DesignTokens
25611
- */ function isDesignTokens(value) {
26885
+ */
26886
+ function isDesignTokens(value) {
25612
26887
  if (!value || "object" != typeof value) return !1;
25613
26888
  // DesignTokens is a flat object with string keys, no nested structures
25614
26889
  const obj = value;
@@ -25620,6 +26895,335 @@ function designTokensToCSSVars(tokens) {
25620
26895
  // Check if keys look like DesignTokens (kebab-case, no nesting)
25621
26896
  }
25622
26897
 
26898
+ /**
26899
+ * Performance monitor class
26900
+ */ class PerformanceMonitor {
26901
+ /**
26902
+ * Create a new performance monitor
26903
+ *
26904
+ * @param config Configuration options
26905
+ */
26906
+ constructor(config) {
26907
+ this.frameCount = 0, this.lastSampleTime = 0, this.lastFpsUpdate = 0, this.frameTimes = [],
26908
+ this.animationFrameId = null, this.isActive = !1, this.startTime = 0, this.config = {
26909
+ fpsTarget: config?.fpsTarget ?? 60,
26910
+ sampleInterval: config?.sampleInterval ?? 500,
26911
+ onUpdate: config?.onUpdate ?? (() => {}),
26912
+ onDegraded: config?.onDegraded ?? (() => {}),
26913
+ enableMemoryMonitoring: config?.enableMemoryMonitoring ?? ("undefined" != typeof window && window.performance && window.performance.memory)
26914
+ };
26915
+ }
26916
+ /**
26917
+ * Start monitoring performance
26918
+ */ start() {
26919
+ this.isActive || (this.isActive = !0, this.frameCount = 0, this.lastSampleTime = performance.now(),
26920
+ this.lastFpsUpdate = this.lastSampleTime, this.frameTimes = [], this.startTime = this.lastSampleTime,
26921
+ this.animationFrameId = requestAnimationFrame(this.onFrame.bind(this)));
26922
+ }
26923
+ /**
26924
+ * Stop monitoring performance
26925
+ */ stop() {
26926
+ this.animationFrameId && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null),
26927
+ this.isActive = !1;
26928
+ }
26929
+ /**
26930
+ * Get current performance metrics
26931
+ */ getMetrics() {
26932
+ var _context;
26933
+ 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;
26934
+ // Get memory stats if available
26935
+ let memory;
26936
+ if (this.config.enableMemoryMonitoring) {
26937
+ const perf = window.performance;
26938
+ perf && perf.memory && (memory = {
26939
+ usedJSHeapSize: perf.memory.usedJSHeapSize,
26940
+ totalJSHeapSize: perf.memory.totalJSHeapSize,
26941
+ jsHeapSizeLimit: perf.memory.jsHeapSizeLimit
26942
+ });
26943
+ }
26944
+ return {
26945
+ fps: fps,
26946
+ frameTime: avgFrameTime,
26947
+ peakFrameTime: peakFrameTime,
26948
+ memory: memory,
26949
+ timestamp: now,
26950
+ isDegraded: fps < .7 * this.config.fpsTarget
26951
+ };
26952
+ }
26953
+ /**
26954
+ * Get the current FPS
26955
+ */ getFps() {
26956
+ return this.getMetrics().fps;
26957
+ }
26958
+ /**
26959
+ * Check if performance is degraded
26960
+ */ isPerformanceDegraded() {
26961
+ return this.getMetrics().isDegraded;
26962
+ }
26963
+ /**
26964
+ * Private method called on each animation frame
26965
+ */ onFrame(timestamp) {
26966
+ if (!this.isActive) return;
26967
+ // Calculate frame time
26968
+ const frameTime = timestamp - this.lastSampleTime;
26969
+ // Check if we need to update metrics
26970
+ if (this.frameTimes.push(frameTime),
26971
+ // Keep only the last 60 frame times for averaging
26972
+ this.frameTimes.length > 60 && this.frameTimes.shift(), this.frameCount++, this.lastSampleTime = timestamp,
26973
+ timestamp - this.lastFpsUpdate >= this.config.sampleInterval) {
26974
+ const metrics = this.getMetrics();
26975
+ // Call update callback
26976
+ this.config.onUpdate(metrics),
26977
+ // Check for degradation
26978
+ metrics.isDegraded && this.config.onDegraded(metrics),
26979
+ // Reset counters
26980
+ this.frameCount = 0, this.lastFpsUpdate = timestamp;
26981
+ }
26982
+ this.animationFrameId = requestAnimationFrame(this.onFrame.bind(this));
26983
+ }
26984
+ /**
26985
+ * Run a performance test for a specific function
26986
+ *
26987
+ * @param fn Function to test
26988
+ * @param iterations Number of iterations (default: 100)
26989
+ * @returns Average execution time in ms
26990
+ */ async testFunctionPerformance(fn, iterations = 100) {
26991
+ const times = [];
26992
+ for (let i = 0; i < iterations; i++) {
26993
+ const start = performance.now();
26994
+ fn();
26995
+ const end = performance.now();
26996
+ times.push(end - start);
26997
+ }
26998
+ return _reduceInstanceProperty(times).call(times, ((a, b) => a + b), 0) / times.length;
26999
+ }
27000
+ }
27001
+
27002
+ /**
27003
+ * Create a performance monitor instance
27004
+ *
27005
+ * @param config Configuration options
27006
+ * @returns PerformanceMonitor instance
27007
+ *
27008
+ * @example
27009
+ * ```typescript
27010
+ * import { createPerformanceMonitor } from '@shohojdhara/atomix/theme';
27011
+ *
27012
+ * const monitor = createPerformanceMonitor({
27013
+ * fpsTarget: 60,
27014
+ * onUpdate: (metrics) => console.log('FPS:', metrics.fps),
27015
+ * onDegraded: (metrics) => console.warn('Performance degraded!', metrics),
27016
+ * });
27017
+ *
27018
+ * monitor.start();
27019
+ *
27020
+ * // Later...
27021
+ * monitor.stop();
27022
+ * ```
27023
+ */ function createPerformanceMonitor(config) {
27024
+ return new PerformanceMonitor(config);
27025
+ }
27026
+
27027
+ /**
27028
+ * Hook for React components to monitor performance
27029
+ *
27030
+ * @param config Configuration options
27031
+ * @returns Performance metrics and monitor controls
27032
+ *
27033
+ * @example
27034
+ * ```typescript
27035
+ * import { usePerformanceMonitor } from '@shohojdhara/atomix/theme';
27036
+ *
27037
+ * function MyComponent() {
27038
+ * const { metrics, start, stop } = usePerformanceMonitor({ fpsTarget: 60 });
27039
+ *
27040
+ * useEffect(() => {
27041
+ * start();
27042
+ * return () => stop();
27043
+ * }, []);
27044
+ *
27045
+ * return <div>FPS: {metrics.fps}</div>;
27046
+ * }
27047
+ * ```
27048
+ */ function usePerformanceMonitor(config) {
27049
+ const [monitor] = React__default.default.useState((() => createPerformanceMonitor(config))), [metrics, setMetrics] = React__default.default.useState((() => "undefined" != typeof window ? monitor.getMetrics() : {
27050
+ fps: 0,
27051
+ frameTime: 0,
27052
+ peakFrameTime: 0,
27053
+ timestamp: 0,
27054
+ isDegraded: !1
27055
+ })), start = React__default.default.useCallback((() => {
27056
+ "undefined" != typeof window && monitor.start();
27057
+ }), [ monitor ]), stop = React__default.default.useCallback((() => {
27058
+ "undefined" != typeof window && monitor.stop();
27059
+ }), [ monitor ]);
27060
+ return React__default.default.useEffect((() => {
27061
+ if ("undefined" == typeof window) return;
27062
+ // Update metrics when monitor callbacks fire
27063
+ const originalOnUpdate = config?.onUpdate;
27064
+ return monitor.config.onUpdate = newMetrics => {
27065
+ setMetrics(newMetrics), originalOnUpdate?.(newMetrics);
27066
+ }, () => {
27067
+ monitor.stop();
27068
+ };
27069
+ }), [ monitor, config?.onUpdate ]), {
27070
+ metrics: metrics,
27071
+ start: start,
27072
+ stop: stop
27073
+ };
27074
+ }
27075
+
27076
+ /**
27077
+ * Responsive Utility for Atomix Theme System
27078
+ *
27079
+ * Provides responsive breakpoint detection and device-aware parameter scaling
27080
+ * based on configuration from the advanced optimization features.
27081
+ */
27082
+ /**
27083
+ * Responsive utility class
27084
+ */ class ResponsiveUtil {
27085
+ constructor(config) {
27086
+ this.currentDevice = "desktop", // Default
27087
+ this.resizeHandler = null, this.observer = null, this.config = config, this.currentDevice = this.getCurrentDeviceType(),
27088
+ // Set up resize listener
27089
+ this.setupResizeListener();
27090
+ }
27091
+ /**
27092
+ * Get the current device type based on viewport width
27093
+ */ getCurrentDeviceType() {
27094
+ if ("undefined" == typeof window) return "desktop";
27095
+ // SSR fallback
27096
+ const width = window.innerWidth;
27097
+ // Parse breakpoint values to numbers
27098
+ this.parsePxValue(this.config.breakpoints.mobile);
27099
+ const tabletWidth = this.parsePxValue(this.config.breakpoints.tablet), desktopWidth = this.parsePxValue(this.config.breakpoints.desktop), wideWidth = this.parsePxValue(this.config.breakpoints.wide);
27100
+ return width < tabletWidth ? "mobile" : width < desktopWidth ? "tablet" : width < wideWidth ? "desktop" : "wide";
27101
+ }
27102
+ /**
27103
+ * Get the scaling factor for the current device
27104
+ */ getCurrentScalingFactor() {
27105
+ // 'wide' devices use the same scaling as 'desktop'
27106
+ const scalingKey = "wide" === this.currentDevice ? "desktop" : this.currentDevice;
27107
+ return this.config.deviceScaling[scalingKey] || 1;
27108
+ }
27109
+ /**
27110
+ * Scale a value based on the current device's scaling factor
27111
+ */ scaleValue(value) {
27112
+ return value * this.getCurrentScalingFactor();
27113
+ }
27114
+ /**
27115
+ * Check if the current device matches a specific type
27116
+ */ isDevice(device) {
27117
+ return this.currentDevice === device;
27118
+ }
27119
+ /**
27120
+ * Check if the current device is mobile or smaller
27121
+ */ isMobileOrSmaller() {
27122
+ return "mobile" === this.currentDevice;
27123
+ }
27124
+ /**
27125
+ * Check if the current device is tablet or smaller
27126
+ */ isTabletOrSmaller() {
27127
+ return "mobile" === this.currentDevice || "tablet" === this.currentDevice;
27128
+ }
27129
+ /**
27130
+ * Check if the current device is desktop or larger
27131
+ */ isDesktopOrLarger() {
27132
+ return "desktop" === this.currentDevice || "wide" === this.currentDevice;
27133
+ }
27134
+ /**
27135
+ * Update the responsive configuration
27136
+ */ updateConfig(config) {
27137
+ this.config = config, this.currentDevice = this.getCurrentDeviceType();
27138
+ }
27139
+ /**
27140
+ * Destroy the responsive utility and clean up listeners
27141
+ */ destroy() {
27142
+ this.resizeHandler && (window.removeEventListener("resize", this.resizeHandler),
27143
+ this.resizeHandler = null), this.observer && (this.observer.disconnect(), this.observer = null);
27144
+ }
27145
+ /**
27146
+ * Parse a CSS value to pixels
27147
+ */ parsePxValue(value) {
27148
+ return value.endsWith("px") ? parseFloat(value.slice(0, -2)) :
27149
+ // For other units, we'll use a rough conversion assuming 16px base
27150
+ value.endsWith("rem") ? 16 * parseFloat(value.slice(0, -3)) : value.endsWith("em") ? 16 * parseFloat(value.slice(0, -2)) : parseFloat(value) || 0;
27151
+ }
27152
+ /**
27153
+ * Set up the resize listener
27154
+ */ setupResizeListener() {
27155
+ if ("undefined" == typeof window) return;
27156
+ // Throttled resize handler
27157
+ let resizeTimeout = null;
27158
+ const handleResize = () => {
27159
+ resizeTimeout && window.clearTimeout(resizeTimeout), resizeTimeout = window.setTimeout((() => {
27160
+ const newDeviceType = this.getCurrentDeviceType();
27161
+ newDeviceType !== this.currentDevice && (this.currentDevice = newDeviceType);
27162
+ }), 150);
27163
+ } // Throttle to 150ms
27164
+ ;
27165
+ this.resizeHandler = handleResize, window.addEventListener("resize", handleResize),
27166
+ // Also observe the document body for size changes
27167
+ "undefined" != typeof ResizeObserver && (this.observer = new ResizeObserver(handleResize),
27168
+ this.observer.observe(document.body));
27169
+ }
27170
+ }
27171
+
27172
+ /**
27173
+ * Create a responsive utility instance
27174
+ *
27175
+ * @param config Responsive configuration
27176
+ * @returns ResponsiveUtil instance
27177
+ */ function createResponsiveUtil(config) {
27178
+ return new ResponsiveUtil(config);
27179
+ }
27180
+
27181
+ /**
27182
+ * Hook for React components to use responsive features
27183
+ *
27184
+ * @param config Responsive configuration
27185
+ * @returns Current device type and utility functions
27186
+ */ function useResponsive(config) {
27187
+ const [util] = React__default.default.useState((() => createResponsiveUtil(config))), [deviceType, setDeviceType] = React__default.default.useState((() => "undefined" != typeof window ? util.getCurrentDeviceType() : "desktop"));
27188
+ return React__default.default.useEffect((() => {
27189
+ if ("undefined" == typeof window) return;
27190
+ const handleResize = () => {
27191
+ const newDeviceType = util.getCurrentDeviceType();
27192
+ newDeviceType !== deviceType && setDeviceType(newDeviceType);
27193
+ };
27194
+ // Update device type on mount
27195
+ return setDeviceType(util.getCurrentDeviceType()),
27196
+ // Listen for resize events
27197
+ window.addEventListener("resize", handleResize), () => {
27198
+ window.removeEventListener("resize", handleResize), util.destroy();
27199
+ };
27200
+ }), [ util, deviceType ]), "undefined" == typeof window ? {
27201
+ deviceType: "desktop",
27202
+ isMobile: !1,
27203
+ isTablet: !1,
27204
+ isDesktop: !0,
27205
+ isWide: !1,
27206
+ scaleValue: value => value,
27207
+ getCurrentDeviceType: () => "desktop",
27208
+ getCurrentScalingFactor: () => 1,
27209
+ isMobileOrSmaller: () => !1,
27210
+ isTabletOrSmaller: () => !0,
27211
+ isDesktopOrLarger: () => !0
27212
+ } : {
27213
+ deviceType: deviceType,
27214
+ isMobile: "mobile" === deviceType,
27215
+ isTablet: "tablet" === deviceType,
27216
+ isDesktop: "desktop" === deviceType,
27217
+ isWide: "wide" === deviceType,
27218
+ scaleValue: value => util.scaleValue(value),
27219
+ getCurrentDeviceType: () => util.getCurrentDeviceType(),
27220
+ getCurrentScalingFactor: () => util.getCurrentScalingFactor(),
27221
+ isMobileOrSmaller: () => util.isMobileOrSmaller(),
27222
+ isTabletOrSmaller: () => util.isTabletOrSmaller(),
27223
+ isDesktopOrLarger: () => util.isDesktopOrLarger()
27224
+ };
27225
+ }
27226
+
25623
27227
  /**
25624
27228
  * RTL (Right-to-Left) Support Utilities
25625
27229
  *
@@ -25805,6 +27409,32 @@ class RTLManager {
25805
27409
  }
25806
27410
  }
25807
27411
 
27412
+ /**
27413
+ * Create RTL manager instance
27414
+ */ function createRTLManager(config) {
27415
+ return new RTLManager(config);
27416
+ }
27417
+
27418
+ /**
27419
+ * Check if locale is RTL
27420
+ */ function isRTLLocale(locale) {
27421
+ return RTL_LOCALES.has(locale.toLowerCase());
27422
+ }
27423
+
27424
+ /**
27425
+ * Get direction from locale
27426
+ */ function getDirectionFromLocale(locale) {
27427
+ return isRTLLocale(locale) ? "rtl" : "ltr";
27428
+ }
27429
+
27430
+ /**
27431
+ * RTL-aware CSS helper
27432
+ *
27433
+ * Returns appropriate CSS based on direction
27434
+ */ function rtlCSS(ltrCSS, rtlCSS, direction = "ltr") {
27435
+ return "rtl" === direction ? rtlCSS : ltrCSS;
27436
+ }
27437
+
25808
27438
  /**
25809
27439
  * Theme System Exports
25810
27440
  *
@@ -25827,8 +27457,6 @@ class RTLManager {
25827
27457
  // ============================================================================
25828
27458
  // Core Theme Functions
25829
27459
  // ============================================================================
25830
- // Create theme CSS from DesignTokens
25831
- // File saving utilities removed to prevent bundling Node.js modules in browser
25832
27460
  /**
25833
27461
  * Inject theme CSS into DOM
25834
27462
  */ function injectTheme(css, id = "atomix-theme") {
@@ -25841,6 +27469,115 @@ class RTLManager {
25841
27469
  removeCSS(id);
25842
27470
  }
25843
27471
 
27472
+ /**
27473
+ * Main theme module interface
27474
+ */ var index = {
27475
+ // Core
27476
+ createTheme: createTheme,
27477
+ injectTheme: injectTheme,
27478
+ removeTheme: removeTheme,
27479
+ // Context and Provider
27480
+ ThemeProvider: ThemeProvider,
27481
+ useTheme: useTheme,
27482
+ useThemeTokens: useThemeTokens,
27483
+ ThemeContext: ThemeContext,
27484
+ ThemeErrorBoundary: ThemeErrorBoundary,
27485
+ // Adapters
27486
+ configToTokens: configToTokens,
27487
+ designTokensToCSSVars: designTokensToCSSVars,
27488
+ // Theme Utils
27489
+ switchTheme: switchTheme,
27490
+ toggleTheme: toggleTheme,
27491
+ getCurrentTheme: getCurrentTheme,
27492
+ getSystemTheme: getSystemTheme,
27493
+ initializeTheme: initializeTheme,
27494
+ listenToSystemTheme: listenToSystemTheme,
27495
+ persistTheme: persistTheme,
27496
+ clearThemePreference: clearThemePreference,
27497
+ // Token Manipulation
27498
+ mergeTokens: mergeTokens,
27499
+ overrideTokens: overrideTokens,
27500
+ pickTokens: pickTokens,
27501
+ omitTokens: omitTokens,
27502
+ // Color Utilities
27503
+ hexToRgb: hexToRgb$1,
27504
+ rgbToHex: rgbToHex,
27505
+ getLuminance: getLuminance,
27506
+ getContrastRatio: getContrastRatio,
27507
+ isAccessible: isAccessible,
27508
+ getContrastText: getContrastText,
27509
+ lighten: lighten,
27510
+ darken: darken,
27511
+ alpha: alpha,
27512
+ emphasize: emphasize,
27513
+ createSpacing: createSpacing,
27514
+ // Performance utilities
27515
+ createPerformanceMonitor: createPerformanceMonitor,
27516
+ usePerformanceMonitor: usePerformanceMonitor,
27517
+ // Responsive utilities
27518
+ createResponsiveUtil: createResponsiveUtil,
27519
+ useResponsive: useResponsive,
27520
+ // Components
27521
+ ThemeToggle: ThemeToggle,
27522
+ ThemeApplicator: ThemeApplicator,
27523
+ applyTheme: applyTheme,
27524
+ getThemeApplicator: getThemeApplicator,
27525
+ // Registry
27526
+ createThemeRegistry: createThemeRegistry,
27527
+ registerTheme: registerTheme,
27528
+ unregisterTheme: unregisterTheme,
27529
+ hasTheme: hasTheme,
27530
+ getTheme: getTheme,
27531
+ getAllThemes: getAllThemes,
27532
+ getThemeIds: getThemeIds,
27533
+ clearThemes: clearThemes,
27534
+ getThemeCount: getThemeCount,
27535
+ // Composition
27536
+ deepMerge: deepMerge,
27537
+ mergeTheme: mergeTheme,
27538
+ extendTheme: extendTheme,
27539
+ // Tokens
27540
+ createTokens: createTokens,
27541
+ defaultTokens: defaultTokens,
27542
+ // Generators
27543
+ generateCSSVariables: generateCSSVariables$1,
27544
+ generateCSSVariablesForSelector: generateCSSVariablesForSelector,
27545
+ // Naming
27546
+ generateClassName: generateClassName,
27547
+ generateCSSVariableName: generateCSSVariableName,
27548
+ normalizeThemeTokens: normalizeThemeTokens,
27549
+ camelToKebab: camelToKebab,
27550
+ themePropertyToCSSVar: themePropertyToCSSVar,
27551
+ // Component Theming
27552
+ getComponentThemeValue: getComponentThemeValue,
27553
+ generateComponentCSSVars: generateComponentCSSVars,
27554
+ applyComponentTheme: applyComponentTheme,
27555
+ useComponentTheme: useComponentTheme,
27556
+ // Hooks
27557
+ useThemeSwitcher: useThemeSwitcher,
27558
+ // Helpers
27559
+ isDesignTokens: isDesignTokens,
27560
+ // CSS Variable Mapper
27561
+ mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
27562
+ applyCSSVariables: applyCSSVariables,
27563
+ removeCSSVariables: removeCSSVariables,
27564
+ getCSSVariable: getCSSVariable,
27565
+ cssVarsToStyle: cssVarsToStyle,
27566
+ mergeCSSVars: mergeCSSVars,
27567
+ isValidCSSVariableName: isValidCSSVariableName,
27568
+ extractComponentName: extractComponentName,
27569
+ // Injection Utils
27570
+ injectCSS: injectCSS$1,
27571
+ removeCSS: removeCSS,
27572
+ isCSSInjected: isCSSInjected,
27573
+ // I18n
27574
+ RTLManager: RTLManager,
27575
+ createRTLManager: createRTLManager,
27576
+ isRTLLocale: isRTLLocale,
27577
+ getDirectionFromLocale: getDirectionFromLocale,
27578
+ rtlCSS: rtlCSS
27579
+ };
27580
+
25844
27581
  /**
25845
27582
  * CSS Variables Constants
25846
27583
  *
@@ -26147,6 +27884,122 @@ function mergePartStyles(base, override) {
26147
27884
  * );
26148
27885
  * }
26149
27886
  */
27887
+ /**
27888
+ * Configuration Validator
27889
+ *
27890
+ * Provides detailed validation and feedback for Atomix configurations,
27891
+ * especially for advanced features (Phases 2, 3, and 4).
27892
+ */
27893
+ /**
27894
+ * Validate an Atomix configuration with detailed feedback
27895
+ *
27896
+ * @param config - The configuration to validate
27897
+ * @param options - Validation options
27898
+ * @returns Detailed validation result
27899
+ *
27900
+ * @example
27901
+ * ```typescript
27902
+ * import { validateConfiguration } from '@shohojdhara/atomix/config';
27903
+ *
27904
+ * const config = { /* your config *\/ };
27905
+ * const result = validateConfiguration(config);
27906
+ *
27907
+ * if (!result.isValid) {
27908
+ * console.warn('Warnings:', result.warnings);
27909
+ * console.info('Suggestions:', result.suggestions);
27910
+ * }
27911
+ * ```
27912
+ */
27913
+ function validateConfiguration(config, options) {
27914
+ const {performanceAnalysis: performanceAnalysis = !0, compatibilityReport: compatibilityReport = !0} = options || {}, warnings = [], suggestions = [];
27915
+ let performanceImpact = "low";
27916
+ // Use the existing validation
27917
+ const baseWarnings = validateConfig$1(config);
27918
+ warnings.push(...baseWarnings),
27919
+ // Analyze advanced features for performance impact
27920
+ performanceAnalysis && (performanceImpact =
27921
+ /**
27922
+ * Analyze the performance impact of a configuration
27923
+ */
27924
+ function(config) {
27925
+ let impactScore = 0;
27926
+ // Analyze interactive effects
27927
+ if (config.interactiveEffects) {
27928
+ const ie = config.interactiveEffects;
27929
+ ie.vortex?.enabled && (impactScore += 2), ie.chromaticAberration?.enabled && (impactScore += 1),
27930
+ ie.mouseInteraction?.trailEffect && (impactScore += 1), ie.mouseInteraction?.pressureSensitivity && (impactScore += 1);
27931
+ }
27932
+ // Analyze visual polish effects
27933
+ if (config.visualPolish) {
27934
+ const vp = config.visualPolish;
27935
+ vp.borders?.iridescentGlow && (impactScore += 1), vp.borders?.shimmerEffect && (impactScore += 1),
27936
+ vp.contentAwareBlur?.enabled && (impactScore += 2), vp.holographicEffects?.enabled && (impactScore += 2),
27937
+ vp.holographicEffects?.scanlineAnimation && (impactScore += 1), vp.holographicEffects?.dataStream && (impactScore += 1),
27938
+ vp.holographicEffects?.pulseRings && (impactScore += 1);
27939
+ }
27940
+ // Analyze optimization settings
27941
+ return config.optimization?.autoScaling?.enabled && (impactScore -= 1),
27942
+ impactScore >= 6 ? "high" : impactScore >= 3 ? "medium" : "low";
27943
+ }
27944
+ /**
27945
+ * Generate suggestions based on the configuration
27946
+ */ (config)),
27947
+ // Generate suggestions based on configuration
27948
+ function(config, suggestions) {
27949
+ // Suggest enabling performance optimizations if heavy effects are used
27950
+ (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"),
27951
+ config.optimization?.performance?.fpsTarget || suggestions.push("Set a target FPS in optimization.performance.fpsTarget to ensure smooth performance when using interactive effects")),
27952
+ // Suggest responsive breakpoints if optimization is partially configured
27953
+ config.optimization && !config.optimization.responsive && suggestions.push("Consider adding responsive breakpoints in optimization.responsive.breakpoints to adapt advanced effects based on device type"),
27954
+ // Suggest disabling heavy effects on lower-end devices
27955
+ config.visualPolish?.holographicEffects?.enabled && suggestions.push("For better performance on lower-end devices, consider conditionally disabling holographic effects based on device capabilities"),
27956
+ // Suggest using content-aware blur with performance considerations
27957
+ 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"),
27958
+ // Suggest using chromatic aberration适度
27959
+ 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"),
27960
+ 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"));
27961
+ }
27962
+ /**
27963
+ * Generate a compatibility report for the configuration
27964
+ */ (config, suggestions);
27965
+ // Determine overall validity
27966
+ const isValid = 0 === warnings.length, compatibility = compatibilityReport ? function(config) {
27967
+ return {
27968
+ browsers: !(config.visualPolish?.holographicEffects?.enabled || config.visualPolish?.contentAwareBlur?.enabled || config.interactiveEffects?.vortex?.enabled || config.interactiveEffects?.chromaticAberration?.enabled),
27969
+ // May have issues on older browsers
27970
+ ssr: !0,
27971
+ // Works fine with SSR
27972
+ frameworks: [ "react", "vue", "angular", "svelte", "vanillajs" ]
27973
+ };
27974
+ }
27975
+ /**
27976
+ * Print a detailed configuration report to the console
27977
+ *
27978
+ * @param config - The configuration to analyze
27979
+ * @param title - Optional title for the report
27980
+ *
27981
+ * @example
27982
+ * ```typescript
27983
+ * import { printConfigReport } from '@shohojdhara/atomix/config';
27984
+ *
27985
+ * const config = { /* your config *\/ };
27986
+ * printConfigReport(config, 'My Application Config');
27987
+ * ```
27988
+ */ (config) : {
27989
+ browsers: !0,
27990
+ ssr: !0,
27991
+ frameworks: [ "react", "vue", "angular", "svelte", "vanillajs" ]
27992
+ };
27993
+ // Generate compatibility report
27994
+ return {
27995
+ isValid: isValid,
27996
+ warnings: warnings,
27997
+ suggestions: suggestions,
27998
+ performanceImpact: performanceImpact,
27999
+ compatibility: compatibility
28000
+ };
28001
+ }
28002
+
26150
28003
  // Import and re-export as namespaces with proper typing
26151
28004
  // Export as namespaces with explicit typing
26152
28005
  const composables = composablesImport, utils = utilsImport, types = typesImport, constants = constantsImport, theme = Object.freeze({
@@ -26161,19 +28014,30 @@ const composables = composablesImport, utils = utilsImport, types = typesImport,
26161
28014
  ThemeLiveEditor: ThemeLiveEditor,
26162
28015
  ThemePreview: ThemePreview,
26163
28016
  ThemeProvider: ThemeProvider,
28017
+ ThemeToggle: ThemeToggle,
26164
28018
  ThemeValidator: ThemeValidator,
28019
+ alpha: alpha,
26165
28020
  applyCSSVariables: applyCSSVariables,
26166
28021
  applyComponentTheme: applyComponentTheme,
26167
28022
  applyTheme: applyTheme,
26168
28023
  camelToKebab: camelToKebab,
28024
+ clearThemePreference: clearThemePreference,
26169
28025
  clearThemes: clearThemes,
28026
+ configToTokens: configToTokens,
28027
+ createPerformanceMonitor: createPerformanceMonitor,
28028
+ createRTLManager: createRTLManager,
28029
+ createResponsiveUtil: createResponsiveUtil,
28030
+ createSpacing: createSpacing,
26170
28031
  createTheme: createTheme,
26171
28032
  createThemeRegistry: createThemeRegistry,
26172
28033
  createTokens: createTokens,
26173
28034
  cssVarsToStyle: cssVarsToStyle,
28035
+ darken: darken,
26174
28036
  deepMerge: deepMerge,
28037
+ default: index,
26175
28038
  defaultTokens: defaultTokens,
26176
28039
  designTokensToCSSVars: designTokensToCSSVars,
28040
+ emphasize: emphasize,
26177
28041
  extendTheme: extendTheme,
26178
28042
  extractComponentName: extractComponentName,
26179
28043
  generateCSSVariableName: generateCSSVariableName,
@@ -26184,29 +28048,53 @@ const composables = composablesImport, utils = utilsImport, types = typesImport,
26184
28048
  getAllThemes: getAllThemes,
26185
28049
  getCSSVariable: getCSSVariable,
26186
28050
  getComponentThemeValue: getComponentThemeValue,
28051
+ getContrastRatio: getContrastRatio,
28052
+ getContrastText: getContrastText,
28053
+ getCurrentTheme: getCurrentTheme,
28054
+ getDirectionFromLocale: getDirectionFromLocale,
28055
+ getLuminance: getLuminance,
28056
+ getSystemTheme: getSystemTheme,
26187
28057
  getTheme: getTheme,
26188
28058
  getThemeApplicator: getThemeApplicator,
26189
28059
  getThemeCount: getThemeCount,
26190
28060
  getThemeIds: getThemeIds,
26191
28061
  hasTheme: hasTheme,
28062
+ hexToRgb: hexToRgb$1,
28063
+ initializeTheme: initializeTheme,
26192
28064
  injectCSS: injectCSS$1,
26193
28065
  injectTheme: injectTheme,
28066
+ isAccessible: isAccessible,
26194
28067
  isCSSInjected: isCSSInjected,
26195
28068
  isDesignTokens: isDesignTokens,
28069
+ isRTLLocale: isRTLLocale,
26196
28070
  isValidCSSVariableName: isValidCSSVariableName,
28071
+ lighten: lighten,
28072
+ listenToSystemTheme: listenToSystemTheme,
26197
28073
  mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
26198
28074
  mergeCSSVars: mergeCSSVars,
26199
28075
  mergeTheme: mergeTheme,
28076
+ mergeTokens: mergeTokens,
26200
28077
  normalizeThemeTokens: normalizeThemeTokens,
28078
+ omitTokens: omitTokens,
28079
+ overrideTokens: overrideTokens,
28080
+ persistTheme: persistTheme,
28081
+ pickTokens: pickTokens,
26201
28082
  registerTheme: registerTheme,
26202
28083
  removeCSS: removeCSS,
26203
28084
  removeCSSVariables: removeCSSVariables,
26204
28085
  removeTheme: removeTheme,
28086
+ rgbToHex: rgbToHex,
28087
+ rtlCSS: rtlCSS,
28088
+ switchTheme: switchTheme,
26205
28089
  themePropertyToCSSVar: themePropertyToCSSVar,
28090
+ toggleTheme: toggleTheme,
26206
28091
  unregisterTheme: unregisterTheme,
26207
28092
  useComponentTheme: useComponentTheme,
26208
28093
  useHistory: useHistory,
28094
+ usePerformanceMonitor: usePerformanceMonitor,
28095
+ useResponsive: useResponsive,
26209
28096
  useTheme: useTheme,
28097
+ useThemeSwitcher: useThemeSwitcher,
26210
28098
  useThemeTokens: useThemeTokens
26211
28099
  }), atomix = {
26212
28100
  // Re-export all components and utilities
@@ -26274,10 +28162,11 @@ exports.TYPEDBUTTON = TYPEDBUTTON, exports.Tabs = Tabs, exports.Testimonial = Te
26274
28162
  exports.Textarea = Textarea, exports.ThemeApplicator = ThemeApplicator, exports.ThemeComparator = ThemeComparator,
26275
28163
  exports.ThemeContext = ThemeContext, exports.ThemeErrorBoundary = ThemeErrorBoundary,
26276
28164
  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,
28165
+ exports.ThemePreview = ThemePreview, exports.ThemeProvider = ThemeProvider, exports.ThemeToggle = ThemeToggle,
28166
+ exports.ThemeValidator = ThemeValidator, exports.Todo = Todo, exports.Toggle = Toggle,
28167
+ exports.Tooltip = Tooltip, exports.TreemapChart = TreemapChart, exports.UPLOAD = UPLOAD,
28168
+ exports.Upload = Upload, exports.VIDEO_PLAYER = VIDEO_PLAYER, exports.VideoPlayer = VideoPlayer,
28169
+ exports.WaterfallChart = WaterfallChart, exports.alpha = alpha, exports.applyCSSVariables = applyCSSVariables,
26281
28170
  exports.applyCSSVarsToStyle =
26282
28171
  /**
26283
28172
  * Utility to apply CSS variables to style object
@@ -26291,60 +28180,16 @@ function(cssVars, baseStyle) {
26291
28180
  };
26292
28181
  }
26293
28182
  /**
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
28183
+ * Configuration Types
26319
28184
  *
26320
- * @param config - Atomix configuration object
26321
- * @returns The configuration object
28185
+ * Type definitions for the Atomix configuration system.
26322
28186
  */
26323
28187
  /**
26324
28188
  * 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
28189
  */ , 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,
28190
+ exports.applyTheme = applyTheme, exports.camelToKebab = camelToKebab, exports.clearThemePreference = clearThemePreference,
28191
+ exports.clearThemes = clearThemes, exports.composables = composables, exports.configToTokens = configToTokens,
28192
+ exports.constants = constants, exports.createBreakpoints = createBreakpoints$1,
26348
28193
  exports.createCSSVarStyle = createCSSVarStyle, exports.createDarkVariant =
26349
28194
  /**
26350
28195
  * Create a dark theme variant from a light theme
@@ -26401,7 +28246,9 @@ function(lightTheme) {
26401
28246
  /**
26402
28247
  * Validate theme structure
26403
28248
  */ , exports.createDebugAttrs = createDebugAttrs, exports.createFontPreloadLink = createFontPreloadLink,
26404
- exports.createPartProps = createPartProps, exports.createSlotComponent =
28249
+ exports.createPartProps = createPartProps, exports.createPerformanceMonitor = createPerformanceMonitor,
28250
+ exports.createRTLManager = createRTLManager, exports.createResponsiveUtil = createResponsiveUtil,
28251
+ exports.createSlotComponent =
26405
28252
  /**
26406
28253
  * Create a slot wrapper component
26407
28254
  *
@@ -26439,11 +28286,13 @@ function(defaultElement = "div") {
26439
28286
  }
26440
28287
  /**
26441
28288
  * Hook to manage slot rendering
26442
- */ , exports.createTheme = createTheme, exports.createThemeRegistry = createThemeRegistry,
26443
- exports.createTokens = createTokens, exports.cssVarsToStyle = cssVarsToStyle, exports.deepMerge = deepMerge,
28289
+ */ , exports.createSpacing = createSpacing, exports.createTheme = createTheme,
28290
+ exports.createThemeRegistry = createThemeRegistry, exports.createTokens = createTokens,
28291
+ exports.cssVarsToStyle = cssVarsToStyle, exports.darken = darken, exports.deepMerge = deepMerge,
26444
28292
  exports.default = atomix, exports.defaultTokens = defaultTokens, exports.defineConfig = function(config) {
26445
28293
  return config;
26446
- }, exports.designTokensToCSSVars = designTokensToCSSVars, exports.exportTheme =
28294
+ }, exports.designTokensToCSSVars = designTokensToCSSVars, exports.emphasize = emphasize,
28295
+ exports.exportTheme =
26447
28296
  /**
26448
28297
  * Export theme as JSON
26449
28298
  */
@@ -26463,9 +28312,12 @@ exports.getAllThemes = getAllThemes, exports.getCSSVariable = getCSSVariable, ex
26463
28312
  */
26464
28313
  function(component) {
26465
28314
  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,
28315
+ }, exports.getComponentThemeValue = getComponentThemeValue, exports.getContrastRatio = getContrastRatio,
28316
+ exports.getContrastText = getContrastText, exports.getCurrentTheme = getCurrentTheme,
28317
+ exports.getDefaultBreakpoints = getDefaultBreakpoints, exports.getDevicePreset = getDevicePreset,
28318
+ exports.getDirectionFromLocale = getDirectionFromLocale, exports.getLuminance = getLuminance,
28319
+ exports.getMobileOptimizedParams = getMobileOptimizedParams, exports.getPartStyles = getPartStyles,
28320
+ exports.getQualityMultipliers = getQualityMultipliers, exports.getSystemTheme = getSystemTheme,
26469
28321
  exports.getTheme = getTheme, exports.getThemeApplicator = getThemeApplicator, exports.getThemeCount = getThemeCount,
26470
28322
  exports.getThemeIds = getThemeIds, exports.getThemeMetadata =
26471
28323
  /**
@@ -26486,7 +28338,7 @@ function(theme) {
26486
28338
  /**
26487
28339
  * Check if theme supports dark mode
26488
28340
  */ , exports.hasCustomization = hasCustomization, exports.hasTheme = hasTheme,
26489
- exports.importTheme = function(json) {
28341
+ exports.hexToRgb = hexToRgb$1, exports.importTheme = function(json) {
26490
28342
  try {
26491
28343
  return JSON.parse(json);
26492
28344
  } catch (error) {
@@ -26497,15 +28349,49 @@ exports.importTheme = function(json) {
26497
28349
  // are already exported from './theme' module. Import them directly from there.
26498
28350
  // This file only exports theme-tools specific utilities.
26499
28351
  // 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) {
28352
+ , exports.initializeTheme = initializeTheme, exports.injectCSS = injectCSS$1, exports.injectTheme = injectTheme,
28353
+ exports.isAccessible = isAccessible, exports.isCSSInjected = isCSSInjected, exports.isDesignTokens = isDesignTokens,
28354
+ exports.isRTLLocale = isRTLLocale, exports.isSlot = function(value) {
26502
28355
  return "object" == typeof value && null !== value && ("render" in value || "component" in value || "children" in value);
26503
28356
  }
26504
28357
  /**
26505
28358
  * Merge multiple slot configurations
26506
28359
  * Later slots override earlier ones
26507
28360
  */ , exports.isValidCSSVariableName = isValidCSSVariableName, exports.isYouTubeUrl = isYouTubeUrl,
26508
- exports.mapSCSSTokensToCSSVars = mapSCSSTokensToCSSVars, exports.mergeCSSVars = mergeCSSVars,
28361
+ exports.lighten = lighten, exports.listenToSystemTheme = listenToSystemTheme, exports.loadAtomixConfig = loadAtomixConfig,
28362
+ exports.loadConfig =
28363
+ /**
28364
+ * Public API for loading and managing Atomix configuration
28365
+ *
28366
+ * This module provides the public-facing API for configuration loading
28367
+ * in external projects.
28368
+ */
28369
+ /**
28370
+ * Load Atomix configuration from an external project.
28371
+ *
28372
+ * @param options - Loading options
28373
+ * @returns The loaded configuration
28374
+ *
28375
+ * @example
28376
+ * ```typescript
28377
+ * import { loadConfig } from '@shohojdhara/atomix/config';
28378
+ *
28379
+ * const config = loadConfig();
28380
+ * console.log(config.prefix); // 'atomix' or user's custom prefix
28381
+ * ```
28382
+ */
28383
+ function(options) {
28384
+ return loadAtomixConfig({
28385
+ configPath: options?.configPath,
28386
+ required: options?.required ?? !1
28387
+ });
28388
+ }
28389
+ /**
28390
+ * Validate Atomix configuration structure.
28391
+ *
28392
+ * @param config - Configuration object to validate
28393
+ * @returns Array of validation warnings (empty if valid)
28394
+ */ , exports.mapSCSSTokensToCSSVars = mapSCSSTokensToCSSVars, exports.mergeCSSVars = mergeCSSVars,
26509
28395
  exports.mergeClassNames = mergeClassNames, exports.mergeComponentProps = mergeComponentProps,
26510
28396
  exports.mergePartStyles = mergePartStyles, exports.mergeSlots = function(...slots) {
26511
28397
  const filtered = slots.filter((s => void 0 !== s));
@@ -26513,8 +28399,17 @@ exports.mergePartStyles = mergePartStyles, exports.mergeSlots = function(...slot
26513
28399
  ...acc,
26514
28400
  ...slot
26515
28401
  })));
26516
- }, exports.mergeTheme = mergeTheme, exports.normalizeThemeTokens = normalizeThemeTokens,
26517
- exports.preloadFonts = preloadFonts, exports.quickTheme =
28402
+ }, exports.mergeTheme = mergeTheme, exports.mergeTokens = mergeTokens, exports.normalizeThemeTokens = normalizeThemeTokens,
28403
+ exports.omitTokens = omitTokens, exports.overrideTokens = overrideTokens, exports.persistTheme = persistTheme,
28404
+ exports.pickTokens = pickTokens, exports.preloadFonts = preloadFonts, exports.printConfigReport = function(config, title) {
28405
+ const result = validateConfiguration(config);
28406
+ result.warnings.length > 0 && result.warnings.forEach((warning => {})), result.suggestions.length > 0 && result.suggestions.forEach((suggestion => {}));
28407
+ const featuresDetected = [];
28408
+ config.interactiveEffects && featuresDetected.push("Interactive Effects"), config.optimization && featuresDetected.push("Optimization"),
28409
+ config.visualPolish && featuresDetected.push("Visual Polish"), config.ai && featuresDetected.push("AI Integration"),
28410
+ config.tokenEngine && featuresDetected.push("Token Engine"), config.generator && featuresDetected.push("Component Generator"),
28411
+ featuresDetected.length > 0 && featuresDetected.forEach((feature => {}));
28412
+ }, exports.quickTheme =
26518
28413
  /**
26519
28414
  * Quick theme creator with sensible defaults
26520
28415
  */
@@ -26531,11 +28426,23 @@ function(name, primaryColor, secondaryColor) {
26531
28426
  }
26532
28427
  });
26533
28428
  }, exports.registerTheme = registerTheme, exports.removeCSS = removeCSS, exports.removeCSSVariables = removeCSSVariables,
26534
- exports.removeTheme = removeTheme, exports.renderSlot = renderSlot, exports.sliderConstants = sliderConstants,
28429
+ exports.removeTheme = removeTheme, exports.renderSlot = renderSlot, exports.resolveConfigPath = function(configPath) {
28430
+ // In browser environments, config resolution is not possible
28431
+ if ("undefined" != typeof window) return null;
28432
+ // If a specific config path is provided, check if it exists
28433
+ if (configPath) {
28434
+ const absPath = path$4.join(process.cwd(), configPath);
28435
+ return fs.existsSync(absPath) ? absPath : null;
28436
+ }
28437
+ // Otherwise, check standard locations
28438
+ const possiblePaths = [ path$4.join(process.cwd(), "atomix.config.ts"), path$4.join(process.cwd(), "atomix.config.js"), path$4.join(process.cwd(), "atomix.config.json") ];
28439
+ for (const path of possiblePaths) if (fs.existsSync(path)) return path;
28440
+ return null;
28441
+ }, exports.rgbToHex = rgbToHex, exports.rtlCSS = rtlCSS, exports.sliderConstants = sliderConstants,
26535
28442
  exports.supportsDarkMode = function(theme) {
26536
28443
  var _context;
26537
28444
  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,
28445
+ }, exports.switchTheme = switchTheme, exports.theme = theme, exports.themePropertyToCSSVar = themePropertyToCSSVar,
26539
28446
  exports.themeToCSS =
26540
28447
  /**
26541
28448
  * Generate CSS string from theme
@@ -26545,10 +28452,11 @@ function(theme, selector = ":root") {
26545
28452
  selector: selector,
26546
28453
  prefix: "atomix"
26547
28454
  });
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) {
28455
+ }, exports.toggleTheme = toggleTheme, exports.types = types, exports.unregisterTheme = unregisterTheme,
28456
+ exports.useAccordion = useAccordion, exports.useAtomixGlass = useAtomixGlass, exports.useBadge = useBadge,
28457
+ exports.useBarChart = useBarChart, exports.useBlock = useBlock, exports.useChartData = useChartData,
28458
+ exports.useChartInteraction = useChartInteraction, exports.useChartScale = useChartScale,
28459
+ exports.useComponentCustomization = function(component, props) {
26552
28460
  const {theme: theme} = useTheme(), cssVars = React.useMemo((() => mergeCSSVars(theme?.components?.[component]?.cssVars || {}, props.cssVars || {})), [ theme, component, props.cssVars ]), parts = React.useMemo((() => {
26553
28461
  const themeParts = theme?.components?.[component]?.parts || {}, propParts = props.parts || {}, merged = {};
26554
28462
  return new Set([ ...Object.keys(themeParts), ...Object.keys(propParts) ]).forEach((partName => {
@@ -26587,14 +28495,16 @@ exports.useMergedProps = function(defaultProps, props) {
26587
28495
  ...props
26588
28496
  })), [ defaultProps, props ]);
26589
28497
  }, 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,
28498
+ exports.useNavbar = useNavbar, exports.usePieChart = usePieChart, exports.useRadio = useRadio,
28499
+ exports.useResponsive = useResponsive, exports.useResponsiveGlass = useResponsiveGlass,
26592
28500
  exports.useRiver = useRiver, exports.useSelect = useSelect, exports.useSideMenu = useSideMenu,
26593
28501
  exports.useSideMenuItem = useSideMenuItem, exports.useSlot = function(slot, props, fallback) {
26594
28502
  return React__default.default.useMemo((() => renderSlot(slot, props, fallback)), [ slot, props, fallback ]);
26595
28503
  }, exports.useSpinner = useSpinner, exports.useTextarea = useTextarea, exports.useTheme = useTheme,
26596
- exports.useThemeTokens = useThemeTokens, exports.useTodo = useTodo, exports.utils = utils,
26597
- exports.validateTheme = function(theme) {
28504
+ exports.useThemeSwitcher = useThemeSwitcher, exports.useThemeTokens = useThemeTokens,
28505
+ exports.useTodo = useTodo, exports.utils = utils, exports.validateConfig = function(config) {
28506
+ return validateConfig$1(config);
28507
+ }, exports.validateConfiguration = validateConfiguration, exports.validateTheme = function(theme) {
26598
28508
  const errors = [];
26599
28509
  return theme.name || errors.push("Theme must have a name"), theme.palette || errors.push("Theme must have a palette"),
26600
28510
  theme.palette && !theme.palette.primary && errors.push("Theme palette must have a primary color"),