@shohojdhara/atomix 0.3.6 → 0.3.7

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 (51) hide show
  1. package/README.md +3 -3
  2. package/dist/charts.js +50 -142
  3. package/dist/charts.js.map +1 -1
  4. package/dist/core.js +179 -274
  5. package/dist/core.js.map +1 -1
  6. package/dist/forms.js +50 -142
  7. package/dist/forms.js.map +1 -1
  8. package/dist/heavy.js +179 -274
  9. package/dist/heavy.js.map +1 -1
  10. package/dist/index.d.ts +669 -703
  11. package/dist/index.esm.js +966 -1649
  12. package/dist/index.esm.js.map +1 -1
  13. package/dist/index.js +1211 -1890
  14. package/dist/index.js.map +1 -1
  15. package/dist/index.min.js +1 -1
  16. package/dist/index.min.js.map +1 -1
  17. package/dist/theme.d.ts +163 -334
  18. package/dist/theme.js +774 -1473
  19. package/dist/theme.js.map +1 -1
  20. package/package.json +1 -1
  21. package/src/components/AtomixGlass/AtomixGlass.tsx +128 -356
  22. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +1 -1
  23. package/src/components/Button/Button.tsx +85 -167
  24. package/src/lib/composables/useAtomixGlass.ts +7 -7
  25. package/src/lib/config/loader.ts +2 -3
  26. package/src/lib/constants/components.ts +7 -0
  27. package/src/lib/hooks/usePerformanceMonitor.ts +1 -1
  28. package/src/lib/hooks/useThemeTokens.ts +105 -0
  29. package/src/lib/theme/config/configLoader.ts +60 -219
  30. package/src/lib/theme/config/loader.ts +15 -21
  31. package/src/lib/theme/constants/constants.ts +1 -1
  32. package/src/lib/theme/core/ThemeRegistry.ts +75 -279
  33. package/src/lib/theme/core/composeTheme.ts +14 -64
  34. package/src/lib/theme/core/createTheme.ts +54 -40
  35. package/src/lib/theme/core/createThemeObject.ts +2 -2
  36. package/src/lib/theme/core/index.ts +15 -1
  37. package/src/lib/theme/errors/errors.ts +1 -1
  38. package/src/lib/theme/generators/generateCSSNested.ts +130 -0
  39. package/src/lib/theme/generators/index.ts +6 -0
  40. package/src/lib/theme/index.ts +35 -10
  41. package/src/lib/theme/runtime/ThemeApplicator.ts +1 -1
  42. package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +4 -4
  43. package/src/lib/theme/runtime/ThemeProvider.tsx +261 -554
  44. package/src/lib/theme/runtime/index.ts +1 -0
  45. package/src/lib/theme/runtime/useThemeTokens.ts +131 -0
  46. package/src/lib/theme/utils/componentTheming.ts +132 -0
  47. package/src/lib/theme/utils/naming.ts +100 -0
  48. package/src/lib/theme/utils/themeUtils.ts +6 -6
  49. package/src/lib/utils/componentUtils.ts +1 -1
  50. package/src/lib/utils/memoryMonitor.ts +3 -3
  51. package/src/lib/utils/themeNaming.ts +135 -0
package/dist/index.esm.js CHANGED
@@ -15,6 +15,11 @@ import { createPortal } from "react-dom";
15
15
  UTILITY: "u-",
16
16
  LAYOUT: "l-",
17
17
  OBJECT: "o-"
18
+ }, THEME_NAMING = {
19
+ BUTTON_PREFIX: "btn",
20
+ ICON_ELEMENT: "icon",
21
+ LABEL_ELEMENT: "label",
22
+ SPINNER_ELEMENT: "spinner"
18
23
  }, BUTTON = {
19
24
  BASE_CLASS: "c-btn",
20
25
  ICON_CLASS: "c-btn__icon",
@@ -1885,7 +1890,7 @@ const GlassFilter = memo(GlassFilterComponent, ((prevProps, nextProps) => prevP
1885
1890
  timestamp: Date.now()
1886
1891
  }),
1887
1892
  // Development mode: log cache size
1888
- "production" !== process.env.NODE_ENV && sharedShaderCache.size;
1893
+ "undefined" != typeof process && "production" === process.env?.NODE_ENV || sharedShaderCache.size;
1889
1894
  })(cacheKey, url), setShaderMapUrl(url);
1890
1895
  };
1891
1896
  "undefined" != typeof requestIdleCallback ? requestIdleCallback(generate, {
@@ -2198,9 +2203,9 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2198
2203
  childRadius > 0 && childRadius !== CONSTANTS.DEFAULT_CORNER_RADIUS && (extractedRadius = childRadius,
2199
2204
  extractionSource = "React children");
2200
2205
  }
2201
- null !== extractedRadius && extractedRadius > 0 ? setDynamicCornerRadius(extractedRadius) : process.env.NODE_ENV;
2206
+ null !== extractedRadius && extractedRadius > 0 ? setDynamicCornerRadius(extractedRadius) : "undefined" == typeof process || process.env;
2202
2207
  } catch (error) {
2203
- "production" !== process.env.NODE_ENV && debugCornerRadius && console.error("[AtomixGlass] Error extracting corner radius:", error);
2208
+ "undefined" != typeof process && "production" === process.env?.NODE_ENV || !debugCornerRadius || console.error("[AtomixGlass] Error extracting corner radius:", error);
2204
2209
  }
2205
2210
  };
2206
2211
  extractRadius();
@@ -2275,7 +2280,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2275
2280
  // For image backgrounds, assume medium luminance
2276
2281
  totalLuminance += .5, validSamples++, hasValidBackground = !0);
2277
2282
  } catch (styleError) {
2278
- process.env.NODE_ENV;
2283
+ "undefined" == typeof process || process.env;
2279
2284
  }
2280
2285
  // Move to parent element for next iteration
2281
2286
  if (!currentElement) break;
@@ -2314,7 +2319,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2314
2319
  }
2315
2320
  } catch (error) {
2316
2321
  // Enhanced error logging with context
2317
- "development" === process.env.NODE_ENV && console.warn("AtomixGlass: Error detecting background brightness:", error);
2322
+ "undefined" != typeof process && "development" !== process.env?.NODE_ENV || console.warn("AtomixGlass: Error detecting background brightness:", error);
2318
2323
  const result = !1;
2319
2324
  if (element && element.parentElement) {
2320
2325
  const threshold = "object" == typeof overLight && null !== overLight && overLight.threshold || .7;
@@ -2371,7 +2376,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2371
2376
  };
2372
2377
  // Calculate offset relative to this container
2373
2378
  // React 18 automatically batches these updates
2374
- setInternalMouseOffset(newOffset), setInternalGlobalMousePosition(globalPos), "production" !== process.env.NODE_ENV && enablePerformanceMonitoring && performance.now();
2379
+ setInternalMouseOffset(newOffset), setInternalGlobalMousePosition(globalPos), "undefined" != typeof process && "production" === process.env?.NODE_ENV || !enablePerformanceMonitoring || performance.now();
2375
2380
  }), [ mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveDisableEffects, enablePerformanceMonitoring ]);
2376
2381
  // Subscribe to shared mouse tracker
2377
2382
  useEffect((() => {
@@ -2511,10 +2516,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2511
2516
  saturationBoost: validatedSaturationBoost + .4 * mouseInfluence
2512
2517
  };
2513
2518
  // Validate and apply object config values with proper clamping
2514
- return process.env.NODE_ENV, finalConfig;
2519
+ return "undefined" == typeof process || process.env, finalConfig;
2515
2520
  }
2516
2521
  // Debug logging for non-object configs
2517
- return process.env.NODE_ENV, baseConfig;
2522
+ return "undefined" == typeof process || process.env, baseConfig;
2518
2523
  }), [ overLight, getEffectiveOverLight, mouseOffset, isHovered, isActive, validateConfigValue, debugOverLight ]), handleMouseEnter = useCallback((() => setIsHovered(!0)), []), handleMouseLeave = useCallback((() => setIsHovered(!1)), []), handleMouseDown = useCallback((() => setIsActive(!0)), []), handleMouseUp = useCallback((() => setIsActive(!1)), []), handleKeyDown = useCallback((e => {
2519
2524
  !onClick || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), onClick());
2520
2525
  }), [ onClick ]), handleMouseMove = useCallback((_e => {}), []);
@@ -2625,7 +2630,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2625
2630
  * <div>Content with debug logging enabled</div>
2626
2631
  * </AtomixGlass>
