@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.js CHANGED
@@ -38,6 +38,11 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
38
38
  UTILITY: "u-",
39
39
  LAYOUT: "l-",
40
40
  OBJECT: "o-"
41
+ }, THEME_NAMING = {
42
+ BUTTON_PREFIX: "btn",
43
+ ICON_ELEMENT: "icon",
44
+ LABEL_ELEMENT: "label",
45
+ SPINNER_ELEMENT: "spinner"
41
46
  }, BUTTON = {
42
47
  BASE_CLASS: "c-btn",
43
48
  ICON_CLASS: "c-btn__icon",
@@ -1910,7 +1915,7 @@ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) =>
1910
1915
  timestamp: Date.now()
1911
1916
  }),
1912
1917
  // Development mode: log cache size
1913
- "production" !== process.env.NODE_ENV && sharedShaderCache.size;
1918
+ "undefined" != typeof process && "production" === process.env?.NODE_ENV || sharedShaderCache.size;
1914
1919
  })(cacheKey, url), setShaderMapUrl(url);
1915
1920
  };
1916
1921
  "undefined" != typeof requestIdleCallback ? requestIdleCallback(generate, {
@@ -2223,9 +2228,9 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2223
2228
  childRadius > 0 && childRadius !== CONSTANTS.DEFAULT_CORNER_RADIUS && (extractedRadius = childRadius,
2224
2229
  extractionSource = "React children");
2225
2230
  }
2226
- null !== extractedRadius && extractedRadius > 0 ? setDynamicCornerRadius(extractedRadius) : process.env.NODE_ENV;
2231
+ null !== extractedRadius && extractedRadius > 0 ? setDynamicCornerRadius(extractedRadius) : "undefined" == typeof process || process.env;
2227
2232
  } catch (error) {
2228
- "production" !== process.env.NODE_ENV && debugCornerRadius && console.error("[AtomixGlass] Error extracting corner radius:", error);
2233
+ "undefined" != typeof process && "production" === process.env?.NODE_ENV || !debugCornerRadius || console.error("[AtomixGlass] Error extracting corner radius:", error);
2229
2234
  }
2230
2235
  };
2231
2236
  extractRadius();
@@ -2300,7 +2305,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2300
2305
  // For image backgrounds, assume medium luminance
2301
2306
  totalLuminance += .5, validSamples++, hasValidBackground = !0);
2302
2307
  } catch (styleError) {
2303
- process.env.NODE_ENV;
2308
+ "undefined" == typeof process || process.env;
2304
2309
  }
2305
2310
  // Move to parent element for next iteration
2306
2311
  if (!currentElement) break;
@@ -2339,7 +2344,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2339
2344
  }
2340
2345
  } catch (error) {
2341
2346
  // Enhanced error logging with context
2342
- "development" === process.env.NODE_ENV && console.warn("AtomixGlass: Error detecting background brightness:", error);
2347
+ "undefined" != typeof process && "development" !== process.env?.NODE_ENV || console.warn("AtomixGlass: Error detecting background brightness:", error);
2343
2348
  const result = !1;
2344
2349
  if (element && element.parentElement) {
2345
2350
  const threshold = "object" == typeof overLight && null !== overLight && overLight.threshold || .7;
@@ -2396,7 +2401,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2396
2401
  };
2397
2402
  // Calculate offset relative to this container
2398
2403
  // React 18 automatically batches these updates
2399
- setInternalMouseOffset(newOffset), setInternalGlobalMousePosition(globalPos), "production" !== process.env.NODE_ENV && enablePerformanceMonitoring && performance.now();
2404
+ setInternalMouseOffset(newOffset), setInternalGlobalMousePosition(globalPos), "undefined" != typeof process && "production" === process.env?.NODE_ENV || !enablePerformanceMonitoring || performance.now();
2400
2405
  }), [ mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveDisableEffects, enablePerformanceMonitoring ]);
2401
2406
  // Subscribe to shared mouse tracker
2402
2407
  React.useEffect((() => {
@@ -2536,10 +2541,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2536
2541
  saturationBoost: validatedSaturationBoost + .4 * mouseInfluence
2537
2542
  };
2538
2543
  // Validate and apply object config values with proper clamping
2539
- return process.env.NODE_ENV, finalConfig;
2544
+ return "undefined" == typeof process || process.env, finalConfig;
2540
2545
  }
2541
2546
  // Debug logging for non-object configs
2542
- return process.env.NODE_ENV, baseConfig;
2547
+ return "undefined" == typeof process || process.env, baseConfig;
2543
2548
  }), [ overLight, getEffectiveOverLight, mouseOffset, isHovered, isActive, validateConfigValue, debugOverLight ]), handleMouseEnter = React.useCallback((() => setIsHovered(!0)), []), handleMouseLeave = React.useCallback((() => setIsHovered(!1)), []), handleMouseDown = React.useCallback((() => setIsActive(!0)), []), handleMouseUp = React.useCallback((() => setIsActive(!1)), []), handleKeyDown = React.useCallback((e => {
2544
2549
  !onClick || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), onClick());
2545
2550
  }), [ onClick ]), handleMouseMove = React.useCallback((_e => {}), []);
@@ -2650,7 +2655,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2650
2655
  * <div>Content with debug logging enabled</div>
2651
2656
  * </AtomixGlass>
2652
2657
  */ 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}) {
2653
- const glassRef = React.useRef(null), contentRef = React.useRef(null), opacityCacheRef = React.useRef(null), rgbCacheRef = React.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({
2658
+ const glassRef = React.useRef(null), contentRef = React.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({
2654
2659
  glassRef: glassRef,
2655
2660
  contentRef: contentRef,
2656
2661
  cornerRadius: cornerRadius,
@@ -2667,143 +2672,51 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2667
2672
  debugOverLight: debugOverLight,
2668
2673
  enablePerformanceMonitoring: enablePerformanceMonitoring,
2669
2674
  children: children
2670
- }), isOverLight = overLightConfig.isOverLight, shouldRenderOverLightLayers = enableOverLightLayers && isOverLight;
2671
- // Read CSS custom properties once on mount and cache them
2672
- React.useEffect((() => {
2673
- if ("undefined" != typeof window && glassRef.current) try {
2674
- const computedStyle = window.getComputedStyle(glassRef.current);
2675
- // Cache opacity values
2676
- if (!opacityCacheRef.current) {
2677
- 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) => {
2678
- if (!value) return defaultValue;
2679
- const parsed = parseFloat(value);
2680
- return isNaN(parsed) ? defaultValue : parsed;
2681
- };
2682
- opacityCacheRef.current = {
2683
- opacity50: parseOpacity(opacity50Value, .5),
2684
- opacity40: parseOpacity(opacity40Value, .4),
2685
- opacity80: parseOpacity(opacity80Value, .8),
2686
- opacity0: parseOpacity(opacity0Value, 0)
2687
- };
2688
- }
2689
- // Cache RGB color values from design tokens
2690
- if (!rgbCacheRef.current) {
2691
- // Try to read from design tokens, fallback to defaults
2692
- 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() || "";
2693
- rgbCacheRef.current = {
2694
- whiteRgb: whiteRgbValue || "255, 255, 255",
2695
- // Fallback to white RGB
2696
- blackRgb: blackRgbValue || "0, 0, 0"
2697
- };
2698
- }
2699
- } catch (error) {
2700
- // Fallback to defaults if reading fails
2701
- opacityCacheRef.current || (opacityCacheRef.current = {
2702
- opacity50: .5,
2703
- opacity40: .4,
2704
- opacity80: .8,
2705
- opacity0: 0
2706
- }), rgbCacheRef.current || (rgbCacheRef.current = {
2707
- whiteRgb: "255, 255, 255",
2708
- blackRgb: "0, 0, 0"
2709
- });
2710
- }
2711
- }), []);
2712
- // Calculate base style with transforms (only dynamic values)
2713
- const baseStyle = React.useMemo((() => ({
2675
+ }), isOverLight = overLightConfig.isOverLight, shouldRenderOverLightLayers = enableOverLightLayers && isOverLight, baseStyle = {
2714
2676
  ...style,
2715
2677
  ...0 !== elasticity && !effectiveDisableEffects && {
2716
2678
  transform: transformStyle
2717
2679
  }
2718
- })), [ style, transformStyle, effectiveDisableEffects, elasticity ]), componentClassName = React.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 = React.useMemo((() => ({
2719
- position: baseStylePosition || "absolute",
2720
- top: baseStyleTop || 0,
2721
- left: baseStyleLeft || 0
2722
- })), [ baseStylePosition, baseStyleTop, baseStyleLeft ]), baseStyleWidth = baseStyle.width, baseStyleHeight = baseStyle.height, glassSizeWidth = glassSize.width, glassSizeHeight = glassSize.height, adjustedSize = React.useMemo((() => ({
2723
- width: "fixed" !== baseStylePosition ? "100%" : baseStyleWidth || Math.max(glassSizeWidth, 0),
2724
- height: "fixed" !== baseStylePosition ? "100%" : baseStyleHeight || Math.max(glassSizeHeight, 0)
2725
- })), [ baseStylePosition, baseStyleWidth, baseStyleHeight, glassSizeWidth, glassSizeHeight ]), mouseOffsetX = mouseOffset.x, mouseOffsetY = mouseOffset.y, GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, gradientCalculations = React.useMemo((() => {
2726
- 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;
2727
- return {
2728
- isOverLight: isOverLight,
2729
- mx: mx,
2730
- my: my,
2731
- borderGradientAngle: borderGradientAngle,
2732
- borderStop1: borderStop1,
2733
- borderStop2: borderStop2,
2734
- borderOpacity1: borderOpacity1,
2735
- borderOpacity2: borderOpacity2,
2736
- borderOpacity3: borderOpacity3,
2737
- borderOpacity4: borderOpacity4,
2738
- hover1X: hover1X,
2739
- hover1Y: hover1Y,
2740
- hover2X: hover2X,
2741
- hover2Y: hover2Y,
2742
- hover3X: hover3X,
2743
- hover3Y: hover3Y,
2744
- baseX: baseX,
2745
- baseY: baseY
2746
- };
2747
- }), [ mouseOffsetX, mouseOffsetY, isOverLight ]), overLightOpacity = overLightConfig.opacity, opacityValues = React.useMemo((() => {
2748
- // Use cached values if available, otherwise fallback to defaults
2749
- const opacity50 = opacityCacheRef.current?.opacity50 ?? .5, opacity40 = opacityCacheRef.current?.opacity40 ?? .4, opacity80 = opacityCacheRef.current?.opacity80 ?? .8, opacity0 = opacityCacheRef.current?.opacity0 ?? 0;
2750
- // Dynamic multiplier for overlay
2751
- return {
2752
- hover1: isHovered || isActive ? opacity50 : opacity0,
2753
- hover2: isActive ? opacity50 : opacity0,
2754
- hover3: isHovered ? opacity40 : isActive ? opacity80 : opacity0,
2755
- base: isOverLight ? overLightOpacity || opacity40 : opacity0,
2756
- over: isOverLight ? 1.1 * (overLightOpacity || opacity40) : opacity0
2757
- };
2758
- }), [ 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 = React.useMemo((() => {
2759
- // RGB color values for rgba() functions
2760
- // Note: CSS doesn't support rgba(var(--rgb), opacity) syntax - this is a CSS specification
2761
- // limitation, not a browser support issue. We read RGB values from design tokens at mount
2762
- // and cache them for performance. Falls back to defaults if tokens are not available.
2763
- // Uses design tokens: --atomix-light-rgb / --atomix-white-rgb and --atomix-dark-rgb / --atomix-black-rgb
2764
- const whiteColor = rgbCacheRef.current?.whiteRgb || "255, 255, 255", blackColor = rgbCacheRef.current?.blackRgb || "0, 0, 0";
2765
- return {
2766
- // Standard CSS custom properties for dynamic values
2767
- "--atomix-glass-radius": `${effectiveCornerRadius}px`,
2768
- "--atomix-glass-transform": baseStyleTransform || "none",
2769
- "--atomix-glass-position": positionStylesPosition,
2770
- "--atomix-glass-top": "fixed" !== positionStylesTop ? `${positionStylesTop}px` : "0",
2771
- "--atomix-glass-left": "fixed" !== positionStylesLeft ? `${positionStylesLeft}px` : "0",
2772
- "--atomix-glass-width": "fixed" !== baseStylePosition ? adjustedSizeWidth : `${adjustedSizeWidth}px`,
2773
- "--atomix-glass-height": "fixed" !== baseStylePosition ? adjustedSizeHeight : `${adjustedSizeHeight}px`,
2774
- // Border width: Use spacing token for consistency
2775
- "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
2776
- "--atomix-glass-blend-mode": gradientIsOverLight ? "multiply" : "overlay",
2777
- // Dynamic gradients and backgrounds
2778
- // Note: RGB values use design token-aligned constants (white: 255,255,255; black: 0,0,0)
2779
- "--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%)`,
2780
- "--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%)`,
2781
- "--atomix-glass-hover-1-opacity": opacityValuesHover1,
2782
- "--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}%)`,
2783
- "--atomix-glass-hover-2-opacity": opacityValuesHover2,
2784
- "--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}%)`,
2785
- "--atomix-glass-hover-3-opacity": opacityValuesHover3,
2786
- "--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}%)`,
2787
- "--atomix-glass-base-opacity": opacityValuesBase,
2788
- "--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})`,
2789
- "--atomix-glass-overlay-opacity": opacityValuesOver,
2790
- "--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})`
2791
- };
2792
- }), [
2793
- // Position styles - only specific properties
2794
- positionStylesPosition, positionStylesTop, positionStylesLeft,
2795
- // Adjusted size - only specific properties
2796
- adjustedSizeWidth, adjustedSizeHeight,
2797
- // Base style - only transform property
2798
- baseStyleTransform, baseStylePosition,
2799
- // Other values
2800
- effectiveCornerRadius, effectiveReducedMotion,
2801
- // Gradient calculations - extracted properties
2802
- gradientIsOverLight, gradientMx, gradientMy, gradientBorderGradientAngle, gradientBorderStop1, gradientBorderStop2, gradientBorderOpacity1, gradientBorderOpacity2, gradientBorderOpacity3, gradientBorderOpacity4, gradientHover1X, gradientHover1Y, gradientHover2X, gradientHover2Y, gradientHover3X, gradientHover3Y, gradientBaseX, gradientBaseY,
2803
- // Opacity values - extracted properties
2804
- opacityValuesHover1, opacityValuesHover2, opacityValuesHover3, opacityValuesBase, opacityValuesOver ]);
2805
- // Build className with state modifiers
2806
- return jsxRuntime.jsxs("div", {
2680
+ }, 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 = {
2681
+ position: style.position || "absolute",
2682
+ top: style.top || 0,
2683
+ left: style.left || 0
2684
+ }, adjustedSize = {
2685
+ width: "fixed" !== style.position ? "100%" : style.width ? style.width : Math.max(glassSize.width, 0),
2686
+ height: "fixed" !== style.position ? "100%" : style.height ? style.height : Math.max(glassSize.height, 0)
2687
+ }, 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 = {
2688
+ hover1: isHovered || isActive ? .5 : 0,
2689
+ hover2: isActive ? .5 : 0,
2690
+ hover3: isHovered ? .4 : isActive ? .8 : 0,
2691
+ base: isOverLight ? overLightOpacity || .4 : 0,
2692
+ over: isOverLight ? 1.1 * (overLightOpacity || .4) : 0
2693
+ }, whiteColor = "255, 255, 255", glassVars = {
2694
+ // Standard CSS custom properties for dynamic values
2695
+ "--atomix-glass-radius": `${effectiveCornerRadius}px`,
2696
+ "--atomix-glass-transform": transformStyle || "none",
2697
+ "--atomix-glass-position": positionStyles.position,
2698
+ "--atomix-glass-top": "fixed" !== positionStyles.top ? `${positionStyles.top}px` : "0",
2699
+ "--atomix-glass-left": "fixed" !== positionStyles.left ? `${positionStyles.left}px` : "0",
2700
+ "--atomix-glass-width": "fixed" !== style.position ? adjustedSize.width : `${adjustedSize.width}px`,
2701
+ "--atomix-glass-height": "fixed" !== style.position ? adjustedSize.height : `${adjustedSize.height}px`,
2702
+ // Border width: Use spacing token for consistency
2703
+ "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
2704
+ "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay",
2705
+ // Dynamic gradients and backgrounds
2706
+ "--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%)`,
2707
+ "--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%)`,
2708
+ "--atomix-glass-hover-1-opacity": opacityValues.hover1,
2709
+ "--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}%)`,
2710
+ "--atomix-glass-hover-2-opacity": opacityValues.hover2,
2711
+ "--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}%)`,
2712
+ "--atomix-glass-hover-3-opacity": opacityValues.hover3,
2713
+ "--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}%)`,
2714
+ "--atomix-glass-base-opacity": opacityValues.base,
2715
+ "--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})`,
2716
+ "--atomix-glass-overlay-opacity": opacityValues.over,
2717
+ "--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})`
2718
+ };
2719
+ return jsxRuntime.jsxs("div", {
2807
2720
  className: componentClassName,
2808
2721
  style: glassVars,
2809
2722
  role: role || (onClick ? "button" : void 0),
@@ -3681,11 +3594,103 @@ const Spinner = React.memo((({size: size = "md", variant: variant = "primary",
3681
3594
 
3682
3595
  Spinner.displayName = "Spinner";
3683
3596
 
3597
+ /**
3598
+ * Theme Naming Utility
3599
+ *
3600
+ * Provides consistent naming conventions for CSS classes, CSS variables,
3601
+ * and JavaScript properties throughout the theme system.
3602
+ */
3603
+ class ThemeNaming {
3604
+ /**
3605
+ * Set the global prefix for all theme tokens
3606
+ * @param newPrefix - New prefix to use
3607
+ */
3608
+ static setPrefix(newPrefix) {
3609
+ this.prefix = newPrefix;
3610
+ }
3611
+ /**
3612
+ * Get the current prefix
3613
+ */ static getPrefix() {
3614
+ return this.prefix;
3615
+ }
3616
+ /**
3617
+ * Convert camelCase to kebab-case for CSS variables
3618
+ * @param str - String to convert
3619
+ */ static camelToKebab(str) {
3620
+ return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").toLowerCase();
3621
+ }
3622
+ /**
3623
+ * Convert kebab-case to camelCase for JavaScript properties
3624
+ * @param str - String to convert
3625
+ */ static kebabToCamel(str) {
3626
+ return str.replace(/-([a-z])/g, (g => g[1].toUpperCase()));
3627
+ }
3628
+ /**
3629
+ * Create a CSS variable name
3630
+ * @param token - Token name in camelCase
3631
+ */ static cssVar(token) {
3632
+ return `--${this.prefix}-${this.camelToKebab(token)}`;
3633
+ }
3634
+ /**
3635
+ * Create a BEM CSS class name
3636
+ * @param block - Block name
3637
+ * @param element - Element name (optional)
3638
+ * @param modifier - Modifier name (optional)
3639
+ */ static bemClass(block, element, modifier) {
3640
+ let className = `c-${block}`;
3641
+ return element && (className += `__${element}`), modifier && (className += `--${modifier}`),
3642
+ className;
3643
+ }
3644
+ /**
3645
+ * Create a variant class name
3646
+ * @param component - Component name
3647
+ * @param variant - Variant name
3648
+ */ static variantClass(component, variant) {
3649
+ return `c-${component}--${variant}`;
3650
+ }
3651
+ /**
3652
+ * Create a size class name
3653
+ * @param component - Component name
3654
+ * @param size - Size name
3655
+ */ static sizeClass(component, size) {
3656
+ return `c-${component}--${size}`;
3657
+ }
3658
+ /**
3659
+ * Create a state class name
3660
+ * @param component - Component name
3661
+ * @param state - State name
3662
+ */ static stateClass(component, state) {
3663
+ return `c-${component}--${state}`;
3664
+ }
3665
+ /**
3666
+ * Create a utility class name
3667
+ * @param utility - Utility name
3668
+ */ static utilityClass(utility) {
3669
+ return `u-${utility}`;
3670
+ }
3671
+ /**
3672
+ * Create a layout class name
3673
+ * @param layout - Layout name
3674
+ */ static layoutClass(layout) {
3675
+ return `l-${layout}`;
3676
+ }
3677
+ /**
3678
+ * Create an object class name
3679
+ * @param object - Object name
3680
+ */ static objectClass(object) {
3681
+ return `o-${object}`;
3682
+ }
3683
+ }
3684
+
3685
+ ThemeNaming.prefix = "atomix";
3686
+
3684
3687
  const Button = React__default.default.memo( React.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) => {
3685
- const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement = React.useMemo((() => loading ? null : iconName ? jsxRuntime.jsx(Icon, {
3688
+ const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement = iconName ? jsxRuntime.jsx(Icon, {
3686
3689
  name: iconName,
3687
3690
  size: iconSize
3688
- }) : icon), [ icon, iconName, iconSize, loading ]), {generateButtonClass: generateButtonClass, handleClick: handleClick} = useButton({
3691
+ }) : icon;
3692
+ // Determine if we should render as a link
3693
+ useButton({
3689
3694
  variant: variant,
3690
3695
  size: size,
3691
3696
  disabled: isDisabled,
@@ -3696,20 +3701,8 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
3696
3701
  block: block,
3697
3702
  active: active,
3698
3703
  selected: selected
3699
- }), buttonClass = React.useMemo((() => generateButtonClass({
3700
- variant: variant,
3701
- size: size,
3702
- disabled: isDisabled,
3703
- rounded: rounded,
3704
- iconOnly: iconOnly,
3705
- glass: glass,
3706
- loading: loading,
3707
- fullWidth: fullWidth,
3708
- block: block,
3709
- active: active,
3710
- selected: selected,
3711
- className: className
3712
- })), [ variant, size, isDisabled, rounded, iconOnly, glass, loading, fullWidth, block, active, selected, className, generateButtonClass ]), handleClickEvent = React.useCallback((event => {
3704
+ });
3705
+ 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 = React.useCallback((event => {
3713
3706
  isDisabled ? event.preventDefault() : onClick?.(event);
3714
3707
  }), [ isDisabled, onClick ]), handleMouseEnter = React.useCallback((event => {
3715
3708
  isDisabled || onHover?.(event);
@@ -3717,28 +3710,23 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
3717
3710
  isDisabled || onFocus?.(event);
3718
3711
  }), [ isDisabled, onFocus ]), handleBlurEvent = React.useCallback((event => {
3719
3712
  isDisabled || onBlur?.(event);
3720
- }), [ isDisabled, onBlur ]), buttonText = React.useMemo((() => loading && loadingText ? loadingText : label || children), [ loading, loadingText, label, children ]), spinnerSize = React.useMemo((() => "sm" === size ? "sm" : "lg" === size ? "md" : "sm"), [ size ]), buttonContent = React.useMemo((() => {
3721
- const iconSpan = iconElement && jsxRuntime.jsx("span", {
3722
- className: BUTTON.ICON_CLASS,
3723
- "aria-hidden": "true",
3724
- children: iconElement
3725
- }), spinnerElement = loading && jsxRuntime.jsx("span", {
3726
- className: BUTTON.SPINNER_CLASS,
3713
+ }), [ isDisabled, onBlur ]), buttonText = loading && loadingText ? loadingText : label || children, spinnerSize = "sm" === size ? "sm" : "lg" === size ? "md" : "sm", buttonContent = jsxRuntime.jsxs(jsxRuntime.Fragment, {
3714
+ children: [ loading && jsxRuntime.jsx("span", {
3715
+ className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.SPINNER_ELEMENT),
3727
3716
  "aria-hidden": "true",
3728
3717
  children: jsxRuntime.jsx(Spinner, {
3729
3718
  size: spinnerSize,
3730
3719
  variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
3731
3720
  })
3732
- }), labelElement = !iconOnly && buttonText && jsxRuntime.jsx("span", {
3733
- className: BUTTON.LABEL_CLASS,
3721
+ }), iconElement && !loading && jsxRuntime.jsx("span", {
3722
+ className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.ICON_ELEMENT),
3723
+ "aria-hidden": "true",
3724
+ children: iconElement
3725
+ }), !iconOnly && buttonText && jsxRuntime.jsx("span", {
3726
+ className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.LABEL_ELEMENT),
3734
3727
  children: buttonText
3735
- });
3736
- return "end" === iconPosition ? jsxRuntime.jsxs(jsxRuntime.Fragment, {
3737
- children: [ labelElement, spinnerElement, iconSpan ]
3738
- }) : jsxRuntime.jsxs(jsxRuntime.Fragment, {
3739
- children: [ spinnerElement, iconSpan, labelElement ]
3740
- });
3741
- }), [ iconElement, iconPosition, iconOnly, buttonText, loading, spinnerSize, variant ]), buttonProps = React.useMemo((() => ({
3728
+ }) ]
3729
+ }), buttonProps = {
3742
3730
  ref: ref,
3743
3731
  className: buttonClass,
3744
3732
  type: "button" !== Component || shouldRenderAsLink ? void 0 : type,
@@ -3756,8 +3744,16 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
3756
3744
  tabIndex: void 0 !== tabIndex ? tabIndex : isDisabled ? -1 : 0,
3757
3745
  style: style,
3758
3746
  ...props
3759
- })), [ ref, buttonClass, Component, type, handleClickEvent, handleMouseEnter, handleFocusEvent, handleBlurEvent, isDisabled, loading, ariaLabel, iconOnly, label, children, ariaDescribedBy, ariaExpanded, ariaControls, tabIndex, style, props ]);
3760
- // Determine if we should render as a link
3747
+ }, defaultGlassProps = {
3748
+ displacementScale: 20,
3749
+ blurAmount: 0,
3750
+ saturation: 200,
3751
+ elasticity: 0
3752
+ }, glassProps = !0 === glass ? defaultGlassProps : {
3753
+ ...defaultGlassProps,
3754
+ ...glass
3755
+ };
3756
+ // Handle click with loading check
3761
3757
  // Render as anchor if href is provided
3762
3758
  if (shouldRenderAsLink) {
3763
3759
  const {ref: _, ...buttonPropsWithoutRef} = buttonProps, anchorButtonProps = {
@@ -3777,22 +3773,10 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
3777
3773
  ...linkProps,
3778
3774
  children: buttonContent
3779
3775
  });
3780
- if (glass) {
3781
- const defaultGlassProps = {
3782
- displacementScale: 20,
3783
- blurAmount: 0,
3784
- saturation: 200,
3785
- elasticity: 0
3786
- }, glassProps = !0 === glass ? defaultGlassProps : {
3787
- ...defaultGlassProps,
3788
- ...glass
3789
- };
3790
- return jsxRuntime.jsx(AtomixGlass, {
3791
- ...glassProps,
3792
- children: linkElement
3793
- });
3794
- }
3795
- return linkElement;
3776
+ return glass ? jsxRuntime.jsx(AtomixGlass, {
3777
+ ...glassProps,
3778
+ children: linkElement
3779
+ }) : linkElement;
3796
3780
  }
3797
3781
  // Fallback to regular anchor tag
3798
3782
  const anchorElement = jsxRuntime.jsx("a", {
@@ -3803,46 +3787,20 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
3803
3787
  rel: "_blank" === target ? "noopener noreferrer" : void 0,
3804
3788
  children: buttonContent
3805
3789
  });
3806
- if (glass) {
3807
- const defaultGlassProps = {
3808
- displacementScale: 20,
3809
- blurAmount: 0,
3810
- saturation: 200,
3811
- elasticity: 0
3812
- }, glassProps = !0 === glass ? defaultGlassProps : {
3813
- ...defaultGlassProps,
3814
- ...glass
3815
- };
3816
- return jsxRuntime.jsx(AtomixGlass, {
3817
- ...glassProps,
3818
- children: anchorElement
3819
- });
3820
- }
3821
- return anchorElement;
3822
- }
3823
- // Default button rendering
3824
- if (glass) {
3825
- const defaultGlassProps = {
3826
- displacementScale: 20,
3827
- blurAmount: 0,
3828
- saturation: 200,
3829
- elasticity: 0
3830
- }, glassProps = !0 === glass ? defaultGlassProps : {
3831
- ...defaultGlassProps,
3832
- ...glass
3833
- };
3834
- return jsxRuntime.jsx(AtomixGlass, {
3790
+ return glass ? jsxRuntime.jsx(AtomixGlass, {
3835
3791
  ...glassProps,
3836
- children: jsxRuntime.jsx(Component, {
3837
- ...buttonProps,
3838
- children: buttonContent
3839
- })
3840
- });
3792
+ children: anchorElement
3793
+ }) : anchorElement;
3841
3794
  }
3842
- return jsxRuntime.jsx(Component, {
3795
+ // Default button rendering
3796
+ const buttonElement = jsxRuntime.jsx(Component, {
3843
3797
  ...buttonProps,
3844
3798
  children: buttonContent
3845
3799
  });
3800
+ return glass ? jsxRuntime.jsx(AtomixGlass, {
3801
+ ...glassProps,
3802
+ children: buttonElement
3803
+ }) : buttonElement;
3846
3804
  })));
3847
3805
 
3848
3806
  Button.displayName = "Button";
@@ -11163,62 +11121,6 @@ function useHero(initialProps) {
11163
11121
  };
11164
11122
  }
11165
11123
 
11166
- /**
11167
- * CSS Variable Mapper
11168
- *
11169
- * Utilities for generating and managing CSS custom properties from SCSS tokens
11170
- * and component configurations.
11171
- */
11172
- /**
11173
- * Generate CSS variable name from parts
11174
- *
11175
- * @example
11176
- * generateCSSVariableName('button', 'bg', { prefix: 'atomix' })
11177
- * // Returns: '--atomix-button-bg'
11178
- */ function generateCSSVariableName(component, property, options = {}) {
11179
- const {prefix: prefix = "atomix", separator: separator = "-", includeComponent: includeComponent = !0} = options, parts = [ prefix ];
11180
- return includeComponent && parts.push(component), parts.push(property), `--${parts.join(separator)}`;
11181
- }
11182
-
11183
- /**
11184
- * Generate CSS variables object from configuration
11185
- *
11186
- * @example
11187
- * const vars = generateComponentCSSVars({
11188
- * component: 'button',
11189
- * properties: { bg: '#000', color: '#fff' }
11190
- * })
11191
- * // Returns: { '--atomix-button-bg': '#000', '--atomix-button-color': '#fff' }
11192
- */ function generateComponentCSSVars(config, options = {}) {
11193
- const vars = {}, {component: component, properties: properties, parts: parts, states: states, variants: variants} = config;
11194
- // Base properties
11195
- return Object.entries(properties).forEach((([key, value]) => {
11196
- const varName = generateCSSVariableName(component, key, options);
11197
- vars[varName] = String(value);
11198
- })),
11199
- // Part properties
11200
- parts && Object.entries(parts).forEach((([partName, partProps]) => {
11201
- Object.entries(partProps).forEach((([key, value]) => {
11202
- const varName = generateCSSVariableName(component, `${partName}-${key}`, options);
11203
- vars[varName] = String(value);
11204
- }));
11205
- })),
11206
- // State properties
11207
- states && Object.entries(states).forEach((([stateName, stateProps]) => {
11208
- Object.entries(stateProps).forEach((([key, value]) => {
11209
- const varName = generateCSSVariableName(component, `${stateName}-${key}`, options);
11210
- vars[varName] = String(value);
11211
- }));
11212
- })),
11213
- // Variant properties
11214
- variants && Object.entries(variants).forEach((([variantName, variantProps]) => {
11215
- Object.entries(variantProps).forEach((([key, value]) => {
11216
- const varName = generateCSSVariableName(component, `${variantName}-${key}`, options);
11217
- vars[varName] = String(value);
11218
- }));
11219
- })), vars;
11220
- }
11221
-
11222
11124
  /**
11223
11125
  * Map SCSS tokens to CSS custom properties
11224
11126
  *
@@ -11381,7 +11283,7 @@ function mergeComponentProps(baseProps, customization) {
11381
11283
  /**
11382
11284
  * Create data attributes for debugging
11383
11285
  */ function createDebugAttrs(componentName, variant) {
11384
- return "development" !== process.env.NODE_ENV ? {} : {
11286
+ return "undefined" == typeof process || "development" !== process.env?.NODE_ENV ? {} : {
11385
11287
  "data-component": componentName,
11386
11288
  ...variant && {
11387
11289
  "data-variant": variant
@@ -18251,6 +18153,7 @@ var components = Object.freeze({
18251
18153
  TESTIMONIAL: TESTIMONIAL,
18252
18154
  TEXTAREA: TEXTAREA,
18253
18155
  THEME_COLORS: THEME_COLORS,
18156
+ THEME_NAMING: THEME_NAMING,
18254
18157
  TODO: TODO,
18255
18158
  TOGGLE: TOGGLE,
18256
18159
  TOOLTIP: TOOLTIP,
@@ -18734,13 +18637,6 @@ const defaultTokens = {
18734
18637
  * @param coefficient - Amount to emphasize (0-1), default 0.15
18735
18638
  * @returns Emphasized hex color
18736
18639
  */
18737
- /**
18738
- * Check if a theme is a JS theme (created with createTheme)
18739
- */
18740
- function isJSTheme(theme) {
18741
- return theme && "object" == typeof theme && !0 === theme.__isJSTheme;
18742
- }
18743
-
18744
18640
  /**
18745
18641
  * Theme Adapter
18746
18642
  *
@@ -18760,7 +18656,8 @@ function isJSTheme(theme) {
18760
18656
  * const tokens = themeToDesignTokens(theme);
18761
18657
  * // Returns: { 'primary': '#7c3aed', ... }
18762
18658
  * ```
18763
- */ function themeToDesignTokens(theme) {
18659
+ */
18660
+ function themeToDesignTokens(theme) {
18764
18661
  const tokens = {};
18765
18662
  // Convert palette colors
18766
18663
  if (theme.palette) {
@@ -18900,160 +18797,10 @@ function isJSTheme(theme) {
18900
18797
  };
18901
18798
  }
18902
18799
 
18903
- /**
18904
- * Config Loader
18905
- *
18906
- * Load design tokens from atomix.config.ts and convert to flat token format.
18907
- */
18908
- /**
18909
- * Convert nested config tokens to flat DesignTokens format
18910
- *
18911
- * Handles conversion from atomix.config.ts structure to flat tokens.
18912
- * Maps config structure to actual DesignTokens key names.
18913
- */ function flattenConfigTokens(tokens, prefix = "atomix") {
18914
- const flat = {};
18915
- // Colors
18916
- return tokens.colors && Object.entries(tokens.colors).forEach((([key, value]) => {
18917
- var _context;
18918
- // Simple color: 'primary': '#7AFFD7'
18919
- // Map directly to DesignTokens keys (e.g., 'primary', 'secondary', 'error')
18920
- // Only map if it's a valid semantic color key
18921
- 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)
18922
- // Color scale or palette
18923
- if ("main" in value) {
18924
- var _context2;
18925
- // PaletteColorOptions: { main: '#7AFFD7', light?: '#...', dark?: '#...' }
18926
- const palette = value, baseKey = key;
18927
- // Map main to base color (e.g., primary, secondary, error)
18928
- _includesInstanceProperty(_context2 = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ]).call(_context2, key) && (flat[baseKey] = palette.main,
18929
- // Map light/dark to appropriate scale values
18930
- // light typically maps to step 3, dark to step 9
18931
- palette.light && (flat[`${key}-3`] = palette.light), palette.dark && (flat[`${key}-9`] = palette.dark));
18932
- } else
18933
- // Color scale: { 1: '#fff', 2: '#eee', ..., 6: '#main', ... }
18934
- // Or full scale: { 1: '#...', 2: '#...', ..., 10: '#...' }
18935
- Object.entries(value).forEach((([scaleKey, scaleValue]) => {
18936
- if ("string" == typeof scaleValue)
18937
- // Map scale keys to DesignTokens format
18938
- if ("main" === scaleKey || "6" === scaleKey) {
18939
- var _context3, _context4;
18940
- // Main color maps to base key (e.g., 'primary')
18941
- _includesInstanceProperty(_context3 = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ]).call(_context3, key) && (flat[key] = scaleValue),
18942
- // Also map to step 6 if it's a scale color
18943
- _includesInstanceProperty(_context4 = [ "primary", "red", "green", "blue", "yellow", "gray" ]).call(_context4, key) && (flat[`${key}-6`] = scaleValue);
18944
- } else {
18945
- // Map scale numbers (1-10) to DesignTokens format
18946
- const scaleNum = parseInt(scaleKey, 10);
18947
- !isNaN(scaleNum) && scaleNum >= 1 && scaleNum <= 10 && (flat[`${key}-${scaleKey}`] = scaleValue);
18948
- }
18949
- }));
18950
- })),
18951
- // Spacing
18952
- tokens.spacing && Object.entries(tokens.spacing).forEach((([key, value]) => {
18953
- flat[`spacing-${key}`] = String(value);
18954
- })),
18955
- // Border Radius
18956
- tokens.borderRadius && Object.entries(tokens.borderRadius).forEach((([key, value]) => {
18957
- // Map to DesignTokens format
18958
- "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);
18959
- })),
18960
- // Typography
18961
- tokens.typography && (
18962
- // Font Families
18963
- tokens.typography.fontFamilies && Object.entries(tokens.typography.fontFamilies).forEach((([key, value]) => {
18964
- // Map to DesignTokens format
18965
- "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);
18966
- })),
18967
- // Font Sizes
18968
- tokens.typography.fontSizes && Object.entries(tokens.typography.fontSizes).forEach((([key, value]) => {
18969
- flat[`font-size-${key}`] = String(value);
18970
- })),
18971
- // Font Weights
18972
- tokens.typography.fontWeights && Object.entries(tokens.typography.fontWeights).forEach((([key, value]) => {
18973
- flat[`font-weight-${key}`] = String(value);
18974
- })),
18975
- // Line Heights
18976
- tokens.typography.lineHeights && Object.entries(tokens.typography.lineHeights).forEach((([key, value]) => {
18977
- "base" === key || "default" === key ? flat["line-height-base"] = String(value) : flat[`line-height-${key}`] = String(value);
18978
- }))),
18979
- // Shadows
18980
- tokens.shadows && Object.entries(tokens.shadows).forEach((([key, value]) => {
18981
- flat[`shadow-${key}`] = String(value);
18982
- })),
18983
- // Z-Index
18984
- tokens.zIndex && Object.entries(tokens.zIndex).forEach((([key, value]) => {
18985
- flat[`z-index-${key}`] = String(value);
18986
- })),
18987
- // Transitions
18988
- tokens.transitions && tokens.transitions.durations && Object.entries(tokens.transitions.durations).forEach((([key, value]) => {
18989
- flat[`transition-${key}`] = String(value);
18990
- })), flat;
18991
- }
18992
-
18993
- /**
18994
- * Load theme tokens from atomix.config.ts
18995
- *
18996
- * Loads atomix.config.ts and extracts theme tokens.
18997
- * Config file is required - throws error if not found.
18998
- *
18999
- * @param configPath - Optional custom config path (default: 'atomix.config.ts')
19000
- * @returns Partial DesignTokens from config
19001
- * @throws Error if config file is not found or cannot be loaded
19002
- *
19003
- * @example
19004
- * ```typescript
19005
- * const tokens = await loadThemeFromConfig();
19006
- * const css = createTheme(tokens);
19007
- * injectTheme(css);
19008
- * ```
19009
- */ async function loadThemeFromConfig(configPath = "atomix.config.ts") {
19010
- // In browser environments, config loading is not supported
19011
- if ("undefined" != typeof window) throw new Error("loadThemeFromConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.");
19012
- // Load config using the existing loader (required)
19013
- const {loadAtomixConfig: loadAtomixConfig} = await Promise.resolve().then((function() {
19014
- return loader;
19015
- })), config = loadAtomixConfig({
19016
- configPath: configPath,
19017
- required: !0
19018
- });
19019
- if (!config || !config.theme) throw new Error(`Config file ${configPath} does not contain theme configuration.`);
19020
- // Extract tokens from config
19021
- const tokens = config.theme.tokens || config.theme.extend || {};
19022
- if (0 === Object.keys(tokens).length) throw new Error(`Config file ${configPath} has empty theme configuration.`);
19023
- // Convert nested structure to flat tokens
19024
- return flattenConfigTokens(tokens, config.prefix || "atomix");
19025
- }
19026
-
19027
- /**
19028
- * Load theme tokens from atomix.config.ts (synchronous version)
19029
- *
19030
- * Synchronous version that uses require() instead of dynamic import.
19031
- * Only works in Node.js environment.
19032
- * Config file is required - throws error if not found.
19033
- *
19034
- * @param configPath - Optional custom config path
19035
- * @returns Partial DesignTokens from config
19036
- * @throws Error if config file is not found or cannot be loaded
19037
- */ function loadThemeFromConfigSync(configPath = "atomix.config.ts") {
19038
- // In browser environments, config loading is not supported
19039
- if ("undefined" != typeof window) throw new Error("loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.");
19040
- // eslint-disable-next-line @typescript-eslint/no-require-imports
19041
- const {loadAtomixConfig: loadAtomixConfig} = require("../../config/loader"), config = loadAtomixConfig({
19042
- configPath: configPath,
19043
- required: !0
19044
- });
19045
- if (!config || !config.theme) throw new Error(`Config file ${configPath} does not contain theme configuration.`);
19046
- // Extract tokens from config
19047
- const tokens = config.theme.tokens || config.theme.extend || {};
19048
- if (0 === Object.keys(tokens).length) throw new Error(`Config file ${configPath} has empty theme configuration.`);
19049
- // Convert nested structure to flat tokens
19050
- return flattenConfigTokens(tokens, config.prefix || "atomix");
19051
- }
19052
-
19053
18800
  /**
19054
18801
  * Core Theme Functions
19055
18802
  *
19056
- * Unified theme system that handles both DesignTokens and Theme objects.
18803
+ * Simplified theme system that handles both DesignTokens and Theme objects.
19057
18804
  * Config-first approach: loads from atomix.config.ts when no input is provided.
19058
18805
  * Config file is required for automatic loading.
19059
18806
  */
@@ -19087,43 +18834,68 @@ function isJSTheme(theme) {
19087
18834
  * const css = createTheme(undefined, { prefix: 'myapp', selector: ':root' });
19088
18835
  * ```
19089
18836
  */ function createTheme(input, options) {
19090
- let tokens, configPrefix;
19091
- // If no input provided, load from config (required)
18837
+ // Determine tokens based on input
18838
+ let tokens;
19092
18839
  if (input)
19093
- // Convert Theme to DesignTokens
19094
- tokens = !0 === input.__isJSTheme || input.palette && input.typography ? themeToDesignTokens(input) : input; else {
19095
- const configTokens = loadThemeFromConfigSync();
19096
- // Get prefix from config
19097
- try {
19098
- // eslint-disable-next-line @typescript-eslint/no-require-imports
19099
- const {loadAtomixConfig: loadAtomixConfig} = require("../../config/loader"), config = loadAtomixConfig({
19100
- configPath: "atomix.config.ts",
19101
- required: !0
19102
- });
19103
- configPrefix = config?.prefix;
18840
+ // Use DesignTokens directly
18841
+ tokens =
18842
+ // Helper functions to simplify main function
18843
+ function(input) {
18844
+ return !0 === input?.__isJSTheme || input?.palette && input?.typography;
18845
+ }
18846
+ /**
18847
+ * Theme Composition Utilities
18848
+ *
18849
+ * Simplified utilities for composing, merging, and extending themes.
18850
+ */
18851
+ // ============================================================================
18852
+ // Deep Merge Utility
18853
+ // ============================================================================
18854
+ /**
18855
+ * Check if value is an object
18856
+ */ (input) ? themeToDesignTokens(input) : input;
18857
+ // Merge with defaults and generate CSS
18858
+ else {
18859
+ // Check if we're in a browser environment
18860
+ 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.");
18861
+ // Load from config when no input provided
18862
+ // Using dynamic import in a way that's more compatible with bundlers
18863
+ let loadThemeFromConfigSync, loadAtomixConfig;
18864
+ try {
18865
+ // Use dynamic require but only in Node.js environments
18866
+ // This approach allows bundlers to properly handle external dependencies
18867
+ const configLoaderModule = require("../config/configLoader"), loaderModule = require("../../config/loader");
18868
+ // Get prefix from config if needed
18869
+ if (loadThemeFromConfigSync = configLoaderModule.loadThemeFromConfigSync, loadAtomixConfig = loaderModule.loadAtomixConfig,
18870
+ tokens = loadThemeFromConfigSync(), !options?.prefix) try {
18871
+ const config = loadAtomixConfig({
18872
+ configPath: "atomix.config.ts",
18873
+ required: !1
18874
+ });
18875
+ options = {
18876
+ ...options,
18877
+ prefix: config?.prefix || "atomix"
18878
+ };
18879
+ } catch (error) {
18880
+ // If config loading fails, use default prefix
18881
+ options = {
18882
+ ...options,
18883
+ prefix: "atomix"
18884
+ };
18885
+ }
19104
18886
  } catch (error) {
19105
- // Prefix loading failed, but tokens were loaded, so continue
18887
+ throw new Error("createTheme: No input provided and config loading is not available in this environment. Please provide tokens explicitly.");
19106
18888
  }
19107
- tokens = configTokens;
19108
18889
  }
19109
- // Merge with defaults and generate CSS
19110
- return generateCSSVariables$1(createTokens(tokens), {
18890
+ const allTokens = createTokens(tokens), prefix = options?.prefix ?? "atomix";
18891
+ // Get prefix from options or use default
18892
+ return generateCSSVariables$1(allTokens, {
19111
18893
  ...options,
19112
- prefix: options?.prefix ?? configPrefix ?? "atomix"
18894
+ prefix: prefix
19113
18895
  });
19114
18896
  }
19115
18897
 
19116
- /**
19117
- * Theme Composition Utilities
19118
- *
19119
- * Utilities for composing, merging, and extending themes.
19120
- */
19121
- // ============================================================================
19122
- // Deep Merge Utility
19123
- // ============================================================================
19124
- /**
19125
- * Check if value is an object
19126
- */ function isObject(item) {
18898
+ function isObject(item) {
19127
18899
  return item && "object" == typeof item && !Array.isArray(item) && "function" != typeof item;
19128
18900
  }
19129
18901
 
@@ -19182,65 +18954,14 @@ function isJSTheme(theme) {
19182
18954
  * });
19183
18955
  * ```
19184
18956
  */ function extendTheme(baseTheme, extension) {
19185
- // If baseTheme is a complete Theme, extract the options
19186
- const baseOptions = baseTheme.__isJSTheme ?
19187
- /**
19188
- * Extract theme options from a complete Theme object
19189
- */
19190
- function(theme) {
19191
- return {
19192
- name: theme.name,
19193
- class: theme.class,
19194
- description: theme.description,
19195
- author: theme.author,
19196
- version: theme.version,
19197
- tags: theme.tags,
19198
- supportsDarkMode: theme.supportsDarkMode,
19199
- status: theme.status,
19200
- a11y: theme.a11y,
19201
- color: theme.color,
19202
- features: theme.features,
19203
- dependencies: theme.dependencies,
19204
- palette: {
19205
- primary: theme.palette.primary,
19206
- secondary: theme.palette.secondary,
19207
- error: theme.palette.error,
19208
- warning: theme.palette.warning,
19209
- info: theme.palette.info,
19210
- success: theme.palette.success,
19211
- background: theme.palette.background,
19212
- text: theme.palette.text
19213
- },
19214
- typography: {
19215
- fontFamily: theme.typography.fontFamily,
19216
- fontSize: theme.typography.fontSize,
19217
- fontWeightLight: theme.typography.fontWeightLight,
19218
- fontWeightRegular: theme.typography.fontWeightRegular,
19219
- fontWeightMedium: theme.typography.fontWeightMedium,
19220
- fontWeightSemiBold: theme.typography.fontWeightSemiBold,
19221
- fontWeightBold: theme.typography.fontWeightBold,
19222
- h1: theme.typography.h1,
19223
- h2: theme.typography.h2,
19224
- h3: theme.typography.h3,
19225
- h4: theme.typography.h4,
19226
- h5: theme.typography.h5,
19227
- h6: theme.typography.h6,
19228
- body1: theme.typography.body1,
19229
- body2: theme.typography.body2
19230
- },
19231
- shadows: theme.shadows,
19232
- transitions: theme.transitions,
19233
- zIndex: theme.zIndex,
19234
- custom: theme.custom
19235
- };
19236
- }
19237
- // ============================================================================
19238
- // Default Theme Values
19239
- // ============================================================================
19240
- (baseTheme) : baseTheme;
19241
- return createThemeObject(mergeTheme(baseOptions, extension));
18957
+ return createThemeObject(mergeTheme(baseTheme.__isJSTheme ? {
18958
+ ...baseTheme
18959
+ } : baseTheme, extension));
19242
18960
  }
19243
18961
 
18962
+ // ============================================================================
18963
+ // Default Theme Values
18964
+ // ============================================================================
19244
18965
  const DEFAULT_PALETTE = {
19245
18966
  primary: {
19246
18967
  main: "#7c3aed",
@@ -19502,7 +19223,10 @@ function createThemeObject(...options) {
19502
19223
  "number" == typeof spacingInput ? (...values) => 0 === values.length ? "0px" : values.map((value => value * spacingInput + "px")).join(" ") :
19503
19224
  // If it's an array, use it as a scale
19504
19225
  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(" ");
19505
- }(mergedOptions.spacing), breakpoints = function(breakpointsInput) {
19226
+ }
19227
+ /**
19228
+ * Check if a theme is a JS theme (created with createTheme)
19229
+ */ (mergedOptions.spacing), breakpoints = function(breakpointsInput) {
19506
19230
  const values = {
19507
19231
  xs: 0,
19508
19232
  sm: 576,
@@ -19562,694 +19286,71 @@ function createThemeObject(...options) {
19562
19286
  }
19563
19287
 
19564
19288
  /**
19565
- * Theme Configuration Validator
19566
- *
19567
- * Validates theme configuration structure and values
19568
- */
19289
+ * Create a new theme registry
19290
+ */ function createThemeRegistry() {
19291
+ return {};
19292
+ }
19293
+
19569
19294
  /**
19570
- * Validate theme configuration
19571
- *
19572
- * @param config - Configuration to validate
19573
- * @returns Validation result with errors and warnings
19574
- */
19295
+ * Register a theme
19296
+ * @param registry - Theme registry object
19297
+ * @param id - Theme identifier
19298
+ * @param metadata - Theme metadata
19299
+ */ function registerTheme(registry, id, metadata) {
19300
+ registry[id] = metadata;
19301
+ }
19302
+
19575
19303
  /**
19576
- * Validate CSS theme
19577
- */
19578
- function validateCSSTheme(themeId, theme) {
19579
- const errors = [];
19580
- // CSS themes don't require createTheme function
19581
- // But can have optional cssPath
19582
- return {
19583
- valid: 0 === errors.length,
19584
- errors: errors,
19585
- warnings: []
19586
- };
19304
+ * Unregister a theme
19305
+ * @param registry - Theme registry object
19306
+ * @param id - Theme identifier
19307
+ */ function unregisterTheme(registry, id) {
19308
+ const exists = id in registry;
19309
+ return delete registry[id], exists;
19587
19310
  }
19588
19311
 
19589
19312
  /**
19590
- * Validate JS theme
19591
- */ function validateJSTheme(themeId, theme) {
19592
- const errors = [];
19593
- // JS themes must have createTheme function
19594
- return theme.createTheme && "function" == typeof theme.createTheme || errors.push(`JS theme "${themeId}" must have a "createTheme" function`),
19595
- {
19596
- valid: 0 === errors.length,
19597
- errors: errors,
19598
- warnings: []
19599
- };
19313
+ * Check if a theme is registered
19314
+ * @param registry - Theme registry object
19315
+ * @param id - Theme identifier
19316
+ */ function hasTheme(registry, id) {
19317
+ return id in registry;
19600
19318
  }
19601
19319
 
19602
19320
  /**
19603
- * Validate build configuration
19604
- */
19321
+ * Get theme metadata
19322
+ * @param registry - Theme registry object
19323
+ * @param id - Theme identifier
19324
+ */ function getTheme(registry, id) {
19325
+ return registry[id];
19326
+ }
19327
+
19605
19328
  /**
19606
- * Theme System Error Handling
19607
- *
19608
- * Centralized error handling for the Atomix theme system.
19609
- * Provides custom error classes and logging utilities.
19610
- */
19611
- /**
19612
- * Theme error codes
19613
- */
19614
- var ThemeErrorCode, LogLevel;
19615
-
19616
- !function(ThemeErrorCode) {
19617
- /** Theme not found in registry */
19618
- ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
19619
- /** Theme failed to load */
19620
- ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
19621
- /** Theme validation failed */
19622
- ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
19623
- /** Configuration loading failed */
19624
- ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
19625
- /** Configuration validation failed */
19626
- ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
19627
- /** Circular dependency detected */
19628
- ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
19629
- /** Missing dependency */
19630
- ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
19631
- /** Storage operation failed */
19632
- ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
19633
- /** Invalid theme name */
19634
- ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
19635
- /** CSS injection failed */
19636
- ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
19637
- /** Unknown error */
19638
- ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
19639
- }(ThemeErrorCode || (ThemeErrorCode = {}));
19640
-
19641
- /**
19642
- * Custom error class for theme-related errors
19643
- */
19644
- class ThemeError extends Error {
19645
- constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
19646
- super(message), this.name = "ThemeError", this.code = code, this.context = context,
19647
- this.timestamp = Date.now(),
19648
- // Maintains proper stack trace for where our error was thrown (only available on V8)
19649
- Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
19650
- }
19651
- /**
19652
- * Convert error to JSON for logging
19653
- */ toJSON() {
19654
- return {
19655
- name: this.name,
19656
- message: this.message,
19657
- code: this.code,
19658
- context: this.context,
19659
- timestamp: this.timestamp,
19660
- stack: this.stack
19661
- };
19662
- }
19329
+ * Get all registered theme metadata
19330
+ * @param registry - Theme registry object
19331
+ */ function getAllThemes(registry) {
19332
+ return Object.values(registry);
19663
19333
  }
19664
19334
 
19665
19335
  /**
19666
- * Log level
19667
- */ !function(LogLevel) {
19668
- LogLevel[LogLevel.ERROR = 0] = "ERROR", LogLevel[LogLevel.WARN = 1] = "WARN", LogLevel[LogLevel.INFO = 2] = "INFO",
19669
- LogLevel[LogLevel.DEBUG = 3] = "DEBUG";
19670
- }(LogLevel || (LogLevel = {}));
19671
-
19672
- /**
19673
- * Theme Logger
19674
- *
19675
- * Centralized logging for the theme system.
19676
- * Replaces console statements with structured logging.
19677
- */
19678
- class ThemeLogger {
19679
- constructor(config = {}) {
19680
- this.config = {
19681
- level: config.level ?? ("production" === process.env.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
19682
- enableConsole: config.enableConsole ?? !0,
19683
- onError: config.onError,
19684
- onWarn: config.onWarn,
19685
- onInfo: config.onInfo,
19686
- onDebug: config.onDebug
19687
- };
19688
- }
19689
- /**
19690
- * Log an error
19691
- */ error(message, error, context) {
19692
- if (this.config.level < LogLevel.ERROR) return;
19693
- const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
19694
- this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
19695
- error: errorObj,
19696
- context: {
19697
- ...context,
19698
- ...themeError.context
19699
- },
19700
- code: themeError.code
19701
- }), this.config.onError?.(themeError, context);
19702
- }
19703
- /**
19704
- * Log a warning
19705
- */ warn(message, context) {
19706
- this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
19707
- this.config.onWarn?.(message, context));
19708
- }
19709
- /**
19710
- * Log an info message
19711
- */ info(message, context) {
19712
- this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
19713
- this.config.onInfo?.(message, context));
19714
- }
19715
- /**
19716
- * Log a debug message
19717
- */ debug(message, context) {
19718
- this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
19719
- }
19336
+ * Get all registered theme IDs
19337
+ * @param registry - Theme registry object
19338
+ */ function getThemeIds(registry) {
19339
+ return Object.keys(registry);
19720
19340
  }
19721
19341
 
19722
19342
  /**
19723
- * Default logger instance
19724
- */ let defaultLogger = null;
19725
-
19726
- /**
19727
- * Get or create default logger
19728
- */ function getLogger() {
19729
- return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
19343
+ * Clear all registered themes
19344
+ * @param registry - Theme registry object
19345
+ */ function clearThemes(registry) {
19346
+ Object.keys(registry).forEach((key => delete registry[key]));
19730
19347
  }
19731
19348
 
19732
19349
  /**
19733
- * Theme System Constants
19734
- *
19735
- * Centralized constants for the theme system to avoid magic numbers and strings.
19736
- */
19737
- /**
19738
- * Default storage key for theme persistence
19739
- */ const DEFAULT_ATOMIX_CONFIG_PATH = "atomix.config.ts";
19740
-
19741
- /**
19742
- * Default data attribute name for theme
19743
- */ process.env.NODE_ENV;
19744
-
19745
- /**
19746
- * Integration default class names
19747
- */
19748
- const DEFAULT_INTEGRATION_CLASS_NAMES = {
19749
- theme: "data-theme",
19750
- colorMode: "data-atomix-color-mode"
19751
- }, DEFAULT_INTEGRATION_CSS_VARIABLES = {
19752
- colorMode: "--storybook-color-mode"
19753
- }, DEFAULT_SASS_CONFIG = {
19754
- style: "expanded",
19755
- sourceMap: !0,
19756
- loadPaths: [ "src" ]
19757
- };
19758
-
19759
- /**
19760
- * Integration default CSS variables
19761
- */
19762
- /**
19763
- * Theme Configuration Loader
19764
- *
19765
- * Loads and validates the theme configuration from atomix.config.ts
19766
- */
19767
- /**
19768
- * Cache for loaded configuration
19769
- */
19770
- let cachedConfig = null;
19771
-
19772
- /**
19773
- * Logger instance
19774
- */ const logger = getLogger();
19775
-
19776
- /**
19777
- * Load theme configuration from atomix.config.ts
19778
- *
19779
- * @param options - Loader options
19780
- * @returns Loaded and validated theme configuration
19781
- *
19782
- * @example
19783
- * ```typescript
19784
- * import { loadThemeConfig } from '@shohojdhara/atomix/theme/config';
19785
- * const config = loadThemeConfig();
19786
- * ```
19787
- */
19788
- /**
19789
- * Theme Registry
19790
- *
19791
- * Manages theme registration, discovery, and dependency resolution
19792
- */
19793
- class ThemeRegistry {
19794
- constructor() {
19795
- this.entries = new Map, this.config = null, this.initialized = !1;
19796
- }
19797
- /**
19798
- * Initialize registry from config
19799
- */ async initialize(config) {
19800
- if (!this.initialized) {
19801
- // Load config if not provided
19802
- if (config) this.config = config; else try {
19803
- this.config = function(options = {}) {
19804
- 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;
19805
- // Return cached config if available
19806
- if (cachedConfig) return cachedConfig;
19807
- // Try to load config dynamically
19808
- let config;
19809
- try {
19810
- // In browser/Vite environment, we can't load config dynamically
19811
- if ("undefined" != typeof window) throw new Error("Theme config loading not supported in browser environment");
19812
- // In ESM environments, require might be undefined.
19813
- let nodeRequire, configModule;
19814
- try {
19815
- nodeRequire = require;
19816
- } catch {
19817
- // require is not defined
19818
- }
19819
- if (!nodeRequire) throw new Error("Theme config loading not supported in this environment (require is undefined)");
19820
- // Try require (Node.js/CommonJS)
19821
- try {
19822
- // Try relative path first
19823
- try {
19824
- configModule = nodeRequire("../../../../atomix.config");
19825
- } catch {
19826
- // If relative path fails, try to resolve from process.cwd()
19827
- const path = nodeRequire("path"), fs = nodeRequire("fs");
19828
- let configFilePath = path.resolve(process.cwd(), configPath);
19829
- // If atomix.config.ts not found at the root, use the default path
19830
- if (fs.existsSync(configFilePath) || configPath !== DEFAULT_ATOMIX_CONFIG_PATH || (configFilePath = path.resolve(process.cwd(), DEFAULT_ATOMIX_CONFIG_PATH)),
19831
- !fs.existsSync(configFilePath)) throw new Error(`Config file not found: ${configFilePath}`);
19832
- {
19833
- const resolvedPath = nodeRequire.resolve(configFilePath);
19834
- nodeRequire.cache && nodeRequire.cache[resolvedPath] && delete nodeRequire.cache[resolvedPath],
19835
- configModule = nodeRequire(configFilePath);
19836
- }
19837
- }
19838
- } catch (requireError) {
19839
- const errorMessage = requireError instanceof Error ? requireError.message : String(requireError);
19840
- throw new ThemeError(`Cannot load config: ${errorMessage}`, ThemeErrorCode.CONFIG_LOAD_FAILED, {
19841
- configPath: configPath,
19842
- error: errorMessage
19843
- });
19844
- }
19845
- const rawConfig = configModule.default || configModule, finalConfig =
19846
- /**
19847
- * Apply environment-specific overrides to configuration
19848
- *
19849
- * @param config - Base configuration
19850
- * @param env - Environment name
19851
- * @returns Configuration with environment overrides applied
19852
- */
19853
- function(config, env) {
19854
- const overridden = {
19855
- ...config
19856
- };
19857
- // Production overrides
19858
- return "production" === env && overridden.runtime && (overridden.runtime = {
19859
- ...overridden.runtime,
19860
- useMinified: !0,
19861
- lazy: !0
19862
- }),
19863
- // Development overrides
19864
- "development" === env && (overridden.runtime && (overridden.runtime = {
19865
- ...overridden.runtime,
19866
- useMinified: !1,
19867
- lazy: !1
19868
- }), overridden.build && (overridden.build = {
19869
- ...overridden.build,
19870
- sass: {
19871
- ...overridden.build.sass,
19872
- sourceMap: !0
19873
- }
19874
- })),
19875
- // Test overrides
19876
- "test" === env && overridden.runtime && (overridden.runtime = {
19877
- ...overridden.runtime,
19878
- enablePersistence: !1,
19879
- preload: []
19880
- }), overridden;
19881
- }({
19882
- themes: rawConfig.theme?.themes || {},
19883
- build: rawConfig.build || {},
19884
- runtime: rawConfig.runtime || {},
19885
- integration: rawConfig.integration || {},
19886
- dependencies: rawConfig.dependencies || {},
19887
- validated: !1,
19888
- // Will be set after validation
19889
- // Store tokens for generator
19890
- __tokens: rawConfig.theme?.tokens,
19891
- __extend: rawConfig.theme?.extend
19892
- }, env);
19893
- // Process the AtomixConfig structure
19894
- // Validate if requested
19895
- let validationResult = null;
19896
- validate && (validationResult = function(config) {
19897
- const errors = [], warnings = [];
19898
- // Validate top-level structure
19899
- if (!config || "object" != typeof config) return errors.push("Configuration must be an object"),
19900
- {
19901
- valid: !1,
19902
- errors: errors,
19903
- warnings: warnings
19904
- };
19905
- // Validate themes
19906
- if (config.themes && "object" == typeof config.themes) {
19907
- const themeErrors =
19908
- /**
19909
- * Validate themes object
19910
- */
19911
- function(themes) {
19912
- const errors = [], warnings = [];
19913
- 0 === Object.keys(themes).length && warnings.push("No themes defined in configuration");
19914
- for (const [themeId, theme] of Object.entries(themes))
19915
- // Validate theme ID
19916
- if (themeId && "string" == typeof themeId)
19917
- // Validate theme object
19918
- if (theme && "object" == typeof theme)
19919
- // Validate theme type
19920
- if (!theme.type || "css" !== theme.type && "js" !== theme.type) errors.push(`Theme "${themeId}" must have type "css" or "js"`); else {
19921
- // Validate CSS theme
19922
- if (
19923
- // Validate required fields
19924
- theme.name && "string" == typeof theme.name || errors.push(`Theme "${themeId}" must have a "name" string`),
19925
- "css" === theme.type) {
19926
- const cssErrors = validateCSSTheme();
19927
- errors.push(...cssErrors.errors), warnings.push(...cssErrors.warnings);
19928
- }
19929
- // Validate JS theme
19930
- if ("js" === theme.type) {
19931
- const jsErrors = validateJSTheme(themeId, theme);
19932
- errors.push(...jsErrors.errors), warnings.push(...jsErrors.warnings);
19933
- }
19934
- // Validate accessibility (only critical checks)
19935
- 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}`);
19936
- } else errors.push(`Theme "${themeId}" must be an object`); else errors.push(`Invalid theme ID: ${themeId}`);
19937
- return {
19938
- valid: 0 === errors.length,
19939
- errors: errors,
19940
- warnings: warnings
19941
- };
19942
- }(config.themes);
19943
- errors.push(...themeErrors.errors), warnings.push(...themeErrors.warnings);
19944
- }
19945
- // Validate build config (only if provided)
19946
- else errors.push('Configuration must have a "themes" object');
19947
- if (config.build) {
19948
- const buildErrors = function(build) {
19949
- const errors = [];
19950
- // Only validate structure if provided
19951
- return build.output && "object" != typeof build.output && errors.push("Build output must be an object"),
19952
- build.sass && "object" != typeof build.sass && errors.push("Build sass config must be an object"),
19953
- {
19954
- valid: 0 === errors.length,
19955
- errors: errors,
19956
- warnings: []
19957
- };
19958
- }
19959
- /**
19960
- * Validate runtime configuration
19961
- */ (config.build);
19962
- errors.push(...buildErrors.errors), warnings.push(...buildErrors.warnings);
19963
- }
19964
- // Validate runtime config (only if provided)
19965
- if (config.runtime) {
19966
- const runtimeErrors = function(runtime) {
19967
- const errors = [];
19968
- return runtime.basePath && "string" != typeof runtime.basePath && errors.push("Runtime basePath must be a string"),
19969
- runtime.defaultTheme && "string" != typeof runtime.defaultTheme && errors.push("Runtime defaultTheme must be a string"),
19970
- runtime.preload && !Array.isArray(runtime.preload) && errors.push("Runtime preload must be an array"),
19971
- runtime.storageKey && "string" != typeof runtime.storageKey && errors.push("Runtime storageKey must be a string"),
19972
- {
19973
- valid: 0 === errors.length,
19974
- errors: errors,
19975
- warnings: []
19976
- };
19977
- }
19978
- /**
19979
- * Validate integration configuration
19980
- */ (config.runtime);
19981
- errors.push(...runtimeErrors.errors), warnings.push(...runtimeErrors.warnings);
19982
- }
19983
- // Validate integration config (only if provided)
19984
- if (config.integration) {
19985
- const integrationErrors = function(integration) {
19986
- const errors = [];
19987
- // Only validate structure if provided
19988
- return integration.classNames && "object" != typeof integration.classNames && errors.push("Integration classNames must be an object"),
19989
- {
19990
- valid: 0 === errors.length,
19991
- errors: errors,
19992
- warnings: []
19993
- };
19994
- }
19995
- /**
19996
- * Validate dependencies
19997
- */ (config.integration);
19998
- errors.push(...integrationErrors.errors), warnings.push(...integrationErrors.warnings);
19999
- }
20000
- // Validate dependencies
20001
- if (config.dependencies) {
20002
- const depErrors = function(dependencies, themes) {
20003
- const errors = [], warnings = [];
20004
- for (const [themeId, deps] of Object.entries(dependencies))
20005
- // Check if theme exists
20006
- if (themes[themeId])
20007
- // Validate dependencies array
20008
- if (Array.isArray(deps))
20009
- // Check if all dependencies exist
20010
- 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}`);
20011
- return {
20012
- valid: 0 === errors.length,
20013
- errors: errors,
20014
- warnings: warnings
20015
- };
20016
- }(config.dependencies, config.themes || {});
20017
- errors.push(...depErrors.errors), warnings.push(...depErrors.warnings);
20018
- }
20019
- return {
20020
- valid: 0 === errors.length,
20021
- errors: errors,
20022
- warnings: warnings
20023
- };
20024
- }(finalConfig)), config = {
20025
- ...finalConfig,
20026
- validated: validate,
20027
- errors: validationResult?.errors,
20028
- warnings: validationResult?.warnings
20029
- };
20030
- } catch (error) {
20031
- // Fallback: return default config structure
20032
- const errorMessage = error instanceof Error ? error.message : String(error);
20033
- logger.warn(`Failed to load theme config from ${configPath}`, {
20034
- configPath: configPath,
20035
- error: errorMessage
20036
- }), config = {
20037
- themes: {},
20038
- build: {
20039
- output: {
20040
- directory: "themes",
20041
- formats: {
20042
- expanded: ".css",
20043
- compressed: ".min.css"
20044
- }
20045
- },
20046
- sass: {
20047
- ...DEFAULT_SASS_CONFIG,
20048
- loadPaths: [ ...DEFAULT_SASS_CONFIG.loadPaths ]
20049
- }
20050
- },
20051
- runtime: {
20052
- basePath: "/themes",
20053
- cdnPath: null,
20054
- preload: [],
20055
- lazy: !0,
20056
- defaultTheme: "",
20057
- // No default - use built-in styles (empty string instead of undefined)
20058
- storageKey: "atomix-theme",
20059
- dataAttribute: "data-theme",
20060
- enablePersistence: !0,
20061
- useMinified: "production" === env
20062
- },
20063
- integration: {
20064
- cssVariables: DEFAULT_INTEGRATION_CSS_VARIABLES,
20065
- classNames: DEFAULT_INTEGRATION_CLASS_NAMES
20066
- },
20067
- dependencies: {},
20068
- validated: !1,
20069
- errors: [ `Failed to load config: ${error instanceof Error ? error.message : String(error)}` ],
20070
- warnings: [],
20071
- __tokens: {},
20072
- __extend: {}
20073
- };
20074
- }
20075
- // Cache the loaded config
20076
- return cachedConfig = config, config;
20077
- }();
20078
- } catch (error) {
20079
- // In browser environments, config loading will fail
20080
- // Use empty config as fallback
20081
- this.config = {
20082
- themes: {},
20083
- build: {
20084
- output: {
20085
- directory: "themes",
20086
- formats: {
20087
- expanded: ".css",
20088
- compressed: ".min.css"
20089
- }
20090
- },
20091
- sass: {
20092
- style: "expanded",
20093
- sourceMap: !0,
20094
- loadPaths: [ "src" ]
20095
- }
20096
- },
20097
- runtime: {
20098
- basePath: "",
20099
- defaultTheme: void 0
20100
- },
20101
- integration: {
20102
- cssVariables: {
20103
- colorMode: "--color-mode"
20104
- },
20105
- classNames: {
20106
- theme: "data-theme",
20107
- colorMode: "data-color-mode"
20108
- }
20109
- },
20110
- dependencies: {},
20111
- validated: !1,
20112
- errors: [],
20113
- warnings: [],
20114
- __tokens: {},
20115
- __extend: {}
20116
- };
20117
- }
20118
- // Register all themes from config
20119
- for (const [themeId, definition] of Object.entries(this.config.themes)) this.register(themeId, definition);
20120
- // Resolve dependencies
20121
- this.resolveDependencies(), this.initialized = !0;
20122
- }
20123
- }
20124
- /**
20125
- * Register a theme
20126
- */ register(themeId, definition) {
20127
- // Get dependencies from config or definition
20128
- const entry = {
20129
- id: themeId,
20130
- definition: definition,
20131
- loaded: !1,
20132
- dependencies: [ ...this.config?.dependencies?.[themeId] || definition.dependencies || [] ],
20133
- dependents: []
20134
- };
20135
- this.entries.set(themeId, entry);
20136
- }
20137
- /**
20138
- * Get theme entry
20139
- */ get(themeId) {
20140
- return this.entries.get(themeId);
20141
- }
20142
- /**
20143
- * Check if theme exists
20144
- */ has(themeId) {
20145
- return this.entries.has(themeId);
20146
- }
20147
- /**
20148
- * Get all theme IDs
20149
- */ getAllIds() {
20150
- return Array.from(this.entries.keys());
20151
- }
20152
- /**
20153
- * Get all theme metadata
20154
- */ getAllMetadata() {
20155
- return Array.from(this.entries.values()).map((entry => ({
20156
- id: entry.id,
20157
- name: entry.definition.name,
20158
- type: entry.definition.type,
20159
- class: entry.definition.class,
20160
- description: entry.definition.description,
20161
- author: entry.definition.author,
20162
- version: entry.definition.version,
20163
- tags: entry.definition.tags,
20164
- supportsDarkMode: entry.definition.supportsDarkMode,
20165
- status: entry.definition.status,
20166
- a11y: entry.definition.a11y,
20167
- color: entry.definition.color,
20168
- features: entry.definition.features,
20169
- dependencies: entry.dependencies
20170
- })));
20171
- }
20172
- /**
20173
- * Get theme definition
20174
- */ getDefinition(themeId) {
20175
- return this.entries.get(themeId)?.definition;
20176
- }
20177
- /**
20178
- * Check if a theme is loaded
20179
- */ isThemeLoaded(themeId) {
20180
- const entry = this.entries.get(themeId);
20181
- return !!entry && entry.loaded;
20182
- }
20183
- /**
20184
- * Mark a theme as loaded
20185
- */ markLoaded(themeId, theme) {
20186
- const entry = this.entries.get(themeId);
20187
- entry && (entry.loaded = !0, theme && (entry.theme = theme));
20188
- }
20189
- /**
20190
- * Get theme object (for JS themes)
20191
- */ getTheme(themeId) {
20192
- const entry = this.entries.get(themeId);
20193
- return entry?.loaded ? entry.theme : void 0;
20194
- }
20195
- /**
20196
- * Get dependencies for a theme
20197
- */ getDependencies(themeId) {
20198
- return this.entries.get(themeId)?.dependencies || [];
20199
- }
20200
- /**
20201
- * Get dependents for a theme (themes that depend on this one)
20202
- */ getDependents(themeId) {
20203
- return this.entries.get(themeId)?.dependents || [];
20204
- }
20205
- /**
20206
- * Resolve all dependencies in correct order
20207
- */ resolveDependencyOrder(themeId) {
20208
- const resolved = [], visited = new Set, visiting = new Set, visit = id => {
20209
- if (visiting.has(id)) throw new Error(`Circular dependency detected involving theme: ${id}`);
20210
- if (visited.has(id)) return;
20211
- visiting.add(id);
20212
- const entry = this.entries.get(id);
20213
- if (entry) for (const dep of entry.dependencies) {
20214
- if (!this.has(dep)) throw new Error(`Theme "${id}" depends on non-existent theme: ${dep}`);
20215
- visit(dep);
20216
- }
20217
- visiting.delete(id), visited.add(id), resolved.push(id);
20218
- };
20219
- return visit(themeId), resolved;
20220
- }
20221
- /**
20222
- * Resolve dependencies and build dependency graph
20223
- */ resolveDependencies() {
20224
- // Build dependents map
20225
- for (const entry of this.entries.values()) for (const dep of entry.dependencies) {
20226
- const depEntry = this.entries.get(dep);
20227
- var _context;
20228
- depEntry && (_includesInstanceProperty(_context = depEntry.dependents).call(_context, entry.id) || depEntry.dependents.push(entry.id));
20229
- }
20230
- }
20231
- /**
20232
- * Validate all themes
20233
- */ validate() {
20234
- const errors = [];
20235
- // Check for circular dependencies
20236
- for (const themeId of this.entries.keys()) try {
20237
- this.resolveDependencyOrder(themeId);
20238
- } catch (error) {
20239
- errors.push(error instanceof Error ? error.message : String(error));
20240
- }
20241
- // Check for missing dependencies
20242
- 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}`);
20243
- return {
20244
- valid: 0 === errors.length,
20245
- errors: errors
20246
- };
20247
- }
20248
- /**
20249
- * Clear registry
20250
- */ clear() {
20251
- this.entries.clear(), this.config = null, this.initialized = !1;
20252
- }
19350
+ * Get the number of registered themes
19351
+ * @param registry - Theme registry object
19352
+ */ function getThemeCount(registry) {
19353
+ return Object.keys(registry).length;
20253
19354
  }
20254
19355
 
20255
19356
  /**
@@ -20334,71 +19435,18 @@ class ThemeRegistry {
20334
19435
  * const css = ':root { --atomix-color-primary: #7AFFD7; }';
20335
19436
  * await saveCSSFile(css, './themes/custom.css');
20336
19437
  * ```
20337
- */ async function saveCSSFile(css, filePath) {
20338
- // Check if in browser environment
20339
- if ("undefined" != typeof window) throw new Error("saveCSSFile can only be used in Node.js environment. Use injectCSS() for browser environments.");
20340
- // Dynamic import to avoid bundling Node.js modules in browser builds
20341
- const fs = await import("fs/promises"), dir = (await import("path")).dirname(filePath);
20342
- await fs.mkdir(dir, {
20343
- recursive: !0
20344
- }),
20345
- // Write file
20346
- await fs.writeFile(filePath, css, "utf8");
20347
- }
20348
-
20349
- /**
20350
- * Save CSS to file (synchronous version)
20351
- *
20352
- * Synchronous version of saveCSSFile. Only works in Node.js environment.
20353
- *
20354
- * @param css - CSS string to save
20355
- * @param filePath - Output file path
20356
- * @throws Error if called in browser environment
20357
- */ function saveCSSFileSync(css, filePath) {
20358
- // Check if in browser environment
20359
- if ("undefined" != typeof window) throw new Error("saveCSSFileSync can only be used in Node.js environment. Use injectCSS() for browser environments.");
20360
- // Use require for synchronous file operations
20361
- // eslint-disable-next-line @typescript-eslint/no-require-imports
20362
- const fs = require("fs"), dir = require("path").dirname(filePath);
20363
- // eslint-disable-next-line @typescript-eslint/no-require-imports
20364
- fs.existsSync(dir) || fs.mkdirSync(dir, {
20365
- recursive: !0
20366
- }),
20367
- // Write file
20368
- fs.writeFileSync(filePath, css, "utf8");
20369
- }
19438
+ */ "undefined" != typeof process && process.env;
20370
19439
 
20371
19440
  /**
20372
19441
  * Check if code is running in a browser environment
20373
- */ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof document, isServer = () => !isBrowser(), getThemeLinkId = themeName => `atomix-theme-${themeName}`, buildThemePath = (themeName, basePath = "/themes", useMinified = !1, cdnPath = null) => {
19442
+ */
19443
+ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof document, isServer = () => !isBrowser(), buildThemePath = (themeName, basePath = "/themes", useMinified = !1, cdnPath = null) => {
20374
19444
  // Validate theme name to prevent path injection
20375
19445
  if (!isValidThemeName(themeName)) throw new Error(`Invalid theme name: "${themeName}". Theme names must be lowercase alphanumeric with hyphens.`);
20376
19446
  const fileName = `${themeName}${useMinified ? ".min.css" : ".css"}`;
20377
19447
  return cdnPath ? `${cdnPath.replace(/[<>"']/g, "")}/${fileName}` : `${basePath.replace(/\/$/, "").replace(/[<>"']/g, "")}/${fileName.replace(/^\//, "")}`;
20378
19448
  // Ensure basePath doesn't end with slash and fileName doesn't start with slash
20379
19449
  // Also sanitize basePath to prevent path injection
20380
- }, loadThemeCSS = (fullPath, linkId) => isServer() ? Promise.resolve() : new Promise(((resolve, reject) => {
20381
- if (document.getElementById(linkId)) return void resolve();
20382
- // Create link element
20383
- const link = document.createElement("link");
20384
- link.id = linkId, link.rel = "stylesheet", link.type = "text/css", link.href = fullPath,
20385
- // Add data attribute for tracking
20386
- link.setAttribute("data-atomix-theme", "true"),
20387
- // Handle load success
20388
- link.onload = () => {
20389
- resolve();
20390
- },
20391
- // Handle load error
20392
- link.onerror = () => {
20393
- // Remove failed link element
20394
- link.remove(), reject(new Error(`Failed to load theme CSS: ${fullPath}`));
20395
- },
20396
- // Append to head
20397
- document.head.appendChild(link);
20398
- })), isThemeLoaded = themeName => {
20399
- if (isServer()) return !1;
20400
- const linkId = getThemeLinkId(themeName);
20401
- return null !== document.getElementById(linkId);
20402
19450
  }, isValidThemeName = themeName => !(!themeName || "string" != typeof themeName) && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(themeName);
20403
19451
 
20404
19452
  /**
@@ -20871,211 +19919,198 @@ function generateCSSVariables(theme, options = {}) {
20871
19919
  styleElement.textContent = css;
20872
19920
  }
20873
19921
  /**
20874
- * Theme Context
19922
+ * Naming Utilities
20875
19923
  *
20876
- * React context for theme management
19924
+ * Provides consistent naming conventions across the theme system
20877
19925
  */
20878
19926
  /**
20879
- * Theme context with default values
19927
+ * Generate consistent CSS class names following BEM methodology
20880
19928
  */ (css, styleId), css;
20881
19929
  }
20882
19930
 
20883
- const ThemeContext = React.createContext(null);
19931
+ function generateClassName(block, element, modifiers) {
19932
+ let className = block;
19933
+ return element && (className += `__${element}`), modifiers && Object.entries(modifiers).forEach((([key, value]) => {
19934
+ value && (className += `--${key}`, "string" == typeof value && value !== key && (className += `-${value}`));
19935
+ })), className;
19936
+ }
20884
19937
 
20885
- ThemeContext.displayName = "ThemeContext";
19938
+ /**
19939
+ * Generate consistent CSS variable names
19940
+ */ function generateCSSVariableName(property, options = {}) {
19941
+ const {prefix: prefix = "atomix", component: component, variant: variant, state: state} = options, parts = [ prefix ];
19942
+ return component && parts.push(component), variant && parts.push(variant), state && parts.push(state),
19943
+ parts.push(property), `--${parts.join("-")}`;
19944
+ }
20886
19945
 
20887
19946
  /**
20888
- * Theme Applicator
20889
- *
20890
- * Applies theme configurations to the DOM, including CSS variables,
20891
- * component overrides, typography, spacing, and color palettes.
20892
- *
20893
- * Uses the unified theme system for CSS generation and injection.
20894
- */
19947
+ * Normalize theme tokens to consistent naming convention
19948
+ */ function normalizeThemeTokens(tokens) {
19949
+ const normalized = {};
19950
+ for (const [key, value] of Object.entries(tokens))
19951
+ // Recursively normalize nested objects
19952
+ normalized[key] = "object" == typeof value && null !== value ? normalizeThemeTokens(value) : value;
19953
+ return normalized;
19954
+ }
19955
+
20895
19956
  /**
20896
- * Theme applicator class for runtime theme application
19957
+ * Convert camelCase to kebab-case for CSS custom properties
19958
+ */ function camelToKebab(str) {
19959
+ return str.replace(/[A-Z]/g, (match => `-${match.toLowerCase()}`));
19960
+ }
19961
+
19962
+ /**
19963
+ * Convert theme property to CSS variable name
19964
+ */ function themePropertyToCSSVar(propertyPath, prefix = "atomix") {
19965
+ return `--${prefix}-${propertyPath.split(".").map((part => camelToKebab(part))).join("-")}`;
19966
+ }
19967
+
19968
+ /**
19969
+ * Component Theming Utilities
20897
19970
  *
20898
- * Uses the unified theme system for efficient CSS variable generation and injection.
19971
+ * Provides consistent patterns for applying theme values to components
20899
19972
  */
20900
- class ThemeApplicator {
20901
- constructor(root = document.documentElement) {
20902
- this.styleId = "atomix-theme-applicator", this.root = root;
20903
- }
20904
- /**
20905
- * Apply a complete theme configuration
20906
- *
20907
- * Uses the unified theme system to convert Theme to DesignTokens and inject CSS.
20908
- * Automatically respects atomix.config.ts when using DesignTokens.
20909
- */ applyTheme(theme) {
20910
- // Clear previously applied variables
20911
- this.clearAppliedVars(),
20912
- // Check if it's DesignTokens
20913
- this.isDesignTokens(theme) ?
20914
- // Direct DesignTokens - use unified theme system (with config support)
20915
- this.applyDesignTokens(theme) : injectCSS$1(createTheme(theme, {
20916
- selector: ":root",
20917
- prefix: "atomix"
20918
- }), this.styleId),
20919
- // Apply component overrides (only for Theme objects)
20920
- !this.isDesignTokens(theme) && theme.components && this.applyComponentOverrides(theme.components);
20921
- }
20922
- /**
20923
- * Apply DesignTokens using unified theme system
20924
- *
20925
- * Uses createTheme() which automatically loads from atomix.config.ts
20926
- * if no tokens are provided, ensuring config is always respected.
20927
- */ applyDesignTokens(tokens) {
20928
- // Inject CSS into DOM
20929
- injectCSS$1(createTheme(tokens, {
20930
- selector: ":root",
20931
- prefix: "atomix"
20932
- }), this.styleId);
20933
- }
20934
- /**
20935
- * Check if object is DesignTokens
20936
- */ isDesignTokens(obj) {
20937
- // DesignTokens is a flat object with string keys, no nested structures
20938
- return null !== obj && "object" == typeof obj && !("palette" in obj) && !("typography" in obj) && !("__isJSTheme" in obj);
20939
- }
20940
- /**
20941
- * Apply global CSS variables (for component overrides)
20942
- */ applyGlobalCSSVars(vars) {
20943
- Object.entries(vars).forEach((([key, value]) => {
20944
- this.root.style.setProperty(key, String(value));
20945
- }));
20946
- }
20947
- /**
20948
- * Apply component-level overrides
20949
- */ applyComponentOverrides(overrides) {
20950
- Object.entries(overrides).forEach((([componentName, override]) => {
20951
- override && this.applyComponentOverride(componentName, override);
20952
- }));
20953
- }
20954
- /**
20955
- * Apply override for a specific component
20956
- */ applyComponentOverride(componentName, override) {
20957
- const vars = {}, componentKey = componentName.toLowerCase();
20958
- // Apply component-level CSS variables
20959
- override.cssVars && Object.entries(override.cssVars).forEach((([key, value]) => {
20960
- // If key doesn't start with --, add component prefix
20961
- const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${key}`;
20962
- vars[varKey] = value;
20963
- })),
20964
- // Apply part-specific CSS variables
20965
- override.parts && Object.entries(override.parts).forEach((([partName, partOverride]) => {
20966
- partOverride.cssVars && Object.entries(partOverride.cssVars).forEach((([key, value]) => {
20967
- const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${partName}-${key}`;
20968
- vars[varKey] = value;
20969
- }));
20970
- })),
20971
- // Apply variant-specific CSS variables
20972
- override.variants && Object.entries(override.variants).forEach((([variantName, variantOverride]) => {
20973
- variantOverride.cssVars && Object.entries(variantOverride.cssVars).forEach((([key, value]) => {
20974
- const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${variantName}-${key}`;
20975
- vars[varKey] = value;
20976
- }));
20977
- })), this.applyGlobalCSSVars(vars);
20978
- }
20979
- /**
20980
- * Clear all applied CSS variables
20981
- */ clearAppliedVars() {
20982
- removeCSS(this.styleId);
20983
- }
20984
- /**
20985
- * Remove theme application
20986
- */ removeTheme() {
20987
- this.clearAppliedVars(), removeCSS(this.styleId);
20988
- }
20989
- /**
20990
- * Update specific CSS variables without clearing all
20991
- */ updateCSSVars(vars) {
20992
- this.applyGlobalCSSVars(vars);
20993
- }
19973
+ /**
19974
+ * Get a theme value for a specific component using CSS variables
19975
+ * This ensures all components access theme values consistently
19976
+ */ function getComponentThemeValue(component, property, variant, size) {
19977
+ // Build CSS variable name following consistent pattern
19978
+ const parts = [ "atomix", component ];
19979
+ // Return CSS variable reference with fallback
19980
+ return variant && parts.push(variant), size && parts.push(size), parts.push(property),
19981
+ `var(--${parts.join("-")}, var(--atomix-${property}, initial))`;
20994
19982
  }
20995
19983
 
20996
19984
  /**
20997
- * Global theme applicator instance
20998
- */ let globalApplicator = null;
19985
+ * Generate component-specific CSS variables from theme
19986
+ */ function generateComponentCSSVars(component, theme, variant, size) {
19987
+ const vars = {}, prefixParts = [ "atomix", component ];
19988
+ // This is a simplified implementation - in a real system you'd have more
19989
+ // sophisticated logic to extract component-specific values from the theme
19990
+ variant && prefixParts.push(variant), size && prefixParts.push(size);
19991
+ const prefix = prefixParts.join("-");
19992
+ // Add common component properties
19993
+ if (theme.palette && (vars[`--${prefix}-color`] = theme.palette.primary?.main || "#7c3aed",
19994
+ vars[`--${prefix}-color-hover`] = theme.palette.primary?.dark || "#5b21b6", vars[`--${prefix}-color-active`] = theme.palette.primary?.main || "#7c3aed",
19995
+ vars[`--${prefix}-color-disabled`] = theme.palette.text?.disabled || "#9ca3af"),
19996
+ theme.typography && (vars[`--${prefix}-font-family`] = theme.typography.fontFamily || "Inter, sans-serif",
19997
+ vars[`--${prefix}-font-size`] = theme.typography.fontSize ? `${theme.typography.fontSize}px` : "16px"),
19998
+ theme.spacing) {
19999
+ const spacing = "function" == typeof theme.spacing ? theme.spacing : val => 8 * val;
20000
+ vars[`--${prefix}-spacing-unit`] = `${spacing(1)}px`, vars[`--${prefix}-spacing-sm`] = `${spacing(.5)}px`,
20001
+ vars[`--${prefix}-spacing-md`] = `${spacing(1)}px`, vars[`--${prefix}-spacing-lg`] = `${spacing(2)}px`;
20002
+ }
20003
+ return vars;
20004
+ }
20999
20005
 
21000
20006
  /**
21001
- * Get or create global theme applicator
21002
- */ function getThemeApplicator() {
21003
- return globalApplicator || (globalApplicator = new ThemeApplicator), globalApplicator;
20007
+ * Apply consistent theme to component style object
20008
+ */ function applyComponentTheme(component, style = {}, variant, size, theme) {
20009
+ // If no theme provided, return original style
20010
+ return theme ? {
20011
+ ...generateComponentCSSVars(component, theme, variant, size),
20012
+ ...style
20013
+ } : style;
20014
+ // Generate component-specific CSS variables
21004
20015
  }
21005
20016
 
21006
20017
  /**
21007
- * Apply theme using global applicator
21008
- */ function applyTheme(theme) {
21009
- getThemeApplicator().applyTheme(theme);
20018
+ * Create a hook for consistent component theming
20019
+ */ function useComponentTheme(component, variant, size, theme) {
20020
+ return property => getComponentThemeValue(component, property, variant, size);
21010
20021
  }
21011
20022
 
21012
20023
  /**
21013
- * ThemeProvider component
21014
- *
21015
- * Provides theme context to child components and manages theme state.
20024
+ * Theme Configuration Loader
21016
20025
  *
21017
- * **Config-First Approach**: If `defaultTheme` is not provided, loads from `atomix.config.ts`.
21018
- * Config file is required when `defaultTheme` is not provided.
20026
+ * Provides functions to load theme configurations from atomix.config.ts
20027
+ * Includes both sync and async versions, with automatic fallbacks
20028
+ */
20029
+ /**
20030
+ * Load theme from config file (synchronous, Node.js only)
20031
+ * @param configPath - Path to config file (default: atomix.config.ts)
20032
+ * @returns DesignTokens from theme configuration
20033
+ * @throws Error if config loading is not available in browser environment
20034
+ */ function loadThemeFromConfigSync(options) {
20035
+ // Check if we're in a browser environment
20036
+ if ("undefined" != typeof window) throw new Error("loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.");
20037
+ // Use dynamic import to load the config loader
20038
+ // This allows bundlers to handle external dependencies properly
20039
+ let loadAtomixConfig;
20040
+ try {
20041
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
20042
+ const {loadAtomixConfig: loader} = require("../../config/loader");
20043
+ loadAtomixConfig = loader;
20044
+ } catch (error) {
20045
+ if (!1 !== options?.required) throw new Error("Config loader module not available");
20046
+ // Return empty tokens if config is not required
20047
+ return createTokens({});
20048
+ }
20049
+ const config = loadAtomixConfig({
20050
+ configPath: options?.configPath || "atomix.config.ts",
20051
+ required: !1 !== options?.required
20052
+ });
20053
+ return config?.theme ? isThemeObject$1(config.theme) ? createDesignTokensFromTheme(config.theme) : createTokens(config.theme) : createTokens({});
20054
+ }
20055
+
20056
+ /**
20057
+ * Load theme from config file (asynchronous)
20058
+ * @param configPath - Path to config file (default: atomix.config.ts)
20059
+ * @returns Promise resolving to DesignTokens from theme configuration
20060
+ */ async function loadThemeFromConfig(options) {
20061
+ // Check if we're in a browser environment
20062
+ if ("undefined" != typeof window) throw new Error("loadThemeFromConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.");
20063
+ // Dynamic import for config loader
20064
+ const {loadAtomixConfig: loadAtomixConfig} = await import("./lib/config/loader"), config = await loadAtomixConfig({
20065
+ configPath: options?.configPath || "atomix.config.ts",
20066
+ required: !1 !== options?.required
20067
+ });
20068
+ return config?.theme ? isThemeObject$1(config.theme) ? createDesignTokensFromTheme(config.theme) : createTokens(config.theme) : createTokens({});
20069
+ }
20070
+
20071
+ /**
20072
+ * Check if the provided object is a Theme object
20073
+ * @param theme - Object to check
20074
+ * @returns True if the object is a Theme object, false otherwise
20075
+ */ function isThemeObject$1(theme) {
20076
+ return "object" == typeof theme && null !== theme;
20077
+ }
20078
+
20079
+ /**
20080
+ * Theme Context
21019
20081
  *
21020
- * @example
21021
- * ```tsx
21022
- * import { ThemeProvider } from '@shohojdhara/atomix/theme';
20082
+ * React context for theme management
20083
+ */
20084
+ /**
20085
+ * Theme context with default values
20086
+ */ const ThemeContext = React.createContext(null);
20087
+
20088
+ ThemeContext.displayName = "ThemeContext";
20089
+
20090
+ /**
20091
+ * Theme Provider
21023
20092
  *
21024
- * // Loads from atomix.config.ts (config file required)
21025
- * function App() {
21026
- * return (
21027
- * <ThemeProvider>
21028
- * <YourApp />
21029
- * </ThemeProvider>
21030
- * );
21031
- * }
20093
+ * React context provider for theme management with separated concerns.
20094
+ * Simplified version focusing on core functionality:
20095
+ * - String-based themes (CSS files)
20096
+ * - JS Theme objects
20097
+ * - Persistence via localStorage
21032
20098
  *
21033
- * // Provide explicit theme (bypasses config)
21034
- * function App() {
21035
- * return (
21036
- * <ThemeProvider defaultTheme="dark">
21037
- * <YourApp />
21038
- * </ThemeProvider>
21039
- * );
21040
- * }
21041
- * ```
21042
- */ 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}) => {
20099
+ * Falls back to 'default' theme if no configuration is found.
20100
+ */
20101
+ 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}) => {
21043
20102
  // Store callbacks in refs to avoid recreating when they change
21044
20103
  const onThemeChangeRef = React.useRef(onThemeChange), onErrorRef = React.useRef(onError);
21045
- // Update refs when callbacks change
20104
+ // Update ref when callback changes
21046
20105
  React.useEffect((() => {
21047
20106
  onThemeChangeRef.current = onThemeChange, onErrorRef.current = onError;
21048
20107
  }), [ onThemeChange, onError ]);
21049
- // Create stable wrapper functions that read from refs
20108
+ // Create stable wrapper functions that read from ref
21050
20109
  const handleThemeChange = React.useCallback((theme => {
21051
20110
  onThemeChangeRef.current?.(theme);
21052
20111
  }), []), handleError = React.useCallback(((error, themeName) => {
21053
20112
  onErrorRef.current?.(error, themeName);
21054
- }), []), themesRef = React.useRef(themes), themesStable = React.useMemo((() => {
21055
- // Only update if themes object actually changed (shallow comparison)
21056
- const currentKeys = Object.keys(themes), prevKeys = Object.keys(themesRef.current);
21057
- return currentKeys.length !== prevKeys.length || currentKeys.some((key => themes[key] !== themesRef.current[key])) ? (themesRef.current = themes,
21058
- themes) : themesRef.current;
21059
- }), [ themes ]), logger = React.useMemo((() => getLogger()), []), registry = React.useMemo((() => {
21060
- const reg = new ThemeRegistry;
21061
- // Register themes from props
21062
- if (themesStable && Object.keys(themesStable).length > 0) for (const [themeId, metadata] of Object.entries(themesStable)) reg.has(themeId) || reg.register(themeId, {
21063
- type: "css",
21064
- name: metadata.name,
21065
- class: metadata.class || themeId,
21066
- description: metadata.description,
21067
- author: metadata.author,
21068
- version: metadata.version,
21069
- tags: metadata.tags,
21070
- supportsDarkMode: metadata.supportsDarkMode,
21071
- status: metadata.status,
21072
- a11y: metadata.a11y,
21073
- color: metadata.color,
21074
- features: metadata.features,
21075
- dependencies: metadata.dependencies
21076
- });
21077
- return reg;
21078
- }), [ themesStable ]), storageAdapter = React.useMemo((() => ({
20113
+ }), []), storageAdapter = React.useMemo((() => ({
21079
20114
  getItem: key => {
21080
20115
  if (isServer()) return null;
21081
20116
  try {
@@ -21107,7 +20142,7 @@ class ThemeApplicator {
21107
20142
  return !1;
21108
20143
  }
21109
20144
  }
21110
- })), []), themeApplicator = React.useMemo((() => isServer() ? null : new ThemeApplicator), []), initialDefaultTheme = React.useMemo((() => {
20145
+ })), []), initialDefaultTheme = React.useMemo((() => {
21111
20146
  // Check storage first
21112
20147
  if (enablePersistence && storageAdapter.isAvailable()) {
21113
20148
  const stored = storageAdapter.getItem(storageKey);
@@ -21115,193 +20150,112 @@ class ThemeApplicator {
21115
20150
  }
21116
20151
  // If defaultTheme is provided, use it
21117
20152
  if (null != defaultTheme) return defaultTheme;
21118
- // Load from atomix.config.ts (required)
21119
- const configTokens = loadThemeFromConfigSync();
21120
- return configTokens && Object.keys(configTokens).length > 0 ? configTokens : null;
21121
- // Config is required - this will be caught in useEffect
21122
- }), [ enablePersistence, storageAdapter, storageKey, defaultTheme ]), [currentTheme, setCurrentTheme] = React.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
21123
- )), [activeTheme, setActiveTheme] = React.useState((() => isJSTheme(initialDefaultTheme) ? initialDefaultTheme : null)), [availableThemes, setAvailableThemes] = React.useState((() => registry.getAllMetadata().map((meta => ({
21124
- name: meta.name || "",
21125
- class: meta.class,
21126
- description: meta.description,
21127
- author: meta.author,
21128
- version: meta.version,
21129
- tags: meta.tags,
21130
- supportsDarkMode: meta.supportsDarkMode,
21131
- status: meta.status,
21132
- a11y: meta.a11y,
21133
- color: meta.color,
21134
- features: meta.features,
21135
- dependencies: meta.dependencies
21136
- }))))), [isLoading, setIsLoading] = React.useState(!1), [error, setError] = React.useState(null), loadedThemesRef = React.useRef(new Set), previousThemeRef = React.useRef(null);
21137
- // Get default theme (with automatic config loading)
21138
- React.useCallback((() => {
21139
- // Check storage first
21140
- if (enablePersistence && storageAdapter.isAvailable()) {
21141
- const stored = storageAdapter.getItem(storageKey);
21142
- if (stored) return stored;
20153
+ // Try to load from atomix.config.ts as fallback, but only in Node.js/SSR environments
20154
+ if ("undefined" == typeof window) try {
20155
+ // Dynamically import the config loader to avoid bundling issues in browser
20156
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
20157
+ const {loadThemeFromConfigSync: loadThemeFromConfigSync} = require("../config/configLoader"), configTokens = loadThemeFromConfigSync();
20158
+ if (configTokens && Object.keys(configTokens).length > 0)
20159
+ // For simplicity, we'll treat config tokens as a special theme name
20160
+ return "config-theme";
20161
+ } catch (error) {
20162
+ console.warn("Failed to load theme from config, using default");
21143
20163
  }
21144
- // If defaultTheme is provided, use it
21145
- if (null != defaultTheme) return defaultTheme;
21146
- // Load from atomix.config.ts (required)
21147
- // Config file must exist - throws error if not found
21148
- const configTokens = loadThemeFromConfigSync();
21149
- if (configTokens && Object.keys(configTokens).length > 0)
21150
- // Return config tokens as Partial<DesignTokens>
21151
- return configTokens;
21152
- throw new Error("ThemeProvider: atomix.config.ts is required when defaultTheme is not provided.");
21153
- }), [ enablePersistence, storageAdapter, storageKey, defaultTheme ]);
21154
- // Apply JS theme (supports both Theme and DesignTokens)
21155
- const applyJSTheme = React.useCallback((async (theme, removePrevious = !0) => {
21156
- !isServer() && themeApplicator && (removePrevious && (
21157
- // Remove previous theme
21158
- removeCSS("atomix-theme"),
21159
- // Also remove any existing CSS variables
21160
- activeTheme && activeTheme.cssVars && Object.keys(activeTheme.cssVars).forEach((key => {
21161
- document.documentElement.style.removeProperty(key);
21162
- }))), null === theme || "object" != typeof theme || "palette" in theme || "typography" in theme || "__isJSTheme" in theme ?
21163
- // Use ThemeApplicator for Theme objects
21164
- themeApplicator?.applyTheme(theme) : injectCSS$1(createTheme(theme), "atomix-theme"));
21165
- }), [ activeTheme, themeApplicator ]), setTheme = React.useCallback((async (theme, options) => {
21166
- const {removePrevious: removePrevious = !0, fallbackOnError: fallbackOnError = !0, customPath: customPath} = options || {};
20164
+ // Default fallback
20165
+ return "default";
20166
+ }), [ defaultTheme, enablePersistence, storageKey ]), [currentTheme, setCurrentTheme] = React.useState((() => initialDefaultTheme)), [activeTheme, setActiveTheme] = React.useState(null), [isLoading, setIsLoading] = React.useState(!1), [error, setError] = React.useState(null), loadedThemesRef = React.useRef(new Set), themePromisesRef = React.useRef({});
20167
+ // Apply initial theme attributes to document element
20168
+ React.useEffect((() => {
20169
+ isServer() || ((dataAttribute, themeName) => {
20170
+ isServer() || (
20171
+ // Set data attribute on body
20172
+ document.body.setAttribute(dataAttribute, themeName),
20173
+ // Also set on documentElement for broader compatibility
20174
+ document.documentElement.setAttribute(dataAttribute, themeName));
20175
+ })(String(currentTheme), dataAttribute);
20176
+ }), [ currentTheme, dataAttribute ]),
20177
+ // Handle theme persistence
20178
+ React.useEffect((() => {
20179
+ enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, String(currentTheme));
20180
+ }), [ currentTheme, storageKey, enablePersistence ]);
20181
+ // Function to set theme with proper type handling
20182
+ const setTheme = React.useCallback((async (theme, options) => {
21167
20183
  setIsLoading(!0), setError(null);
21168
20184
  try {
21169
- // Handle Theme or DesignTokens object directly
21170
- if ("string" != typeof theme) {
21171
- if (null !== theme && "object" == typeof theme && !("palette" in theme) && !("typography" in theme) && !("__isJSTheme" in theme)) {
21172
- // Handle DesignTokens using unified theme system
21173
- await applyJSTheme(theme, removePrevious);
21174
- const themeName = "design-tokens-theme";
21175
- return previousThemeRef.current = currentTheme, setCurrentTheme(themeName), setActiveTheme(null),
21176
- previousThemeRef.current, Date.now(), handleThemeChange(themeName),
21177
- // Persist to storage
21178
- enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, themeName),
21179
- void setIsLoading(!1);
21180
- }
21181
- if (isJSTheme(theme)) {
21182
- // Handle Theme object
21183
- await applyJSTheme(theme, removePrevious);
21184
- const themeName = theme.name || "js-theme";
21185
- return previousThemeRef.current = currentTheme, setCurrentTheme(themeName), setActiveTheme(theme),
21186
- previousThemeRef.current, Date.now(), handleThemeChange(theme),
21187
- // Persist to storage
21188
- enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, themeName),
21189
- void setIsLoading(!1);
21190
- }
21191
- {
21192
- const error = new Error("Invalid theme object provided");
21193
- throw handleError(error, "js-theme"), setError(error), setIsLoading(!1), error;
21194
- }
21195
- }
21196
- // Check if theme exists
21197
- if (!registry.has(theme)) {
21198
- const error = new Error(`Theme "${theme}" not found in registry`);
21199
- if (handleError(error, theme), setError(error), fallbackOnError && currentTheme) return void setIsLoading(!1);
21200
- throw setIsLoading(!1), error;
21201
- }
21202
- // Load theme CSS if needed
21203
- const themePath = customPath || buildThemePath(theme, basePath, useMinified, cdnPath || void 0), linkId = getThemeLinkId(theme);
21204
- // Remove previous theme if requested
21205
- removePrevious && previousThemeRef.current && previousThemeRef.current !== theme && (themeNameOrLinkId => {
21206
- if (isServer()) return;
21207
- // Try as link ID first, then as theme name
21208
- let link = document.getElementById(themeNameOrLinkId);
21209
- if (!link) {
21210
- const linkId = getThemeLinkId(themeNameOrLinkId);
21211
- link = document.getElementById(linkId);
21212
- }
21213
- link && link.remove();
21214
- })(previousThemeRef.current),
21215
- // Load CSS if not already loaded
21216
- isThemeLoaded(theme) || (await loadThemeCSS(themePath, linkId), loadedThemesRef.current.add(theme)),
21217
- // Apply theme attributes
21218
- ((dataAttribute, themeName) => {
21219
- isServer() || (
21220
- // Set data attribute on body
21221
- document.body.setAttribute(dataAttribute, themeName),
21222
- // Also set on documentElement for broader compatibility
21223
- document.documentElement.setAttribute(dataAttribute, themeName));
21224
- })(dataAttribute, theme),
21225
- // Update state
21226
- previousThemeRef.current = currentTheme, setCurrentTheme(theme), setActiveTheme(null),
21227
- previousThemeRef.current, Date.now(), handleThemeChange(theme),
21228
- // Persist to storage
21229
- enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, theme),
21230
- setIsLoading(!1);
20185
+ let themeName, themeObj = null;
20186
+ // If it's a string theme name, load the associated CSS
20187
+ if ("string" == typeof theme ? themeName = theme :
20188
+ // If it's a Theme object or DesignTokens, we need to process it
20189
+ function(theme) {
20190
+ return "object" == typeof theme && null !== theme && "__isJSTheme" in theme && !0 === theme.__isJSTheme;
20191
+ }(theme) ? (themeObj = theme,
20192
+ // For JS themes, we use a generic name
20193
+ themeName = "js-theme", setActiveTheme(themeObj)) :
20194
+ // For DesignTokens, we might create a theme from tokens
20195
+ themeName = "tokens-theme", "string" == typeof theme && themes[theme]) {
20196
+ // Check if theme is already loading
20197
+ if (themePromisesRef.current[theme]) return await themePromisesRef.current[theme],
20198
+ setCurrentTheme(theme), setActiveTheme(null), void handleThemeChange(theme);
20199
+ // Load CSS theme
20200
+ const themeLoadPromise = new Promise((async (resolve, reject) => {
20201
+ try {
20202
+ if (!themes[theme]) throw new Error(`Theme metadata not found for theme: ${theme}`);
20203
+ {
20204
+ // Build CSS path using utility function
20205
+ const cssPath = buildThemePath(theme, basePath, useMinified, cdnPath);
20206
+ // Remove any previously loaded theme CSS
20207
+ removeCSS(`theme-${String(currentTheme)}`),
20208
+ // Inject new theme CSS
20209
+ await injectCSS$1(cssPath, `theme-${theme}`), loadedThemesRef.current.add(theme),
20210
+ setCurrentTheme(theme), setActiveTheme(null), handleThemeChange(theme), resolve();
20211
+ }
20212
+ } catch (err) {
20213
+ const error = err instanceof Error ? err : new Error(String(err));
20214
+ setError(error), handleError(error, String(theme)), reject(error);
20215
+ }
20216
+ }));
20217
+ themePromisesRef.current[theme] = themeLoadPromise, await themeLoadPromise;
20218
+ } else themeObj ? (
20219
+ // For JS themes, set them directly
20220
+ setCurrentTheme(themeName), setActiveTheme(themeObj), handleThemeChange(themeObj)) : (
20221
+ // For string theme that isn't in our themes record, just set the name
20222
+ setCurrentTheme(themeName), setActiveTheme(null), handleThemeChange(themeName));
21231
20223
  } catch (err) {
21232
20224
  const error = err instanceof Error ? err : new Error(String(err));
21233
- throw handleError(error, "string" == typeof theme ? theme : "js-theme"), setError(error),
21234
- setIsLoading(!1), err;
20225
+ setError(error), handleError(error, String(theme));
20226
+ } finally {
20227
+ setIsLoading(!1);
21235
20228
  }
21236
- }), [ registry, basePath, cdnPath, useMinified, dataAttribute, enablePersistence, storageAdapter, storageKey, currentTheme, activeTheme, applyJSTheme, handleThemeChange, handleError ]), preloadTheme = React.useCallback((async themeName => {
21237
- if (!isServer() && !isThemeLoaded(themeName)) {
20229
+ }), [ themes, currentTheme, handleThemeChange, handleError, basePath, useMinified, cdnPath ]), isThemeLoaded = React.useCallback((themeName => loadedThemesRef.current.has(themeName)), []), preloadTheme = React.useCallback((async themeName => {
20230
+ if (themes[themeName] && !isThemeLoaded(themeName)) {
21238
20231
  setIsLoading(!0);
21239
20232
  try {
21240
- if (!registry.has(themeName)) throw new Error(`Theme "${themeName}" not found in registry`);
21241
- const themePath = buildThemePath(themeName, basePath, useMinified, cdnPath || void 0), linkId = getThemeLinkId(themeName);
21242
- await loadThemeCSS(themePath, linkId), loadedThemesRef.current.add(themeName);
20233
+ // Build CSS path using utility function
20234
+ const cssPath = buildThemePath(themeName, basePath, useMinified, cdnPath);
20235
+ // Preload CSS by fetching it
20236
+ await fetch(cssPath), loadedThemesRef.current.add(themeName);
21243
20237
  } catch (err) {
21244
20238
  const error = err instanceof Error ? err : new Error(String(err));
21245
- handleError(error, themeName), setError(error);
20239
+ setError(error), handleError(error, themeName);
21246
20240
  } finally {
21247
20241
  setIsLoading(!1);
21248
20242
  }
21249
20243
  }
21250
- }), [ registry, basePath, cdnPath, useMinified, handleError ]), isThemeLoaded$1 = React.useCallback((themeName => isThemeLoaded(themeName)), []);
21251
- // Set theme function (supports string, Theme, or DesignTokens)
21252
- // Initialize default theme on mount
21253
- React.useEffect((() => {
21254
- isServer() || (async () => {
21255
- // Use the initial default theme we computed
21256
- const defaultThemeValue = initialDefaultTheme;
21257
- if (defaultThemeValue) try {
21258
- null === defaultThemeValue || "object" != typeof defaultThemeValue || "palette" in defaultThemeValue || "typography" in defaultThemeValue || "__isJSTheme" in defaultThemeValue || "string" == typeof defaultThemeValue ?
21259
- // Handle string or Theme object
21260
- await setTheme(defaultThemeValue, {
21261
- removePrevious: !1,
21262
- fallbackOnError: !0
21263
- }) : (
21264
- // Apply config tokens directly
21265
- await applyJSTheme(defaultThemeValue, !1),
21266
- // Update state and emit events
21267
- setCurrentTheme("config-theme"), setActiveTheme(null), Date.now(), handleThemeChange("config-theme"),
21268
- // Persist to storage
21269
- enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, "config-theme"));
21270
- } catch (err) {
21271
- const error = err instanceof Error ? err : new Error(String(err));
21272
- throw logger.error("Failed to load theme from config", error, {
21273
- theme: defaultThemeValue
21274
- }), handleError(error, "config-theme"), setError(error), error;
21275
- }
21276
- })();
21277
- }
21278
- // eslint-disable-next-line react-hooks/exhaustive-deps
21279
- ), []), // Only run once on mount - initialDefaultTheme is stable
21280
- // Preload themes
21281
- React.useEffect((() => {
21282
- !isServer() && preload && 0 !== preload.length && (async () => {
21283
- for (const themeName of preload) if (!isThemeLoaded(themeName)) try {
21284
- await preloadTheme(themeName);
21285
- } catch (err) {
21286
- // Silently fail for preload
21287
- logger.warn(`Failed to preload theme "${themeName}"`, {
21288
- error: err instanceof Error ? err.message : String(err)
21289
- });
21290
- }
21291
- })();
21292
- }), [ preload, preloadTheme, logger ]);
21293
- // Context value
21294
- const contextValue = React.useMemo((() => ({
21295
- theme: currentTheme,
20244
+ }), [ themes, isThemeLoaded, handleError, basePath, useMinified, cdnPath ]), themeManager = React.useMemo((() => ({})), []), contextValue = React.useMemo((() => ({
20245
+ theme: "string" == typeof currentTheme ? currentTheme : "js-theme",
21296
20246
  activeTheme: activeTheme,
21297
20247
  setTheme: setTheme,
21298
- availableThemes: availableThemes,
20248
+ availableThemes: Object.entries(themes).map((([name, metadata]) => ({
20249
+ ...metadata
20250
+ }))),
21299
20251
  isLoading: isLoading,
21300
20252
  error: error,
21301
- isThemeLoaded: isThemeLoaded$1,
21302
- preloadTheme: preloadTheme
21303
- })), [ currentTheme, activeTheme, setTheme, availableThemes, isLoading, error, isThemeLoaded$1, preloadTheme ]);
21304
- return jsxRuntime.jsx(ThemeContext.Provider, {
20253
+ isThemeLoaded: isThemeLoaded,
20254
+ preloadTheme: preloadTheme,
20255
+ themeManager: themeManager
20256
+ })), [ currentTheme, activeTheme, setTheme, themes, isLoading, error, isThemeLoaded, preloadTheme, themeManager ]);
20257
+ // Check if theme is loaded
20258
+ return jsxRuntime.jsx(ThemeContext.Provider, {
21305
20259
  value: contextValue,
21306
20260
  children: children
21307
20261
  });
@@ -21347,6 +20301,219 @@ class ThemeApplicator {
21347
20301
  };
21348
20302
  }
21349
20303
 
20304
+ function useThemeTokens() {
20305
+ const {theme: theme, activeTheme: activeTheme} = useTheme(), getToken = React.useCallback(((tokenName, fallback) => {
20306
+ if ("undefined" == typeof window) return fallback || "";
20307
+ const cssVarName = `--atomix-${tokenName}`;
20308
+ return getComputedStyle(document.documentElement).getPropertyValue(cssVarName).trim() || fallback || "";
20309
+ }), []), getThemeValue = React.useCallback(((path, fallback) => {
20310
+ var _context;
20311
+ return activeTheme && _reduceInstanceProperty(_context = path.split(".")).call(_context, ((obj, key) => obj?.[key]), activeTheme) || fallback;
20312
+ // Navigate through nested theme object using dot notation
20313
+ }), [ activeTheme ]);
20314
+ // Helper function to get CSS variable value
20315
+ // Return unified API for accessing theme values
20316
+ return {
20317
+ theme: theme,
20318
+ activeTheme: activeTheme,
20319
+ getToken: getToken,
20320
+ getThemeValue: getThemeValue,
20321
+ // Commonly used tokens with fallbacks
20322
+ colors: {
20323
+ primary: getToken("primary", "#3b82f6"),
20324
+ secondary: getToken("secondary", "#10b981"),
20325
+ error: getToken("error", "#ef4444"),
20326
+ success: getToken("success", "#22c55e"),
20327
+ warning: getToken("warning", "#eab308"),
20328
+ info: getToken("info", "#3b82f6"),
20329
+ light: getToken("light", "#f9fafb"),
20330
+ dark: getToken("dark", "#111827")
20331
+ },
20332
+ spacing: {
20333
+ 1: getToken("spacing-1", "0.25rem"),
20334
+ 2: getToken("spacing-2", "0.5rem"),
20335
+ 3: getToken("spacing-3", "0.75rem"),
20336
+ 4: getToken("spacing-4", "1rem"),
20337
+ 5: getToken("spacing-5", "1.25rem"),
20338
+ 6: getToken("spacing-6", "1.5rem"),
20339
+ 8: getToken("spacing-8", "2rem"),
20340
+ 10: getToken("spacing-10", "2.5rem"),
20341
+ 12: getToken("spacing-12", "3rem"),
20342
+ 16: getToken("spacing-16", "4rem"),
20343
+ 20: getToken("spacing-20", "5rem")
20344
+ },
20345
+ borderRadius: {
20346
+ sm: getToken("border-radius-sm", "0.25rem"),
20347
+ md: getToken("border-radius-md", "0.5rem"),
20348
+ lg: getToken("border-radius-lg", "0.75rem"),
20349
+ xl: getToken("border-radius-xl", "1rem"),
20350
+ full: getToken("border-radius-full", "9999px")
20351
+ },
20352
+ typography: {
20353
+ fontFamily: {
20354
+ sans: getToken("font-sans-serif", "Inter, system-ui, sans-serif"),
20355
+ serif: getToken("font-serif", "Georgia, serif"),
20356
+ mono: getToken("font-monospace", "Fira Code, monospace")
20357
+ },
20358
+ fontSize: {
20359
+ xs: getToken("font-size-xs", "0.75rem"),
20360
+ sm: getToken("font-size-sm", "0.875rem"),
20361
+ md: getToken("font-size-md", "1rem"),
20362
+ lg: getToken("font-size-lg", "1.125rem"),
20363
+ xl: getToken("font-size-xl", "1.25rem"),
20364
+ "2xl": getToken("font-size-2xl", "1.5rem"),
20365
+ "3xl": getToken("font-size-3xl", "1.875rem"),
20366
+ "4xl": getToken("font-size-4xl", "2.25rem")
20367
+ },
20368
+ fontWeight: {
20369
+ light: getToken("font-weight-light", "300"),
20370
+ normal: getToken("font-weight-normal", "400"),
20371
+ medium: getToken("font-weight-medium", "500"),
20372
+ semibold: getToken("font-weight-semibold", "600"),
20373
+ bold: getToken("font-weight-bold", "700")
20374
+ }
20375
+ },
20376
+ shadows: {
20377
+ sm: getToken("box-shadow-sm", "0 1px 2px 0 rgba(0, 0, 0, 0.05)"),
20378
+ md: getToken("box-shadow-md", "0 4px 6px -1px rgba(0, 0, 0, 0.1)"),
20379
+ lg: getToken("box-shadow-lg", "0 10px 15px -3px rgba(0, 0, 0, 0.1)"),
20380
+ xl: getToken("box-shadow-xl", "0 20px 25px -5px rgba(0, 0, 0, 0.1)"),
20381
+ inset: getToken("box-shadow-inset", "inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)")
20382
+ },
20383
+ transitions: {
20384
+ fast: getToken("transition-fast", "150ms"),
20385
+ base: getToken("transition-base", "200ms"),
20386
+ slow: getToken("transition-slow", "300ms")
20387
+ }
20388
+ };
20389
+ }
20390
+
20391
+ /**
20392
+ * Theme System Error Handling
20393
+ *
20394
+ * Centralized error handling for the Atomix theme system.
20395
+ * Provides custom error classes and logging utilities.
20396
+ */
20397
+ /**
20398
+ * Theme error codes
20399
+ */ var ThemeErrorCode, LogLevel;
20400
+
20401
+ !function(ThemeErrorCode) {
20402
+ /** Theme not found in registry */
20403
+ ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
20404
+ /** Theme failed to load */
20405
+ ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
20406
+ /** Theme validation failed */
20407
+ ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
20408
+ /** Configuration loading failed */
20409
+ ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
20410
+ /** Configuration validation failed */
20411
+ ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
20412
+ /** Circular dependency detected */
20413
+ ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
20414
+ /** Missing dependency */
20415
+ ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
20416
+ /** Storage operation failed */
20417
+ ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
20418
+ /** Invalid theme name */
20419
+ ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
20420
+ /** CSS injection failed */
20421
+ ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
20422
+ /** Unknown error */
20423
+ ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
20424
+ }(ThemeErrorCode || (ThemeErrorCode = {}));
20425
+
20426
+ /**
20427
+ * Custom error class for theme-related errors
20428
+ */
20429
+ class ThemeError extends Error {
20430
+ constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
20431
+ super(message), this.name = "ThemeError", this.code = code, this.context = context,
20432
+ this.timestamp = Date.now(),
20433
+ // Maintains proper stack trace for where our error was thrown (only available on V8)
20434
+ Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
20435
+ }
20436
+ /**
20437
+ * Convert error to JSON for logging
20438
+ */ toJSON() {
20439
+ return {
20440
+ name: this.name,
20441
+ message: this.message,
20442
+ code: this.code,
20443
+ context: this.context,
20444
+ timestamp: this.timestamp,
20445
+ stack: this.stack
20446
+ };
20447
+ }
20448
+ }
20449
+
20450
+ /**
20451
+ * Log level
20452
+ */ !function(LogLevel) {
20453
+ LogLevel[LogLevel.ERROR = 0] = "ERROR", LogLevel[LogLevel.WARN = 1] = "WARN", LogLevel[LogLevel.INFO = 2] = "INFO",
20454
+ LogLevel[LogLevel.DEBUG = 3] = "DEBUG";
20455
+ }(LogLevel || (LogLevel = {}));
20456
+
20457
+ /**
20458
+ * Theme Logger
20459
+ *
20460
+ * Centralized logging for the theme system.
20461
+ * Replaces console statements with structured logging.
20462
+ */
20463
+ class ThemeLogger {
20464
+ constructor(config = {}) {
20465
+ this.config = {
20466
+ level: config.level ?? ("undefined" != typeof process && "production" === process.env?.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
20467
+ enableConsole: config.enableConsole ?? !0,
20468
+ onError: config.onError,
20469
+ onWarn: config.onWarn,
20470
+ onInfo: config.onInfo,
20471
+ onDebug: config.onDebug
20472
+ };
20473
+ }
20474
+ /**
20475
+ * Log an error
20476
+ */ error(message, error, context) {
20477
+ if (this.config.level < LogLevel.ERROR) return;
20478
+ const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
20479
+ this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
20480
+ error: errorObj,
20481
+ context: {
20482
+ ...context,
20483
+ ...themeError.context
20484
+ },
20485
+ code: themeError.code
20486
+ }), this.config.onError?.(themeError, context);
20487
+ }
20488
+ /**
20489
+ * Log a warning
20490
+ */ warn(message, context) {
20491
+ this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
20492
+ this.config.onWarn?.(message, context));
20493
+ }
20494
+ /**
20495
+ * Log an info message
20496
+ */ info(message, context) {
20497
+ this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
20498
+ this.config.onInfo?.(message, context));
20499
+ }
20500
+ /**
20501
+ * Log a debug message
20502
+ */ debug(message, context) {
20503
+ this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
20504
+ }
20505
+ }
20506
+
20507
+ /**
20508
+ * Default logger instance
20509
+ */ let defaultLogger = null;
20510
+
20511
+ /**
20512
+ * Get or create default logger
20513
+ */ function getLogger() {
20514
+ return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
20515
+ }
20516
+
21350
20517
  /**
21351
20518
  * Default fallback UI
21352
20519
  */ const DefaultFallback = ({error: error, errorInfo: errorInfo}) => {
@@ -21395,7 +20562,7 @@ class ThemeApplicator {
21395
20562
  },
21396
20563
  children: JSON.stringify(context, null, 2)
21397
20564
  }) ]
21398
- }), "development" === process.env.NODE_ENV && errorInfo && jsxRuntime.jsxs("details", {
20565
+ }), ("undefined" == typeof process || "development" === process.env?.NODE_ENV) && errorInfo && jsxRuntime.jsxs("details", {
21399
20566
  style: {
21400
20567
  marginTop: "1rem"
21401
20568
  },
@@ -21491,6 +20658,130 @@ class ThemeApplicator {
21491
20658
  }
21492
20659
  }
21493
20660
 
20661
+ /**
20662
+ * Theme Applicator
20663
+ *
20664
+ * Applies theme configurations to the DOM, including CSS variables,
20665
+ * component overrides, typography, spacing, and color palettes.
20666
+ *
20667
+ * Uses the unified theme system for CSS generation and injection.
20668
+ */
20669
+ /**
20670
+ * Theme applicator class for runtime theme application
20671
+ *
20672
+ * Uses the unified theme system for efficient CSS variable generation and injection.
20673
+ */ class ThemeApplicator {
20674
+ constructor(root = document.documentElement) {
20675
+ this.styleId = "atomix-theme-applicator", this.root = root;
20676
+ }
20677
+ /**
20678
+ * Apply a complete theme configuration
20679
+ *
20680
+ * Uses the unified theme system to convert Theme to DesignTokens and inject CSS.
20681
+ * Automatically respects atomix.config.ts when using DesignTokens.
20682
+ */ applyTheme(theme) {
20683
+ // Clear previously applied variables
20684
+ this.clearAppliedVars(),
20685
+ // Check if it's DesignTokens
20686
+ this.isDesignTokens(theme) ?
20687
+ // Direct DesignTokens - use unified theme system (with config support)
20688
+ this.applyDesignTokens(theme) : injectCSS$1(createTheme(theme, {
20689
+ selector: ":root",
20690
+ prefix: "atomix"
20691
+ }), this.styleId),
20692
+ // Apply component overrides (only for Theme objects)
20693
+ !this.isDesignTokens(theme) && theme.components && this.applyComponentOverrides(theme.components);
20694
+ }
20695
+ /**
20696
+ * Apply DesignTokens using unified theme system
20697
+ *
20698
+ * Uses createTheme() which automatically loads from atomix.config.ts
20699
+ * if no tokens are provided, ensuring config is always respected.
20700
+ */ applyDesignTokens(tokens) {
20701
+ // Inject CSS into DOM
20702
+ injectCSS$1(createTheme(tokens, {
20703
+ selector: ":root",
20704
+ prefix: "atomix"
20705
+ }), this.styleId);
20706
+ }
20707
+ /**
20708
+ * Check if object is DesignTokens
20709
+ */ isDesignTokens(obj) {
20710
+ // DesignTokens is a flat object with string keys, no nested structures
20711
+ return null !== obj && "object" == typeof obj && !("palette" in obj) && !("typography" in obj) && !("__isJSTheme" in obj);
20712
+ }
20713
+ /**
20714
+ * Apply global CSS variables (for component overrides)
20715
+ */ applyGlobalCSSVars(vars) {
20716
+ Object.entries(vars).forEach((([key, value]) => {
20717
+ this.root.style.setProperty(key, String(value));
20718
+ }));
20719
+ }
20720
+ /**
20721
+ * Apply component-level overrides
20722
+ */ applyComponentOverrides(overrides) {
20723
+ Object.entries(overrides).forEach((([componentName, override]) => {
20724
+ override && this.applyComponentOverride(componentName, override);
20725
+ }));
20726
+ }
20727
+ /**
20728
+ * Apply override for a specific component
20729
+ */ applyComponentOverride(componentName, override) {
20730
+ const vars = {}, componentKey = componentName.toLowerCase();
20731
+ // Apply component-level CSS variables
20732
+ override.cssVars && Object.entries(override.cssVars).forEach((([key, value]) => {
20733
+ // If key doesn't start with --, add component prefix
20734
+ const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${key}`;
20735
+ vars[varKey] = value;
20736
+ })),
20737
+ // Apply part-specific CSS variables
20738
+ override.parts && Object.entries(override.parts).forEach((([partName, partOverride]) => {
20739
+ partOverride.cssVars && Object.entries(partOverride.cssVars).forEach((([key, value]) => {
20740
+ const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${partName}-${key}`;
20741
+ vars[varKey] = value;
20742
+ }));
20743
+ })),
20744
+ // Apply variant-specific CSS variables
20745
+ override.variants && Object.entries(override.variants).forEach((([variantName, variantOverride]) => {
20746
+ variantOverride.cssVars && Object.entries(variantOverride.cssVars).forEach((([key, value]) => {
20747
+ const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${variantName}-${key}`;
20748
+ vars[varKey] = value;
20749
+ }));
20750
+ })), this.applyGlobalCSSVars(vars);
20751
+ }
20752
+ /**
20753
+ * Clear all applied CSS variables
20754
+ */ clearAppliedVars() {
20755
+ removeCSS(this.styleId);
20756
+ }
20757
+ /**
20758
+ * Remove theme application
20759
+ */ removeTheme() {
20760
+ this.clearAppliedVars(), removeCSS(this.styleId);
20761
+ }
20762
+ /**
20763
+ * Update specific CSS variables without clearing all
20764
+ */ updateCSSVars(vars) {
20765
+ this.applyGlobalCSSVars(vars);
20766
+ }
20767
+ }
20768
+
20769
+ /**
20770
+ * Global theme applicator instance
20771
+ */ let globalApplicator = null;
20772
+
20773
+ /**
20774
+ * Get or create global theme applicator
20775
+ */ function getThemeApplicator() {
20776
+ return globalApplicator || (globalApplicator = new ThemeApplicator), globalApplicator;
20777
+ }
20778
+
20779
+ /**
20780
+ * Apply theme using global applicator
20781
+ */ function applyTheme(theme) {
20782
+ getThemeApplicator().applyTheme(theme);
20783
+ }
20784
+
21494
20785
  const VIEWPORT_PRESETS = {
21495
20786
  mobile: {
21496
20787
  width: 375,
@@ -23717,64 +23008,27 @@ class RTLManager {
23717
23008
  /**
23718
23009
  * Save theme to CSS file
23719
23010
  */ async function saveTheme(css, filePath) {
23720
- await saveCSSFile(css, filePath);
23011
+ await async function(css, filePath) {
23012
+ // Check if in browser environment
23013
+ if ("undefined" != typeof window) throw new Error("saveCSSFile can only be used in Node.js environment. Use injectCSS() for browser environments.");
23014
+ // Dynamic import to avoid bundling Node.js modules in browser builds
23015
+ const fs = await import("fs/promises"), dir = (await import("path")).dirname(filePath);
23016
+ await fs.mkdir(dir, {
23017
+ recursive: !0
23018
+ }),
23019
+ // Write file
23020
+ await fs.writeFile(filePath, css, "utf8");
23021
+ }
23022
+ /**
23023
+ * Theme System Constants
23024
+ *
23025
+ * Centralized constants for the theme system to avoid magic numbers and strings.
23026
+ */
23027
+ /**
23028
+ * Default storage key for theme persistence
23029
+ */ (css, filePath);
23721
23030
  }
23722
23031
 
23723
- var themeImport = Object.freeze({
23724
- __proto__: null,
23725
- RTLManager: RTLManager,
23726
- ThemeApplicator: ThemeApplicator,
23727
- ThemeComparator: ThemeComparator,
23728
- ThemeContext: ThemeContext,
23729
- ThemeErrorBoundary: ThemeErrorBoundary,
23730
- ThemeInspector: ThemeInspector,
23731
- ThemeLiveEditor: ThemeLiveEditor,
23732
- ThemePreview: ThemePreview,
23733
- ThemeProvider: ThemeProvider,
23734
- ThemeRegistry: ThemeRegistry,
23735
- ThemeValidator: ThemeValidator,
23736
- applyCSSVariables: applyCSSVariables,
23737
- applyTheme: applyTheme,
23738
- createDesignTokensFromTheme: createDesignTokensFromTheme,
23739
- createTheme: createTheme,
23740
- createThemeObject: createThemeObject,
23741
- createTokens: createTokens,
23742
- cssVarsToStyle: cssVarsToStyle,
23743
- deepMerge: deepMerge,
23744
- defaultTokens: defaultTokens,
23745
- designTokensToCSSVars: designTokensToCSSVars,
23746
- designTokensToTheme: designTokensToTheme,
23747
- extendTheme: extendTheme,
23748
- extractComponentName: extractComponentName,
23749
- generateCSSVariableName: generateCSSVariableName,
23750
- generateCSSVariables: generateCSSVariables$1,
23751
- generateCSSVariablesForSelector: generateCSSVariablesForSelector,
23752
- generateComponentCSSVars: generateComponentCSSVars,
23753
- getCSSVariable: getCSSVariable,
23754
- getDesignTokensFromTheme: getDesignTokensFromTheme,
23755
- getThemeApplicator: getThemeApplicator,
23756
- injectCSS: injectCSS$1,
23757
- injectTheme: injectTheme,
23758
- isCSSInjected: isCSSInjected,
23759
- isDesignTokens: isDesignTokens,
23760
- isThemeObject: isThemeObject,
23761
- isValidCSSVariableName: isValidCSSVariableName,
23762
- loadThemeFromConfig: loadThemeFromConfig,
23763
- loadThemeFromConfigSync: loadThemeFromConfigSync,
23764
- mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
23765
- mergeCSSVars: mergeCSSVars,
23766
- mergeTheme: mergeTheme,
23767
- removeCSS: removeCSS,
23768
- removeCSSVariables: removeCSSVariables,
23769
- removeTheme: removeTheme,
23770
- saveCSSFile: saveCSSFile,
23771
- saveCSSFileSync: saveCSSFileSync,
23772
- saveTheme: saveTheme,
23773
- themeToDesignTokens: themeToDesignTokens,
23774
- useHistory: useHistory,
23775
- useTheme: useTheme
23776
- });
23777
-
23778
23032
  /**
23779
23033
  * CSS Variables Constants
23780
23034
  *
@@ -23783,7 +23037,8 @@ var themeImport = Object.freeze({
23783
23037
  */
23784
23038
  /**
23785
23039
  * Button CSS Variables
23786
- */ const BUTTON_CSS_VARS = {
23040
+ */
23041
+ const BUTTON_CSS_VARS = {
23787
23042
  // Base properties
23788
23043
  "--atomix-button-bg": "background-color",
23789
23044
  "--atomix-button-color": "text color",
@@ -24054,216 +23309,126 @@ var themeImport = Object.freeze({
24054
23309
  * Utility function to merge part styles
24055
23310
  */
24056
23311
  function mergePartStyles(base, override) {
24057
- if (base || override) return base ? override ? {
24058
- className: [ base.className, override.className ].filter(Boolean).join(" "),
24059
- style: {
24060
- ...base.style,
24061
- ...override.style
24062
- }
24063
- } : base : override;
24064
- }
24065
-
24066
- /**
24067
- * Render a slot with the given props
24068
- *
24069
- * Priority order:
24070
- * 1. render function
24071
- * 2. component
24072
- * 3. children
24073
- * 4. fallback
24074
- *
24075
- * @example
24076
- * renderSlot(
24077
- * { render: (props) => <CustomButton {...props} /> },
24078
- * { onClick: handleClick, children: 'Click me' }
24079
- * )
24080
- */ function renderSlot(slot, props, fallback) {
24081
- // No slot provided, use fallback
24082
- if (!slot) return fallback;
24083
- // Slot is a plain React node
24084
- if ( React__default.default.isValidElement(slot) || "string" == typeof slot || "number" == typeof slot) return slot;
24085
- // Slot is an object with rendering options
24086
- if ("object" == typeof slot && null !== slot) {
24087
- const slotObj = slot;
24088
- // Priority 1: render function
24089
- if (slotObj.render && "function" == typeof slotObj.render) return slotObj.render(props);
24090
- // Priority 2: component
24091
- if (slotObj.component) {
24092
- const Component = slotObj.component;
24093
- return jsxRuntime.jsx(Component, {
24094
- ...props
24095
- });
24096
- }
24097
- // Priority 3: children
24098
- if (void 0 !== slotObj.children) return slotObj.children;
24099
- }
24100
- // Fallback
24101
- return fallback;
24102
- }
24103
-
24104
- /**
24105
- * Check if a value is a slot configuration
24106
- */
24107
- /**
24108
- * Atomix Config Loader
24109
- *
24110
- * Helper functions to load atomix.config.ts from external projects.
24111
- * Similar to how Tailwind loads tailwind.config.js
24112
- */
24113
- /**
24114
- * Load Atomix configuration from project root
24115
- *
24116
- * Attempts to load atomix.config.ts from the current working directory.
24117
- * Falls back to default config if file doesn't exist.
24118
- *
24119
- * @param options - Loader options
24120
- * @returns Loaded configuration or default
24121
- *
24122
- * @example
24123
- * ```typescript
24124
- * import { loadAtomixConfig } from '@shohojdhara/atomix/config';
24125
- * import { createTheme } from '@shohojdhara/atomix/theme';
24126
- *
24127
- * const config = loadAtomixConfig();
24128
- * const theme = createTheme(config.theme?.tokens || {});
24129
- * ```
24130
- */
24131
- function loadAtomixConfig(options = {}) {
24132
- const {configPath: configPath = "atomix.config.ts", required: required = !1} = options, defaultConfig = {
24133
- prefix: "atomix",
24134
- theme: {
24135
- extend: {}
24136
- }
24137
- };
24138
- // Default config
24139
- // In browser environments, config loading is not supported
24140
- if ("undefined" != typeof window) {
24141
- if (required) throw new Error("Config loading not supported in browser environment");
24142
- return defaultConfig;
24143
- }
24144
- // Try to load config file
24145
- try {
24146
- // Use dynamic import for ESM compatibility
24147
- const configModule = require(configPath), config = configModule.default || configModule;
24148
- // Validate it's an AtomixConfig
24149
- if (config && "object" == typeof config) return config;
24150
- throw new Error("Invalid config format");
24151
- } catch (error) {
24152
- if (required) throw new Error(`Failed to load config from ${configPath}: ${error.message}`);
24153
- // Return default config if not required
24154
- return defaultConfig;
24155
- }
24156
- }
24157
-
24158
- /**
24159
- * Resolve config path
24160
- *
24161
- * Finds atomix.config.ts in the project, checking common locations.
24162
- * Returns null in browser environments where file system access is not available.
24163
- *
24164
- * This function is designed to work in Node.js environments only.
24165
- * In browser builds, it will always return null without attempting to access Node.js modules.
24166
- *
24167
- * @internal This function uses Node.js modules and should not be called in browser environments.
24168
- */ function resolveConfigPath() {
24169
- // Early return for browser environments - prevents any Node.js module access
24170
- // This check happens before any require() calls, preventing bundlers from analyzing them
24171
- if ("undefined" != typeof window || "undefined" == typeof process || !process.cwd) return null;
24172
- // Only attempt to load Node.js modules in Node.js runtime
24173
- // Use a lazy-loading pattern that prevents static analysis by bundlers
24174
- try {
24175
- // Create a function that only executes in Node.js runtime
24176
- // Use string-based module names to prevent static analysis by bundlers
24177
- const modules = (() => {
24178
- // These requires are only executed at runtime in Node.js environments
24179
- // They are marked as external in Rollup config and should not be bundled
24180
- // Using string concatenation and computed property access to prevent static analysis
24181
- if ("undefined" == typeof require) return null;
24182
- // Use a try-catch wrapper to safely access require
24183
- try {
24184
- // Build module names dynamically to prevent static analysis
24185
- const moduleNames = [ "fs", "path" ];
24186
- // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
24187
- return {
24188
- fs: require(moduleNames[0]),
24189
- path: require(moduleNames[1])
24190
- };
24191
- } catch {
24192
- return null;
24193
- }
24194
- })();
24195
- if (!modules) return null;
24196
- const {fs: fs, path: path} = modules, cwd = process.cwd(), possiblePaths = [ path.join(cwd, "atomix.config.ts"), path.join(cwd, "atomix.config.js"), path.join(cwd, "atomix.config.mjs") ];
24197
- for (const configPath of possiblePaths) if (fs.existsSync(configPath)) return configPath;
24198
- } catch (error) {
24199
- // Silently fail in browser environments or when modules are unavailable
24200
- return null;
24201
- }
24202
- return null;
24203
- }
24204
-
24205
- var loader = Object.freeze({
24206
- __proto__: null,
24207
- loadAtomixConfig: loadAtomixConfig,
24208
- resolveConfigPath: resolveConfigPath
24209
- });
24210
-
24211
- /**
24212
- * Atomix Configuration System
24213
- *
24214
- * Tailwind-like configuration for customizing the Atomix Design System.
24215
- *
24216
- * External developers can create `atomix.config.ts` in their project root
24217
- * to customize design tokens, similar to Tailwind's tailwind.config.js
24218
- *
24219
- * @example
24220
- * ```typescript
24221
- * // atomix.config.ts (in your project)
24222
- * import { defineConfig } from '@shohojdhara/atomix/config';
24223
- *
24224
- * export default defineConfig({
24225
- * theme: {
24226
- * extend: {
24227
- * colors: {
24228
- * primary: { main: '#7AFFD7' },
24229
- * },
24230
- * },
24231
- * },
24232
- * });
24233
- * ```
24234
- */
24235
- /**
24236
- * Helper function to define Atomix configuration with type safety
24237
- *
24238
- * @param config - Atomix configuration object
24239
- * @returns The configuration object
24240
- */
23312
+ if (base || override) return base ? override ? {
23313
+ className: [ base.className, override.className ].filter(Boolean).join(" "),
23314
+ style: {
23315
+ ...base.style,
23316
+ ...override.style
23317
+ }
23318
+ } : base : override;
23319
+ }
23320
+
24241
23321
  /**
24242
- * Helper function to define Atomix configuration with type safety
24243
- *
24244
- * Similar to Tailwind's defineConfig, provides autocomplete and type checking.
23322
+ * Render a slot with the given props
24245
23323
  *
24246
- * @param config - Atomix configuration object
24247
- * @returns The configuration object
23324
+ * Priority order:
23325
+ * 1. render function
23326
+ * 2. component
23327
+ * 3. children
23328
+ * 4. fallback
24248
23329
  *
24249
23330
  * @example
24250
- * ```typescript
24251
- * import { defineConfig } from '@shohojdhara/atomix/config';
24252
- *
24253
- * export default defineConfig({
24254
- * theme: {
24255
- * extend: {
24256
- * colors: {
24257
- * primary: { main: '#7AFFD7' },
24258
- * },
24259
- * },
24260
- * },
24261
- * });
24262
- * ```
23331
+ * renderSlot(
23332
+ * { render: (props) => <CustomButton {...props} /> },
23333
+ * { onClick: handleClick, children: 'Click me' }
23334
+ * )
23335
+ */ function renderSlot(slot, props, fallback) {
23336
+ // No slot provided, use fallback
23337
+ if (!slot) return fallback;
23338
+ // Slot is a plain React node
23339
+ if ( React__default.default.isValidElement(slot) || "string" == typeof slot || "number" == typeof slot) return slot;
23340
+ // Slot is an object with rendering options
23341
+ if ("object" == typeof slot && null !== slot) {
23342
+ const slotObj = slot;
23343
+ // Priority 1: render function
23344
+ if (slotObj.render && "function" == typeof slotObj.render) return slotObj.render(props);
23345
+ // Priority 2: component
23346
+ if (slotObj.component) {
23347
+ const Component = slotObj.component;
23348
+ return jsxRuntime.jsx(Component, {
23349
+ ...props
23350
+ });
23351
+ }
23352
+ // Priority 3: children
23353
+ if (void 0 !== slotObj.children) return slotObj.children;
23354
+ }
23355
+ // Fallback
23356
+ return fallback;
23357
+ }
23358
+
23359
+ /**
23360
+ * Check if a value is a slot configuration
24263
23361
  */
24264
23362
  // Import and re-export as namespaces with proper typing
24265
23363
  // Export as namespaces with explicit typing
24266
- const composables = composablesImport, utils = utilsImport, types = typesImport, constants = constantsImport, theme = themeImport, atomix = {
23364
+ const composables = composablesImport, utils = utilsImport, types = typesImport, constants = constantsImport, theme = Object.freeze({
23365
+ __proto__: null,
23366
+ RTLManager: RTLManager,
23367
+ ThemeApplicator: ThemeApplicator,
23368
+ ThemeComparator: ThemeComparator,
23369
+ ThemeContext: ThemeContext,
23370
+ ThemeErrorBoundary: ThemeErrorBoundary,
23371
+ ThemeInspector: ThemeInspector,
23372
+ ThemeLiveEditor: ThemeLiveEditor,
23373
+ ThemePreview: ThemePreview,
23374
+ ThemeProvider: ThemeProvider,
23375
+ ThemeValidator: ThemeValidator,
23376
+ applyCSSVariables: applyCSSVariables,
23377
+ applyComponentTheme: applyComponentTheme,
23378
+ applyTheme: applyTheme,
23379
+ camelToKebab: camelToKebab,
23380
+ clearThemes: clearThemes,
23381
+ createDesignTokensFromTheme: createDesignTokensFromTheme,
23382
+ createTheme: createTheme,
23383
+ createThemeObject: createThemeObject,
23384
+ createThemeRegistry: createThemeRegistry,
23385
+ createTokens: createTokens,
23386
+ cssVarsToStyle: cssVarsToStyle,
23387
+ deepMerge: deepMerge,
23388
+ defaultTokens: defaultTokens,
23389
+ designTokensToCSSVars: designTokensToCSSVars,
23390
+ designTokensToTheme: designTokensToTheme,
23391
+ extendTheme: extendTheme,
23392
+ extractComponentName: extractComponentName,
23393
+ generateCSSVariableName: generateCSSVariableName,
23394
+ generateCSSVariables: generateCSSVariables$1,
23395
+ generateCSSVariablesForSelector: generateCSSVariablesForSelector,
23396
+ generateClassName: generateClassName,
23397
+ generateComponentCSSVars: generateComponentCSSVars,
23398
+ getAllThemes: getAllThemes,
23399
+ getCSSVariable: getCSSVariable,
23400
+ getComponentThemeValue: getComponentThemeValue,
23401
+ getDesignTokensFromTheme: getDesignTokensFromTheme,
23402
+ getTheme: getTheme,
23403
+ getThemeApplicator: getThemeApplicator,
23404
+ getThemeCount: getThemeCount,
23405
+ getThemeIds: getThemeIds,
23406
+ hasTheme: hasTheme,
23407
+ injectCSS: injectCSS$1,
23408
+ injectTheme: injectTheme,
23409
+ isCSSInjected: isCSSInjected,
23410
+ isDesignTokens: isDesignTokens,
23411
+ isThemeObject: isThemeObject,
23412
+ isValidCSSVariableName: isValidCSSVariableName,
23413
+ loadThemeFromConfig: loadThemeFromConfig,
23414
+ loadThemeFromConfigSync: loadThemeFromConfigSync,
23415
+ mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
23416
+ mergeCSSVars: mergeCSSVars,
23417
+ mergeTheme: mergeTheme,
23418
+ normalizeThemeTokens: normalizeThemeTokens,
23419
+ registerTheme: registerTheme,
23420
+ removeCSS: removeCSS,
23421
+ removeCSSVariables: removeCSSVariables,
23422
+ removeTheme: removeTheme,
23423
+ saveTheme: saveTheme,
23424
+ themePropertyToCSSVar: themePropertyToCSSVar,
23425
+ themeToDesignTokens: themeToDesignTokens,
23426
+ unregisterTheme: unregisterTheme,
23427
+ useComponentTheme: useComponentTheme,
23428
+ useHistory: useHistory,
23429
+ useTheme: useTheme,
23430
+ useThemeTokens: useThemeTokens
23431
+ }), atomix = {
24267
23432
  // Re-export all components and utilities
24268
23433
  ...components,
24269
23434
  ...layouts,
@@ -24320,13 +23485,13 @@ exports.ScatterChart = ScatterChart, exports.SectionIntro = SectionIntro, export
24320
23485
  exports.SideMenu = SideMenu, exports.SideMenuItem = SideMenuItem, exports.SideMenuList = SideMenuList,
24321
23486
  exports.Slider = Slider, exports.Spinner = Spinner, exports.Steps = Steps, exports.TAB = TAB,
24322
23487
  exports.TABS_CSS_VARS = TABS_CSS_VARS, exports.TESTIMONIAL = TESTIMONIAL, exports.TEXTAREA = TEXTAREA,
24323
- exports.THEME_COLORS = THEME_COLORS, exports.TODO = TODO, exports.TOGGLE = TOGGLE,
24324
- exports.TOOLTIP = TOOLTIP, exports.TOOLTIP_CSS_VARS = TOOLTIP_CSS_VARS, exports.Tabs = Tabs,
24325
- exports.Testimonial = Testimonial, exports.Textarea = Textarea, exports.ThemeApplicator = ThemeApplicator,
24326
- exports.ThemeComparator = ThemeComparator, exports.ThemeContext = ThemeContext,
24327
- exports.ThemeErrorBoundary = ThemeErrorBoundary, exports.ThemeInspector = ThemeInspector,
24328
- exports.ThemeLiveEditor = ThemeLiveEditor, exports.ThemePreview = ThemePreview,
24329
- exports.ThemeProvider = ThemeProvider, exports.ThemeRegistry = ThemeRegistry, exports.ThemeValidator = ThemeValidator,
23488
+ exports.THEME_COLORS = THEME_COLORS, exports.THEME_NAMING = THEME_NAMING, exports.TODO = TODO,
23489
+ exports.TOGGLE = TOGGLE, exports.TOOLTIP = TOOLTIP, exports.TOOLTIP_CSS_VARS = TOOLTIP_CSS_VARS,
23490
+ exports.Tabs = Tabs, exports.Testimonial = Testimonial, exports.Textarea = Textarea,
23491
+ exports.ThemeApplicator = ThemeApplicator, exports.ThemeComparator = ThemeComparator,
23492
+ exports.ThemeContext = ThemeContext, exports.ThemeErrorBoundary = ThemeErrorBoundary,
23493
+ exports.ThemeInspector = ThemeInspector, exports.ThemeLiveEditor = ThemeLiveEditor,
23494
+ exports.ThemePreview = ThemePreview, exports.ThemeProvider = ThemeProvider, exports.ThemeValidator = ThemeValidator,
24330
23495
  exports.Todo = Todo, exports.Toggle = Toggle, exports.Tooltip = Tooltip, exports.TreemapChart = TreemapChart,
24331
23496
  exports.UPLOAD = UPLOAD, exports.Upload = Upload, exports.VIDEO_PLAYER = VIDEO_PLAYER,
24332
23497
  exports.VideoPlayer = VideoPlayer, exports.WaterfallChart = WaterfallChart, exports.applyCSSVariables = applyCSSVariables,
@@ -24341,8 +23506,34 @@ function(cssVars, baseStyle) {
24341
23506
  acc)), {}),
24342
23507
  ...baseStyle
24343
23508
  };
24344
- }, exports.applyPartStyles = applyPartStyles, exports.applyTheme = applyTheme, exports.composables = composables,
24345
- exports.constants = constants, exports.createCSSVarStyle = createCSSVarStyle, exports.createDarkVariant =
23509
+ }
23510
+ /**
23511
+ * Atomix Config Loader
23512
+ *
23513
+ * Helper functions to load atomix.config.ts from external projects.
23514
+ * Similar to how Tailwind loads tailwind.config.js
23515
+ */
23516
+ /**
23517
+ * Load Atomix configuration from project root
23518
+ *
23519
+ * Attempts to load atomix.config.ts from the current working directory.
23520
+ * Falls back to default config if file doesn't exist.
23521
+ *
23522
+ * @param options - Loader options
23523
+ * @returns Loaded configuration or default
23524
+ *
23525
+ * @example
23526
+ * ```typescript
23527
+ * import { loadAtomixConfig } from '@shohojdhara/atomix/config';
23528
+ * import { createTheme } from '@shohojdhara/atomix/theme';
23529
+ *
23530
+ * const config = loadAtomixConfig();
23531
+ * const theme = createTheme(config.theme?.tokens || {});
23532
+ * ```
23533
+ */ , exports.applyComponentTheme = applyComponentTheme, exports.applyPartStyles = applyPartStyles,
23534
+ exports.applyTheme = applyTheme, exports.camelToKebab = camelToKebab, exports.clearThemes = clearThemes,
23535
+ exports.composables = composables, exports.constants = constants, exports.createCSSVarStyle = createCSSVarStyle,
23536
+ exports.createDarkVariant =
24346
23537
  /**
24347
23538
  * Create a dark theme variant from a light theme
24348
23539
  */
@@ -24405,8 +23596,63 @@ function(defaultElement = "div") {
24405
23596
  /**
24406
23597
  * Hook to manage slot rendering
24407
23598
  */ , exports.createTheme = createTheme, exports.createThemeObject = createThemeObject,
24408
- exports.createTokens = createTokens, exports.cssVarsToStyle = cssVarsToStyle, exports.deepMerge = deepMerge,
24409
- exports.default = atomix, exports.defaultTokens = defaultTokens, exports.defineConfig = function(config) {
23599
+ exports.createThemeRegistry = createThemeRegistry, exports.createTokens = createTokens,
23600
+ exports.cssVarsToStyle = cssVarsToStyle, exports.deepMerge = deepMerge, exports.default = atomix,
23601
+ exports.defaultTokens = defaultTokens, exports.defineConfig =
23602
+ /**
23603
+ * Atomix Configuration System
23604
+ *
23605
+ * Tailwind-like configuration for customizing the Atomix Design System.
23606
+ *
23607
+ * External developers can create `atomix.config.ts` in their project root
23608
+ * to customize design tokens, similar to Tailwind's tailwind.config.js
23609
+ *
23610
+ * @example
23611
+ * ```typescript
23612
+ * // atomix.config.ts (in your project)
23613
+ * import { defineConfig } from '@shohojdhara/atomix/config';
23614
+ *
23615
+ * export default defineConfig({
23616
+ * theme: {
23617
+ * extend: {
23618
+ * colors: {
23619
+ * primary: { main: '#7AFFD7' },
23620
+ * },
23621
+ * },
23622
+ * },
23623
+ * });
23624
+ * ```
23625
+ */
23626
+ /**
23627
+ * Helper function to define Atomix configuration with type safety
23628
+ *
23629
+ * @param config - Atomix configuration object
23630
+ * @returns The configuration object
23631
+ */
23632
+ /**
23633
+ * Helper function to define Atomix configuration with type safety
23634
+ *
23635
+ * Similar to Tailwind's defineConfig, provides autocomplete and type checking.
23636
+ *
23637
+ * @param config - Atomix configuration object
23638
+ * @returns The configuration object
23639
+ *
23640
+ * @example
23641
+ * ```typescript
23642
+ * import { defineConfig } from '@shohojdhara/atomix/config';
23643
+ *
23644
+ * export default defineConfig({
23645
+ * theme: {
23646
+ * extend: {
23647
+ * colors: {
23648
+ * primary: { main: '#7AFFD7' },
23649
+ * },
23650
+ * },
23651
+ * },
23652
+ * });
23653
+ * ```
23654
+ */
23655
+ function(config) {
24410
23656
  return config;
24411
23657
  }, exports.designTokensToCSSVars = designTokensToCSSVars, exports.designTokensToTheme = designTokensToTheme,
24412
23658
  exports.exportTheme =
@@ -24421,15 +23667,17 @@ function(theme) {
24421
23667
  */ , exports.extendTheme = extendTheme, exports.extractComponentName = extractComponentName,
24422
23668
  exports.extractYouTubeId = extractYouTubeId, exports.generateCSSVariableName = generateCSSVariableName,
24423
23669
  exports.generateCSSVariables = generateCSSVariables$1, exports.generateCSSVariablesForSelector = generateCSSVariablesForSelector,
24424
- exports.generateComponentCSSVars = generateComponentCSSVars, exports.generateFontPreloadTags = generateFontPreloadTags,
24425
- exports.generateUUID = generateUUID, exports.getCSSVariable = getCSSVariable, exports.getComponentCSSVars =
23670
+ exports.generateClassName = generateClassName, exports.generateComponentCSSVars = generateComponentCSSVars,
23671
+ exports.generateFontPreloadTags = generateFontPreloadTags, exports.generateUUID = generateUUID,
23672
+ exports.getAllThemes = getAllThemes, exports.getCSSVariable = getCSSVariable, exports.getComponentCSSVars =
24426
23673
  /**
24427
23674
  * Get CSS variables for a component
24428
23675
  */
24429
23676
  function(component) {
24430
23677
  return COMPONENT_CSS_VARS[component];
24431
- }, exports.getDesignTokensFromTheme = getDesignTokensFromTheme, exports.getPartStyles = getPartStyles,
24432
- exports.getThemeApplicator = getThemeApplicator, exports.getThemeMetadata =
23678
+ }, exports.getComponentThemeValue = getComponentThemeValue, exports.getDesignTokensFromTheme = getDesignTokensFromTheme,
23679
+ exports.getPartStyles = getPartStyles, exports.getTheme = getTheme, exports.getThemeApplicator = getThemeApplicator,
23680
+ exports.getThemeCount = getThemeCount, exports.getThemeIds = getThemeIds, exports.getThemeMetadata =
24433
23681
  /**
24434
23682
  * Get theme metadata
24435
23683
  */
@@ -24447,7 +23695,8 @@ function(theme) {
24447
23695
  }
24448
23696
  /**
24449
23697
  * Check if theme supports dark mode
24450
- */ , exports.hasCustomization = hasCustomization, exports.importTheme = function(json) {
23698
+ */ , exports.hasCustomization = hasCustomization, exports.hasTheme = hasTheme,
23699
+ exports.importTheme = function(json) {
24451
23700
  try {
24452
23701
  return JSON.parse(json);
24453
23702
  } catch (error) {
@@ -24466,8 +23715,43 @@ exports.isDesignTokens = isDesignTokens, exports.isSlot = function(value) {
24466
23715
  * Merge multiple slot configurations
24467
23716
  * Later slots override earlier ones
24468
23717
  */ , exports.isThemeObject = isThemeObject, exports.isValidCSSVariableName = isValidCSSVariableName,
24469
- exports.isYouTubeUrl = isYouTubeUrl, exports.loadAtomixConfig = loadAtomixConfig,
24470
- exports.loadThemeFromConfig = loadThemeFromConfig, exports.loadThemeFromConfigSync = loadThemeFromConfigSync,
23718
+ exports.isYouTubeUrl = isYouTubeUrl, exports.loadAtomixConfig = function(options = {}) {
23719
+ const {configPath: configPath = "atomix.config.ts", required: required = !1} = options, defaultConfig = {
23720
+ prefix: "atomix",
23721
+ theme: {
23722
+ extend: {}
23723
+ }
23724
+ };
23725
+ // Default config
23726
+ // In browser environments, config loading is not supported
23727
+ if ("undefined" != typeof window) {
23728
+ if (required) throw new Error("loadAtomixConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.");
23729
+ return defaultConfig;
23730
+ }
23731
+ // Try to load config file
23732
+ try {
23733
+ // Use dynamic import for ESM compatibility
23734
+ const configModule = require(configPath), config = configModule.default || configModule;
23735
+ // Validate it's an AtomixConfig
23736
+ if (config && "object" == typeof config) return config;
23737
+ throw new Error("Invalid config format");
23738
+ } catch (error) {
23739
+ if (required) throw new Error(`Failed to load config from ${configPath}: ${error.message}`);
23740
+ // Return default config if not required
23741
+ return defaultConfig;
23742
+ }
23743
+ }
23744
+ /**
23745
+ * Resolve config path
23746
+ *
23747
+ * Finds atomix.config.ts in the project, checking common locations.
23748
+ * Returns null in browser environments where file system access is not available.
23749
+ *
23750
+ * This function is designed to work in Node.js environments only.
23751
+ * In browser builds, it will always return null without attempting to access Node.js modules.
23752
+ *
23753
+ * @internal This function uses Node.js modules and should not be called in browser environments.
23754
+ */ , exports.loadThemeFromConfig = loadThemeFromConfig, exports.loadThemeFromConfigSync = loadThemeFromConfigSync,
24471
23755
  exports.mapSCSSTokensToCSSVars = mapSCSSTokensToCSSVars, exports.mergeCSSVars = mergeCSSVars,
24472
23756
  exports.mergeClassNames = mergeClassNames, exports.mergeComponentProps = mergeComponentProps,
24473
23757
  exports.mergePartStyles = mergePartStyles, exports.mergeSlots = function(...slots) {
@@ -24476,7 +23760,8 @@ exports.mergePartStyles = mergePartStyles, exports.mergeSlots = function(...slot
24476
23760
  ...acc,
24477
23761
  ...slot
24478
23762
  })));
24479
- }, exports.mergeTheme = mergeTheme, exports.preloadFonts = preloadFonts, exports.quickTheme =
23763
+ }, exports.mergeTheme = mergeTheme, exports.normalizeThemeTokens = normalizeThemeTokens,
23764
+ exports.preloadFonts = preloadFonts, exports.quickTheme =
24480
23765
  /**
24481
23766
  * Quick theme creator with sensible defaults
24482
23767
  */
@@ -24492,13 +23777,47 @@ function(name, primaryColor, secondaryColor) {
24492
23777
  } : void 0
24493
23778
  }
24494
23779
  });
24495
- }, exports.removeCSS = removeCSS, exports.removeCSSVariables = removeCSSVariables,
24496
- exports.removeTheme = removeTheme, exports.renderSlot = renderSlot, exports.resolveConfigPath = resolveConfigPath,
24497
- exports.saveCSSFile = saveCSSFile, exports.saveCSSFileSync = saveCSSFileSync, exports.saveTheme = saveTheme,
24498
- exports.sliderConstants = sliderConstants, exports.supportsDarkMode = function(theme) {
23780
+ }, exports.registerTheme = registerTheme, exports.removeCSS = removeCSS, exports.removeCSSVariables = removeCSSVariables,
23781
+ exports.removeTheme = removeTheme, exports.renderSlot = renderSlot, exports.resolveConfigPath = function() {
23782
+ // Early return for browser environments - prevents any Node.js module access
23783
+ // This check happens before any require() calls, preventing bundlers from analyzing them
23784
+ if ("undefined" != typeof window || "undefined" == typeof process || !process.cwd) return null;
23785
+ // Only attempt to load Node.js modules in Node.js runtime
23786
+ // Use a lazy-loading pattern that prevents static analysis by bundlers
23787
+ try {
23788
+ // Create a function that only executes in Node.js runtime
23789
+ // Use string-based module names to prevent static analysis by bundlers
23790
+ const modules = (() => {
23791
+ // These requires are only executed at runtime in Node.js environments
23792
+ // They are marked as external in Rollup config and should not be bundled
23793
+ // Using string concatenation and computed property access to prevent static analysis
23794
+ if ("undefined" == typeof require) return null;
23795
+ // Use a try-catch wrapper to safely access require
23796
+ try {
23797
+ // Build module names dynamically to prevent static analysis
23798
+ const moduleNames = [ "fs", "path" ];
23799
+ // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
23800
+ return {
23801
+ fs: require(moduleNames[0]),
23802
+ path: require(moduleNames[1])
23803
+ };
23804
+ } catch {
23805
+ return null;
23806
+ }
23807
+ })();
23808
+ if (!modules) return null;
23809
+ const {fs: fs, path: path} = modules, cwd = process.cwd(), possiblePaths = [ path.join(cwd, "atomix.config.ts"), path.join(cwd, "atomix.config.js"), path.join(cwd, "atomix.config.mjs") ];
23810
+ for (const configPath of possiblePaths) if (fs.existsSync(configPath)) return configPath;
23811
+ } catch (error) {
23812
+ // Silently fail in browser environments or when modules are unavailable
23813
+ return null;
23814
+ }
23815
+ return null;
23816
+ }, exports.saveTheme = saveTheme, exports.sliderConstants = sliderConstants, exports.supportsDarkMode = function(theme) {
24499
23817
  var _context;
24500
23818
  return "dark" === theme.palette?.mode || !0 === theme.supportsDarkMode || Boolean((null == (_context = theme.a11y?.modes) ? void 0 : Function.call.bind(_includesInstanceProperty(_context), _context))?.("dark"));
24501
- }, exports.theme = theme, exports.themeToCSS =
23819
+ }, exports.theme = theme, exports.themePropertyToCSSVar = themePropertyToCSSVar,
23820
+ exports.themeToCSS =
24502
23821
  /**
24503
23822
  * Generate CSS string from theme
24504
23823
  */
@@ -24507,11 +23826,12 @@ function(theme, selector = ":root") {
24507
23826
  selector: selector,
24508
23827
  prefix: "atomix"
24509
23828
  });
24510
- }, exports.themeToDesignTokens = themeToDesignTokens, exports.types = types, exports.useAccordion = useAccordion,
24511
- exports.useAtomixGlass = useAtomixGlass, exports.useBadge = useBadge, exports.useBarChart = useBarChart,
24512
- exports.useBlock = useBlock, exports.useBreadcrumb = useBreadcrumb, exports.useButton = useButton,
24513
- exports.useCard = useCard, exports.useChartData = useChartData, exports.useChartInteraction = useChartInteraction,
24514
- exports.useChartScale = useChartScale, exports.useCheckbox = useCheckbox, exports.useComponentCustomization =
23829
+ }, exports.themeToDesignTokens = themeToDesignTokens, exports.types = types, exports.unregisterTheme = unregisterTheme,
23830
+ exports.useAccordion = useAccordion, exports.useAtomixGlass = useAtomixGlass, exports.useBadge = useBadge,
23831
+ exports.useBarChart = useBarChart, exports.useBlock = useBlock, exports.useBreadcrumb = useBreadcrumb,
23832
+ exports.useButton = useButton, exports.useCard = useCard, exports.useChartData = useChartData,
23833
+ exports.useChartInteraction = useChartInteraction, exports.useChartScale = useChartScale,
23834
+ exports.useCheckbox = useCheckbox, exports.useComponentCustomization =
24515
23835
  /**
24516
23836
  * Hook to merge theme overrides with component props
24517
23837
  *
@@ -24559,10 +23879,10 @@ function(component, props) {
24559
23879
  }
24560
23880
  /**
24561
23881
  * Hook to merge default props with provided props
24562
- */ , exports.useDataTable = useDataTable, exports.useEdgePanel = useEdgePanel,
24563
- exports.useForm = useForm, exports.useFormGroup = useFormGroup, exports.useGlassContainer = useGlassContainer,
24564
- exports.useHero = useHero, exports.useHistory = useHistory, exports.useInput = useInput,
24565
- exports.useLineChart = useLineChart, exports.useMergedProps = function(defaultProps, props) {
23882
+ */ , exports.useComponentTheme = useComponentTheme, exports.useDataTable = useDataTable,
23883
+ exports.useEdgePanel = useEdgePanel, exports.useForm = useForm, exports.useFormGroup = useFormGroup,
23884
+ exports.useGlassContainer = useGlassContainer, exports.useHero = useHero, exports.useHistory = useHistory,
23885
+ exports.useInput = useInput, exports.useLineChart = useLineChart, exports.useMergedProps = function(defaultProps, props) {
24566
23886
  return React.useMemo((() => ({
24567
23887
  ...defaultProps,
24568
23888
  ...props
@@ -24574,7 +23894,8 @@ exports.useSelect = useSelect, exports.useSideMenu = useSideMenu, exports.useSid
24574
23894
  exports.useSlider = useSlider, exports.useSlot = function(slot, props, fallback) {
24575
23895
  return React__default.default.useMemo((() => renderSlot(slot, props, fallback)), [ slot, props, fallback ]);
24576
23896
  }, exports.useSpinner = useSpinner, exports.useTextarea = useTextarea, exports.useTheme = useTheme,
24577
- exports.useTodo = useTodo, exports.utils = utils, exports.validateTheme = function(theme) {
23897
+ exports.useThemeTokens = useThemeTokens, exports.useTodo = useTodo, exports.utils = utils,
23898
+ exports.validateTheme = function(theme) {
24578
23899
  const errors = [];
24579
23900
  return theme.name || errors.push("Theme must have a name"), theme.palette || errors.push("Theme must have a palette"),
24580
23901
  theme.palette && !theme.palette.primary && errors.push("Theme palette must have a primary color"),