2627
2632
  */ function AtomixGlass({children: children, displacementScale: displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, aberrationIntensity: aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, cornerRadius: cornerRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer = null, className: className = "", padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, style: style = {}, mode: mode = ATOMIX_GLASS.DEFAULTS.MODE, onClick: onClick, shaderVariant: shaderVariant = "liquidGlass", "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, role: role, tabIndex: tabIndex, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, disableEffects: disableEffects = !1, enableLiquidBlur: enableLiquidBlur = !1, enableBorderEffect: enableBorderEffect = !0, enableOverLightLayers: enableOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS, enablePerformanceMonitoring: enablePerformanceMonitoring = !1, debugCornerRadius: debugCornerRadius = !1, debugOverLight: debugOverLight = !1}) {
2628
- const glassRef = useRef(null), contentRef = useRef(null), opacityCacheRef = useRef(null), rgbCacheRef = useRef(null), {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveCornerRadius: effectiveCornerRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveDisableEffects: effectiveDisableEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
2633
+ const glassRef = useRef(null), contentRef = useRef(null), {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveCornerRadius: effectiveCornerRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveDisableEffects: effectiveDisableEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
2629
2634
  glassRef: glassRef,
2630
2635
  contentRef: contentRef,
2631
2636
  cornerRadius: cornerRadius,
@@ -2642,143 +2647,51 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2642
2647
  debugOverLight: debugOverLight,
2643
2648
  enablePerformanceMonitoring: enablePerformanceMonitoring,
2644
2649
  children: children
2645
- }), isOverLight = overLightConfig.isOverLight, shouldRenderOverLightLayers = enableOverLightLayers && isOverLight;
2646
- // Read CSS custom properties once on mount and cache them
2647
- useEffect((() => {
2648
- if ("undefined" != typeof window && glassRef.current) try {
2649
- const computedStyle = window.getComputedStyle(glassRef.current);
2650
- // Cache opacity values
2651
- if (!opacityCacheRef.current) {
2652
- const opacity50Value = computedStyle.getPropertyValue("--atomix-opacity-50").trim(), opacity40Value = computedStyle.getPropertyValue("--atomix-opacity-40").trim(), opacity80Value = computedStyle.getPropertyValue("--atomix-opacity-80").trim(), opacity0Value = computedStyle.getPropertyValue("--atomix-opacity-0").trim(), parseOpacity = (value, defaultValue) => {
2653
- if (!value) return defaultValue;
2654
- const parsed = parseFloat(value);
2655
- return isNaN(parsed) ? defaultValue : parsed;
2656
- };
2657
- opacityCacheRef.current = {
2658
- opacity50: parseOpacity(opacity50Value, .5),
2659
- opacity40: parseOpacity(opacity40Value, .4),
2660
- opacity80: parseOpacity(opacity80Value, .8),
2661
- opacity0: parseOpacity(opacity0Value, 0)
2662
- };
2663
- }
2664
- // Cache RGB color values from design tokens
2665
- if (!rgbCacheRef.current) {
2666
- // Try to read from design tokens, fallback to defaults
2667
- const whiteRgbValue = computedStyle.getPropertyValue("--atomix-light-rgb").trim() || computedStyle.getPropertyValue("--atomix-white-rgb").trim() || "", blackRgbValue = computedStyle.getPropertyValue("--atomix-dark-rgb").trim() || computedStyle.getPropertyValue("--atomix-black-rgb").trim() || "";
2668
- rgbCacheRef.current = {
2669
- whiteRgb: whiteRgbValue || "255, 255, 255",
2670
- // Fallback to white RGB
2671
- blackRgb: blackRgbValue || "0, 0, 0"
2672
- };
2673
- }
2674
- } catch (error) {
2675
- // Fallback to defaults if reading fails
2676
- opacityCacheRef.current || (opacityCacheRef.current = {
2677
- opacity50: .5,
2678
- opacity40: .4,
2679
- opacity80: .8,
2680
- opacity0: 0
2681
- }), rgbCacheRef.current || (rgbCacheRef.current = {
2682
- whiteRgb: "255, 255, 255",
2683
- blackRgb: "0, 0, 0"
2684
- });
2685
- }
2686
- }), []);
2687
- // Calculate base style with transforms (only dynamic values)
2688
- const baseStyle = useMemo((() => ({
2650
+ }), isOverLight = overLightConfig.isOverLight, shouldRenderOverLightLayers = enableOverLightLayers && isOverLight, baseStyle = {
2689
2651
  ...style,
2690
2652
  ...0 !== elasticity && !effectiveDisableEffects && {
2691
2653
  transform: transformStyle
2692
2654
  }
2693
- })), [ style, transformStyle, effectiveDisableEffects, elasticity ]), componentClassName = useMemo((() => [ ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`, effectiveDisableEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`, className ].filter(Boolean).join(" ")), [ effectiveReducedMotion, effectiveHighContrast, effectiveDisableEffects, className ]), baseStylePosition = baseStyle.position, baseStyleTop = baseStyle.top, baseStyleLeft = baseStyle.left, positionStyles = useMemo((() => ({
2694
- position: baseStylePosition || "absolute",
2695
- top: baseStyleTop || 0,
2696
- left: baseStyleLeft || 0
2697
- })), [ baseStylePosition, baseStyleTop, baseStyleLeft ]), baseStyleWidth = baseStyle.width, baseStyleHeight = baseStyle.height, glassSizeWidth = glassSize.width, glassSizeHeight = glassSize.height, adjustedSize = useMemo((() => ({
2698
- width: "fixed" !== baseStylePosition ? "100%" : baseStyleWidth || Math.max(glassSizeWidth, 0),
2699
- height: "fixed" !== baseStylePosition ? "100%" : baseStyleHeight || Math.max(glassSizeHeight, 0)
2700
- })), [ baseStylePosition, baseStyleWidth, baseStyleHeight, glassSizeWidth, glassSizeHeight ]), mouseOffsetX = mouseOffset.x, mouseOffsetY = mouseOffset.y, GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, gradientCalculations = useMemo((() => {
2701
- const mx = mouseOffsetX, my = mouseOffsetY, borderGradientAngle = GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER, borderStop1 = Math.max(GRADIENT.BORDER_STOP_1.MIN, GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER), borderStop2 = Math.min(GRADIENT.BORDER_STOP_2.MAX, GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER), borderOpacity1 = GRADIENT.BORDER_OPACITY.BASE_1 + Math.abs(mx) * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, borderOpacity2 = GRADIENT.BORDER_OPACITY.BASE_2 + Math.abs(mx) * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH, borderOpacity3 = GRADIENT.BORDER_OPACITY.BASE_3 + Math.abs(mx) * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, borderOpacity4 = GRADIENT.BORDER_OPACITY.BASE_4 + Math.abs(mx) * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH, hover1X = GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1, hover1Y = GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1, hover2X = GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_2, hover2Y = GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_2, hover3X = GRADIENT.CENTER_POSITION + mx * GRADIENT.HOVER_POSITION.MULTIPLIER_3, hover3Y = GRADIENT.CENTER_POSITION + my * GRADIENT.HOVER_POSITION.MULTIPLIER_3, baseX = GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER, baseY = GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER;
2702
- return {
2703
- isOverLight: isOverLight,
2704
- mx: mx,
2705
- my: my,
2706
- borderGradientAngle: borderGradientAngle,
2707
- borderStop1: borderStop1,
2708
- borderStop2: borderStop2,
2709
- borderOpacity1: borderOpacity1,
2710
- borderOpacity2: borderOpacity2,
2711
- borderOpacity3: borderOpacity3,
2712
- borderOpacity4: borderOpacity4,
2713
- hover1X: hover1X,
2714
- hover1Y: hover1Y,
2715
- hover2X: hover2X,
2716
- hover2Y: hover2Y,
2717
- hover3X: hover3X,
2718
- hover3Y: hover3Y,
2719
- baseX: baseX,
2720
- baseY: baseY
2721
- };
2722
- }), [ mouseOffsetX, mouseOffsetY, isOverLight ]), overLightOpacity = overLightConfig.opacity, opacityValues = useMemo((() => {
2723
- // Use cached values if available, otherwise fallback to defaults
2724
- const opacity50 = opacityCacheRef.current?.opacity50 ?? .5, opacity40 = opacityCacheRef.current?.opacity40 ?? .4, opacity80 = opacityCacheRef.current?.opacity80 ?? .8, opacity0 = opacityCacheRef.current?.opacity0 ?? 0;
2725
- // Dynamic multiplier for overlay
2726
- return {
2727
- hover1: isHovered || isActive ? opacity50 : opacity0,
2728
- hover2: isActive ? opacity50 : opacity0,
2729
- hover3: isHovered ? opacity40 : isActive ? opacity80 : opacity0,
2730
- base: isOverLight ? overLightOpacity || opacity40 : opacity0,
2731
- over: isOverLight ? 1.1 * (overLightOpacity || opacity40) : opacity0
2732
- };
2733
- }), [ isHovered, isActive, isOverLight, overLightOpacity ]), gradientIsOverLight = gradientCalculations.isOverLight, gradientMx = gradientCalculations.mx, gradientMy = gradientCalculations.my, gradientBorderGradientAngle = gradientCalculations.borderGradientAngle, gradientBorderStop1 = gradientCalculations.borderStop1, gradientBorderStop2 = gradientCalculations.borderStop2, gradientBorderOpacity1 = gradientCalculations.borderOpacity1, gradientBorderOpacity2 = gradientCalculations.borderOpacity2, gradientBorderOpacity3 = gradientCalculations.borderOpacity3, gradientBorderOpacity4 = gradientCalculations.borderOpacity4, gradientHover1X = gradientCalculations.hover1X, gradientHover1Y = gradientCalculations.hover1Y, gradientHover2X = gradientCalculations.hover2X, gradientHover2Y = gradientCalculations.hover2Y, gradientHover3X = gradientCalculations.hover3X, gradientHover3Y = gradientCalculations.hover3Y, gradientBaseX = gradientCalculations.baseX, gradientBaseY = gradientCalculations.baseY, positionStylesPosition = positionStyles.position, positionStylesTop = positionStyles.top, positionStylesLeft = positionStyles.left, adjustedSizeWidth = adjustedSize.width, adjustedSizeHeight = adjustedSize.height, baseStyleTransform = baseStyle.transform, opacityValuesHover1 = opacityValues.hover1, opacityValuesHover2 = opacityValues.hover2, opacityValuesHover3 = opacityValues.hover3, opacityValuesBase = opacityValues.base, opacityValuesOver = opacityValues.over, glassVars = useMemo((() => {
2734
- // RGB color values for rgba() functions
2735
- // Note: CSS doesn't support rgba(var(--rgb), opacity) syntax - this is a CSS specification
2736
- // limitation, not a browser support issue. We read RGB values from design tokens at mount
2737
- // and cache them for performance. Falls back to defaults if tokens are not available.
2738
- // Uses design tokens: --atomix-light-rgb / --atomix-white-rgb and --atomix-dark-rgb / --atomix-black-rgb
2739
- const whiteColor = rgbCacheRef.current?.whiteRgb || "255, 255, 255", blackColor = rgbCacheRef.current?.blackRgb || "0, 0, 0";
2740
- return {
2741
- // Standard CSS custom properties for dynamic values
2742
- "--atomix-glass-radius": `${effectiveCornerRadius}px`,
2743
- "--atomix-glass-transform": baseStyleTransform || "none",
2744
- "--atomix-glass-position": positionStylesPosition,
2745
- "--atomix-glass-top": "fixed" !== positionStylesTop ? `${positionStylesTop}px` : "0",
2746
- "--atomix-glass-left": "fixed" !== positionStylesLeft ? `${positionStylesLeft}px` : "0",
2747
- "--atomix-glass-width": "fixed" !== baseStylePosition ? adjustedSizeWidth : `${adjustedSizeWidth}px`,
2748
- "--atomix-glass-height": "fixed" !== baseStylePosition ? adjustedSizeHeight : `${adjustedSizeHeight}px`,
2749
- // Border width: Use spacing token for consistency
2750
- "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
2751
- "--atomix-glass-blend-mode": gradientIsOverLight ? "multiply" : "overlay",
2752
- // Dynamic gradients and backgrounds
2753
- // Note: RGB values use design token-aligned constants (white: 255,255,255; black: 0,0,0)
2754
- "--atomix-glass-border-gradient-1": `linear-gradient(${gradientBorderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${gradientBorderOpacity1}) ${gradientBorderStop1}%, rgba(${whiteColor}, ${gradientBorderOpacity2}) ${gradientBorderStop2}%, rgba(${whiteColor}, 0) 100%)`,
2755
- "--atomix-glass-border-gradient-2": `linear-gradient(${gradientBorderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${gradientBorderOpacity3}) ${gradientBorderStop1}%, rgba(${whiteColor}, ${gradientBorderOpacity4}) ${gradientBorderStop2}%, rgba(${whiteColor}, 0) 100%)`,
2756
- "--atomix-glass-hover-1-opacity": opacityValuesHover1,
2757
- "--atomix-glass-hover-1-gradient": gradientIsOverLight ? `radial-gradient(circle at ${gradientHover1X}% ${gradientHover1Y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_END}%)` : `radial-gradient(circle at ${gradientHover1X}% ${gradientHover1Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_STOP}%)`,
2758
- "--atomix-glass-hover-2-opacity": opacityValuesHover2,
2759
- "--atomix-glass-hover-2-gradient": gradientIsOverLight ? `radial-gradient(circle at ${gradientHover2X}% ${gradientHover2Y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_END}%)` : `radial-gradient(circle at ${gradientHover2X}% ${gradientHover2Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_STOP}%)`,
2760
- "--atomix-glass-hover-3-opacity": opacityValuesHover3,
2761
- "--atomix-glass-hover-3-gradient": gradientIsOverLight ? `radial-gradient(circle at ${gradientHover3X}% ${gradientHover3Y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_END}%)` : `radial-gradient(circle at ${gradientHover3X}% ${gradientHover3Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_STOP}%)`,
2762
- "--atomix-glass-base-opacity": opacityValuesBase,
2763
- "--atomix-glass-base-gradient": gradientIsOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + gradientMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + gradientMy * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + Math.abs(gradientMx) * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`,
2764
- "--atomix-glass-overlay-opacity": opacityValuesOver,
2765
- "--atomix-glass-overlay-gradient": gradientIsOverLight ? `radial-gradient(circle at ${gradientBaseX}% ${gradientBaseY}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + Math.abs(gradientMx) * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + Math.abs(gradientMy) * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`
2766
- };
2767
- }), [
2768
- // Position styles - only specific properties
2769
- positionStylesPosition, positionStylesTop, positionStylesLeft,
2770
- // Adjusted size - only specific properties
2771
- adjustedSizeWidth, adjustedSizeHeight,
2772
- // Base style - only transform property
2773
- baseStyleTransform, baseStylePosition,
2774
- // Other values
2775
- effectiveCornerRadius, effectiveReducedMotion,
2776
- // Gradient calculations - extracted properties
2777
- gradientIsOverLight, gradientMx, gradientMy, gradientBorderGradientAngle, gradientBorderStop1, gradientBorderStop2, gradientBorderOpacity1, gradientBorderOpacity2, gradientBorderOpacity3, gradientBorderOpacity4, gradientHover1X, gradientHover1Y, gradientHover2X, gradientHover2Y, gradientHover3X, gradientHover3Y, gradientBaseX, gradientBaseY,
2778
- // Opacity values - extracted properties
2779
- opacityValuesHover1, opacityValuesHover2, opacityValuesHover3, opacityValuesBase, opacityValuesOver ]);
2780
- // Build className with state modifiers
2781
- return jsxs("div", {
2655
+ }, componentClassName = [ ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`, effectiveDisableEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`, className ].filter(Boolean).join(" "), positionStyles = {
2656
+ position: style.position || "absolute",
2657
+ top: style.top || 0,
2658
+ left: style.left || 0
2659
+ }, adjustedSize = {
2660
+ width: "fixed" !== style.position ? "100%" : style.width ? style.width : Math.max(glassSize.width, 0),
2661
+ height: "fixed" !== style.position ? "100%" : style.height ? style.height : Math.max(glassSize.height, 0)
2662
+ }, mx = mouseOffset.x, my = mouseOffset.y, GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, borderGradientAngle = GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER, borderStop1 = Math.max(GRADIENT.BORDER_STOP_1.MIN, GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER), borderStop2 = Math.min(GRADIENT.BORDER_STOP_2.MAX, GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER), borderOpacity1 = GRADIENT.BORDER_OPACITY.BASE_1 + Math.abs(mx) * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, borderOpacity2 = GRADIENT.BORDER_OPACITY.BASE_2 + Math.abs(mx) * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH, borderOpacity3 = GRADIENT.BORDER_OPACITY.BASE_3 + Math.abs(mx) * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, borderOpacity4 = GRADIENT.BORDER_OPACITY.BASE_4 + Math.abs(mx) * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH, hover1X = GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1, hover1Y = GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1, hover2X = GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_2, hover2Y = GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_2, hover3X = GRADIENT.CENTER_POSITION + mx * GRADIENT.HOVER_POSITION.MULTIPLIER_3, hover3Y = GRADIENT.CENTER_POSITION + my * GRADIENT.HOVER_POSITION.MULTIPLIER_3, baseX = GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER, baseY = GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER, overLightOpacity = overLightConfig.opacity, opacityValues = {
2663
+ hover1: isHovered || isActive ? .5 : 0,
2664
+ hover2: isActive ? .5 : 0,
2665
+ hover3: isHovered ? .4 : isActive ? .8 : 0,
2666
+ base: isOverLight ? overLightOpacity || .4 : 0,
2667
+ over: isOverLight ? 1.1 * (overLightOpacity || .4) : 0
2668
+ }, whiteColor = "255, 255, 255", glassVars = {
2669
+ // Standard CSS custom properties for dynamic values
2670
+ "--atomix-glass-radius": `${effectiveCornerRadius}px`,
2671
+ "--atomix-glass-transform": transformStyle || "none",
2672
+ "--atomix-glass-position": positionStyles.position,
2673
+ "--atomix-glass-top": "fixed" !== positionStyles.top ? `${positionStyles.top}px` : "0",
2674
+ "--atomix-glass-left": "fixed" !== positionStyles.left ? `${positionStyles.left}px` : "0",
2675
+ "--atomix-glass-width": "fixed" !== style.position ? adjustedSize.width : `${adjustedSize.width}px`,
2676
+ "--atomix-glass-height": "fixed" !== style.position ? adjustedSize.height : `${adjustedSize.height}px`,
2677
+ // Border width: Use spacing token for consistency
2678
+ "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
2679
+ "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay",
2680
+ // Dynamic gradients and backgrounds
2681
+ "--atomix-glass-border-gradient-1": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${borderOpacity1}) ${borderStop1}%, rgba(${whiteColor}, ${borderOpacity2}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
2682
+ "--atomix-glass-border-gradient-2": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${borderOpacity3}) ${borderStop1}%, rgba(${whiteColor}, ${borderOpacity4}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
2683
+ "--atomix-glass-hover-1-opacity": opacityValues.hover1,
2684
+ "--atomix-glass-hover-1-gradient": isOverLight ? `radial-gradient(circle at ${hover1X}% ${hover1Y}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_START}) 0%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_STOP}%, rgba(0, 0, 0, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_END}%)` : `radial-gradient(circle at ${hover1X}% ${hover1Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_STOP}%)`,
2685
+ "--atomix-glass-hover-2-opacity": opacityValues.hover2,
2686
+ "--atomix-glass-hover-2-gradient": isOverLight ? `radial-gradient(circle at ${hover2X}% ${hover2Y}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_START}) 0%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_STOP}%, rgba(0, 0, 0, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_END}%)` : `radial-gradient(circle at ${hover2X}% ${hover2Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_STOP}%)`,
2687
+ "--atomix-glass-hover-3-opacity": opacityValues.hover3,
2688
+ "--atomix-glass-hover-3-gradient": isOverLight ? `radial-gradient(circle at ${hover3X}% ${hover3Y}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_START}) 0%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_STOP}%, rgba(0, 0, 0, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_END}%)` : `radial-gradient(circle at ${hover3X}% ${hover3Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_STOP}%)`,
2689
+ "--atomix-glass-base-opacity": opacityValues.base,
2690
+ "--atomix-glass-base-gradient": isOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + mx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + my * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + Math.abs(mx) * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`,
2691
+ "--atomix-glass-overlay-opacity": opacityValues.over,
2692
+ "--atomix-glass-overlay-gradient": isOverLight ? `radial-gradient(circle at ${baseX}% ${baseY}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + Math.abs(mx) * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + Math.abs(my) * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`
2693
+ };
2694
+ return jsxs("div", {
2782
2695
  className: componentClassName,
2783
2696
  style: glassVars,
2784
2697
  role: role || (onClick ? "button" : void 0),
@@ -3642,11 +3555,103 @@ const Spinner = memo((({size: size = "md", variant: variant = "primary", fullsc
3642
3555
 
3643
3556
  Spinner.displayName = "Spinner";
3644
3557
 
3558
+ /**
3559
+ * Theme Naming Utility
3560
+ *
3561
+ * Provides consistent naming conventions for CSS classes, CSS variables,
3562
+ * and JavaScript properties throughout the theme system.
3563
+ */
3564
+ class ThemeNaming {
3565
+ /**
3566
+ * Set the global prefix for all theme tokens
3567
+ * @param newPrefix - New prefix to use
3568
+ */
3569
+ static setPrefix(newPrefix) {
3570
+ this.prefix = newPrefix;
3571
+ }
3572
+ /**
3573
+ * Get the current prefix
3574
+ */ static getPrefix() {
3575
+ return this.prefix;
3576
+ }
3577
+ /**
3578
+ * Convert camelCase to kebab-case for CSS variables
3579
+ * @param str - String to convert
3580
+ */ static camelToKebab(str) {
3581
+ return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").toLowerCase();
3582
+ }
3583
+ /**
3584
+ * Convert kebab-case to camelCase for JavaScript properties
3585
+ * @param str - String to convert
3586
+ */ static kebabToCamel(str) {
3587
+ return str.replace(/-([a-z])/g, (g => g[1].toUpperCase()));
3588
+ }
3589
+ /**
3590
+ * Create a CSS variable name
3591
+ * @param token - Token name in camelCase
3592
+ */ static cssVar(token) {
3593
+ return `--${this.prefix}-${this.camelToKebab(token)}`;
3594
+ }
3595
+ /**
3596
+ * Create a BEM CSS class name
3597
+ * @param block - Block name
3598
+ * @param element - Element name (optional)
3599
+ * @param modifier - Modifier name (optional)
3600
+ */ static bemClass(block, element, modifier) {
3601
+ let className = `c-${block}`;
3602
+ return element && (className += `__${element}`), modifier && (className += `--${modifier}`),
3603
+ className;
3604
+ }
3605
+ /**
3606
+ * Create a variant class name
3607
+ * @param component - Component name
3608
+ * @param variant - Variant name
3609
+ */ static variantClass(component, variant) {
3610
+ return `c-${component}--${variant}`;
3611
+ }
3612
+ /**
3613
+ * Create a size class name
3614
+ * @param component - Component name
3615
+ * @param size - Size name
3616
+ */ static sizeClass(component, size) {
3617
+ return `c-${component}--${size}`;
3618
+ }
3619
+ /**
3620
+ * Create a state class name
3621
+ * @param component - Component name
3622
+ * @param state - State name
3623
+ */ static stateClass(component, state) {
3624
+ return `c-${component}--${state}`;
3625
+ }
3626
+ /**
3627
+ * Create a utility class name
3628
+ * @param utility - Utility name
3629
+ */ static utilityClass(utility) {
3630
+ return `u-${utility}`;
3631
+ }
3632
+ /**
3633
+ * Create a layout class name
3634
+ * @param layout - Layout name
3635
+ */ static layoutClass(layout) {
3636
+ return `l-${layout}`;
3637
+ }
3638
+ /**
3639
+ * Create an object class name
3640
+ * @param object - Object name
3641
+ */ static objectClass(object) {
3642
+ return `o-${object}`;
3643
+ }
3644
+ }
3645
+
3646
+ ThemeNaming.prefix = "atomix";
3647
+
3645
3648
  const Button = React.memo( forwardRef((({label: label, children: children, onClick: onClick, variant: variant = "primary", size: size = "md", disabled: disabled = !1, loading: loading = !1, loadingText: loadingText, icon: icon, iconName: iconName, iconSize: iconSize = "sm", iconPosition: iconPosition = "start", iconOnly: iconOnly = !1, rounded: rounded = !1, fullWidth: fullWidth = !1, block: block = !1, active: active = !1, selected: selected = !1, type: type = "button", className: className = "", as: Component = "button", href: href, target: target, glass: glass, onHover: onHover, onFocus: onFocus, onBlur: onBlur, ariaLabel: ariaLabel, ariaDescribedBy: ariaDescribedBy, ariaExpanded: ariaExpanded, ariaControls: ariaControls, tabIndex: tabIndex, style: style, LinkComponent: LinkComponent, ...props}, ref) => {
3646
- const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement = useMemo((() => loading ? null : iconName ? jsx(Icon, {
3649
+ const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement = iconName ? jsx(Icon, {
3647
3650
  name: iconName,
3648
3651
  size: iconSize
3649
- }) : icon), [ icon, iconName, iconSize, loading ]), {generateButtonClass: generateButtonClass, handleClick: handleClick} = useButton({
3652
+ }) : icon;
3653
+ // Determine if we should render as a link
3654
+ useButton({
3650
3655
  variant: variant,
3651
3656
  size: size,
3652
3657
  disabled: isDisabled,
@@ -3657,20 +3662,8 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
3657
3662
  block: block,
3658
3663
  active: active,
3659
3664
  selected: selected
3660
- }), buttonClass = useMemo((() => generateButtonClass({
3661
- variant: variant,
3662
- size: size,
3663
- disabled: isDisabled,
3664
- rounded: rounded,
3665
- iconOnly: iconOnly,
3666
- glass: glass,
3667
- loading: loading,
3668
- fullWidth: fullWidth,
3669
- block: block,
3670
- active: active,
3671
- selected: selected,
3672
- className: className
3673
- })), [ variant, size, isDisabled, rounded, iconOnly, glass, loading, fullWidth, block, active, selected, className, generateButtonClass ]), handleClickEvent = useCallback((event => {
3665
+ });
3666
+ const buttonClass = [ BUTTON.BASE_CLASS, ThemeNaming.variantClass(THEME_NAMING.BUTTON_PREFIX, variant), "md" !== size ? ThemeNaming.sizeClass(THEME_NAMING.BUTTON_PREFIX, size) : "", iconOnly ? ThemeNaming.stateClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.ICON_ELEMENT) : "", rounded ? ThemeNaming.stateClass(THEME_NAMING.BUTTON_PREFIX, "rounded") : "", isDisabled ? ThemeNaming.stateClass(THEME_NAMING.BUTTON_PREFIX, "disabled") : "", glass ? ThemeNaming.stateClass(THEME_NAMING.BUTTON_PREFIX, "glass") : "", loading ? BUTTON.CLASSES.LOADING : "", fullWidth ? BUTTON.CLASSES.FULL_WIDTH : "", block ? BUTTON.CLASSES.BLOCK : "", active ? BUTTON.CLASSES.ACTIVE : "", selected ? BUTTON.CLASSES.SELECTED : "", className ].filter(Boolean).join(" "), handleClickEvent = useCallback((event => {
3674
3667
  isDisabled ? event.preventDefault() : onClick?.(event);
3675
3668
  }), [ isDisabled, onClick ]), handleMouseEnter = useCallback((event => {
3676
3669
  isDisabled || onHover?.(event);
@@ -3678,28 +3671,23 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
3678
3671
  isDisabled || onFocus?.(event);
3679
3672
  }), [ isDisabled, onFocus ]), handleBlurEvent = useCallback((event => {
3680
3673
  isDisabled || onBlur?.(event);
3681
- }), [ isDisabled, onBlur ]), buttonText = useMemo((() => loading && loadingText ? loadingText : label || children), [ loading, loadingText, label, children ]), spinnerSize = useMemo((() => "sm" === size ? "sm" : "lg" === size ? "md" : "sm"), [ size ]), buttonContent = useMemo((() => {
3682
- const iconSpan = iconElement && jsx("span", {
3683
- className: BUTTON.ICON_CLASS,
3684
- "aria-hidden": "true",
3685
- children: iconElement
3686
- }), spinnerElement = loading && jsx("span", {
3687
- className: BUTTON.SPINNER_CLASS,
3674
+ }), [ isDisabled, onBlur ]), buttonText = loading && loadingText ? loadingText : label || children, spinnerSize = "sm" === size ? "sm" : "lg" === size ? "md" : "sm", buttonContent = jsxs(Fragment, {
3675
+ children: [ loading && jsx("span", {
3676
+ className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.SPINNER_ELEMENT),
3688
3677
  "aria-hidden": "true",
3689
3678
  children: jsx(Spinner, {
3690
3679
  size: spinnerSize,
3691
3680
  variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
3692
3681
  })
3693
- }), labelElement = !iconOnly && buttonText && jsx("span", {
3694
- className: BUTTON.LABEL_CLASS,
3682
+ }), iconElement && !loading && jsx("span", {
3683
+ className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.ICON_ELEMENT),
3684
+ "aria-hidden": "true",
3685
+ children: iconElement
3686
+ }), !iconOnly && buttonText && jsx("span", {
3687
+ className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.LABEL_ELEMENT),
3695
3688
  children: buttonText
3696
- });
3697
- return jsxs(Fragment, "end" === iconPosition ? {
3698
- children: [ labelElement, spinnerElement, iconSpan ]
3699
- } : {
3700
- children: [ spinnerElement, iconSpan, labelElement ]
3701
- });
3702
- }), [ iconElement, iconPosition, iconOnly, buttonText, loading, spinnerSize, variant ]), buttonProps = useMemo((() => ({
3689
+ }) ]
3690
+ }), buttonProps = {
3703
3691
  ref: ref,
3704
3692
  className: buttonClass,
3705
3693
  type: "button" !== Component || shouldRenderAsLink ? void 0 : type,
@@ -3717,8 +3705,16 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
3717
3705
  tabIndex: void 0 !== tabIndex ? tabIndex : isDisabled ? -1 : 0,
3718
3706
  style: style,
3719
3707
  ...props
3720
- })), [ ref, buttonClass, Component, type, handleClickEvent, handleMouseEnter, handleFocusEvent, handleBlurEvent, isDisabled, loading, ariaLabel, iconOnly, label, children, ariaDescribedBy, ariaExpanded, ariaControls, tabIndex, style, props ]);
3721
- // Determine if we should render as a link
3708
+ }, defaultGlassProps = {
3709
+ displacementScale: 20,
3710
+ blurAmount: 0,
3711
+ saturation: 200,
3712
+ elasticity: 0
3713
+ }, glassProps = !0 === glass ? defaultGlassProps : {
3714
+ ...defaultGlassProps,
3715
+ ...glass
3716
+ };
3717
+ // Handle click with loading check
3722
3718
  // Render as anchor if href is provided
3723
3719
  if (shouldRenderAsLink) {
3724
3720
  const {ref: _, ...buttonPropsWithoutRef} = buttonProps, anchorButtonProps = {
@@ -3738,22 +3734,10 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
3738
3734
  ...linkProps,
3739
3735
  children: buttonContent
3740
3736
  });
3741
- if (glass) {
3742
- const defaultGlassProps = {
3743
- displacementScale: 20,
3744
- blurAmount: 0,
3745
- saturation: 200,
3746
- elasticity: 0
3747
- }, glassProps = !0 === glass ? defaultGlassProps : {
3748
- ...defaultGlassProps,
3749
- ...glass
3750
- };
3751
- return jsx(AtomixGlass, {
3752
- ...glassProps,
3753
- children: linkElement
3754
- });
3755
- }
3756
- return linkElement;
3737
+ return glass ? jsx(AtomixGlass, {
3738
+ ...glassProps,
3739
+ children: linkElement
3740
+ }) : linkElement;
3757
3741
  }
3758
3742
  // Fallback to regular anchor tag
3759
3743
  const anchorElement = jsx("a", {
@@ -3764,46 +3748,20 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
3764
3748
  rel: "_blank" === target ? "noopener noreferrer" : void 0,
3765
3749
  children: buttonContent
3766
3750
  });
3767
- if (glass) {
3768
- const defaultGlassProps = {
3769
- displacementScale: 20,
3770
- blurAmount: 0,
3771
- saturation: 200,
3772
- elasticity: 0
3773
- }, glassProps = !0 === glass ? defaultGlassProps : {
3774
- ...defaultGlassProps,
3775
- ...glass
3776
- };
3777
- return jsx(AtomixGlass, {
3778
- ...glassProps,
3779
- children: anchorElement
3780
- });
3781
- }
3782
- return anchorElement;
3783
- }
3784
- // Default button rendering
3785
- if (glass) {
3786
- const defaultGlassProps = {
3787
- displacementScale: 20,
3788
- blurAmount: 0,
3789
- saturation: 200,
3790
- elasticity: 0
3791
- }, glassProps = !0 === glass ? defaultGlassProps : {
3792
- ...defaultGlassProps,
3793
- ...glass
3794
- };
3795
- return jsx(AtomixGlass, {
3751
+ return glass ? jsx(AtomixGlass, {
3796
3752
  ...glassProps,
3797
- children: jsx(Component, {
3798
- ...buttonProps,
3799
- children: buttonContent
3800
- })
3801
- });
3753
+ children: anchorElement
3754
+ }) : anchorElement;
3802
3755
  }
3803
- return jsx(Component, {
3756
+ // Default button rendering
3757
+ const buttonElement = jsx(Component, {
3804
3758
  ...buttonProps,
3805
3759
  children: buttonContent
3806
3760
  });
3761
+ return glass ? jsx(AtomixGlass, {
3762
+ ...glassProps,
3763
+ children: buttonElement
3764
+ }) : buttonElement;
3807
3765
  })));
3808
3766
 
3809
3767
  Button.displayName = "Button";
@@ -11104,62 +11062,6 @@ function useHero(initialProps) {
11104
11062
  };
11105
11063
  }
11106
11064
 
11107
- /**
11108
- * CSS Variable Mapper
11109
- *
11110
- * Utilities for generating and managing CSS custom properties from SCSS tokens
11111
- * and component configurations.
11112
- */
11113
- /**
11114
- * Generate CSS variable name from parts
11115
- *
11116
- * @example
11117
- * generateCSSVariableName('button', 'bg', { prefix: 'atomix' })
11118
- * // Returns: '--atomix-button-bg'
11119
- */ function generateCSSVariableName(component, property, options = {}) {
11120
- const {prefix: prefix = "atomix", separator: separator = "-", includeComponent: includeComponent = !0} = options, parts = [ prefix ];
11121
- return includeComponent && parts.push(component), parts.push(property), `--${parts.join(separator)}`;
11122
- }
11123
-
11124
- /**
11125
- * Generate CSS variables object from configuration
11126
- *
11127
- * @example
11128
- * const vars = generateComponentCSSVars({
11129
- * component: 'button',
11130
- * properties: { bg: '#000', color: '#fff' }
11131
- * })
11132
- * // Returns: { '--atomix-button-bg': '#000', '--atomix-button-color': '#fff' }
11133
- */ function generateComponentCSSVars(config, options = {}) {
11134
- const vars = {}, {component: component, properties: properties, parts: parts, states: states, variants: variants} = config;
11135
- // Base properties
11136
- return Object.entries(properties).forEach((([key, value]) => {
11137
- const varName = generateCSSVariableName(component, key, options);
11138
- vars[varName] = String(value);
11139
- })),
11140
- // Part properties
11141
- parts && Object.entries(parts).forEach((([partName, partProps]) => {
11142
- Object.entries(partProps).forEach((([key, value]) => {
11143
- const varName = generateCSSVariableName(component, `${partName}-${key}`, options);
11144
- vars[varName] = String(value);
11145
- }));
11146
- })),
11147
- // State properties
11148
- states && Object.entries(states).forEach((([stateName, stateProps]) => {
11149
- Object.entries(stateProps).forEach((([key, value]) => {
11150
- const varName = generateCSSVariableName(component, `${stateName}-${key}`, options);
11151
- vars[varName] = String(value);
11152
- }));
11153
- })),
11154
- // Variant properties
11155
- variants && Object.entries(variants).forEach((([variantName, variantProps]) => {
11156
- Object.entries(variantProps).forEach((([key, value]) => {
11157
- const varName = generateCSSVariableName(component, `${variantName}-${key}`, options);
11158
- vars[varName] = String(value);
11159
- }));
11160
- })), vars;
11161
- }
11162
-
11163
11065
  /**
11164
11066
  * Map SCSS tokens to CSS custom properties
11165
11067
  *
@@ -11322,7 +11224,7 @@ function mergeComponentProps(baseProps, customization) {
11322
11224
  /**
11323
11225
  * Create data attributes for debugging
11324
11226
  */ function createDebugAttrs(componentName, variant) {
11325
- return "development" !== process.env.NODE_ENV ? {} : {
11227
+ return "undefined" == typeof process || "development" !== process.env?.NODE_ENV ? {} : {
11326
11228
  "data-component": componentName,
11327
11229
  ...variant && {
11328
11230
  "data-variant": variant
@@ -18180,6 +18082,7 @@ const components = Object.freeze( Object.defineProperty({
18180
18082
  TESTIMONIAL: TESTIMONIAL,
18181
18083
  TEXTAREA: TEXTAREA,
18182
18084
  THEME_COLORS: THEME_COLORS,
18085
+ THEME_NAMING: THEME_NAMING,
18183
18086
  TODO: TODO,
18184
18087
  TOGGLE: TOGGLE,
18185
18088
  TOOLTIP: TOOLTIP,
@@ -18652,13 +18555,6 @@ function createTokens(overrides) {
18652
18555
  * @param coefficient - Amount to emphasize (0-1), default 0.15
18653
18556
  * @returns Emphasized hex color
18654
18557
  */
18655
- /**
18656
- * Check if a theme is a JS theme (created with createTheme)
18657
- */
18658
- function isJSTheme(theme) {
18659
- return theme && "object" == typeof theme && !0 === theme.__isJSTheme;
18660
- }
18661
-
18662
18558
  /**
18663
18559
  * Theme Adapter
18664
18560
  *
@@ -18678,7 +18574,8 @@ function isJSTheme(theme) {
18678
18574
  * const tokens = themeToDesignTokens(theme);
18679
18575
  * // Returns: { 'primary': '#7c3aed', ... }
18680
18576
  * ```
18681
- */ function themeToDesignTokens(theme) {
18577
+ */
18578
+ function themeToDesignTokens(theme) {
18682
18579
  const tokens = {};
18683
18580
  // Convert palette colors
18684
18581
  if (theme.palette) {
@@ -18818,158 +18715,10 @@ function isJSTheme(theme) {
18818
18715
  };
18819
18716
  }
18820
18717
 
18821
- /**
18822
- * Config Loader
18823
- *
18824
- * Load design tokens from atomix.config.ts and convert to flat token format.
18825
- */
18826
- /**
18827
- * Convert nested config tokens to flat DesignTokens format
18828
- *
18829
- * Handles conversion from atomix.config.ts structure to flat tokens.
18830
- * Maps config structure to actual DesignTokens key names.
18831
- */ function flattenConfigTokens(tokens, prefix = "atomix") {
18832
- const flat = {};
18833
- // Colors
18834
- return tokens.colors && Object.entries(tokens.colors).forEach((([key, value]) => {
18835
- var _context;
18836
- // Simple color: 'primary': '#7AFFD7'
18837
- // Map directly to DesignTokens keys (e.g., 'primary', 'secondary', 'error')
18838
- // Only map if it's a valid semantic color key
18839
- if ("string" == typeof value) _includesInstanceProperty(_context = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ]).call(_context, key) && (flat[key] = value); else if (value && "object" == typeof value)
18840
- // Color scale or palette
18841
- if ("main" in value) {
18842
- var _context2;
18843
- // PaletteColorOptions: { main: '#7AFFD7', light?: '#...', dark?: '#...' }
18844
- const palette = value, baseKey = key;
18845
- // Map main to base color (e.g., primary, secondary, error)
18846
- _includesInstanceProperty(_context2 = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ]).call(_context2, key) && (flat[baseKey] = palette.main,
18847
- // Map light/dark to appropriate scale values
18848
- // light typically maps to step 3, dark to step 9
18849
- palette.light && (flat[`${key}-3`] = palette.light), palette.dark && (flat[`${key}-9`] = palette.dark));
18850
- } else
18851
- // Color scale: { 1: '#fff', 2: '#eee', ..., 6: '#main', ... }
18852
- // Or full scale: { 1: '#...', 2: '#...', ..., 10: '#...' }
18853
- Object.entries(value).forEach((([scaleKey, scaleValue]) => {
18854
- if ("string" == typeof scaleValue)
18855
- // Map scale keys to DesignTokens format
18856
- if ("main" === scaleKey || "6" === scaleKey) {
18857
- var _context3, _context4;
18858
- // Main color maps to base key (e.g., 'primary')
18859
- _includesInstanceProperty(_context3 = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ]).call(_context3, key) && (flat[key] = scaleValue),
18860
- // Also map to step 6 if it's a scale color
18861
- _includesInstanceProperty(_context4 = [ "primary", "red", "green", "blue", "yellow", "gray" ]).call(_context4, key) && (flat[`${key}-6`] = scaleValue);
18862
- } else {
18863
- // Map scale numbers (1-10) to DesignTokens format
18864
- const scaleNum = parseInt(scaleKey, 10);
18865
- !isNaN(scaleNum) && scaleNum >= 1 && scaleNum <= 10 && (flat[`${key}-${scaleKey}`] = scaleValue);
18866
- }
18867
- }));
18868
- })),
18869
- // Spacing
18870
- tokens.spacing && Object.entries(tokens.spacing).forEach((([key, value]) => {
18871
- flat[`spacing-${key}`] = String(value);
18872
- })),
18873
- // Border Radius
18874
- tokens.borderRadius && Object.entries(tokens.borderRadius).forEach((([key, value]) => {
18875
- // Map to DesignTokens format
18876
- "sm" === key || "base" === key || "" === key ? flat["border-radius-sm"] = String(value) : "md" === key || "default" === key ? flat["border-radius"] = String(value) : "lg" === key ? flat["border-radius-lg"] = String(value) : flat[`border-radius-${key}`] = String(value);
18877
- })),
18878
- // Typography
18879
- tokens.typography && (
18880
- // Font Families
18881
- tokens.typography.fontFamilies && Object.entries(tokens.typography.fontFamilies).forEach((([key, value]) => {
18882
- // Map to DesignTokens format
18883
- "sans" === key || "base" === key ? (flat["font-sans-serif"] = String(value), flat["body-font-family"] = String(value)) : "mono" === key ? flat["font-monospace"] = String(value) : flat[`font-family-${key}`] = String(value);
18884
- })),
18885
- // Font Sizes
18886
- tokens.typography.fontSizes && Object.entries(tokens.typography.fontSizes).forEach((([key, value]) => {
18887
- flat[`font-size-${key}`] = String(value);
18888
- })),
18889
- // Font Weights
18890
- tokens.typography.fontWeights && Object.entries(tokens.typography.fontWeights).forEach((([key, value]) => {
18891
- flat[`font-weight-${key}`] = String(value);
18892
- })),
18893
- // Line Heights
18894
- tokens.typography.lineHeights && Object.entries(tokens.typography.lineHeights).forEach((([key, value]) => {
18895
- "base" === key || "default" === key ? flat["line-height-base"] = String(value) : flat[`line-height-${key}`] = String(value);
18896
- }))),
18897
- // Shadows
18898
- tokens.shadows && Object.entries(tokens.shadows).forEach((([key, value]) => {
18899
- flat[`shadow-${key}`] = String(value);
18900
- })),
18901
- // Z-Index
18902
- tokens.zIndex && Object.entries(tokens.zIndex).forEach((([key, value]) => {
18903
- flat[`z-index-${key}`] = String(value);
18904
- })),
18905
- // Transitions
18906
- tokens.transitions && tokens.transitions.durations && Object.entries(tokens.transitions.durations).forEach((([key, value]) => {
18907
- flat[`transition-${key}`] = String(value);
18908
- })), flat;
18909
- }
18910
-
18911
- /**
18912
- * Load theme tokens from atomix.config.ts
18913
- *
18914
- * Loads atomix.config.ts and extracts theme tokens.
18915
- * Config file is required - throws error if not found.
18916
- *
18917
- * @param configPath - Optional custom config path (default: 'atomix.config.ts')
18918
- * @returns Partial DesignTokens from config
18919
- * @throws Error if config file is not found or cannot be loaded
18920
- *
18921
- * @example
18922
- * ```typescript
18923
- * const tokens = await loadThemeFromConfig();
18924
- * const css = createTheme(tokens);
18925
- * injectTheme(css);
18926
- * ```
18927
- */ async function loadThemeFromConfig(configPath = "atomix.config.ts") {
18928
- // In browser environments, config loading is not supported
18929
- if ("undefined" != typeof window) throw new Error("loadThemeFromConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.");
18930
- // Load config using the existing loader (required)
18931
- const {loadAtomixConfig: loadAtomixConfig} = await Promise.resolve().then((() => loader)), config = loadAtomixConfig({
18932
- configPath: configPath,
18933
- required: !0
18934
- });
18935
- if (!config || !config.theme) throw new Error(`Config file ${configPath} does not contain theme configuration.`);
18936
- // Extract tokens from config
18937
- const tokens = config.theme.tokens || config.theme.extend || {};
18938
- if (0 === Object.keys(tokens).length) throw new Error(`Config file ${configPath} has empty theme configuration.`);
18939
- // Convert nested structure to flat tokens
18940
- return flattenConfigTokens(tokens, config.prefix || "atomix");
18941
- }
18942
-
18943
- /**
18944
- * Load theme tokens from atomix.config.ts (synchronous version)
18945
- *
18946
- * Synchronous version that uses require() instead of dynamic import.
18947
- * Only works in Node.js environment.
18948
- * Config file is required - throws error if not found.
18949
- *
18950
- * @param configPath - Optional custom config path
18951
- * @returns Partial DesignTokens from config
18952
- * @throws Error if config file is not found or cannot be loaded
18953
- */ function loadThemeFromConfigSync(configPath = "atomix.config.ts") {
18954
- // In browser environments, config loading is not supported
18955
- if ("undefined" != typeof window) throw new Error("loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.");
18956
- // eslint-disable-next-line @typescript-eslint/no-require-imports
18957
- const {loadAtomixConfig: loadAtomixConfig} = require("../../config/loader"), config = loadAtomixConfig({
18958
- configPath: configPath,
18959
- required: !0
18960
- });
18961
- if (!config || !config.theme) throw new Error(`Config file ${configPath} does not contain theme configuration.`);
18962
- // Extract tokens from config
18963
- const tokens = config.theme.tokens || config.theme.extend || {};
18964
- if (0 === Object.keys(tokens).length) throw new Error(`Config file ${configPath} has empty theme configuration.`);
18965
- // Convert nested structure to flat tokens
18966
- return flattenConfigTokens(tokens, config.prefix || "atomix");
18967
- }
18968
-
18969
18718
  /**
18970
18719
  * Core Theme Functions
18971
18720
  *
18972
- * Unified theme system that handles both DesignTokens and Theme objects.
18721
+ * Simplified theme system that handles both DesignTokens and Theme objects.
18973
18722
  * Config-first approach: loads from atomix.config.ts when no input is provided.
18974
18723
  * Config file is required for automatic loading.
18975
18724
  */
@@ -19003,43 +18752,68 @@ function isJSTheme(theme) {
19003
18752
  * const css = createTheme(undefined, { prefix: 'myapp', selector: ':root' });
19004
18753
  * ```
19005
18754
  */ function createTheme(input, options) {
19006
- let tokens, configPrefix;
19007
- // If no input provided, load from config (required)
18755
+ // Determine tokens based on input
18756
+ let tokens;
19008
18757
  if (input)
19009
- // Convert Theme to DesignTokens
19010
- tokens = !0 === input.__isJSTheme || input.palette && input.typography ? themeToDesignTokens(input) : input; else {
19011
- const configTokens = loadThemeFromConfigSync();
19012
- // Get prefix from config
19013
- try {
19014
- // eslint-disable-next-line @typescript-eslint/no-require-imports
19015
- const {loadAtomixConfig: loadAtomixConfig} = require("../../config/loader"), config = loadAtomixConfig({
19016
- configPath: "atomix.config.ts",
19017
- required: !0
19018
- });
19019
- configPrefix = config?.prefix;
18758
+ // Use DesignTokens directly
18759
+ tokens =
18760
+ // Helper functions to simplify main function
18761
+ function(input) {
18762
+ return !0 === input?.__isJSTheme || input?.palette && input?.typography;
18763
+ }
18764
+ /**
18765
+ * Theme Composition Utilities
18766
+ *
18767
+ * Simplified utilities for composing, merging, and extending themes.
18768
+ */
18769
+ // ============================================================================
18770
+ // Deep Merge Utility
18771
+ // ============================================================================
18772
+ /**
18773
+ * Check if value is an object
18774
+ */ (input) ? themeToDesignTokens(input) : input;
18775
+ // Merge with defaults and generate CSS
18776
+ else {
18777
+ // Check if we're in a browser environment
18778
+ if ("undefined" != typeof window) throw new Error("createTheme: No input provided and config loading is not available in browser environment. Please provide tokens explicitly or use Node.js/SSR environment.");
18779
+ // Load from config when no input provided
18780
+ // Using dynamic import in a way that's more compatible with bundlers
18781
+ let loadThemeFromConfigSync, loadAtomixConfig;
18782
+ try {
18783
+ // Use dynamic require but only in Node.js environments
18784
+ // This approach allows bundlers to properly handle external dependencies
18785
+ const configLoaderModule = require("../config/configLoader"), loaderModule = require("../../config/loader");
18786
+ // Get prefix from config if needed
18787
+ if (loadThemeFromConfigSync = configLoaderModule.loadThemeFromConfigSync, loadAtomixConfig = loaderModule.loadAtomixConfig,
18788
+ tokens = loadThemeFromConfigSync(), !options?.prefix) try {
18789
+ const config = loadAtomixConfig({
18790
+ configPath: "atomix.config.ts",
18791
+ required: !1
18792
+ });
18793
+ options = {
18794
+ ...options,
18795
+ prefix: config?.prefix || "atomix"
18796
+ };
18797
+ } catch (error) {
18798
+ // If config loading fails, use default prefix
18799
+ options = {
18800
+ ...options,
18801
+ prefix: "atomix"
18802
+ };
18803
+ }
19020
18804
  } catch (error) {
19021
- // Prefix loading failed, but tokens were loaded, so continue
18805
+ throw new Error("createTheme: No input provided and config loading is not available in this environment. Please provide tokens explicitly.");
19022
18806
  }
19023
- tokens = configTokens;
19024
18807
  }
19025
- // Merge with defaults and generate CSS
19026
- return generateCSSVariables$1(createTokens(tokens), {
18808
+ const allTokens = createTokens(tokens), prefix = options?.prefix ?? "atomix";
18809
+ // Get prefix from options or use default
18810
+ return generateCSSVariables$1(allTokens, {
19027
18811
  ...options,
19028
- prefix: options?.prefix ?? configPrefix ?? "atomix"
18812
+ prefix: prefix
19029
18813
  });
19030
18814
  }
19031
18815
 
19032
- /**
19033
- * Theme Composition Utilities
19034
- *
19035
- * Utilities for composing, merging, and extending themes.
19036
- */
19037
- // ============================================================================
19038
- // Deep Merge Utility
19039
- // ============================================================================
19040
- /**
19041
- * Check if value is an object
19042
- */ function isObject(item) {
18816
+ function isObject(item) {
19043
18817
  return item && "object" == typeof item && !Array.isArray(item) && "function" != typeof item;
19044
18818
  }
19045
18819
 
@@ -19098,65 +18872,14 @@ function isJSTheme(theme) {
19098
18872
  * });
19099
18873
  * ```
19100
18874
  */ function extendTheme(baseTheme, extension) {
19101
- // If baseTheme is a complete Theme, extract the options
19102
- const baseOptions = baseTheme.__isJSTheme ?
19103
- /**
19104
- * Extract theme options from a complete Theme object
19105
- */
19106
- function(theme) {
19107
- return {
19108
- name: theme.name,
19109
- class: theme.class,
19110
- description: theme.description,
19111
- author: theme.author,
19112
- version: theme.version,
19113
- tags: theme.tags,
19114
- supportsDarkMode: theme.supportsDarkMode,
19115
- status: theme.status,
19116
- a11y: theme.a11y,
19117
- color: theme.color,
19118
- features: theme.features,
19119
- dependencies: theme.dependencies,
19120
- palette: {
19121
- primary: theme.palette.primary,
19122
- secondary: theme.palette.secondary,
19123
- error: theme.palette.error,
19124
- warning: theme.palette.warning,
19125
- info: theme.palette.info,
19126
- success: theme.palette.success,
19127
- background: theme.palette.background,
19128
- text: theme.palette.text
19129
- },
19130
- typography: {
19131
- fontFamily: theme.typography.fontFamily,
19132
- fontSize: theme.typography.fontSize,
19133
- fontWeightLight: theme.typography.fontWeightLight,
19134
- fontWeightRegular: theme.typography.fontWeightRegular,
19135
- fontWeightMedium: theme.typography.fontWeightMedium,
19136
- fontWeightSemiBold: theme.typography.fontWeightSemiBold,
19137
- fontWeightBold: theme.typography.fontWeightBold,
19138
- h1: theme.typography.h1,
19139
- h2: theme.typography.h2,
19140
- h3: theme.typography.h3,
19141
- h4: theme.typography.h4,
19142
- h5: theme.typography.h5,
19143
- h6: theme.typography.h6,
19144
- body1: theme.typography.body1,
19145
- body2: theme.typography.body2
19146
- },
19147
- shadows: theme.shadows,
19148
- transitions: theme.transitions,
19149
- zIndex: theme.zIndex,
19150
- custom: theme.custom
19151
- };
19152
- }
19153
- // ============================================================================
19154
- // Default Theme Values
19155
- // ============================================================================
19156
- (baseTheme) : baseTheme;
19157
- return createThemeObject(mergeTheme(baseOptions, extension));
18875
+ return createThemeObject(mergeTheme(baseTheme.__isJSTheme ? {
18876
+ ...baseTheme
18877
+ } : baseTheme, extension));
19158
18878
  }
19159
18879
 
18880
+ // ============================================================================
18881
+ // Default Theme Values
18882
+ // ============================================================================
19160
18883
  const DEFAULT_PALETTE = {
19161
18884
  primary: {
19162
18885
  main: "#7c3aed",
@@ -19418,7 +19141,10 @@ function createThemeObject(...options) {
19418
19141
  "number" == typeof spacingInput ? (...values) => 0 === values.length ? "0px" : values.map((value => value * spacingInput + "px")).join(" ") :
19419
19142
  // If it's an array, use it as a scale
19420
19143
  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(" ");
19421
- }(mergedOptions.spacing), breakpoints = function(breakpointsInput) {
19144
+ }
19145
+ /**
19146
+ * Check if a theme is a JS theme (created with createTheme)
19147
+ */ (mergedOptions.spacing), breakpoints = function(breakpointsInput) {
19422
19148
  const values = {
19423
19149
  xs: 0,
19424
19150
  sm: 576,
@@ -19478,694 +19204,71 @@ function createThemeObject(...options) {
19478
19204
  }
19479
19205
 
19480
19206
  /**
19481
- * Theme Configuration Validator
19482
- *
19483
- * Validates theme configuration structure and values
19484
- */
19207
+ * Create a new theme registry
19208
+ */ function createThemeRegistry() {
19209
+ return {};
19210
+ }
19211
+
19485
19212
  /**
19486
- * Validate theme configuration
19487
- *
19488
- * @param config - Configuration to validate
19489
- * @returns Validation result with errors and warnings
19490
- */
19213
+ * Register a theme
19214
+ * @param registry - Theme registry object
19215
+ * @param id - Theme identifier
19216
+ * @param metadata - Theme metadata
19217
+ */ function registerTheme(registry, id, metadata) {
19218
+ registry[id] = metadata;
19219
+ }
19220
+
19491
19221
  /**
19492
- * Validate CSS theme
19493
- */
19494
- function validateCSSTheme(themeId, theme) {
19495
- const errors = [];
19496
- // CSS themes don't require createTheme function
19497
- // But can have optional cssPath
19498
- return {
19499
- valid: 0 === errors.length,
19500
- errors: errors,
19501
- warnings: []
19502
- };
19222
+ * Unregister a theme
19223
+ * @param registry - Theme registry object
19224
+ * @param id - Theme identifier
19225
+ */ function unregisterTheme(registry, id) {
19226
+ const exists = id in registry;
19227
+ return delete registry[id], exists;
19503
19228
  }
19504
19229
 
19505
19230
  /**
19506
- * Validate JS theme
19507
- */ function validateJSTheme(themeId, theme) {
19508
- const errors = [];
19509
- // JS themes must have createTheme function
19510
- return theme.createTheme && "function" == typeof theme.createTheme || errors.push(`JS theme "${themeId}" must have a "createTheme" function`),
19511
- {
19512
- valid: 0 === errors.length,
19513
- errors: errors,
19514
- warnings: []
19515
- };
19231
+ * Check if a theme is registered
19232
+ * @param registry - Theme registry object
19233
+ * @param id - Theme identifier
19234
+ */ function hasTheme(registry, id) {
19235
+ return id in registry;
19516
19236
  }
19517
19237
 
19518
19238
  /**
19519
- * Validate build configuration
19520
- */
19239
+ * Get theme metadata
19240
+ * @param registry - Theme registry object
19241
+ * @param id - Theme identifier
19242
+ */ function getTheme(registry, id) {
19243
+ return registry[id];
19244
+ }
19245
+
19521
19246
  /**
19522
- * Theme System Error Handling
19523
- *
19524
- * Centralized error handling for the Atomix theme system.
19525
- * Provides custom error classes and logging utilities.
19526
- */
19527
- /**
19528
- * Theme error codes
19529
- */
19530
- var ThemeErrorCode, LogLevel;
19531
-
19532
- !function(ThemeErrorCode) {
19533
- /** Theme not found in registry */
19534
- ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
19535
- /** Theme failed to load */
19536
- ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
19537
- /** Theme validation failed */
19538
- ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
19539
- /** Configuration loading failed */
19540
- ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
19541
- /** Configuration validation failed */
19542
- ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
19543
- /** Circular dependency detected */
19544
- ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
19545
- /** Missing dependency */
19546
- ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
19547
- /** Storage operation failed */
19548
- ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
19549
- /** Invalid theme name */
19550
- ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
19551
- /** CSS injection failed */
19552
- ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
19553
- /** Unknown error */
19554
- ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
19555
- }(ThemeErrorCode || (ThemeErrorCode = {}));
19556
-
19557
- /**
19558
- * Custom error class for theme-related errors
19559
- */
19560
- class ThemeError extends Error {
19561
- constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
19562
- super(message), this.name = "ThemeError", this.code = code, this.context = context,
19563
- this.timestamp = Date.now(),
19564
- // Maintains proper stack trace for where our error was thrown (only available on V8)
19565
- Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
19566
- }
19567
- /**
19568
- * Convert error to JSON for logging
19569
- */ toJSON() {
19570
- return {
19571
- name: this.name,
19572
- message: this.message,
19573
- code: this.code,
19574
- context: this.context,
19575
- timestamp: this.timestamp,
19576
- stack: this.stack
19577
- };
19578
- }
19247
+ * Get all registered theme metadata
19248
+ * @param registry - Theme registry object
19249
+ */ function getAllThemes(registry) {
19250
+ return Object.values(registry);
19579
19251
  }
19580
19252
 
19581
19253
  /**
19582
- * Log level
19583
- */ !function(LogLevel) {
19584
- LogLevel[LogLevel.ERROR = 0] = "ERROR", LogLevel[LogLevel.WARN = 1] = "WARN", LogLevel[LogLevel.INFO = 2] = "INFO",
19585
- LogLevel[LogLevel.DEBUG = 3] = "DEBUG";
19586
- }(LogLevel || (LogLevel = {}));
19587
-
19588
- /**
19589
- * Theme Logger
19590
- *
19591
- * Centralized logging for the theme system.
19592
- * Replaces console statements with structured logging.
19593
- */
19594
- class ThemeLogger {
19595
- constructor(config = {}) {
19596
- this.config = {
19597
- level: config.level ?? ("production" === process.env.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
19598
- enableConsole: config.enableConsole ?? !0,
19599
- onError: config.onError,
19600
- onWarn: config.onWarn,
19601
- onInfo: config.onInfo,
19602
- onDebug: config.onDebug
19603
- };
19604
- }
19605
- /**
19606
- * Log an error
19607
- */ error(message, error, context) {
19608
- if (this.config.level < LogLevel.ERROR) return;
19609
- const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
19610
- this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
19611
- error: errorObj,
19612
- context: {
19613
- ...context,
19614
- ...themeError.context
19615
- },
19616
- code: themeError.code
19617
- }), this.config.onError?.(themeError, context);
19618
- }
19619
- /**
19620
- * Log a warning
19621
- */ warn(message, context) {
19622
- this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
19623
- this.config.onWarn?.(message, context));
19624
- }
19625
- /**
19626
- * Log an info message
19627
- */ info(message, context) {
19628
- this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
19629
- this.config.onInfo?.(message, context));
19630
- }
19631
- /**
19632
- * Log a debug message
19633
- */ debug(message, context) {
19634
- this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
19635
- }
19254
+ * Get all registered theme IDs
19255
+ * @param registry - Theme registry object
19256
+ */ function getThemeIds(registry) {
19257
+ return Object.keys(registry);
19636
19258
  }
19637
19259
 
19638
19260
  /**
19639
- * Default logger instance
19640
- */ let defaultLogger = null;
19641
-
19642
- /**
19643
- * Get or create default logger
19644
- */ function getLogger() {
19645
- return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
19261
+ * Clear all registered themes
19262
+ * @param registry - Theme registry object
19263
+ */ function clearThemes(registry) {
19264
+ Object.keys(registry).forEach((key => delete registry[key]));
19646
19265
  }
19647
19266
 
19648
19267
  /**
19649
- * Theme System Constants
19650
- *
19651
- * Centralized constants for the theme system to avoid magic numbers and strings.
19652
- */
19653
- /**
19654
- * Default storage key for theme persistence
19655
- */ const DEFAULT_ATOMIX_CONFIG_PATH = "atomix.config.ts";
19656
-
19657
- /**
19658
- * Default data attribute name for theme
19659
- */ process.env.NODE_ENV;
19660
-
19661
- /**
19662
- * Integration default class names
19663
- */
19664
- const DEFAULT_INTEGRATION_CLASS_NAMES = {
19665
- theme: "data-theme",
19666
- colorMode: "data-atomix-color-mode"
19667
- }, DEFAULT_INTEGRATION_CSS_VARIABLES = {
19668
- colorMode: "--storybook-color-mode"
19669
- }, DEFAULT_SASS_CONFIG = {
19670
- style: "expanded",
19671
- sourceMap: !0,
19672
- loadPaths: [ "src" ]
19673
- };
19674
-
19675
- /**
19676
- * Integration default CSS variables
19677
- */
19678
- /**
19679
- * Theme Configuration Loader
19680
- *
19681
- * Loads and validates the theme configuration from atomix.config.ts
19682
- */
19683
- /**
19684
- * Cache for loaded configuration
19685
- */
19686
- let cachedConfig = null;
19687
-
19688
- /**
19689
- * Logger instance
19690
- */ const logger = getLogger();
19691
-
19692
- /**
19693
- * Load theme configuration from atomix.config.ts
19694
- *
19695
- * @param options - Loader options
19696
- * @returns Loaded and validated theme configuration
19697
- *
19698
- * @example
19699
- * ```typescript
19700
- * import { loadThemeConfig } from '@shohojdhara/atomix/theme/config';
19701
- * const config = loadThemeConfig();
19702
- * ```
19703
- */
19704
- /**
19705
- * Theme Registry
19706
- *
19707
- * Manages theme registration, discovery, and dependency resolution
19708
- */
19709
- class ThemeRegistry {
19710
- constructor() {
19711
- this.entries = new Map, this.config = null, this.initialized = !1;
19712
- }
19713
- /**
19714
- * Initialize registry from config
19715
- */ async initialize(config) {
19716
- if (!this.initialized) {
19717
- // Load config if not provided
19718
- if (config) this.config = config; else try {
19719
- this.config = function(options = {}) {
19720
- const {configPath: configPath = DEFAULT_ATOMIX_CONFIG_PATH, validate: validate = !0, env: env = ("undefined" != typeof process && process.env && "production" === process.env.NODE_ENV ? "production" : "development")} = options;
19721
- // Return cached config if available
19722
- if (cachedConfig) return cachedConfig;
19723
- // Try to load config dynamically
19724
- let config;
19725
- try {
19726
- // In browser/Vite environment, we can't load config dynamically
19727
- if ("undefined" != typeof window) throw new Error("Theme config loading not supported in browser environment");
19728
- // In ESM environments, require might be undefined.
19729
- let nodeRequire, configModule;
19730
- try {
19731
- nodeRequire = require;
19732
- } catch {
19733
- // require is not defined
19734
- }
19735
- if (!nodeRequire) throw new Error("Theme config loading not supported in this environment (require is undefined)");
19736
- // Try require (Node.js/CommonJS)
19737
- try {
19738
- // Try relative path first
19739
- try {
19740
- configModule = nodeRequire("../../../../atomix.config");
19741
- } catch {
19742
- // If relative path fails, try to resolve from process.cwd()
19743
- const path = nodeRequire("path"), fs = nodeRequire("fs");
19744
- let configFilePath = path.resolve(process.cwd(), configPath);
19745
- // If atomix.config.ts not found at the root, use the default path
19746
- if (fs.existsSync(configFilePath) || configPath !== DEFAULT_ATOMIX_CONFIG_PATH || (configFilePath = path.resolve(process.cwd(), DEFAULT_ATOMIX_CONFIG_PATH)),
19747
- !fs.existsSync(configFilePath)) throw new Error(`Config file not found: ${configFilePath}`);
19748
- {
19749
- const resolvedPath = nodeRequire.resolve(configFilePath);
19750
- nodeRequire.cache && nodeRequire.cache[resolvedPath] && delete nodeRequire.cache[resolvedPath],
19751
- configModule = nodeRequire(configFilePath);
19752
- }
19753
- }
19754
- } catch (requireError) {
19755
- const errorMessage = requireError instanceof Error ? requireError.message : String(requireError);
19756
- throw new ThemeError(`Cannot load config: ${errorMessage}`, ThemeErrorCode.CONFIG_LOAD_FAILED, {
19757
- configPath: configPath,
19758
- error: errorMessage
19759
- });
19760
- }
19761
- const rawConfig = configModule.default || configModule, finalConfig =
19762
- /**
19763
- * Apply environment-specific overrides to configuration
19764
- *
19765
- * @param config - Base configuration
19766
- * @param env - Environment name
19767
- * @returns Configuration with environment overrides applied
19768
- */
19769
- function(config, env) {
19770
- const overridden = {
19771
- ...config
19772
- };
19773
- // Production overrides
19774
- return "production" === env && overridden.runtime && (overridden.runtime = {
19775
- ...overridden.runtime,
19776
- useMinified: !0,
19777
- lazy: !0
19778
- }),
19779
- // Development overrides
19780
- "development" === env && (overridden.runtime && (overridden.runtime = {
19781
- ...overridden.runtime,
19782
- useMinified: !1,
19783
- lazy: !1
19784
- }), overridden.build && (overridden.build = {
19785
- ...overridden.build,
19786
- sass: {
19787
- ...overridden.build.sass,
19788
- sourceMap: !0
19789
- }
19790
- })),
19791
- // Test overrides
19792
- "test" === env && overridden.runtime && (overridden.runtime = {
19793
- ...overridden.runtime,
19794
- enablePersistence: !1,
19795
- preload: []
19796
- }), overridden;
19797
- }({
19798
- themes: rawConfig.theme?.themes || {},
19799
- build: rawConfig.build || {},
19800
- runtime: rawConfig.runtime || {},
19801
- integration: rawConfig.integration || {},
19802
- dependencies: rawConfig.dependencies || {},
19803
- validated: !1,
19804
- // Will be set after validation
19805
- // Store tokens for generator
19806
- __tokens: rawConfig.theme?.tokens,
19807
- __extend: rawConfig.theme?.extend
19808
- }, env);
19809
- // Process the AtomixConfig structure
19810
- // Validate if requested
19811
- let validationResult = null;
19812
- validate && (validationResult = function(config) {
19813
- const errors = [], warnings = [];
19814
- // Validate top-level structure
19815
- if (!config || "object" != typeof config) return errors.push("Configuration must be an object"),
19816
- {
19817
- valid: !1,
19818
- errors: errors,
19819
- warnings: warnings
19820
- };
19821
- // Validate themes
19822
- if (config.themes && "object" == typeof config.themes) {
19823
- const themeErrors =
19824
- /**
19825
- * Validate themes object
19826
- */
19827
- function(themes) {
19828
- const errors = [], warnings = [];
19829
- 0 === Object.keys(themes).length && warnings.push("No themes defined in configuration");
19830
- for (const [themeId, theme] of Object.entries(themes))
19831
- // Validate theme ID
19832
- if (themeId && "string" == typeof themeId)
19833
- // Validate theme object
19834
- if (theme && "object" == typeof theme)
19835
- // Validate theme type
19836
- if (!theme.type || "css" !== theme.type && "js" !== theme.type) errors.push(`Theme "${themeId}" must have type "css" or "js"`); else {
19837
- // Validate CSS theme
19838
- if (
19839
- // Validate required fields
19840
- theme.name && "string" == typeof theme.name || errors.push(`Theme "${themeId}" must have a "name" string`),
19841
- "css" === theme.type) {
19842
- const cssErrors = validateCSSTheme();
19843
- errors.push(...cssErrors.errors), warnings.push(...cssErrors.warnings);
19844
- }
19845
- // Validate JS theme
19846
- if ("js" === theme.type) {
19847
- const jsErrors = validateJSTheme(themeId, theme);
19848
- errors.push(...jsErrors.errors), warnings.push(...jsErrors.warnings);
19849
- }
19850
- // Validate accessibility (only critical checks)
19851
- theme.a11y?.contrastTarget && ("number" != typeof theme.a11y.contrastTarget || theme.a11y.contrastTarget < 1 || theme.a11y.contrastTarget > 21) && warnings.push(`Theme "${themeId}" has invalid contrast target: ${theme.a11y.contrastTarget}`);
19852
- } else errors.push(`Theme "${themeId}" must be an object`); else errors.push(`Invalid theme ID: ${themeId}`);
19853
- return {
19854
- valid: 0 === errors.length,
19855
- errors: errors,
19856
- warnings: warnings
19857
- };
19858
- }(config.themes);
19859
- errors.push(...themeErrors.errors), warnings.push(...themeErrors.warnings);
19860
- }
19861
- // Validate build config (only if provided)
19862
- else errors.push('Configuration must have a "themes" object');
19863
- if (config.build) {
19864
- const buildErrors = function(build) {
19865
- const errors = [];
19866
- // Only validate structure if provided
19867
- return build.output && "object" != typeof build.output && errors.push("Build output must be an object"),
19868
- build.sass && "object" != typeof build.sass && errors.push("Build sass config must be an object"),
19869
- {
19870
- valid: 0 === errors.length,
19871
- errors: errors,
19872
- warnings: []
19873
- };
19874
- }
19875
- /**
19876
- * Validate runtime configuration
19877
- */ (config.build);
19878
- errors.push(...buildErrors.errors), warnings.push(...buildErrors.warnings);
19879
- }
19880
- // Validate runtime config (only if provided)
19881
- if (config.runtime) {
19882
- const runtimeErrors = function(runtime) {
19883
- const errors = [];
19884
- return runtime.basePath && "string" != typeof runtime.basePath && errors.push("Runtime basePath must be a string"),
19885
- runtime.defaultTheme && "string" != typeof runtime.defaultTheme && errors.push("Runtime defaultTheme must be a string"),
19886
- runtime.preload && !Array.isArray(runtime.preload) && errors.push("Runtime preload must be an array"),
19887
- runtime.storageKey && "string" != typeof runtime.storageKey && errors.push("Runtime storageKey must be a string"),
19888
- {
19889
- valid: 0 === errors.length,
19890
- errors: errors,
19891
- warnings: []
19892
- };
19893
- }
19894
- /**
19895
- * Validate integration configuration
19896
- */ (config.runtime);
19897
- errors.push(...runtimeErrors.errors), warnings.push(...runtimeErrors.warnings);
19898
- }
19899
- // Validate integration config (only if provided)
19900
- if (config.integration) {
19901
- const integrationErrors = function(integration) {
19902
- const errors = [];
19903
- // Only validate structure if provided
19904
- return integration.classNames && "object" != typeof integration.classNames && errors.push("Integration classNames must be an object"),
19905
- {
19906
- valid: 0 === errors.length,
19907
- errors: errors,
19908
- warnings: []
19909
- };
19910
- }
19911
- /**
19912
- * Validate dependencies
19913
- */ (config.integration);
19914
- errors.push(...integrationErrors.errors), warnings.push(...integrationErrors.warnings);
19915
- }
19916
- // Validate dependencies
19917
- if (config.dependencies) {
19918
- const depErrors = function(dependencies, themes) {
19919
- const errors = [], warnings = [];
19920
- for (const [themeId, deps] of Object.entries(dependencies))
19921
- // Check if theme exists
19922
- if (themes[themeId])
19923
- // Validate dependencies array
19924
- if (Array.isArray(deps))
19925
- // Check if all dependencies exist
19926
- for (const dep of deps) themes[dep] || errors.push(`Theme "${themeId}" depends on non-existent theme: ${dep}`); else errors.push(`Dependencies for "${themeId}" must be an array`); else warnings.push(`Dependencies defined for non-existent theme: ${themeId}`);
19927
- return {
19928
- valid: 0 === errors.length,
19929
- errors: errors,
19930
- warnings: warnings
19931
- };
19932
- }(config.dependencies, config.themes || {});
19933
- errors.push(...depErrors.errors), warnings.push(...depErrors.warnings);
19934
- }
19935
- return {
19936
- valid: 0 === errors.length,
19937
- errors: errors,
19938
- warnings: warnings
19939
- };
19940
- }(finalConfig)), config = {
19941
- ...finalConfig,
19942
- validated: validate,
19943
- errors: validationResult?.errors,
19944
- warnings: validationResult?.warnings
19945
- };
19946
- } catch (error) {
19947
- // Fallback: return default config structure
19948
- const errorMessage = error instanceof Error ? error.message : String(error);
19949
- logger.warn(`Failed to load theme config from ${configPath}`, {
19950
- configPath: configPath,
19951
- error: errorMessage
19952
- }), config = {
19953
- themes: {},
19954
- build: {
19955
- output: {
19956
- directory: "themes",
19957
- formats: {
19958
- expanded: ".css",
19959
- compressed: ".min.css"
19960
- }
19961
- },
19962
- sass: {
19963
- ...DEFAULT_SASS_CONFIG,
19964
- loadPaths: [ ...DEFAULT_SASS_CONFIG.loadPaths ]
19965
- }
19966
- },
19967
- runtime: {
19968
- basePath: "/themes",
19969
- cdnPath: null,
19970
- preload: [],
19971
- lazy: !0,
19972
- defaultTheme: "",
19973
- // No default - use built-in styles (empty string instead of undefined)
19974
- storageKey: "atomix-theme",
19975
- dataAttribute: "data-theme",
19976
- enablePersistence: !0,
19977
- useMinified: "production" === env
19978
- },
19979
- integration: {
19980
- cssVariables: DEFAULT_INTEGRATION_CSS_VARIABLES,
19981
- classNames: DEFAULT_INTEGRATION_CLASS_NAMES
19982
- },
19983
- dependencies: {},
19984
- validated: !1,
19985
- errors: [ `Failed to load config: ${error instanceof Error ? error.message : String(error)}` ],
19986
- warnings: [],
19987
- __tokens: {},
19988
- __extend: {}
19989
- };
19990
- }
19991
- // Cache the loaded config
19992
- return cachedConfig = config, config;
19993
- }();
19994
- } catch (error) {
19995
- // In browser environments, config loading will fail
19996
- // Use empty config as fallback
19997
- this.config = {
19998
- themes: {},
19999
- build: {
20000
- output: {
20001
- directory: "themes",
20002
- formats: {
20003
- expanded: ".css",
20004
- compressed: ".min.css"
20005
- }
20006
- },
20007
- sass: {
20008
- style: "expanded",
20009
- sourceMap: !0,
20010
- loadPaths: [ "src" ]
20011
- }
20012
- },
20013
- runtime: {
20014
- basePath: "",
20015
- defaultTheme: void 0
20016
- },
20017
- integration: {
20018
- cssVariables: {
20019
- colorMode: "--color-mode"
20020
- },
20021
- classNames: {
20022
- theme: "data-theme",
20023
- colorMode: "data-color-mode"
20024
- }
20025
- },
20026
- dependencies: {},
20027
- validated: !1,
20028
- errors: [],
20029
- warnings: [],
20030
- __tokens: {},
20031
- __extend: {}
20032
- };
20033
- }
20034
- // Register all themes from config
20035
- for (const [themeId, definition] of Object.entries(this.config.themes)) this.register(themeId, definition);
20036
- // Resolve dependencies
20037
- this.resolveDependencies(), this.initialized = !0;
20038
- }
20039
- }
20040
- /**
20041
- * Register a theme
20042
- */ register(themeId, definition) {
20043
- // Get dependencies from config or definition
20044
- const entry = {
20045
- id: themeId,
20046
- definition: definition,
20047
- loaded: !1,
20048
- dependencies: [ ...this.config?.dependencies?.[themeId] || definition.dependencies || [] ],
20049
- dependents: []
20050
- };
20051
- this.entries.set(themeId, entry);
20052
- }
20053
- /**
20054
- * Get theme entry
20055
- */ get(themeId) {
20056
- return this.entries.get(themeId);
20057
- }
20058
- /**
20059
- * Check if theme exists
20060
- */ has(themeId) {
20061
- return this.entries.has(themeId);
20062
- }
20063
- /**
20064
- * Get all theme IDs
20065
- */ getAllIds() {
20066
- return Array.from(this.entries.keys());
20067
- }
20068
- /**
20069
- * Get all theme metadata
20070
- */ getAllMetadata() {
20071
- return Array.from(this.entries.values()).map((entry => ({
20072
- id: entry.id,
20073
- name: entry.definition.name,
20074
- type: entry.definition.type,
20075
- class: entry.definition.class,
20076
- description: entry.definition.description,
20077
- author: entry.definition.author,
20078
- version: entry.definition.version,
20079
- tags: entry.definition.tags,
20080
- supportsDarkMode: entry.definition.supportsDarkMode,
20081
- status: entry.definition.status,
20082
- a11y: entry.definition.a11y,
20083
- color: entry.definition.color,
20084
- features: entry.definition.features,
20085
- dependencies: entry.dependencies
20086
- })));
20087
- }
20088
- /**
20089
- * Get theme definition
20090
- */ getDefinition(themeId) {
20091
- return this.entries.get(themeId)?.definition;
20092
- }
20093
- /**
20094
- * Check if a theme is loaded
20095
- */ isThemeLoaded(themeId) {
20096
- const entry = this.entries.get(themeId);
20097
- return !!entry && entry.loaded;
20098
- }
20099
- /**
20100
- * Mark a theme as loaded
20101
- */ markLoaded(themeId, theme) {
20102
- const entry = this.entries.get(themeId);
20103
- entry && (entry.loaded = !0, theme && (entry.theme = theme));
20104
- }
20105
- /**
20106
- * Get theme object (for JS themes)
20107
- */ getTheme(themeId) {
20108
- const entry = this.entries.get(themeId);
20109
- return entry?.loaded ? entry.theme : void 0;
20110
- }
20111
- /**
20112
- * Get dependencies for a theme
20113
- */ getDependencies(themeId) {
20114
- return this.entries.get(themeId)?.dependencies || [];
20115
- }
20116
- /**
20117
- * Get dependents for a theme (themes that depend on this one)
20118
- */ getDependents(themeId) {
20119
- return this.entries.get(themeId)?.dependents || [];
20120
- }
20121
- /**
20122
- * Resolve all dependencies in correct order
20123
- */ resolveDependencyOrder(themeId) {
20124
- const resolved = [], visited = new Set, visiting = new Set, visit = id => {
20125
- if (visiting.has(id)) throw new Error(`Circular dependency detected involving theme: ${id}`);
20126
- if (visited.has(id)) return;
20127
- visiting.add(id);
20128
- const entry = this.entries.get(id);
20129
- if (entry) for (const dep of entry.dependencies) {
20130
- if (!this.has(dep)) throw new Error(`Theme "${id}" depends on non-existent theme: ${dep}`);
20131
- visit(dep);
20132
- }
20133
- visiting.delete(id), visited.add(id), resolved.push(id);
20134
- };
20135
- return visit(themeId), resolved;
20136
- }
20137
- /**
20138
- * Resolve dependencies and build dependency graph
20139
- */ resolveDependencies() {
20140
- // Build dependents map
20141
- for (const entry of this.entries.values()) for (const dep of entry.dependencies) {
20142
- const depEntry = this.entries.get(dep);
20143
- var _context;
20144
- depEntry && (_includesInstanceProperty(_context = depEntry.dependents).call(_context, entry.id) || depEntry.dependents.push(entry.id));
20145
- }
20146
- }
20147
- /**
20148
- * Validate all themes
20149
- */ validate() {
20150
- const errors = [];
20151
- // Check for circular dependencies
20152
- for (const themeId of this.entries.keys()) try {
20153
- this.resolveDependencyOrder(themeId);
20154
- } catch (error) {
20155
- errors.push(error instanceof Error ? error.message : String(error));
20156
- }
20157
- // Check for missing dependencies
20158
- for (const [themeId, entry] of this.entries.entries()) for (const dep of entry.dependencies) this.has(dep) || errors.push(`Theme "${themeId}" depends on non-existent theme: ${dep}`);
20159
- return {
20160
- valid: 0 === errors.length,
20161
- errors: errors
20162
- };
20163
- }
20164
- /**
20165
- * Clear registry
20166
- */ clear() {
20167
- this.entries.clear(), this.config = null, this.initialized = !1;
20168
- }
19268
+ * Get the number of registered themes
19269
+ * @param registry - Theme registry object
19270
+ */ function getThemeCount(registry) {
19271
+ return Object.keys(registry).length;
20169
19272
  }
20170
19273
 
20171
19274
  /**
@@ -20250,71 +19353,18 @@ class ThemeRegistry {
20250
19353
  * const css = ':root { --atomix-color-primary: #7AFFD7; }';
20251
19354
  * await saveCSSFile(css, './themes/custom.css');
20252
19355
  * ```
20253
- */ async function saveCSSFile(css, filePath) {
20254
- // Check if in browser environment
20255
- if ("undefined" != typeof window) throw new Error("saveCSSFile can only be used in Node.js environment. Use injectCSS() for browser environments.");
20256
- // Dynamic import to avoid bundling Node.js modules in browser builds
20257
- const fs = await import("fs/promises"), dir = (await import("path")).dirname(filePath);
20258
- await fs.mkdir(dir, {
20259
- recursive: !0
20260
- }),
20261
- // Write file
20262
- await fs.writeFile(filePath, css, "utf8");
20263
- }
20264
-
20265
- /**
20266
- * Save CSS to file (synchronous version)
20267
- *
20268
- * Synchronous version of saveCSSFile. Only works in Node.js environment.
20269
- *
20270
- * @param css - CSS string to save
20271
- * @param filePath - Output file path
20272
- * @throws Error if called in browser environment
20273
- */ function saveCSSFileSync(css, filePath) {
20274
- // Check if in browser environment
20275
- if ("undefined" != typeof window) throw new Error("saveCSSFileSync can only be used in Node.js environment. Use injectCSS() for browser environments.");
20276
- // Use require for synchronous file operations
20277
- // eslint-disable-next-line @typescript-eslint/no-require-imports
20278
- const fs = require("fs"), dir = require("path").dirname(filePath);
20279
- // eslint-disable-next-line @typescript-eslint/no-require-imports
20280
- fs.existsSync(dir) || fs.mkdirSync(dir, {
20281
- recursive: !0
20282
- }),
20283
- // Write file
20284
- fs.writeFileSync(filePath, css, "utf8");
20285
- }
19356
+ */ "undefined" != typeof process && process.env;
20286
19357
 
20287
19358
  /**
20288
19359
  * Check if code is running in a browser environment
20289
- */ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof document, isServer = () => !isBrowser(), getThemeLinkId = themeName => `atomix-theme-${themeName}`, buildThemePath = (themeName, basePath = "/themes", useMinified = !1, cdnPath = null) => {
19360
+ */
19361
+ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof document, isServer = () => !isBrowser(), buildThemePath = (themeName, basePath = "/themes", useMinified = !1, cdnPath = null) => {
20290
19362
  // Validate theme name to prevent path injection
20291
19363
  if (!isValidThemeName(themeName)) throw new Error(`Invalid theme name: "${themeName}". Theme names must be lowercase alphanumeric with hyphens.`);
20292
19364
  const fileName = `${themeName}${useMinified ? ".min.css" : ".css"}`;
20293
19365
  return cdnPath ? `${cdnPath.replace(/[<>"']/g, "")}/${fileName}` : `${basePath.replace(/\/$/, "").replace(/[<>"']/g, "")}/${fileName.replace(/^\//, "")}`;
20294
19366
  // Ensure basePath doesn't end with slash and fileName doesn't start with slash
20295
19367
  // Also sanitize basePath to prevent path injection
20296
- }, loadThemeCSS = (fullPath, linkId) => isServer() ? Promise.resolve() : new Promise(((resolve, reject) => {
20297
- if (document.getElementById(linkId)) return void resolve();
20298
- // Create link element
20299
- const link = document.createElement("link");
20300
- link.id = linkId, link.rel = "stylesheet", link.type = "text/css", link.href = fullPath,
20301
- // Add data attribute for tracking
20302
- link.setAttribute("data-atomix-theme", "true"),
20303
- // Handle load success
20304
- link.onload = () => {
20305
- resolve();
20306
- },
20307
- // Handle load error
20308
- link.onerror = () => {
20309
- // Remove failed link element
20310
- link.remove(), reject(new Error(`Failed to load theme CSS: ${fullPath}`));
20311
- },
20312
- // Append to head
20313
- document.head.appendChild(link);
20314
- })), isThemeLoaded = themeName => {
20315
- if (isServer()) return !1;
20316
- const linkId = getThemeLinkId(themeName);
20317
- return null !== document.getElementById(linkId);
20318
19368
  }, isValidThemeName = themeName => !(!themeName || "string" != typeof themeName) && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(themeName);
20319
19369
 
20320
19370
  /**
@@ -20787,211 +19837,198 @@ function generateCSSVariables(theme, options = {}) {
20787
19837
  styleElement.textContent = css;
20788
19838
  }
20789
19839
  /**
20790
- * Theme Context
19840
+ * Naming Utilities
20791
19841
  *
20792
- * React context for theme management
19842
+ * Provides consistent naming conventions across the theme system
20793
19843
  */
20794
19844
  /**
20795
- * Theme context with default values
19845
+ * Generate consistent CSS class names following BEM methodology
20796
19846
  */ (css, styleId), css;
20797
19847
  }
20798
19848
 
20799
- const ThemeContext = createContext(null);
19849
+ function generateClassName(block, element, modifiers) {
19850
+ let className = block;
19851
+ return element && (className += `__${element}`), modifiers && Object.entries(modifiers).forEach((([key, value]) => {
19852
+ value && (className += `--${key}`, "string" == typeof value && value !== key && (className += `-${value}`));
19853
+ })), className;
19854
+ }
20800
19855
 
20801
- ThemeContext.displayName = "ThemeContext";
19856
+ /**
19857
+ * Generate consistent CSS variable names
19858
+ */ function generateCSSVariableName(property, options = {}) {
19859
+ const {prefix: prefix = "atomix", component: component, variant: variant, state: state} = options, parts = [ prefix ];
19860
+ return component && parts.push(component), variant && parts.push(variant), state && parts.push(state),
19861
+ parts.push(property), `--${parts.join("-")}`;
19862
+ }
20802
19863
 
20803
19864
  /**
20804
- * Theme Applicator
20805
- *
20806
- * Applies theme configurations to the DOM, including CSS variables,
20807
- * component overrides, typography, spacing, and color palettes.
20808
- *
20809
- * Uses the unified theme system for CSS generation and injection.
20810
- */
19865
+ * Normalize theme tokens to consistent naming convention
19866
+ */ function normalizeThemeTokens(tokens) {
19867
+ const normalized = {};
19868
+ for (const [key, value] of Object.entries(tokens))
19869
+ // Recursively normalize nested objects
19870
+ normalized[key] = "object" == typeof value && null !== value ? normalizeThemeTokens(value) : value;
19871
+ return normalized;
19872
+ }
19873
+
20811
19874
  /**
20812
- * Theme applicator class for runtime theme application
19875
+ * Convert camelCase to kebab-case for CSS custom properties
19876
+ */ function camelToKebab(str) {
19877
+ return str.replace(/[A-Z]/g, (match => `-${match.toLowerCase()}`));
19878
+ }
19879
+
19880
+ /**
19881
+ * Convert theme property to CSS variable name
19882
+ */ function themePropertyToCSSVar(propertyPath, prefix = "atomix") {
19883
+ return `--${prefix}-${propertyPath.split(".").map((part => camelToKebab(part))).join("-")}`;
19884
+ }
19885
+
19886
+ /**
19887
+ * Component Theming Utilities
20813
19888
  *
20814
- * Uses the unified theme system for efficient CSS variable generation and injection.
19889
+ * Provides consistent patterns for applying theme values to components
20815
19890
  */
20816
- class ThemeApplicator {
20817
- constructor(root = document.documentElement) {
20818
- this.styleId = "atomix-theme-applicator", this.root = root;
20819
- }
20820
- /**
20821
- * Apply a complete theme configuration
20822
- *
20823
- * Uses the unified theme system to convert Theme to DesignTokens and inject CSS.
20824
- * Automatically respects atomix.config.ts when using DesignTokens.
20825
- */ applyTheme(theme) {
20826
- // Clear previously applied variables
20827
- this.clearAppliedVars(),
20828
- // Check if it's DesignTokens
20829
- this.isDesignTokens(theme) ?
20830
- // Direct DesignTokens - use unified theme system (with config support)
20831
- this.applyDesignTokens(theme) : injectCSS$1(createTheme(theme, {
20832
- selector: ":root",
20833
- prefix: "atomix"
20834
- }), this.styleId),
20835
- // Apply component overrides (only for Theme objects)
20836
- !this.isDesignTokens(theme) && theme.components && this.applyComponentOverrides(theme.components);
20837
- }
20838
- /**
20839
- * Apply DesignTokens using unified theme system
20840
- *
20841
- * Uses createTheme() which automatically loads from atomix.config.ts
20842
- * if no tokens are provided, ensuring config is always respected.
20843
- */ applyDesignTokens(tokens) {
20844
- // Inject CSS into DOM
20845
- injectCSS$1(createTheme(tokens, {
20846
- selector: ":root",
20847
- prefix: "atomix"
20848
- }), this.styleId);
20849
- }
20850
- /**
20851
- * Check if object is DesignTokens
20852
- */ isDesignTokens(obj) {
20853
- // DesignTokens is a flat object with string keys, no nested structures
20854
- return null !== obj && "object" == typeof obj && !("palette" in obj) && !("typography" in obj) && !("__isJSTheme" in obj);
20855
- }
20856
- /**
20857
- * Apply global CSS variables (for component overrides)
20858
- */ applyGlobalCSSVars(vars) {
20859
- Object.entries(vars).forEach((([key, value]) => {
20860
- this.root.style.setProperty(key, String(value));
20861
- }));
20862
- }
20863
- /**
20864
- * Apply component-level overrides
20865
- */ applyComponentOverrides(overrides) {
20866
- Object.entries(overrides).forEach((([componentName, override]) => {
20867
- override && this.applyComponentOverride(componentName, override);
20868
- }));
20869
- }
20870
- /**
20871
- * Apply override for a specific component
20872
- */ applyComponentOverride(componentName, override) {
20873
- const vars = {}, componentKey = componentName.toLowerCase();
20874
- // Apply component-level CSS variables
20875
- override.cssVars && Object.entries(override.cssVars).forEach((([key, value]) => {
20876
- // If key doesn't start with --, add component prefix
20877
- const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${key}`;
20878
- vars[varKey] = value;
20879
- })),
20880
- // Apply part-specific CSS variables
20881
- override.parts && Object.entries(override.parts).forEach((([partName, partOverride]) => {
20882
- partOverride.cssVars && Object.entries(partOverride.cssVars).forEach((([key, value]) => {
20883
- const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${partName}-${key}`;
20884
- vars[varKey] = value;
20885
- }));
20886
- })),
20887
- // Apply variant-specific CSS variables
20888
- override.variants && Object.entries(override.variants).forEach((([variantName, variantOverride]) => {
20889
- variantOverride.cssVars && Object.entries(variantOverride.cssVars).forEach((([key, value]) => {
20890
- const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${variantName}-${key}`;
20891
- vars[varKey] = value;
20892
- }));
20893
- })), this.applyGlobalCSSVars(vars);
20894
- }
20895
- /**
20896
- * Clear all applied CSS variables
20897
- */ clearAppliedVars() {
20898
- removeCSS(this.styleId);
20899
- }
20900
- /**
20901
- * Remove theme application
20902
- */ removeTheme() {
20903
- this.clearAppliedVars(), removeCSS(this.styleId);
20904
- }
20905
- /**
20906
- * Update specific CSS variables without clearing all
20907
- */ updateCSSVars(vars) {
20908
- this.applyGlobalCSSVars(vars);
20909
- }
19891
+ /**
19892
+ * Get a theme value for a specific component using CSS variables
19893
+ * This ensures all components access theme values consistently
19894
+ */ function getComponentThemeValue(component, property, variant, size) {
19895
+ // Build CSS variable name following consistent pattern
19896
+ const parts = [ "atomix", component ];
19897
+ // Return CSS variable reference with fallback
19898
+ return variant && parts.push(variant), size && parts.push(size), parts.push(property),
19899
+ `var(--${parts.join("-")}, var(--atomix-${property}, initial))`;
20910
19900
  }
20911
19901
 
20912
19902
  /**
20913
- * Global theme applicator instance
20914
- */ let globalApplicator = null;
19903
+ * Generate component-specific CSS variables from theme
19904
+ */ function generateComponentCSSVars(component, theme, variant, size) {
19905
+ const vars = {}, prefixParts = [ "atomix", component ];
19906
+ // This is a simplified implementation - in a real system you'd have more
19907
+ // sophisticated logic to extract component-specific values from the theme
19908
+ variant && prefixParts.push(variant), size && prefixParts.push(size);
19909
+ const prefix = prefixParts.join("-");
19910
+ // Add common component properties
19911
+ if (theme.palette && (vars[`--${prefix}-color`] = theme.palette.primary?.main || "#7c3aed",
19912
+ vars[`--${prefix}-color-hover`] = theme.palette.primary?.dark || "#5b21b6", vars[`--${prefix}-color-active`] = theme.palette.primary?.main || "#7c3aed",
19913
+ vars[`--${prefix}-color-disabled`] = theme.palette.text?.disabled || "#9ca3af"),
19914
+ theme.typography && (vars[`--${prefix}-font-family`] = theme.typography.fontFamily || "Inter, sans-serif",
19915
+ vars[`--${prefix}-font-size`] = theme.typography.fontSize ? `${theme.typography.fontSize}px` : "16px"),
19916
+ theme.spacing) {
19917
+ const spacing = "function" == typeof theme.spacing ? theme.spacing : val => 8 * val;
19918
+ vars[`--${prefix}-spacing-unit`] = `${spacing(1)}px`, vars[`--${prefix}-spacing-sm`] = `${spacing(.5)}px`,
19919
+ vars[`--${prefix}-spacing-md`] = `${spacing(1)}px`, vars[`--${prefix}-spacing-lg`] = `${spacing(2)}px`;
19920
+ }
19921
+ return vars;
19922
+ }
20915
19923
 
20916
19924
  /**
20917
- * Get or create global theme applicator
20918
- */ function getThemeApplicator() {
20919
- return globalApplicator || (globalApplicator = new ThemeApplicator), globalApplicator;
19925
+ * Apply consistent theme to component style object
19926
+ */ function applyComponentTheme(component, style = {}, variant, size, theme) {
19927
+ // If no theme provided, return original style
19928
+ return theme ? {
19929
+ ...generateComponentCSSVars(component, theme, variant, size),
19930
+ ...style
19931
+ } : style;
19932
+ // Generate component-specific CSS variables
20920
19933
  }
20921
19934
 
20922
19935
  /**
20923
- * Apply theme using global applicator
20924
- */ function applyTheme(theme) {
20925
- getThemeApplicator().applyTheme(theme);
19936
+ * Create a hook for consistent component theming
19937
+ */ function useComponentTheme(component, variant, size, theme) {
19938
+ return property => getComponentThemeValue(component, property, variant, size);
20926
19939
  }
20927
19940
 
20928
19941
  /**
20929
- * ThemeProvider component
20930
- *
20931
- * Provides theme context to child components and manages theme state.
19942
+ * Theme Configuration Loader
20932
19943
  *
20933
- * **Config-First Approach**: If `defaultTheme` is not provided, loads from `atomix.config.ts`.
20934
- * Config file is required when `defaultTheme` is not provided.
19944
+ * Provides functions to load theme configurations from atomix.config.ts
19945
+ * Includes both sync and async versions, with automatic fallbacks
19946
+ */
19947
+ /**
19948
+ * Load theme from config file (synchronous, Node.js only)
19949
+ * @param configPath - Path to config file (default: atomix.config.ts)
19950
+ * @returns DesignTokens from theme configuration
19951
+ * @throws Error if config loading is not available in browser environment
19952
+ */ function loadThemeFromConfigSync(options) {
19953
+ // Check if we're in a browser environment
19954
+ if ("undefined" != typeof window) throw new Error("loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.");
19955
+ // Use dynamic import to load the config loader
19956
+ // This allows bundlers to handle external dependencies properly
19957
+ let loadAtomixConfig;
19958
+ try {
19959
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
19960
+ const {loadAtomixConfig: loader} = require("../../config/loader");
19961
+ loadAtomixConfig = loader;
19962
+ } catch (error) {
19963
+ if (!1 !== options?.required) throw new Error("Config loader module not available");
19964
+ // Return empty tokens if config is not required
19965
+ return createTokens({});
19966
+ }
19967
+ const config = loadAtomixConfig({
19968
+ configPath: options?.configPath || "atomix.config.ts",
19969
+ required: !1 !== options?.required
19970
+ });
19971
+ return config?.theme ? isThemeObject$1(config.theme) ? createDesignTokensFromTheme(config.theme) : createTokens(config.theme) : createTokens({});
19972
+ }
19973
+
19974
+ /**
19975
+ * Load theme from config file (asynchronous)
19976
+ * @param configPath - Path to config file (default: atomix.config.ts)
19977
+ * @returns Promise resolving to DesignTokens from theme configuration
19978
+ */ async function loadThemeFromConfig(options) {
19979
+ // Check if we're in a browser environment
19980
+ if ("undefined" != typeof window) throw new Error("loadThemeFromConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.");
19981
+ // Dynamic import for config loader
19982
+ const {loadAtomixConfig: loadAtomixConfig} = await import("./lib/config/loader"), config = await loadAtomixConfig({
19983
+ configPath: options?.configPath || "atomix.config.ts",
19984
+ required: !1 !== options?.required
19985
+ });
19986
+ return config?.theme ? isThemeObject$1(config.theme) ? createDesignTokensFromTheme(config.theme) : createTokens(config.theme) : createTokens({});
19987
+ }
19988
+
19989
+ /**
19990
+ * Check if the provided object is a Theme object
19991
+ * @param theme - Object to check
19992
+ * @returns True if the object is a Theme object, false otherwise
19993
+ */ function isThemeObject$1(theme) {
19994
+ return "object" == typeof theme && null !== theme;
19995
+ }
19996
+
19997
+ /**
19998
+ * Theme Context
20935
19999
  *
20936
- * @example
20937
- * ```tsx
20938
- * import { ThemeProvider } from '@shohojdhara/atomix/theme';
20000
+ * React context for theme management
20001
+ */
20002
+ /**
20003
+ * Theme context with default values
20004
+ */ const ThemeContext = createContext(null);
20005
+
20006
+ ThemeContext.displayName = "ThemeContext";
20007
+
20008
+ /**
20009
+ * Theme Provider
20939
20010
  *
20940
- * // Loads from atomix.config.ts (config file required)
20941
- * function App() {
20942
- * return (
20943
- * <ThemeProvider>
20944
- * <YourApp />
20945
- * </ThemeProvider>
20946
- * );
20947
- * }
20011
+ * React context provider for theme management with separated concerns.
20012
+ * Simplified version focusing on core functionality:
20013
+ * - String-based themes (CSS files)
20014
+ * - JS Theme objects
20015
+ * - Persistence via localStorage
20948
20016
  *
20949
- * // Provide explicit theme (bypasses config)
20950
- * function App() {
20951
- * return (
20952
- * <ThemeProvider defaultTheme="dark">
20953
- * <YourApp />
20954
- * </ThemeProvider>
20955
- * );
20956
- * }
20957
- * ```
20958
- */ const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes: themes = {}, basePath: basePath = "/themes", cdnPath: cdnPath = null, preload: preload = [], lazy: lazy = !0, storageKey: storageKey = "atomix-theme", dataAttribute: dataAttribute = "data-theme", enablePersistence: enablePersistence = !0, useMinified: useMinified = !1, onThemeChange: onThemeChange, onError: onError}) => {
20017
+ * Falls back to 'default' theme if no configuration is found.
20018
+ */
20019
+ const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes: themes = {}, basePath: basePath = "/themes", cdnPath: cdnPath = null, useMinified: useMinified = !1, storageKey: storageKey = "atomix-theme", dataAttribute: dataAttribute = "data-theme", enablePersistence: enablePersistence = !0, onThemeChange: onThemeChange, onError: onError}) => {
20959
20020
  // Store callbacks in refs to avoid recreating when they change
20960
20021
  const onThemeChangeRef = useRef(onThemeChange), onErrorRef = useRef(onError);
20961
- // Update refs when callbacks change
20022
+ // Update ref when callback changes
20962
20023
  useEffect((() => {
20963
20024
  onThemeChangeRef.current = onThemeChange, onErrorRef.current = onError;
20964
20025
  }), [ onThemeChange, onError ]);
20965
- // Create stable wrapper functions that read from refs
20026
+ // Create stable wrapper functions that read from ref
20966
20027
  const handleThemeChange = useCallback((theme => {
20967
20028
  onThemeChangeRef.current?.(theme);
20968
20029
  }), []), handleError = useCallback(((error, themeName) => {
20969
20030
  onErrorRef.current?.(error, themeName);
20970
- }), []), themesRef = useRef(themes), themesStable = useMemo((() => {
20971
- // Only update if themes object actually changed (shallow comparison)
20972
- const currentKeys = Object.keys(themes), prevKeys = Object.keys(themesRef.current);
20973
- return currentKeys.length !== prevKeys.length || currentKeys.some((key => themes[key] !== themesRef.current[key])) ? (themesRef.current = themes,
20974
- themes) : themesRef.current;
20975
- }), [ themes ]), logger = useMemo((() => getLogger()), []), registry = useMemo((() => {
20976
- const reg = new ThemeRegistry;
20977
- // Register themes from props
20978
- if (themesStable && Object.keys(themesStable).length > 0) for (const [themeId, metadata] of Object.entries(themesStable)) reg.has(themeId) || reg.register(themeId, {
20979
- type: "css",
20980
- name: metadata.name,
20981
- class: metadata.class || themeId,
20982
- description: metadata.description,
20983
- author: metadata.author,
20984
- version: metadata.version,
20985
- tags: metadata.tags,
20986
- supportsDarkMode: metadata.supportsDarkMode,
20987
- status: metadata.status,
20988
- a11y: metadata.a11y,
20989
- color: metadata.color,
20990
- features: metadata.features,
20991
- dependencies: metadata.dependencies
20992
- });
20993
- return reg;
20994
- }), [ themesStable ]), storageAdapter = useMemo((() => ({
20031
+ }), []), storageAdapter = useMemo((() => ({
20995
20032
  getItem: key => {
20996
20033
  if (isServer()) return null;
20997
20034
  try {
@@ -21023,7 +20060,7 @@ class ThemeApplicator {
21023
20060
  return !1;
21024
20061
  }
21025
20062
  }
21026
- })), []), themeApplicator = useMemo((() => isServer() ? null : new ThemeApplicator), []), initialDefaultTheme = useMemo((() => {
20063
+ })), []), initialDefaultTheme = useMemo((() => {
21027
20064
  // Check storage first
21028
20065
  if (enablePersistence && storageAdapter.isAvailable()) {
21029
20066
  const stored = storageAdapter.getItem(storageKey);
@@ -21031,236 +20068,368 @@ class ThemeApplicator {
21031
20068
  }
21032
20069
  // If defaultTheme is provided, use it
21033
20070
  if (null != defaultTheme) return defaultTheme;
21034
- // Load from atomix.config.ts (required)
21035
- const configTokens = loadThemeFromConfigSync();
21036
- return configTokens && Object.keys(configTokens).length > 0 ? configTokens : null;
21037
- // Config is required - this will be caught in useEffect
21038
- }), [ enablePersistence, storageAdapter, storageKey, defaultTheme ]), [currentTheme, setCurrentTheme] = useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : isJSTheme(initialDefaultTheme) ? initialDefaultTheme.name || "js-theme" : initialDefaultTheme && "object" == typeof initialDefaultTheme && !isJSTheme(initialDefaultTheme) ? "config-theme" : "" // No default theme - use built-in styles
21039
- )), [activeTheme, setActiveTheme] = useState((() => isJSTheme(initialDefaultTheme) ? initialDefaultTheme : null)), [availableThemes, setAvailableThemes] = useState((() => registry.getAllMetadata().map((meta => ({
21040
- name: meta.name || "",
21041
- class: meta.class,
21042
- description: meta.description,
21043
- author: meta.author,
21044
- version: meta.version,
21045
- tags: meta.tags,
21046
- supportsDarkMode: meta.supportsDarkMode,
21047
- status: meta.status,
21048
- a11y: meta.a11y,
21049
- color: meta.color,
21050
- features: meta.features,
21051
- dependencies: meta.dependencies
21052
- }))))), [isLoading, setIsLoading] = useState(!1), [error, setError] = useState(null), loadedThemesRef = useRef(new Set), previousThemeRef = useRef(null);
21053
- // Get default theme (with automatic config loading)
21054
- useCallback((() => {
21055
- // Check storage first
21056
- if (enablePersistence && storageAdapter.isAvailable()) {
21057
- const stored = storageAdapter.getItem(storageKey);
21058
- if (stored) return stored;
20071
+ // Try to load from atomix.config.ts as fallback, but only in Node.js/SSR environments
20072
+ if ("undefined" == typeof window) try {
20073
+ // Dynamically import the config loader to avoid bundling issues in browser
20074
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
20075
+ const {loadThemeFromConfigSync: loadThemeFromConfigSync} = require("../config/configLoader"), configTokens = loadThemeFromConfigSync();
20076
+ if (configTokens && Object.keys(configTokens).length > 0)
20077
+ // For simplicity, we'll treat config tokens as a special theme name
20078
+ return "config-theme";
20079
+ } catch (error) {
20080
+ console.warn("Failed to load theme from config, using default");
21059
20081
  }
21060
- // If defaultTheme is provided, use it
21061
- if (null != defaultTheme) return defaultTheme;
21062
- // Load from atomix.config.ts (required)
21063
- // Config file must exist - throws error if not found
21064
- const configTokens = loadThemeFromConfigSync();
21065
- if (configTokens && Object.keys(configTokens).length > 0)
21066
- // Return config tokens as Partial<DesignTokens>
21067
- return configTokens;
21068
- throw new Error("ThemeProvider: atomix.config.ts is required when defaultTheme is not provided.");
21069
- }), [ enablePersistence, storageAdapter, storageKey, defaultTheme ]);
21070
- // Apply JS theme (supports both Theme and DesignTokens)
21071
- const applyJSTheme = useCallback((async (theme, removePrevious = !0) => {
21072
- !isServer() && themeApplicator && (removePrevious && (
21073
- // Remove previous theme
21074
- removeCSS("atomix-theme"),
21075
- // Also remove any existing CSS variables
21076
- activeTheme && activeTheme.cssVars && Object.keys(activeTheme.cssVars).forEach((key => {
21077
- document.documentElement.style.removeProperty(key);
21078
- }))), null === theme || "object" != typeof theme || "palette" in theme || "typography" in theme || "__isJSTheme" in theme ?
21079
- // Use ThemeApplicator for Theme objects
21080
- themeApplicator?.applyTheme(theme) : injectCSS$1(createTheme(theme), "atomix-theme"));
21081
- }), [ activeTheme, themeApplicator ]), setTheme = useCallback((async (theme, options) => {
21082
- const {removePrevious: removePrevious = !0, fallbackOnError: fallbackOnError = !0, customPath: customPath} = options || {};
20082
+ // Default fallback
20083
+ return "default";
20084
+ }), [ defaultTheme, enablePersistence, storageKey ]), [currentTheme, setCurrentTheme] = useState((() => initialDefaultTheme)), [activeTheme, setActiveTheme] = useState(null), [isLoading, setIsLoading] = useState(!1), [error, setError] = useState(null), loadedThemesRef = useRef(new Set), themePromisesRef = useRef({});
20085
+ // Apply initial theme attributes to document element
20086
+ useEffect((() => {
20087
+ isServer() || ((dataAttribute, themeName) => {
20088
+ isServer() || (
20089
+ // Set data attribute on body
20090
+ document.body.setAttribute(dataAttribute, themeName),
20091
+ // Also set on documentElement for broader compatibility
20092
+ document.documentElement.setAttribute(dataAttribute, themeName));
20093
+ })(String(currentTheme), dataAttribute);
20094
+ }), [ currentTheme, dataAttribute ]),
20095
+ // Handle theme persistence
20096
+ useEffect((() => {
20097
+ enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, String(currentTheme));
20098
+ }), [ currentTheme, storageKey, enablePersistence ]);
20099
+ // Function to set theme with proper type handling
20100
+ const setTheme = useCallback((async (theme, options) => {
21083
20101
  setIsLoading(!0), setError(null);
21084
20102
  try {
21085
- // Handle Theme or DesignTokens object directly
21086
- if ("string" != typeof theme) {
21087
- if (null !== theme && "object" == typeof theme && !("palette" in theme) && !("typography" in theme) && !("__isJSTheme" in theme)) {
21088
- // Handle DesignTokens using unified theme system
21089
- await applyJSTheme(theme, removePrevious);
21090
- const themeName = "design-tokens-theme";
21091
- return previousThemeRef.current = currentTheme, setCurrentTheme(themeName), setActiveTheme(null),
21092
- previousThemeRef.current, Date.now(), handleThemeChange(themeName),
21093
- // Persist to storage
21094
- enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, themeName),
21095
- void setIsLoading(!1);
21096
- }
21097
- if (isJSTheme(theme)) {
21098
- // Handle Theme object
21099
- await applyJSTheme(theme, removePrevious);
21100
- const themeName = theme.name || "js-theme";
21101
- return previousThemeRef.current = currentTheme, setCurrentTheme(themeName), setActiveTheme(theme),
21102
- previousThemeRef.current, Date.now(), handleThemeChange(theme),
21103
- // Persist to storage
21104
- enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, themeName),
21105
- void setIsLoading(!1);
21106
- }
21107
- {
21108
- const error = new Error("Invalid theme object provided");
21109
- throw handleError(error, "js-theme"), setError(error), setIsLoading(!1), error;
21110
- }
21111
- }
21112
- // Check if theme exists
21113
- if (!registry.has(theme)) {
21114
- const error = new Error(`Theme "${theme}" not found in registry`);
21115
- if (handleError(error, theme), setError(error), fallbackOnError && currentTheme) return void setIsLoading(!1);
21116
- throw setIsLoading(!1), error;
21117
- }
21118
- // Load theme CSS if needed
21119
- const themePath = customPath || buildThemePath(theme, basePath, useMinified, cdnPath || void 0), linkId = getThemeLinkId(theme);
21120
- // Remove previous theme if requested
21121
- removePrevious && previousThemeRef.current && previousThemeRef.current !== theme && (themeNameOrLinkId => {
21122
- if (isServer()) return;
21123
- // Try as link ID first, then as theme name
21124
- let link = document.getElementById(themeNameOrLinkId);
21125
- if (!link) {
21126
- const linkId = getThemeLinkId(themeNameOrLinkId);
21127
- link = document.getElementById(linkId);
21128
- }
21129
- link && link.remove();
21130
- })(previousThemeRef.current),
21131
- // Load CSS if not already loaded
21132
- isThemeLoaded(theme) || (await loadThemeCSS(themePath, linkId), loadedThemesRef.current.add(theme)),
21133
- // Apply theme attributes
21134
- ((dataAttribute, themeName) => {
21135
- isServer() || (
21136
- // Set data attribute on body
21137
- document.body.setAttribute(dataAttribute, themeName),
21138
- // Also set on documentElement for broader compatibility
21139
- document.documentElement.setAttribute(dataAttribute, themeName));
21140
- })(dataAttribute, theme),
21141
- // Update state
21142
- previousThemeRef.current = currentTheme, setCurrentTheme(theme), setActiveTheme(null),
21143
- previousThemeRef.current, Date.now(), handleThemeChange(theme),
21144
- // Persist to storage
21145
- enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, theme),
21146
- setIsLoading(!1);
20103
+ let themeName, themeObj = null;
20104
+ // If it's a string theme name, load the associated CSS
20105
+ if ("string" == typeof theme ? themeName = theme :
20106
+ // If it's a Theme object or DesignTokens, we need to process it
20107
+ function(theme) {
20108
+ return "object" == typeof theme && null !== theme && "__isJSTheme" in theme && !0 === theme.__isJSTheme;
20109
+ }(theme) ? (themeObj = theme,
20110
+ // For JS themes, we use a generic name
20111
+ themeName = "js-theme", setActiveTheme(themeObj)) :
20112
+ // For DesignTokens, we might create a theme from tokens
20113
+ themeName = "tokens-theme", "string" == typeof theme && themes[theme]) {
20114
+ // Check if theme is already loading
20115
+ if (themePromisesRef.current[theme]) return await themePromisesRef.current[theme],
20116
+ setCurrentTheme(theme), setActiveTheme(null), void handleThemeChange(theme);
20117
+ // Load CSS theme
20118
+ const themeLoadPromise = new Promise((async (resolve, reject) => {
20119
+ try {
20120
+ if (!themes[theme]) throw new Error(`Theme metadata not found for theme: ${theme}`);
20121
+ {
20122
+ // Build CSS path using utility function
20123
+ const cssPath = buildThemePath(theme, basePath, useMinified, cdnPath);
20124
+ // Remove any previously loaded theme CSS
20125
+ removeCSS(`theme-${String(currentTheme)}`),
20126
+ // Inject new theme CSS
20127
+ await injectCSS$1(cssPath, `theme-${theme}`), loadedThemesRef.current.add(theme),
20128
+ setCurrentTheme(theme), setActiveTheme(null), handleThemeChange(theme), resolve();
20129
+ }
20130
+ } catch (err) {
20131
+ const error = err instanceof Error ? err : new Error(String(err));
20132
+ setError(error), handleError(error, String(theme)), reject(error);
20133
+ }
20134
+ }));
20135
+ themePromisesRef.current[theme] = themeLoadPromise, await themeLoadPromise;
20136
+ } else themeObj ? (
20137
+ // For JS themes, set them directly
20138
+ setCurrentTheme(themeName), setActiveTheme(themeObj), handleThemeChange(themeObj)) : (
20139
+ // For string theme that isn't in our themes record, just set the name
20140
+ setCurrentTheme(themeName), setActiveTheme(null), handleThemeChange(themeName));
21147
20141
  } catch (err) {
21148
20142
  const error = err instanceof Error ? err : new Error(String(err));
21149
- throw handleError(error, "string" == typeof theme ? theme : "js-theme"), setError(error),
21150
- setIsLoading(!1), err;
20143
+ setError(error), handleError(error, String(theme));
20144
+ } finally {
20145
+ setIsLoading(!1);
21151
20146
  }
21152
- }), [ registry, basePath, cdnPath, useMinified, dataAttribute, enablePersistence, storageAdapter, storageKey, currentTheme, activeTheme, applyJSTheme, handleThemeChange, handleError ]), preloadTheme = useCallback((async themeName => {
21153
- if (!isServer() && !isThemeLoaded(themeName)) {
20147
+ }), [ themes, currentTheme, handleThemeChange, handleError, basePath, useMinified, cdnPath ]), isThemeLoaded = useCallback((themeName => loadedThemesRef.current.has(themeName)), []), preloadTheme = useCallback((async themeName => {
20148
+ if (themes[themeName] && !isThemeLoaded(themeName)) {
21154
20149
  setIsLoading(!0);
21155
20150
  try {
21156
- if (!registry.has(themeName)) throw new Error(`Theme "${themeName}" not found in registry`);
21157
- const themePath = buildThemePath(themeName, basePath, useMinified, cdnPath || void 0), linkId = getThemeLinkId(themeName);
21158
- await loadThemeCSS(themePath, linkId), loadedThemesRef.current.add(themeName);
20151
+ // Build CSS path using utility function
20152
+ const cssPath = buildThemePath(themeName, basePath, useMinified, cdnPath);
20153
+ // Preload CSS by fetching it
20154
+ await fetch(cssPath), loadedThemesRef.current.add(themeName);
21159
20155
  } catch (err) {
21160
20156
  const error = err instanceof Error ? err : new Error(String(err));
21161
- handleError(error, themeName), setError(error);
20157
+ setError(error), handleError(error, themeName);
21162
20158
  } finally {
21163
20159
  setIsLoading(!1);
21164
20160
  }
21165
20161
  }
21166
- }), [ registry, basePath, cdnPath, useMinified, handleError ]), isThemeLoaded$1 = useCallback((themeName => isThemeLoaded(themeName)), []);
21167
- // Set theme function (supports string, Theme, or DesignTokens)
21168
- // Initialize default theme on mount
21169
- useEffect((() => {
21170
- isServer() || (async () => {
21171
- // Use the initial default theme we computed
21172
- const defaultThemeValue = initialDefaultTheme;
21173
- if (defaultThemeValue) try {
21174
- null === defaultThemeValue || "object" != typeof defaultThemeValue || "palette" in defaultThemeValue || "typography" in defaultThemeValue || "__isJSTheme" in defaultThemeValue || "string" == typeof defaultThemeValue ?
21175
- // Handle string or Theme object
21176
- await setTheme(defaultThemeValue, {
21177
- removePrevious: !1,
21178
- fallbackOnError: !0
21179
- }) : (
21180
- // Apply config tokens directly
21181
- await applyJSTheme(defaultThemeValue, !1),
21182
- // Update state and emit events
21183
- setCurrentTheme("config-theme"), setActiveTheme(null), Date.now(), handleThemeChange("config-theme"),
21184
- // Persist to storage
21185
- enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, "config-theme"));
21186
- } catch (err) {
21187
- const error = err instanceof Error ? err : new Error(String(err));
21188
- throw logger.error("Failed to load theme from config", error, {
21189
- theme: defaultThemeValue
21190
- }), handleError(error, "config-theme"), setError(error), error;
20162
+ }), [ themes, isThemeLoaded, handleError, basePath, useMinified, cdnPath ]), themeManager = useMemo((() => ({})), []), contextValue = useMemo((() => ({
20163
+ theme: "string" == typeof currentTheme ? currentTheme : "js-theme",
20164
+ activeTheme: activeTheme,
20165
+ setTheme: setTheme,
20166
+ availableThemes: Object.entries(themes).map((([name, metadata]) => ({
20167
+ ...metadata
20168
+ }))),
20169
+ isLoading: isLoading,
20170
+ error: error,
20171
+ isThemeLoaded: isThemeLoaded,
20172
+ preloadTheme: preloadTheme,
20173
+ themeManager: themeManager
20174
+ })), [ currentTheme, activeTheme, setTheme, themes, isLoading, error, isThemeLoaded, preloadTheme, themeManager ]);
20175
+ // Check if theme is loaded
20176
+ return jsx(ThemeContext.Provider, {
20177
+ value: contextValue,
20178
+ children: children
20179
+ });
20180
+ };
20181
+
20182
+ /**
20183
+ * useTheme Hook
20184
+ *
20185
+ * React hook for accessing theme context
20186
+ */
20187
+ /**
20188
+ * useTheme hook
20189
+ *
20190
+ * Access theme context and theme management functions
20191
+ *
20192
+ * @example
20193
+ * ```tsx
20194
+ * function MyComponent() {
20195
+ * const { theme, setTheme, availableThemes } = useTheme();
20196
+ *
20197
+ * return (
20198
+ * <div>
20199
+ * <p>Current theme: {theme}</p>
20200
+ * <button onClick={() => setTheme('dark-theme')}>
20201
+ * Switch to Dark
20202
+ * </button>
20203
+ * </div>
20204
+ * );
20205
+ * }
20206
+ * ```
20207
+ */ function useTheme() {
20208
+ const context = useContext(ThemeContext);
20209
+ if (!context) throw new Error("useTheme must be used within a ThemeProvider");
20210
+ return {
20211
+ theme: context.theme,
20212
+ activeTheme: context.activeTheme,
20213
+ setTheme: context.setTheme,
20214
+ availableThemes: context.availableThemes,
20215
+ isLoading: context.isLoading,
20216
+ error: context.error,
20217
+ isThemeLoaded: context.isThemeLoaded,
20218
+ preloadTheme: context.preloadTheme
20219
+ };
20220
+ }
20221
+
20222
+ function useThemeTokens() {
20223
+ const {theme: theme, activeTheme: activeTheme} = useTheme(), getToken = useCallback(((tokenName, fallback) => {
20224
+ if ("undefined" == typeof window) return fallback || "";
20225
+ const cssVarName = `--atomix-${tokenName}`;
20226
+ return getComputedStyle(document.documentElement).getPropertyValue(cssVarName).trim() || fallback || "";
20227
+ }), []), getThemeValue = useCallback(((path, fallback) => {
20228
+ var _context;
20229
+ return activeTheme && _reduceInstanceProperty(_context = path.split(".")).call(_context, ((obj, key) => obj?.[key]), activeTheme) || fallback;
20230
+ // Navigate through nested theme object using dot notation
20231
+ }), [ activeTheme ]);
20232
+ // Helper function to get CSS variable value
20233
+ // Return unified API for accessing theme values
20234
+ return {
20235
+ theme: theme,
20236
+ activeTheme: activeTheme,
20237
+ getToken: getToken,
20238
+ getThemeValue: getThemeValue,
20239
+ // Commonly used tokens with fallbacks
20240
+ colors: {
20241
+ primary: getToken("primary", "#3b82f6"),
20242
+ secondary: getToken("secondary", "#10b981"),
20243
+ error: getToken("error", "#ef4444"),
20244
+ success: getToken("success", "#22c55e"),
20245
+ warning: getToken("warning", "#eab308"),
20246
+ info: getToken("info", "#3b82f6"),
20247
+ light: getToken("light", "#f9fafb"),
20248
+ dark: getToken("dark", "#111827")
20249
+ },
20250
+ spacing: {
20251
+ 1: getToken("spacing-1", "0.25rem"),
20252
+ 2: getToken("spacing-2", "0.5rem"),
20253
+ 3: getToken("spacing-3", "0.75rem"),
20254
+ 4: getToken("spacing-4", "1rem"),
20255
+ 5: getToken("spacing-5", "1.25rem"),
20256
+ 6: getToken("spacing-6", "1.5rem"),
20257
+ 8: getToken("spacing-8", "2rem"),
20258
+ 10: getToken("spacing-10", "2.5rem"),
20259
+ 12: getToken("spacing-12", "3rem"),
20260
+ 16: getToken("spacing-16", "4rem"),
20261
+ 20: getToken("spacing-20", "5rem")
20262
+ },
20263
+ borderRadius: {
20264
+ sm: getToken("border-radius-sm", "0.25rem"),
20265
+ md: getToken("border-radius-md", "0.5rem"),
20266
+ lg: getToken("border-radius-lg", "0.75rem"),
20267
+ xl: getToken("border-radius-xl", "1rem"),
20268
+ full: getToken("border-radius-full", "9999px")
20269
+ },
20270
+ typography: {
20271
+ fontFamily: {
20272
+ sans: getToken("font-sans-serif", "Inter, system-ui, sans-serif"),
20273
+ serif: getToken("font-serif", "Georgia, serif"),
20274
+ mono: getToken("font-monospace", "Fira Code, monospace")
20275
+ },
20276
+ fontSize: {
20277
+ xs: getToken("font-size-xs", "0.75rem"),
20278
+ sm: getToken("font-size-sm", "0.875rem"),
20279
+ md: getToken("font-size-md", "1rem"),
20280
+ lg: getToken("font-size-lg", "1.125rem"),
20281
+ xl: getToken("font-size-xl", "1.25rem"),
20282
+ "2xl": getToken("font-size-2xl", "1.5rem"),
20283
+ "3xl": getToken("font-size-3xl", "1.875rem"),
20284
+ "4xl": getToken("font-size-4xl", "2.25rem")
20285
+ },
20286
+ fontWeight: {
20287
+ light: getToken("font-weight-light", "300"),
20288
+ normal: getToken("font-weight-normal", "400"),
20289
+ medium: getToken("font-weight-medium", "500"),
20290
+ semibold: getToken("font-weight-semibold", "600"),
20291
+ bold: getToken("font-weight-bold", "700")
21191
20292
  }
21192
- })();
20293
+ },
20294
+ shadows: {
20295
+ sm: getToken("box-shadow-sm", "0 1px 2px 0 rgba(0, 0, 0, 0.05)"),
20296
+ md: getToken("box-shadow-md", "0 4px 6px -1px rgba(0, 0, 0, 0.1)"),
20297
+ lg: getToken("box-shadow-lg", "0 10px 15px -3px rgba(0, 0, 0, 0.1)"),
20298
+ xl: getToken("box-shadow-xl", "0 20px 25px -5px rgba(0, 0, 0, 0.1)"),
20299
+ inset: getToken("box-shadow-inset", "inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)")
20300
+ },
20301
+ transitions: {
20302
+ fast: getToken("transition-fast", "150ms"),
20303
+ base: getToken("transition-base", "200ms"),
20304
+ slow: getToken("transition-slow", "300ms")
20305
+ }
20306
+ };
20307
+ }
20308
+
20309
+ /**
20310
+ * Theme System Error Handling
20311
+ *
20312
+ * Centralized error handling for the Atomix theme system.
20313
+ * Provides custom error classes and logging utilities.
20314
+ */
20315
+ /**
20316
+ * Theme error codes
20317
+ */ var ThemeErrorCode, LogLevel;
20318
+
20319
+ !function(ThemeErrorCode) {
20320
+ /** Theme not found in registry */
20321
+ ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
20322
+ /** Theme failed to load */
20323
+ ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
20324
+ /** Theme validation failed */
20325
+ ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
20326
+ /** Configuration loading failed */
20327
+ ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
20328
+ /** Configuration validation failed */
20329
+ ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
20330
+ /** Circular dependency detected */
20331
+ ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
20332
+ /** Missing dependency */
20333
+ ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
20334
+ /** Storage operation failed */
20335
+ ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
20336
+ /** Invalid theme name */
20337
+ ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
20338
+ /** CSS injection failed */
20339
+ ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
20340
+ /** Unknown error */
20341
+ ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
20342
+ }(ThemeErrorCode || (ThemeErrorCode = {}));
20343
+
20344
+ /**
20345
+ * Custom error class for theme-related errors
20346
+ */
20347
+ class ThemeError extends Error {
20348
+ constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
20349
+ super(message), this.name = "ThemeError", this.code = code, this.context = context,
20350
+ this.timestamp = Date.now(),
20351
+ // Maintains proper stack trace for where our error was thrown (only available on V8)
20352
+ Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
20353
+ }
20354
+ /**
20355
+ * Convert error to JSON for logging
20356
+ */ toJSON() {
20357
+ return {
20358
+ name: this.name,
20359
+ message: this.message,
20360
+ code: this.code,
20361
+ context: this.context,
20362
+ timestamp: this.timestamp,
20363
+ stack: this.stack
20364
+ };
21193
20365
  }
21194
- // eslint-disable-next-line react-hooks/exhaustive-deps
21195
- ), []), // Only run once on mount - initialDefaultTheme is stable
21196
- // Preload themes
21197
- useEffect((() => {
21198
- !isServer() && preload && 0 !== preload.length && (async () => {
21199
- for (const themeName of preload) if (!isThemeLoaded(themeName)) try {
21200
- await preloadTheme(themeName);
21201
- } catch (err) {
21202
- // Silently fail for preload
21203
- logger.warn(`Failed to preload theme "${themeName}"`, {
21204
- error: err instanceof Error ? err.message : String(err)
21205
- });
21206
- }
21207
- })();
21208
- }), [ preload, preloadTheme, logger ]);
21209
- // Context value
21210
- const contextValue = useMemo((() => ({
21211
- theme: currentTheme,
21212
- activeTheme: activeTheme,
21213
- setTheme: setTheme,
21214
- availableThemes: availableThemes,
21215
- isLoading: isLoading,
21216
- error: error,
21217
- isThemeLoaded: isThemeLoaded$1,
21218
- preloadTheme: preloadTheme
21219
- })), [ currentTheme, activeTheme, setTheme, availableThemes, isLoading, error, isThemeLoaded$1, preloadTheme ]);
21220
- return jsx(ThemeContext.Provider, {
21221
- value: contextValue,
21222
- children: children
21223
- });
21224
- };
20366
+ }
21225
20367
 
21226
20368
  /**
21227
- * useTheme Hook
20369
+ * Log level
20370
+ */ !function(LogLevel) {
20371
+ LogLevel[LogLevel.ERROR = 0] = "ERROR", LogLevel[LogLevel.WARN = 1] = "WARN", LogLevel[LogLevel.INFO = 2] = "INFO",
20372
+ LogLevel[LogLevel.DEBUG = 3] = "DEBUG";
20373
+ }(LogLevel || (LogLevel = {}));
20374
+
20375
+ /**
20376
+ * Theme Logger
21228
20377
  *
21229
- * React hook for accessing theme context
20378
+ * Centralized logging for the theme system.
20379
+ * Replaces console statements with structured logging.
21230
20380
  */
20381
+ class ThemeLogger {
20382
+ constructor(config = {}) {
20383
+ this.config = {
20384
+ level: config.level ?? ("undefined" != typeof process && "production" === process.env?.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
20385
+ enableConsole: config.enableConsole ?? !0,
20386
+ onError: config.onError,
20387
+ onWarn: config.onWarn,
20388
+ onInfo: config.onInfo,
20389
+ onDebug: config.onDebug
20390
+ };
20391
+ }
20392
+ /**
20393
+ * Log an error
20394
+ */ error(message, error, context) {
20395
+ if (this.config.level < LogLevel.ERROR) return;
20396
+ const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
20397
+ this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
20398
+ error: errorObj,
20399
+ context: {
20400
+ ...context,
20401
+ ...themeError.context
20402
+ },
20403
+ code: themeError.code
20404
+ }), this.config.onError?.(themeError, context);
20405
+ }
20406
+ /**
20407
+ * Log a warning
20408
+ */ warn(message, context) {
20409
+ this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
20410
+ this.config.onWarn?.(message, context));
20411
+ }
20412
+ /**
20413
+ * Log an info message
20414
+ */ info(message, context) {
20415
+ this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
20416
+ this.config.onInfo?.(message, context));
20417
+ }
20418
+ /**
20419
+ * Log a debug message
20420
+ */ debug(message, context) {
20421
+ this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
20422
+ }
20423
+ }
20424
+
21231
20425
  /**
21232
- * useTheme hook
21233
- *
21234
- * Access theme context and theme management functions
21235
- *
21236
- * @example
21237
- * ```tsx
21238
- * function MyComponent() {
21239
- * const { theme, setTheme, availableThemes } = useTheme();
21240
- *
21241
- * return (
21242
- * <div>
21243
- * <p>Current theme: {theme}</p>
21244
- * <button onClick={() => setTheme('dark-theme')}>
21245
- * Switch to Dark
21246
- * </button>
21247
- * </div>
21248
- * );
21249
- * }
21250
- * ```
21251
- */ function useTheme() {
21252
- const context = useContext(ThemeContext);
21253
- if (!context) throw new Error("useTheme must be used within a ThemeProvider");
21254
- return {
21255
- theme: context.theme,
21256
- activeTheme: context.activeTheme,
21257
- setTheme: context.setTheme,
21258
- availableThemes: context.availableThemes,
21259
- isLoading: context.isLoading,
21260
- error: context.error,
21261
- isThemeLoaded: context.isThemeLoaded,
21262
- preloadTheme: context.preloadTheme
21263
- };
20426
+ * Default logger instance
20427
+ */ let defaultLogger = null;
20428
+
20429
+ /**
20430
+ * Get or create default logger
20431
+ */ function getLogger() {
20432
+ return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
21264
20433
  }
21265
20434
 
21266
20435
  /**
@@ -21311,7 +20480,7 @@ class ThemeApplicator {
21311
20480
  },
21312
20481
  children: JSON.stringify(context, null, 2)
21313
20482
  }) ]
21314
- }), "development" === process.env.NODE_ENV && errorInfo && jsxs("details", {
20483
+ }), ("undefined" == typeof process || "development" === process.env?.NODE_ENV) && errorInfo && jsxs("details", {
21315
20484
  style: {
21316
20485
  marginTop: "1rem"
21317
20486
  },
@@ -21407,6 +20576,130 @@ class ThemeApplicator {
21407
20576
  }
21408
20577
  }
21409
20578
 
20579
+ /**
20580
+ * Theme Applicator
20581
+ *
20582
+ * Applies theme configurations to the DOM, including CSS variables,
20583
+ * component overrides, typography, spacing, and color palettes.
20584
+ *
20585
+ * Uses the unified theme system for CSS generation and injection.
20586
+ */
20587
+ /**
20588
+ * Theme applicator class for runtime theme application
20589
+ *
20590
+ * Uses the unified theme system for efficient CSS variable generation and injection.
20591
+ */ class ThemeApplicator {
20592
+ constructor(root = document.documentElement) {
20593
+ this.styleId = "atomix-theme-applicator", this.root = root;
20594
+ }
20595
+ /**
20596
+ * Apply a complete theme configuration
20597
+ *
20598
+ * Uses the unified theme system to convert Theme to DesignTokens and inject CSS.
20599
+ * Automatically respects atomix.config.ts when using DesignTokens.
20600
+ */ applyTheme(theme) {
20601
+ // Clear previously applied variables
20602
+ this.clearAppliedVars(),
20603
+ // Check if it's DesignTokens
20604
+ this.isDesignTokens(theme) ?
20605
+ // Direct DesignTokens - use unified theme system (with config support)
20606
+ this.applyDesignTokens(theme) : injectCSS$1(createTheme(theme, {
20607
+ selector: ":root",
20608
+ prefix: "atomix"
20609
+ }), this.styleId),
20610
+ // Apply component overrides (only for Theme objects)
20611
+ !this.isDesignTokens(theme) && theme.components && this.applyComponentOverrides(theme.components);
20612
+ }
20613
+ /**
20614
+ * Apply DesignTokens using unified theme system
20615
+ *
20616
+ * Uses createTheme() which automatically loads from atomix.config.ts
20617
+ * if no tokens are provided, ensuring config is always respected.
20618
+ */ applyDesignTokens(tokens) {
20619
+ // Inject CSS into DOM
20620
+ injectCSS$1(createTheme(tokens, {
20621
+ selector: ":root",
20622
+ prefix: "atomix"
20623
+ }), this.styleId);
20624
+ }
20625
+ /**
20626
+ * Check if object is DesignTokens
20627
+ */ isDesignTokens(obj) {
20628
+ // DesignTokens is a flat object with string keys, no nested structures
20629
+ return null !== obj && "object" == typeof obj && !("palette" in obj) && !("typography" in obj) && !("__isJSTheme" in obj);
20630
+ }
20631
+ /**
20632
+ * Apply global CSS variables (for component overrides)
20633
+ */ applyGlobalCSSVars(vars) {
20634
+ Object.entries(vars).forEach((([key, value]) => {
20635
+ this.root.style.setProperty(key, String(value));
20636
+ }));
20637
+ }
20638
+ /**
20639
+ * Apply component-level overrides
20640
+ */ applyComponentOverrides(overrides) {
20641
+ Object.entries(overrides).forEach((([componentName, override]) => {
20642
+ override && this.applyComponentOverride(componentName, override);
20643
+ }));
20644
+ }
20645
+ /**
20646
+ * Apply override for a specific component
20647
+ */ applyComponentOverride(componentName, override) {
20648
+ const vars = {}, componentKey = componentName.toLowerCase();
20649
+ // Apply component-level CSS variables
20650
+ override.cssVars && Object.entries(override.cssVars).forEach((([key, value]) => {
20651
+ // If key doesn't start with --, add component prefix
20652
+ const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${key}`;
20653
+ vars[varKey] = value;
20654
+ })),
20655
+ // Apply part-specific CSS variables
20656
+ override.parts && Object.entries(override.parts).forEach((([partName, partOverride]) => {
20657
+ partOverride.cssVars && Object.entries(partOverride.cssVars).forEach((([key, value]) => {
20658
+ const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${partName}-${key}`;
20659
+ vars[varKey] = value;
20660
+ }));
20661
+ })),
20662
+ // Apply variant-specific CSS variables
20663
+ override.variants && Object.entries(override.variants).forEach((([variantName, variantOverride]) => {
20664
+ variantOverride.cssVars && Object.entries(variantOverride.cssVars).forEach((([key, value]) => {
20665
+ const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${variantName}-${key}`;
20666
+ vars[varKey] = value;
20667
+ }));
20668
+ })), this.applyGlobalCSSVars(vars);
20669
+ }
20670
+ /**
20671
+ * Clear all applied CSS variables
20672
+ */ clearAppliedVars() {
20673
+ removeCSS(this.styleId);
20674
+ }
20675
+ /**
20676
+ * Remove theme application
20677
+ */ removeTheme() {
20678
+ this.clearAppliedVars(), removeCSS(this.styleId);
20679
+ }
20680
+ /**
20681
+ * Update specific CSS variables without clearing all
20682
+ */ updateCSSVars(vars) {
20683
+ this.applyGlobalCSSVars(vars);
20684
+ }
20685
+ }
20686
+
20687
+ /**
20688
+ * Global theme applicator instance
20689
+ */ let globalApplicator = null;
20690
+
20691
+ /**
20692
+ * Get or create global theme applicator
20693
+ */ function getThemeApplicator() {
20694
+ return globalApplicator || (globalApplicator = new ThemeApplicator), globalApplicator;
20695
+ }
20696
+
20697
+ /**
20698
+ * Apply theme using global applicator
20699
+ */ function applyTheme(theme) {
20700
+ getThemeApplicator().applyTheme(theme);
20701
+ }
20702
+
21410
20703
  const VIEWPORT_PRESETS = {
21411
20704
  mobile: {
21412
20705
  width: 375,
@@ -23633,7 +22926,25 @@ class RTLManager {
23633
22926
  /**
23634
22927
  * Save theme to CSS file
23635
22928
  */ async function saveTheme(css, filePath) {
23636
- await saveCSSFile(css, filePath);
22929
+ await async function(css, filePath) {
22930
+ // Check if in browser environment
22931
+ if ("undefined" != typeof window) throw new Error("saveCSSFile can only be used in Node.js environment. Use injectCSS() for browser environments.");
22932
+ // Dynamic import to avoid bundling Node.js modules in browser builds
22933
+ const fs = await import("fs/promises"), dir = (await import("path")).dirname(filePath);
22934
+ await fs.mkdir(dir, {
22935
+ recursive: !0
22936
+ }),
22937
+ // Write file
22938
+ await fs.writeFile(filePath, css, "utf8");
22939
+ }
22940
+ /**
22941
+ * Theme System Constants
22942
+ *
22943
+ * Centralized constants for the theme system to avoid magic numbers and strings.
22944
+ */
22945
+ /**
22946
+ * Default storage key for theme persistence
22947
+ */ (css, filePath);
23637
22948
  }
23638
22949
 
23639
22950
  const themeImport = Object.freeze( Object.defineProperty({
@@ -23647,13 +22958,16 @@ const themeImport = Object.freeze( Object.defineProperty({
23647
22958
  ThemeLiveEditor: ThemeLiveEditor,
23648
22959
  ThemePreview: ThemePreview,
23649
22960
  ThemeProvider: ThemeProvider,
23650
- ThemeRegistry: ThemeRegistry,
23651
22961
  ThemeValidator: ThemeValidator,
23652
22962
  applyCSSVariables: applyCSSVariables,
22963
+ applyComponentTheme: applyComponentTheme,
23653
22964
  applyTheme: applyTheme,
22965
+ camelToKebab: camelToKebab,
22966
+ clearThemes: clearThemes,
23654
22967
  createDesignTokensFromTheme: createDesignTokensFromTheme,
23655
22968
  createTheme: createTheme,
23656
22969
  createThemeObject: createThemeObject,
22970
+ createThemeRegistry: createThemeRegistry,
23657
22971
  createTokens: createTokens,
23658
22972
  cssVarsToStyle: cssVarsToStyle,
23659
22973
  deepMerge: deepMerge,
@@ -23665,10 +22979,17 @@ const themeImport = Object.freeze( Object.defineProperty({
23665
22979
  generateCSSVariableName: generateCSSVariableName,
23666
22980
  generateCSSVariables: generateCSSVariables$1,
23667
22981
  generateCSSVariablesForSelector: generateCSSVariablesForSelector,
22982
+ generateClassName: generateClassName,
23668
22983
  generateComponentCSSVars: generateComponentCSSVars,
22984
+ getAllThemes: getAllThemes,
23669
22985
  getCSSVariable: getCSSVariable,
22986
+ getComponentThemeValue: getComponentThemeValue,
23670
22987
  getDesignTokensFromTheme: getDesignTokensFromTheme,
22988
+ getTheme: getTheme,
23671
22989
  getThemeApplicator: getThemeApplicator,
22990
+ getThemeCount: getThemeCount,
22991
+ getThemeIds: getThemeIds,
22992
+ hasTheme: hasTheme,
23672
22993
  injectCSS: injectCSS$1,
23673
22994
  injectTheme: injectTheme,
23674
22995
  isCSSInjected: isCSSInjected,
@@ -23680,15 +23001,19 @@ const themeImport = Object.freeze( Object.defineProperty({
23680
23001
  mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
23681
23002
  mergeCSSVars: mergeCSSVars,
23682
23003
  mergeTheme: mergeTheme,
23004
+ normalizeThemeTokens: normalizeThemeTokens,
23005
+ registerTheme: registerTheme,
23683
23006
  removeCSS: removeCSS,
23684
23007
  removeCSSVariables: removeCSSVariables,
23685
23008
  removeTheme: removeTheme,
23686
- saveCSSFile: saveCSSFile,
23687
- saveCSSFileSync: saveCSSFileSync,
23688
23009
  saveTheme: saveTheme,
23010
+ themePropertyToCSSVar: themePropertyToCSSVar,
23689
23011
  themeToDesignTokens: themeToDesignTokens,
23012
+ unregisterTheme: unregisterTheme,
23013
+ useComponentTheme: useComponentTheme,
23690
23014
  useHistory: useHistory,
23691
- useTheme: useTheme
23015
+ useTheme: useTheme,
23016
+ useThemeTokens: useThemeTokens
23692
23017
  }, Symbol.toStringTag, {
23693
23018
  value: "Module"
23694
23019
  })), BUTTON_CSS_VARS = {
@@ -24173,7 +23498,7 @@ function getComponentCSSVars(component) {
24173
23498
  // Default config
24174
23499
  // In browser environments, config loading is not supported
24175
23500
  if ("undefined" != typeof window) {
24176
- if (required) throw new Error("Config loading not supported in browser environment");
23501
+ if (required) throw new Error("loadAtomixConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.");
24177
23502
  return defaultConfig;
24178
23503
  }
24179
23504
  // Try to load config file
@@ -24237,14 +23562,6 @@ function getComponentCSSVars(component) {
24237
23562
  return null;
24238
23563
  }
24239
23564
 
24240
- const loader = Object.freeze( Object.defineProperty({
24241
- __proto__: null,
24242
- loadAtomixConfig: loadAtomixConfig,
24243
- resolveConfigPath: resolveConfigPath
24244
- }, Symbol.toStringTag, {
24245
- value: "Module"
24246
- }));
24247
-
24248
23565
  /**
24249
23566
  * Atomix Configuration System
24250
23567
  *
@@ -24414,5 +23731,5 @@ const atomix = {
24414
23731
  types: types
24415
23732
  };
24416
23733
 
24417
- export { ACCORDION, ATOMIX_GLASS, AVATAR, AVATAR_GROUP, Accordion, AnimatedChart, AreaChart, AtomixGlass, AtomixLogo, Avatar, AvatarGroup, BADGE, BADGE_CSS_VARS, BLOCK, BREADCRUMB, BUTTON, BUTTON_CSS_VARS, BUTTON_GROUP, Badge, BarChart, Block, Breadcrumb, BubbleChart, Button, ButtonGroup, CALLOUT, CARD, CARD_CSS_VARS, CHART, CHECKBOX_CSS_VARS, CLASS_PREFIX, CODE_SNIPPET, COMPONENT_CSS_VARS, COUNTDOWN, Callout, CandlestickChart, Card, Chart, ChartRenderer, Checkbox, ColorModeToggle, Container, Countdown, DATA_TABLE_CLASSES, DATA_TABLE_SELECTORS, DATEPICKER, DEFAULT_ATOMIX_FONTS, DOTS, DROPDOWN, DROPDOWN_CSS_VARS, DataTable, DatePicker, DonutChart, Dropdown, EDGE_PANEL, EdgePanel, ElevationCard, FOOTER, FORM, FORM_GROUP, Footer, FooterLink, FooterSection, FooterSocialLink, Form, FormGroup, FunnelChart, GLASS_CONTAINER, GaugeChart, Grid, GridCol, HERO, HeatmapChart, Hero, INPUT, INPUT_CSS_VARS, Icon, Input, LIST, LIST_GROUP, LineChart, List, ListGroup, MESSAGES, MODAL, MODAL_CSS_VARS, MasonryGrid, MasonryGridItem, MegaMenu, MegaMenuColumn, MegaMenuLink, Menu, MenuDivider, MenuItem, Messages, Modal, MultiAxisChart, NAV, NAVBAR, Nav, NavDropdown, NavItem, Navbar, PAGINATION_DEFAULTS, PHOTOVIEWER, POPOVER, PROGRESS, PROGRESS_CSS_VARS, Pagination, PhotoViewer, PieChart, Popover, ProductReview, Progress, RADIO, RADIO_CSS_VARS, RATING, RIVER, RTLManager, RadarChart, Radio, Rating, River, Row, SECTION_INTRO, SELECT, SIDE_MENU, SIZES, SLIDER, SPINNER, STEPS, ScatterChart, SectionIntro, Select, SideMenu, SideMenuItem, SideMenuList, Slider, Spinner, Steps, TAB, TABS_CSS_VARS, TESTIMONIAL, TEXTAREA, THEME_COLORS, TODO, TOGGLE, TOOLTIP, TOOLTIP_CSS_VARS, Tabs, Testimonial, Textarea, ThemeApplicator, ThemeComparator, ThemeContext, ThemeErrorBoundary, ThemeInspector, ThemeLiveEditor, ThemePreview, ThemeProvider, ThemeRegistry, ThemeValidator, Todo, Toggle, Tooltip, TreemapChart, UPLOAD, Upload, VIDEO_PLAYER, VideoPlayer, WaterfallChart, applyCSSVariables, applyCSSVarsToStyle, applyPartStyles, applyTheme, composables, constants, createCSSVarStyle, createDarkVariant, createDebugAttrs, createDesignTokensFromTheme, createFontPreloadLink, createPartProps, createSlotComponent, createSlotProps, createTheme, createThemeObject, createTokens, cssVarsToStyle, deepMerge, atomix as default, defaultTokens, defineConfig, designTokensToCSSVars, designTokensToTheme, exportTheme, extendTheme, extractComponentName, extractYouTubeId, generateCSSVariableName, generateCSSVariables$1 as generateCSSVariables, generateCSSVariablesForSelector, generateComponentCSSVars, generateFontPreloadTags, generateUUID, getCSSVariable, getComponentCSSVars, getDesignTokensFromTheme, getPartStyles, getThemeApplicator, getThemeMetadata, hasCustomization, importTheme, injectCSS$1 as injectCSS, injectTheme, isCSSInjected, isDesignTokens, isSlot, isThemeObject, isValidCSSVariableName, isYouTubeUrl, loadAtomixConfig, loadThemeFromConfig, loadThemeFromConfigSync, mapSCSSTokensToCSSVars, mergeCSSVars, mergeClassNames, mergeComponentProps, mergePartStyles, mergeSlots, mergeTheme, preloadFonts, quickTheme, removeCSS, removeCSSVariables, removeTheme, renderSlot, resolveConfigPath, saveCSSFile, saveCSSFileSync, saveTheme, sliderConstants, supportsDarkMode, theme, themeToCSS, themeToDesignTokens, types, useAccordion, useAtomixGlass, useBadge, useBarChart, useBlock, useBreadcrumb, useButton, useCard, useChartData, useChartInteraction, useChartScale, useCheckbox, useComponentCustomization, useComponentDefaultProps, useDataTable, useEdgePanel, useForm, useFormGroup, useGlassContainer, useHero, useHistory, useInput, useLineChart, useMergedProps, useModal$1 as useModal, useNav, useNavDropdown, useNavItem, useNavbar, usePagination, usePieChart, useRadio, useRiver, useSelect, useSideMenu, useSideMenuItem, useSlider, useSlot, useSpinner, useTextarea, useTheme, useTodo, utils, validateTheme };
23734
+ export { ACCORDION, ATOMIX_GLASS, AVATAR, AVATAR_GROUP, Accordion, AnimatedChart, AreaChart, AtomixGlass, AtomixLogo, Avatar, AvatarGroup, BADGE, BADGE_CSS_VARS, BLOCK, BREADCRUMB, BUTTON, BUTTON_CSS_VARS, BUTTON_GROUP, Badge, BarChart, Block, Breadcrumb, BubbleChart, Button, ButtonGroup, CALLOUT, CARD, CARD_CSS_VARS, CHART, CHECKBOX_CSS_VARS, CLASS_PREFIX, CODE_SNIPPET, COMPONENT_CSS_VARS, COUNTDOWN, Callout, CandlestickChart, Card, Chart, ChartRenderer, Checkbox, ColorModeToggle, Container, Countdown, DATA_TABLE_CLASSES, DATA_TABLE_SELECTORS, DATEPICKER, DEFAULT_ATOMIX_FONTS, DOTS, DROPDOWN, DROPDOWN_CSS_VARS, DataTable, DatePicker, DonutChart, Dropdown, EDGE_PANEL, EdgePanel, ElevationCard, FOOTER, FORM, FORM_GROUP, Footer, FooterLink, FooterSection, FooterSocialLink, Form, FormGroup, FunnelChart, GLASS_CONTAINER, GaugeChart, Grid, GridCol, HERO, HeatmapChart, Hero, INPUT, INPUT_CSS_VARS, Icon, Input, LIST, LIST_GROUP, LineChart, List, ListGroup, MESSAGES, MODAL, MODAL_CSS_VARS, MasonryGrid, MasonryGridItem, MegaMenu, MegaMenuColumn, MegaMenuLink, Menu, MenuDivider, MenuItem, Messages, Modal, MultiAxisChart, NAV, NAVBAR, Nav, NavDropdown, NavItem, Navbar, PAGINATION_DEFAULTS, PHOTOVIEWER, POPOVER, PROGRESS, PROGRESS_CSS_VARS, Pagination, PhotoViewer, PieChart, Popover, ProductReview, Progress, RADIO, RADIO_CSS_VARS, RATING, RIVER, RTLManager, RadarChart, Radio, Rating, River, Row, SECTION_INTRO, SELECT, SIDE_MENU, SIZES, SLIDER, SPINNER, STEPS, ScatterChart, SectionIntro, Select, SideMenu, SideMenuItem, SideMenuList, Slider, Spinner, Steps, TAB, TABS_CSS_VARS, TESTIMONIAL, TEXTAREA, THEME_COLORS, THEME_NAMING, TODO, TOGGLE, TOOLTIP, TOOLTIP_CSS_VARS, Tabs, Testimonial, Textarea, ThemeApplicator, ThemeComparator, ThemeContext, ThemeErrorBoundary, ThemeInspector, ThemeLiveEditor, ThemePreview, ThemeProvider, ThemeValidator, Todo, Toggle, Tooltip, TreemapChart, UPLOAD, Upload, VIDEO_PLAYER, VideoPlayer, WaterfallChart, applyCSSVariables, applyCSSVarsToStyle, applyComponentTheme, applyPartStyles, applyTheme, camelToKebab, clearThemes, composables, constants, createCSSVarStyle, createDarkVariant, createDebugAttrs, createDesignTokensFromTheme, createFontPreloadLink, createPartProps, createSlotComponent, createSlotProps, createTheme, createThemeObject, createThemeRegistry, createTokens, cssVarsToStyle, deepMerge, atomix as default, defaultTokens, defineConfig, designTokensToCSSVars, designTokensToTheme, exportTheme, extendTheme, extractComponentName, extractYouTubeId, generateCSSVariableName, generateCSSVariables$1 as generateCSSVariables, generateCSSVariablesForSelector, generateClassName, generateComponentCSSVars, generateFontPreloadTags, generateUUID, getAllThemes, getCSSVariable, getComponentCSSVars, getComponentThemeValue, getDesignTokensFromTheme, getPartStyles, getTheme, getThemeApplicator, getThemeCount, getThemeIds, getThemeMetadata, hasCustomization, hasTheme, importTheme, injectCSS$1 as injectCSS, injectTheme, isCSSInjected, isDesignTokens, isSlot, isThemeObject, isValidCSSVariableName, isYouTubeUrl, loadAtomixConfig, loadThemeFromConfig, loadThemeFromConfigSync, mapSCSSTokensToCSSVars, mergeCSSVars, mergeClassNames, mergeComponentProps, mergePartStyles, mergeSlots, mergeTheme, normalizeThemeTokens, preloadFonts, quickTheme, registerTheme, removeCSS, removeCSSVariables, removeTheme, renderSlot, resolveConfigPath, saveTheme, sliderConstants, supportsDarkMode, theme, themePropertyToCSSVar, themeToCSS, themeToDesignTokens, types, unregisterTheme, useAccordion, useAtomixGlass, useBadge, useBarChart, useBlock, useBreadcrumb, useButton, useCard, useChartData, useChartInteraction, useChartScale, useCheckbox, useComponentCustomization, useComponentDefaultProps, useComponentTheme, useDataTable, useEdgePanel, useForm, useFormGroup, useGlassContainer, useHero, useHistory, useInput, useLineChart, useMergedProps, useModal$1 as useModal, useNav, useNavDropdown, useNavItem, useNavbar, usePagination, usePieChart, useRadio, useRiver, useSelect, useSideMenu, useSideMenuItem, useSlider, useSlot, useSpinner, useTextarea, useTheme, useThemeTokens, useTodo, utils, validateTheme };
24418
23735
  //# sourceMappingURL=index.esm.js.map