@shohojdhara/atomix 0.3.10 → 0.3.12

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 (47) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/dist/atomix.css +9 -6
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +9 -6
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/charts.js +82 -60
  7. package/dist/charts.js.map +1 -1
  8. package/dist/core.js +82 -60
  9. package/dist/core.js.map +1 -1
  10. package/dist/forms.js +82 -60
  11. package/dist/forms.js.map +1 -1
  12. package/dist/heavy.js +82 -60
  13. package/dist/heavy.js.map +1 -1
  14. package/dist/index.d.ts +11 -107
  15. package/dist/index.esm.js +165 -407
  16. package/dist/index.esm.js.map +1 -1
  17. package/dist/index.js +169 -412
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.min.js +1 -1
  20. package/dist/index.min.js.map +1 -1
  21. package/dist/theme.d.ts +1 -32
  22. package/dist/theme.js +12 -207
  23. package/dist/theme.js.map +1 -1
  24. package/package.json +1 -1
  25. package/src/components/AtomixGlass/AtomixGlass.tsx +124 -127
  26. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +28 -32
  27. package/src/components/AtomixGlass/GlassFilter.tsx +15 -4
  28. package/src/components/EdgePanel/EdgePanel.stories.tsx +2 -7
  29. package/src/components/EdgePanel/EdgePanel.tsx +0 -10
  30. package/src/components/Form/Radio.stories.tsx +235 -103
  31. package/src/components/Navigation/Nav/NavDropdown.tsx +8 -4
  32. package/src/components/Navigation/SideMenu/SideMenu.tsx +2 -22
  33. package/src/components/Navigation/SideMenu/SideMenuItem.tsx +11 -15
  34. package/src/lib/config/index.ts +5 -5
  35. package/src/lib/theme/config/index.ts +1 -1
  36. package/src/lib/theme/core/createTheme.ts +11 -40
  37. package/src/lib/theme/generators/index.ts +1 -4
  38. package/src/lib/theme/index.ts +4 -16
  39. package/src/lib/theme/runtime/ThemeProvider.tsx +1 -16
  40. package/src/lib/types/components.ts +2 -26
  41. package/src/styles/06-components/_components.edge-panel.scss +4 -4
  42. package/src/styles/06-components/_components.nav.scss +3 -0
  43. package/src/lib/config/loader.ts +0 -147
  44. package/src/lib/theme/config/__tests__/configLoader.test.ts +0 -207
  45. package/src/lib/theme/config/configLoader.ts +0 -113
  46. package/src/lib/theme/config/loader.ts +0 -293
  47. package/src/lib/theme/generators/cssFile.ts +0 -79
package/dist/index.js CHANGED
@@ -1715,7 +1715,6 @@ const {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS, calculateDistance = (pos1, pos2)
1715
1715
  inset: 0
1716
1716
  },
1717
1717
  "aria-hidden": "true",
1718
- suppressHydrationWarning: !0,
1719
1718
  children: jsxRuntime.jsxs("defs", {
1720
1719
  children: [ jsxRuntime.jsxs("radialGradient", {
1721
1720
  id: `${id}-edge-mask`,
@@ -1743,7 +1742,7 @@ const {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS, calculateDistance = (pos1, pos2)
1743
1742
  height: "170%",
1744
1743
  colorInterpolationFilters: "sRGB",
1745
1744
  children: [ jsxRuntime.jsx("feImage", {
1746
- id: "feimage",
1745
+ id: `${id}-image`,
1747
1746
  x: "0",
1748
1747
  y: "0",
1749
1748
  width: "100%",
@@ -1860,10 +1859,10 @@ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) =>
1860
1859
  height: 0
1861
1860
  }, onClick: onClick, mode: mode = "standard", effectiveDisableEffects: effectiveDisableEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", enableLiquidBlur: enableLiquidBlur = !1, elasticity: elasticity = 0, contentRef: contentRef}, ref) => {
1862
1861
  // Generate a stable, deterministic ID for SSR compatibility
1863
- // React's useId() should produce the same ID on server and client for the same
1864
- // component position in the tree. We use useState to ensure the ID is only
1865
- // generated once and remains stable across renders.
1866
- const baseId = React.useId(), [filterId] = React.useState((() => `atomix-glass-filter-${baseId.replace(/:/g, "-").replace(/^[^a-z]/i, "atomix-")}`)), [shaderMapUrl, setShaderMapUrl] = React.useState(""), shaderGeneratorRef = React.useRef(null), shaderUtilsRef = React.useRef(null), shaderDebounceTimeoutRef = React.useRef(null);
1862
+ // Use a counter-based approach to avoid hydration mismatches
1863
+ const [filterId] = React.useState((() =>
1864
+ // Use a simple counter for deterministic IDs
1865
+ "undefined" == typeof window ? `atomix-glass-filter-ssr-${Math.random().toString(36).substring(2, 11)}` : `atomix-glass-filter-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`)), [shaderMapUrl, setShaderMapUrl] = React.useState(""), shaderGeneratorRef = React.useRef(null), shaderUtilsRef = React.useRef(null), shaderDebounceTimeoutRef = React.useRef(null);
1867
1866
  // Lazy load shader utilities only when shader mode is needed
1868
1867
  React.useEffect((() => {
1869
1868
  "shader" === mode ?
@@ -1876,7 +1875,7 @@ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) =>
1876
1875
  fragmentShaders: shaderUtils.fragmentShaders
1877
1876
  };
1878
1877
  })).catch((error => {
1879
- console.warn("AtomixGlassContainer: Error loading shader utilities", error);
1878
+ console.warn("AtomixGlassContainer: Error loading shader utilities", String(error).replace(/[\r\n]/g, ""));
1880
1879
  })) :
1881
1880
  // Clear shader utils when not in shader mode to free memory
1882
1881
  shaderUtilsRef.current = null;
@@ -2066,7 +2065,6 @@ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) =>
2066
2065
  shaderMapUrl: shaderMapUrl
2067
2066
  }), jsxRuntime.jsx("div", {
2068
2067
  className: ATOMIX_GLASS.FILTER_OVERLAY_CLASS,
2069
- suppressHydrationWarning: !0,
2070
2068
  style: {
2071
2069
  filter: `url(#${filterId})`,
2072
2070
  backdropFilter: "var(--atomix-glass-container-backdrop)",
@@ -2694,38 +2692,80 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2694
2692
  }, adjustedSize = {
2695
2693
  width: "fixed" !== style.position ? "100%" : style.width ? style.width : Math.max(glassSize.width, 0),
2696
2694
  height: "fixed" !== style.position ? "100%" : style.height ? style.height : Math.max(glassSize.height, 0)
2697
- }, 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 = {
2698
- hover1: isHovered || isActive ? .5 : 0,
2699
- hover2: isActive ? .5 : 0,
2700
- hover3: isHovered ? .4 : isActive ? .8 : 0,
2701
- base: isOverLight ? overLightOpacity || .4 : 0,
2702
- over: isOverLight ? 1.1 * (overLightOpacity || .4) : 0
2703
- }, whiteColor = "255, 255, 255", glassVars = {
2704
- // Standard CSS custom properties for dynamic values
2705
- "--atomix-glass-radius": `${effectiveCornerRadius}px`,
2706
- "--atomix-glass-transform": transformStyle || "none",
2707
- "--atomix-glass-position": positionStyles.position,
2708
- "--atomix-glass-top": "fixed" !== positionStyles.top ? `${positionStyles.top}px` : "0",
2709
- "--atomix-glass-left": "fixed" !== positionStyles.left ? `${positionStyles.left}px` : "0",
2710
- "--atomix-glass-width": "fixed" !== style.position ? adjustedSize.width : `${adjustedSize.width}px`,
2711
- "--atomix-glass-height": "fixed" !== style.position ? adjustedSize.height : `${adjustedSize.height}px`,
2712
- // Border width: Use spacing token for consistency
2713
- "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
2714
- "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay",
2715
- // Dynamic gradients and backgrounds
2716
- "--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%)`,
2717
- "--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%)`,
2718
- "--atomix-glass-hover-1-opacity": opacityValues.hover1,
2719
- "--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}%)`,
2720
- "--atomix-glass-hover-2-opacity": opacityValues.hover2,
2721
- "--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}%)`,
2722
- "--atomix-glass-hover-3-opacity": opacityValues.hover3,
2723
- "--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}%)`,
2724
- "--atomix-glass-base-opacity": opacityValues.base,
2725
- "--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})`,
2726
- "--atomix-glass-overlay-opacity": opacityValues.over,
2727
- "--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})`
2728
- };
2695
+ }, gradientValues = React.useMemo((() => {
2696
+ const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT;
2697
+ return {
2698
+ borderGradientAngle: GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER,
2699
+ borderStop1: Math.max(GRADIENT.BORDER_STOP_1.MIN, GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER),
2700
+ borderStop2: Math.min(GRADIENT.BORDER_STOP_2.MAX, GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER),
2701
+ borderOpacities: [ GRADIENT.BORDER_OPACITY.BASE_1 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, GRADIENT.BORDER_OPACITY.BASE_2 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH, GRADIENT.BORDER_OPACITY.BASE_3 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, GRADIENT.BORDER_OPACITY.BASE_4 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH ],
2702
+ hoverPositions: {
2703
+ hover1: {
2704
+ x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
2705
+ y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1
2706
+ },
2707
+ hover2: {
2708
+ x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_2,
2709
+ y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_2
2710
+ },
2711
+ hover3: {
2712
+ x: GRADIENT.CENTER_POSITION + mx * GRADIENT.HOVER_POSITION.MULTIPLIER_3,
2713
+ y: GRADIENT.CENTER_POSITION + my * GRADIENT.HOVER_POSITION.MULTIPLIER_3
2714
+ }
2715
+ },
2716
+ basePosition: {
2717
+ x: GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER,
2718
+ y: GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER
2719
+ },
2720
+ mx: mx,
2721
+ my: my,
2722
+ absMx: absMx,
2723
+ absMy: absMy
2724
+ };
2725
+ }), [ mouseOffset.x, mouseOffset.y ]), opacityValues = React.useMemo((() => {
2726
+ const overLightOpacity = overLightConfig.opacity;
2727
+ return {
2728
+ hover1: isHovered || isActive ? .5 : 0,
2729
+ hover2: isActive ? .5 : 0,
2730
+ hover3: isHovered ? .4 : isActive ? .8 : 0,
2731
+ base: isOverLight ? overLightOpacity || .4 : 0,
2732
+ over: isOverLight ? 1.1 * (overLightOpacity || .4) : 0
2733
+ };
2734
+ }), [ isHovered, isActive, isOverLight, overLightConfig.opacity ]), glassVars = React.useMemo((() => {
2735
+ const whiteColor = "255, 255, 255", {borderGradientAngle: borderGradientAngle, borderStop1: borderStop1, borderStop2: borderStop2, borderOpacities: borderOpacities, hoverPositions: hoverPositions, basePosition: basePosition, mx: mx, my: my, absMx: absMx, absMy: absMy} = gradientValues;
2736
+ return {
2737
+ "--atomix-glass-radius": `${effectiveCornerRadius}px`,
2738
+ "--atomix-glass-transform": transformStyle || "none",
2739
+ "--atomix-glass-position": positionStyles.position,
2740
+ "--atomix-glass-top": "fixed" !== positionStyles.top ? `${positionStyles.top}px` : "0",
2741
+ "--atomix-glass-left": "fixed" !== positionStyles.left ? `${positionStyles.left}px` : "0",
2742
+ "--atomix-glass-width": "fixed" !== style.position ? adjustedSize.width : `${adjustedSize.width}px`,
2743
+ "--atomix-glass-height": "fixed" !== style.position ? adjustedSize.height : `${adjustedSize.height}px`,
2744
+ "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
2745
+ "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay",
2746
+ "--atomix-glass-border-gradient-1": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${borderOpacities[0]}) ${borderStop1}%, rgba(${whiteColor}, ${borderOpacities[1]}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
2747
+ "--atomix-glass-border-gradient-2": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${borderOpacities[2]}) ${borderStop1}%, rgba(${whiteColor}, ${borderOpacities[3]}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
2748
+ "--atomix-glass-hover-1-opacity": opacityValues.hover1,
2749
+ "--atomix-glass-hover-1-gradient": isOverLight ? `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, 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 ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_STOP}%)`,
2750
+ "--atomix-glass-hover-2-opacity": opacityValues.hover2,
2751
+ "--atomix-glass-hover-2-gradient": isOverLight ? `radial-gradient(circle at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, 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 ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_STOP}%)`,
2752
+ "--atomix-glass-hover-3-opacity": opacityValues.hover3,
2753
+ "--atomix-glass-hover-3-gradient": isOverLight ? `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, 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 ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_STOP}%)`,
2754
+ "--atomix-glass-base-opacity": opacityValues.base,
2755
+ "--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 + absMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`,
2756
+ "--atomix-glass-overlay-opacity": opacityValues.over,
2757
+ "--atomix-glass-overlay-gradient": isOverLight ? `radial-gradient(circle at ${basePosition.x}% ${basePosition.y}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + absMx * 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 + absMy * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`
2758
+ };
2759
+ }), [ gradientValues, opacityValues, effectiveCornerRadius, transformStyle, positionStyles, adjustedSize, style.position, isOverLight ]), renderBackgroundLayer = layerType => jsxRuntime.jsx("div", {
2760
+ className: [ ATOMIX_GLASS.BACKGROUND_LAYER_CLASS, "dark" === layerType ? ATOMIX_GLASS.BACKGROUND_LAYER_DARK_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_BLACK_CLASS, isOverLight ? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS ].filter(Boolean).join(" "),
2761
+ style: {
2762
+ ...positionStyles,
2763
+ height: adjustedSize.height,
2764
+ width: adjustedSize.width,
2765
+ borderRadius: `${effectiveCornerRadius}px`,
2766
+ transform: baseStyle.transform
2767
+ }
2768
+ });
2729
2769
  return jsxRuntime.jsxs("div", {
2730
2770
  className: componentClassName,
2731
2771
  style: glassVars,
@@ -2781,25 +2821,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2781
2821
  }), jsxRuntime.jsx("div", {
2782
2822
  className: ATOMIX_GLASS.HOVER_3_CLASS
2783
2823
  }) ]
2784
- }), jsxRuntime.jsx("div", {
2785
- className: [ ATOMIX_GLASS.BACKGROUND_LAYER_CLASS, ATOMIX_GLASS.BACKGROUND_LAYER_DARK_CLASS, isOverLight ? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS ].filter(Boolean).join(" "),
2786
- style: {
2787
- ...positionStyles,
2788
- height: adjustedSize.height,
2789
- width: adjustedSize.width,
2790
- borderRadius: `${effectiveCornerRadius}px`,
2791
- transform: baseStyle.transform
2792
- }
2793
- }), jsxRuntime.jsx("div", {
2794
- className: [ ATOMIX_GLASS.BACKGROUND_LAYER_CLASS, ATOMIX_GLASS.BACKGROUND_LAYER_BLACK_CLASS, isOverLight ? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS ].filter(Boolean).join(" "),
2795
- style: {
2796
- ...positionStyles,
2797
- height: adjustedSize.height,
2798
- width: adjustedSize.width,
2799
- borderRadius: `${effectiveCornerRadius}px`,
2800
- transform: baseStyle.transform
2801
- }
2802
- }), shouldRenderOverLightLayers && jsxRuntime.jsxs(jsxRuntime.Fragment, {
2824
+ }), renderBackgroundLayer("dark"), renderBackgroundLayer("black"), shouldRenderOverLightLayers && jsxRuntime.jsxs(jsxRuntime.Fragment, {
2803
2825
  children: [ jsxRuntime.jsx("div", {
2804
2826
  className: ATOMIX_GLASS.BASE_LAYER_CLASS
2805
2827
  }), jsxRuntime.jsx("div", {
@@ -10831,16 +10853,6 @@ const EdgePanel = ({title: title, children: children, position: position = "star
10831
10853
  className: "c-edge-panel__container",
10832
10854
  children: glass ? jsxRuntime.jsx(AtomixGlass, {
10833
10855
  ...glassProps,
10834
- className: "c-edge-panel__glass-wrapper",
10835
- style: {
10836
- position: "fixed",
10837
- width: glassContentRef.current?.offsetWidth,
10838
- height: glassContentRef.current?.offsetHeight,
10839
- top: containerRef.current?.offsetTop,
10840
- left: containerRef.current?.offsetLeft,
10841
- bottom: containerRef.current?.style.bottom,
10842
- right: containerRef.current?.style.right
10843
- },
10844
10856
  children: jsxRuntime.jsx("div", {
10845
10857
  ref: glassContentRef,
10846
10858
  className: "c-edge-panel__glass-content",
@@ -14432,7 +14444,13 @@ SideMenuList.displayName = "SideMenuList";
14432
14444
  * Click me
14433
14445
  * </SideMenuItem>
14434
14446
  *
14435
- * // With icon
14447
+ * // With icon and custom link component
14448
+ * import Link from 'next/link';
14449
+ * <SideMenuItem href="/settings" icon={<Icon name="Settings" />} LinkComponent={Link}>
14450
+ * Settings
14451
+ * </SideMenuItem>
14452
+ *
14453
+ * // With icon and custom link component
14436
14454
  * <SideMenuItem href="/settings" icon={<Icon name="Settings" />}>
14437
14455
  * Settings
14438
14456
  * </SideMenuItem>
@@ -14444,17 +14462,15 @@ SideMenuList.displayName = "SideMenuList";
14444
14462
  * ```
14445
14463
  */
14446
14464
  const SideMenuItem = React.forwardRef((({children: children, href: href, onClick: onClick, active: active = !1, disabled: disabled = !1, icon: icon, className: className = "", target: target, rel: rel, LinkComponent: LinkComponentProp}, ref) => {
14447
- const {LinkComponent: LinkComponentFromContext} = useSideMenuContext(), LinkComponent = LinkComponentProp ?? LinkComponentFromContext, {generateSideMenuItemClass: generateSideMenuItemClass, handleClick: handleClick} = useSideMenuItem({
14465
+ const {generateSideMenuItemClass: generateSideMenuItemClass, handleClick: handleClick} = useSideMenuItem({
14448
14466
  active: active,
14449
14467
  disabled: disabled,
14450
14468
  className: className
14451
14469
  }), itemClass = generateSideMenuItemClass();
14452
- // Use LinkComponent from props first, then fall back to context
14453
- // Render as link if href is provided
14470
+ // Render as link if href is provided
14454
14471
  if (href) {
14455
- // When using a custom LinkComponent (e.g., Next.js Link, React Router Link)
14456
- if (LinkComponent) {
14457
- const Component = LinkComponent, linkProps = {
14472
+ if (LinkComponentProp) {
14473
+ const LinkComp = LinkComponentProp, linkProps = {
14458
14474
  ref: ref,
14459
14475
  className: itemClass,
14460
14476
  onClick: disabled ? e => {
@@ -14465,16 +14481,12 @@ const SideMenuItem = React.forwardRef((({children: children, href: href, onClic
14465
14481
  target: target,
14466
14482
  rel: rel,
14467
14483
  tabIndex: disabled ? -1 : 0,
14468
- // Support both Next.js (href) and React Router (to) Link components
14469
- // Pass both props - the Link component will use whichever it needs
14470
14484
  ...disabled ? {} : {
14471
14485
  href: href,
14472
14486
  to: href
14473
14487
  }
14474
14488
  };
14475
- // Build link props - support both 'href' (Next.js) and 'to' (React Router)
14476
- // The Link component will use whichever prop it needs
14477
- return jsxRuntime.jsxs(Component, {
14489
+ return jsxRuntime.jsxs(LinkComp, {
14478
14490
  ...linkProps,
14479
14491
  children: [ icon && jsxRuntime.jsx("span", {
14480
14492
  className: "c-side-menu__link-icon",
@@ -14529,8 +14541,6 @@ const SideMenuItem = React.forwardRef((({children: children, href: href, onClic
14529
14541
 
14530
14542
  SideMenuItem.displayName = "SideMenuItem";
14531
14543
 
14532
- // Context for passing LinkComponent to SideMenuItem children
14533
- const SideMenuContext = React.createContext({}), useSideMenuContext = () => React.useContext(SideMenuContext)
14534
14544
  /**
14535
14545
  * SideMenu component provides a collapsible navigation menu with title and menu items.
14536
14546
  * Automatically collapses on mobile devices and can be toggled via a header button.
@@ -14545,7 +14555,8 @@ const SideMenuContext = React.createContext({}), useSideMenuContext = () => Rea
14545
14555
  * </SideMenuList>
14546
14556
  * </SideMenu>
14547
14557
  * ```
14548
- */ , SideMenu = React.forwardRef((({title: title, children: children, menuItems: menuItems = [], isOpen: isOpen, onToggle: onToggle, collapsible: collapsible = !0, collapsibleDesktop: collapsibleDesktop = !1, defaultCollapsedDesktop: defaultCollapsedDesktop = !1, className: className = "", style: style, disabled: disabled = !1, toggleIcon: toggleIcon, id: id, glass: glass, LinkComponent: LinkComponent}, ref) => {
14558
+ */
14559
+ const SideMenu = React.forwardRef((({title: title, children: children, menuItems: menuItems = [], isOpen: isOpen, onToggle: onToggle, collapsible: collapsible = !0, collapsibleDesktop: collapsibleDesktop = !1, defaultCollapsedDesktop: defaultCollapsedDesktop = !1, className: className = "", style: style, disabled: disabled = !1, toggleIcon: toggleIcon, id: id, glass: glass, LinkComponent: LinkComponent}, ref) => {
14549
14560
  const {isOpenState: isOpenState, wrapperRef: wrapperRef, innerRef: innerRef, sideMenuRef: sideMenuRef, generateSideMenuClass: generateSideMenuClass, generateWrapperClass: generateWrapperClass, handleToggle: handleToggle} = useSideMenu({
14550
14561
  isOpen: isOpen,
14551
14562
  onToggle: onToggle,
@@ -14650,68 +14661,63 @@ const SideMenuContext = React.createContext({}), useSideMenuContext = () => Rea
14650
14661
  className: wrapperClass,
14651
14662
  id: id ? `${id}-content` : void 0,
14652
14663
  "aria-hidden": !!shouldShowToggler && !isOpenState,
14653
- children: jsxRuntime.jsx(SideMenuContext.Provider, {
14654
- value: {
14655
- LinkComponent: LinkComponent
14656
- },
14657
- children: jsxRuntime.jsxs("div", {
14658
- ref: innerRef,
14659
- className: "c-side-menu__inner",
14660
- children: [ children, menuItems?.map(((item, index) => {
14661
- const isNestedItemOpen = nestedItemStates[index] ?? !0, hasItems = item.items && item.items.length > 0, canToggle = hasItems && !disabled, handleNestedToggle = () => {
14662
- canToggle && setNestedItemStates((prev => ({
14663
- ...prev,
14664
- [index]: !prev[index]
14665
- })));
14666
- };
14667
- return jsxRuntime.jsxs("div", {
14668
- className: "c-side-menu__item",
14669
- children: [ item.title && jsxRuntime.jsxs("div", {
14670
- className: [ "c-side-menu__toggler", canToggle && "c-side-menu__toggler--nested", isNestedItemOpen && "is-open" ].filter(Boolean).join(" "),
14671
- onClick: canToggle ? handleNestedToggle : void 0,
14672
- role: canToggle ? "button" : void 0,
14673
- tabIndex: canToggle && !disabled ? 0 : void 0,
14674
- "aria-expanded": canToggle ? isNestedItemOpen : void 0,
14675
- "aria-disabled": disabled,
14676
- onKeyDown: canToggle ? e => {
14677
- "Enter" !== e.key && " " !== e.key || disabled || (e.preventDefault(), handleNestedToggle());
14678
- } : void 0,
14679
- children: [ jsxRuntime.jsx("span", {
14680
- className: "c-side-menu__title",
14681
- children: item.title
14682
- }), canToggle && jsxRuntime.jsx("span", {
14683
- className: "c-side-menu__toggler-icon",
14684
- children: item.toggleIcon || jsxRuntime.jsx(Icon, {
14685
- name: "CaretRight",
14686
- size: "xs"
14687
- })
14688
- }) ]
14689
- }), hasItems && jsxRuntime.jsx("div", {
14664
+ children: jsxRuntime.jsxs("div", {
14665
+ ref: innerRef,
14666
+ className: "c-side-menu__inner",
14667
+ children: [ children, menuItems?.map(((item, index) => {
14668
+ const isNestedItemOpen = nestedItemStates[index] ?? !0, hasItems = item.items && item.items.length > 0, canToggle = hasItems && !disabled, handleNestedToggle = () => {
14669
+ canToggle && setNestedItemStates((prev => ({
14670
+ ...prev,
14671
+ [index]: !prev[index]
14672
+ })));
14673
+ };
14674
+ return jsxRuntime.jsxs("div", {
14675
+ className: "c-side-menu__item",
14676
+ children: [ item.title && jsxRuntime.jsxs("div", {
14677
+ className: [ "c-side-menu__toggler", canToggle && "c-side-menu__toggler--nested", isNestedItemOpen && "is-open" ].filter(Boolean).join(" "),
14678
+ onClick: canToggle ? handleNestedToggle : void 0,
14679
+ role: canToggle ? "button" : void 0,
14680
+ tabIndex: canToggle && !disabled ? 0 : void 0,
14681
+ "aria-expanded": canToggle ? isNestedItemOpen : void 0,
14682
+ "aria-disabled": disabled,
14683
+ onKeyDown: canToggle ? e => {
14684
+ "Enter" !== e.key && " " !== e.key || disabled || (e.preventDefault(), handleNestedToggle());
14685
+ } : void 0,
14686
+ children: [ jsxRuntime.jsx("span", {
14687
+ className: "c-side-menu__title",
14688
+ children: item.title
14689
+ }), canToggle && jsxRuntime.jsx("span", {
14690
+ className: "c-side-menu__toggler-icon",
14691
+ children: item.toggleIcon || jsxRuntime.jsx(Icon, {
14692
+ name: "CaretRight",
14693
+ size: "xs"
14694
+ })
14695
+ }) ]
14696
+ }), hasItems && jsxRuntime.jsx("div", {
14697
+ ref: node => {
14698
+ nestedWrapperRefs.current[index] = node;
14699
+ },
14700
+ className: "c-side-menu__nested-wrapper",
14701
+ children: jsxRuntime.jsx("div", {
14690
14702
  ref: node => {
14691
- nestedWrapperRefs.current[index] = node;
14703
+ nestedInnerRefs.current[index] = node;
14692
14704
  },
14693
- className: "c-side-menu__nested-wrapper",
14694
- children: jsxRuntime.jsx("div", {
14695
- ref: node => {
14696
- nestedInnerRefs.current[index] = node;
14697
- },
14698
- className: "c-side-menu__nested-inner",
14699
- children: jsxRuntime.jsx(SideMenuList, {
14700
- children: item.items?.map(((subItem, subIndex) => jsxRuntime.jsx(SideMenuItem, {
14701
- href: subItem.href,
14702
- onClick: subItem.onClick,
14703
- active: subItem.active,
14704
- disabled: subItem.disabled,
14705
- icon: subItem.icon,
14706
- LinkComponent: LinkComponent,
14707
- children: subItem.title
14708
- }, subIndex)))
14709
- })
14705
+ className: "c-side-menu__nested-inner",
14706
+ children: jsxRuntime.jsx(SideMenuList, {
14707
+ children: item.items?.map(((subItem, subIndex) => jsxRuntime.jsx(SideMenuItem, {
14708
+ href: subItem.href,
14709
+ onClick: subItem.onClick,
14710
+ active: subItem.active,
14711
+ disabled: subItem.disabled,
14712
+ icon: subItem.icon,
14713
+ LinkComponent: LinkComponent,
14714
+ children: subItem.title
14715
+ }, subIndex)))
14710
14716
  })
14711
- }) ]
14712
- }, index);
14713
- })) ]
14714
- })
14717
+ })
14718
+ }) ]
14719
+ }, index);
14720
+ })) ]
14715
14721
  })
14716
14722
  }) ]
14717
14723
  });
@@ -14745,7 +14751,6 @@ const SideMenuContext = React.createContext({}), useSideMenuContext = () => Rea
14745
14751
  });
14746
14752
  }));
14747
14753
 
14748
- // Hook to use SideMenu context
14749
14754
  SideMenu.displayName = "SideMenu";
14750
14755
 
14751
14756
  const Menu = React.forwardRef((({children: children, className: className = "", style: style, disabled: disabled = !1}, ref) => jsxRuntime.jsx("div", {
@@ -14947,14 +14952,13 @@ const NavDropdown = React.forwardRef((({title: title, children: children, align
14947
14952
  size: "sm",
14948
14953
  className: "c-nav__icon"
14949
14954
  }) ]
14950
- }), menuContent = jsxRuntime.jsx("div", {
14955
+ }), MenuTag = megaMenu ? "div" : "ul", menuContent = jsxRuntime.jsx(MenuTag, {
14951
14956
  className: dropdownMenuClass,
14952
14957
  ref: dropdownRef,
14953
14958
  "aria-hidden": !isActive,
14954
14959
  children: children
14955
14960
  });
14956
- // Create the dropdown/mega menu content
14957
- return jsxRuntime.jsxs(NavItem, {
14961
+ return jsxRuntime.jsxs(NavItem, {
14958
14962
  dropdown: !megaMenu,
14959
14963
  megaMenu: megaMenu,
14960
14964
  disabled: disabled,
@@ -19337,39 +19341,13 @@ class ThemeLogger {
19337
19341
  tokens = input;
19338
19342
  }
19339
19343
  // Merge with defaults and generate CSS
19340
- else {
19341
- // Check if we're in a browser environment
19342
- if ("undefined" != typeof window) throw new ThemeError("No input provided and config loading is not available in browser environment. Please provide tokens explicitly or use Node.js/SSR environment.", ThemeErrorCode.CONFIG_LOAD_FAILED, {
19343
- environment: "browser"
19344
- });
19345
- // Load from config when no input provided
19346
- let loadThemeFromConfigSync, loadAtomixConfig;
19347
- try {
19348
- const configLoaderModule = require("../config/configLoader"), loaderModule = require("../../config/loader");
19349
- // Get prefix from config if needed
19350
- if (loadThemeFromConfigSync = configLoaderModule.loadThemeFromConfigSync, loadAtomixConfig = loaderModule.loadAtomixConfig,
19351
- tokens = loadThemeFromConfigSync(), !options?.prefix) try {
19352
- const config = loadAtomixConfig({
19353
- configPath: "atomix.config.ts",
19354
- required: !1
19355
- });
19356
- options = {
19357
- ...options,
19358
- prefix: config?.prefix || "atomix"
19359
- };
19360
- } catch (error) {
19361
- // If config loading fails, use default prefix
19362
- options = {
19363
- ...options,
19364
- prefix: "atomix"
19365
- };
19366
- }
19367
- } catch (error) {
19368
- throw new ThemeError("No input provided and config loading is not available in this environment. Please provide tokens explicitly.", ThemeErrorCode.CONFIG_LOAD_FAILED, {
19369
- error: error instanceof Error ? error.message : String(error)
19370
- });
19371
- }
19372
- }
19344
+ else
19345
+ // Auto-loading config from file system is removed for browser compatibility.
19346
+ // If no input is provided, we return an empty theme (using defaults only) or user must provide tokens.
19347
+ // This allows createTheme to be isomorphic.
19348
+ // Warn in development if no input provided
19349
+ "production" !== process.env.NODE_ENV && "undefined" != typeof window && console.warn("Atomix: createTheme() called without tokens. Using default tokens only."),
19350
+ tokens = {};
19373
19351
  const allTokens = createTokens(tokens), prefix = options?.prefix ?? "atomix";
19374
19352
  // Get prefix from options or use default
19375
19353
  return generateCSSVariables$1(allTokens, {
@@ -19600,24 +19578,12 @@ class ThemeLogger {
19600
19578
  }
19601
19579
 
19602
19580
  /**
19603
- * CSS File Utilities
19581
+ * Theme System Constants
19604
19582
  *
19605
- * Save CSS to file system (Node.js only).
19583
+ * Centralized constants for the theme system to avoid magic numbers and strings.
19606
19584
  */
19607
19585
  /**
19608
- * Save CSS to file
19609
- *
19610
- * Writes CSS string to a file. Only works in Node.js environment.
19611
- *
19612
- * @param css - CSS string to save
19613
- * @param filePath - Output file path
19614
- * @throws Error if called in browser environment
19615
- *
19616
- * @example
19617
- * ```typescript
19618
- * const css = ':root { --atomix-color-primary: #7AFFD7; }';
19619
- * await saveCSSFile(css, './themes/custom.css');
19620
- * ```
19586
+ * Default storage key for theme persistence
19621
19587
  */ "undefined" != typeof process && process.env;
19622
19588
 
19623
19589
  /**
@@ -20392,141 +20358,6 @@ function generateClassName(block, element, modifiers) {
20392
20358
  return property => getComponentThemeValue(component, property, variant, size);
20393
20359
  }
20394
20360
 
20395
- /**
20396
- * Atomix Config Loader
20397
- *
20398
- * Helper functions to load atomix.config.ts from external projects.
20399
- * Similar to how Tailwind loads tailwind.config.js
20400
- */
20401
- /**
20402
- * Load Atomix configuration from project root
20403
- *
20404
- * Attempts to load atomix.config.ts from the current working directory.
20405
- * Falls back to default config if file doesn't exist.
20406
- *
20407
- * @param options - Loader options
20408
- * @returns Loaded configuration or default
20409
- *
20410
- * @example
20411
- * ```typescript
20412
- * import { loadAtomixConfig } from '@shohojdhara/atomix/config';
20413
- * import { createTheme } from '@shohojdhara/atomix/theme';
20414
- *
20415
- * const config = loadAtomixConfig();
20416
- * const theme = createTheme(config.theme?.tokens || {});
20417
- * ```
20418
- */ function loadAtomixConfig(options = {}) {
20419
- const {configPath: configPath = "atomix.config.ts", required: required = !1} = options, defaultConfig = {
20420
- prefix: "atomix",
20421
- theme: {
20422
- extend: {}
20423
- }
20424
- };
20425
- // Default config
20426
- // In browser environments, config loading is not supported
20427
- if ("undefined" != typeof window) {
20428
- if (required) throw new Error("loadAtomixConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.");
20429
- return defaultConfig;
20430
- }
20431
- // Try to load config file
20432
- try {
20433
- // Use dynamic import for ESM compatibility
20434
- const configModule = require(configPath), config = configModule.default || configModule;
20435
- // Validate it's an AtomixConfig
20436
- if (config && "object" == typeof config) return config;
20437
- throw new Error("Invalid config format");
20438
- } catch (error) {
20439
- if (required) throw new Error(`Failed to load config from ${configPath}: ${error.message}`);
20440
- // Return default config if not required
20441
- return defaultConfig;
20442
- }
20443
- }
20444
-
20445
- /**
20446
- * Resolve config path
20447
- *
20448
- * Finds atomix.config.ts in the project, checking common locations.
20449
- * Returns null in browser environments where file system access is not available.
20450
- *
20451
- * This function is designed to work in Node.js environments only.
20452
- * In browser builds, it will always return null without attempting to access Node.js modules.
20453
- *
20454
- * @internal This function uses Node.js modules and should not be called in browser environments.
20455
- */
20456
- /**
20457
- * Theme Configuration Loader
20458
- *
20459
- * Provides functions to load theme configurations from atomix.config.ts
20460
- * Includes both sync and async versions, with automatic fallbacks
20461
- */
20462
- /**
20463
- * Load theme from config file (synchronous, Node.js only)
20464
- * @param configPath - Path to config file (default: atomix.config.ts)
20465
- * @returns DesignTokens from theme configuration
20466
- * @throws Error if config loading is not available in browser environment
20467
- */
20468
- function loadThemeFromConfigSync(options) {
20469
- // Check if we're in a browser environment
20470
- if ("undefined" != typeof window) throw new Error("loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.");
20471
- // Use static import - the function handles browser environment checks internally
20472
- let config;
20473
- try {
20474
- config = loadAtomixConfig({
20475
- configPath: options?.configPath || "atomix.config.ts",
20476
- required: !1 !== options?.required
20477
- });
20478
- } catch (error) {
20479
- if (!1 !== options?.required) throw new Error("Config loader module not available");
20480
- // Return empty tokens if config is not required
20481
- return createTokens({});
20482
- }
20483
- if (!config?.theme) return createTokens({});
20484
- // Extract tokens from config.theme structure
20485
- // config.theme can have: { extend?: ThemeTokens, tokens?: ThemeTokens, themes?: ... }
20486
- // We need to extract the actual DesignTokens (flat structure)
20487
- const themeConfig = config.theme;
20488
- // Check if theme is directly a flat object (DesignTokens format)
20489
- // This handles the case where config.theme might be passed as DesignTokens directly
20490
- return createTokens(!themeConfig || "object" != typeof themeConfig || "extend" in themeConfig || "tokens" in themeConfig || "themes" in themeConfig ? {} : themeConfig);
20491
- // If theme has nested structure (extend/tokens/themes), we can't directly use it
20492
- // Return empty tokens - the theme system will use defaults
20493
- // TODO: Add proper conversion from ThemeTokens to DesignTokens if needed
20494
- }
20495
-
20496
- /**
20497
- * Load theme from config file (asynchronous)
20498
- * @param configPath - Path to config file (default: atomix.config.ts)
20499
- * @returns Promise resolving to DesignTokens from theme configuration
20500
- */ async function loadThemeFromConfig(options) {
20501
- // Check if we're in a browser environment
20502
- if ("undefined" != typeof window) throw new Error("loadThemeFromConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.");
20503
- // Use static import with runtime check
20504
- // The function will handle browser environment checks internally
20505
- let config;
20506
- try {
20507
- // loadAtomixConfig is synchronous, not async
20508
- config = loadAtomixConfig({
20509
- configPath: options?.configPath || "atomix.config.ts",
20510
- required: !1 !== options?.required
20511
- });
20512
- } catch (error) {
20513
- if (!1 !== options?.required) throw new Error("Config loader module not available");
20514
- // Return empty tokens if config is not required
20515
- return createTokens({});
20516
- }
20517
- if (!config?.theme) return createTokens({});
20518
- // Extract tokens from config.theme structure
20519
- // config.theme can have: { extend?: ThemeTokens, tokens?: ThemeTokens, themes?: ... }
20520
- // We need to extract the actual DesignTokens (flat structure)
20521
- const themeConfig = config.theme;
20522
- // Check if theme is directly a flat object (DesignTokens format)
20523
- // This handles the case where config.theme might be passed as DesignTokens directly
20524
- return createTokens(!themeConfig || "object" != typeof themeConfig || "extend" in themeConfig || "tokens" in themeConfig || "themes" in themeConfig ? {} : themeConfig);
20525
- // If theme has nested structure (extend/tokens/themes), we can't directly use it
20526
- // Return empty tokens - the theme system will use defaults
20527
- // TODO: Add proper conversion from ThemeTokens to DesignTokens if needed
20528
- }
20529
-
20530
20361
  /**
20531
20362
  * Theme Context
20532
20363
  *
@@ -20568,21 +20399,9 @@ const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes:
20568
20399
  if (stored) return stored;
20569
20400
  }
20570
20401
  // If defaultTheme is provided, use it
20571
- if (null != defaultTheme) return defaultTheme;
20572
- // Try to load from atomix.config.ts as fallback, but only in Node.js/SSR environments
20573
- if ("undefined" == typeof window) try {
20574
- // Dynamically import the config loader to avoid bundling issues in browser
20575
- // eslint-disable-next-line @typescript-eslint/no-var-requires
20576
- const {loadThemeFromConfigSync: loadThemeFromConfigSync} = require("../config/configLoader"), configTokens = loadThemeFromConfigSync();
20577
- if (configTokens && Object.keys(configTokens).length > 0)
20578
- // For simplicity, we'll treat config tokens as a special theme name
20579
- return "config-theme";
20580
- } catch (error) {
20581
- // Failed to load theme from config, using default
20582
- }
20402
+ return null != defaultTheme ? defaultTheme : "default";
20583
20403
  // Default fallback
20584
- return "default";
20585
- }), [ defaultTheme, enablePersistence, storageKey ]), [currentTheme, setCurrentTheme] = React.useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : "tokens-theme")), [activeTokens, setActiveTokens] = React.useState((() =>
20404
+ }), [ defaultTheme, enablePersistence, storageKey ]), [currentTheme, setCurrentTheme] = React.useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : "tokens-theme")), [activeTokens, setActiveTokens] = React.useState((() =>
20586
20405
  // If defaultTheme is DesignTokens, store them
20587
20406
  defaultTheme && "string" != typeof defaultTheme ? createTokens(defaultTheme) : null)), [isLoading, setIsLoading] = React.useState(!1), [error, setError] = React.useState(null), loadedThemesRef = React.useRef(new Set), themePromisesRef = React.useRef({}), abortControllerRef = React.useRef(null);
20588
20407
  // Handle initial DesignTokens defaultTheme
@@ -23577,6 +23396,7 @@ class RTLManager {
23577
23396
  // Core Theme Functions
23578
23397
  // ============================================================================
23579
23398
  // Create theme CSS from DesignTokens
23399
+ // File saving utilities removed to prevent bundling Node.js modules in browser
23580
23400
  /**
23581
23401
  * Inject theme CSS into DOM
23582
23402
  */ function injectTheme(css, id = "atomix-theme") {
@@ -23589,30 +23409,6 @@ class RTLManager {
23589
23409
  removeCSS(id);
23590
23410
  }
23591
23411
 
23592
- /**
23593
- * Save theme to CSS file
23594
- */ async function saveTheme(css, filePath) {
23595
- await async function(css, filePath) {
23596
- // Check if in browser environment
23597
- if ("undefined" != typeof window) throw new Error("saveCSSFile can only be used in Node.js environment. Use injectCSS() for browser environments.");
23598
- // Dynamic import to avoid bundling Node.js modules in browser builds
23599
- const fs = await import("fs/promises"), dir = (await import("path")).dirname(filePath);
23600
- await fs.mkdir(dir, {
23601
- recursive: !0
23602
- }),
23603
- // Write file
23604
- await fs.writeFile(filePath, css, "utf8");
23605
- }
23606
- /**
23607
- * Theme System Constants
23608
- *
23609
- * Centralized constants for the theme system to avoid magic numbers and strings.
23610
- */
23611
- /**
23612
- * Default storage key for theme persistence
23613
- */ (css, filePath);
23614
- }
23615
-
23616
23412
  /**
23617
23413
  * CSS Variables Constants
23618
23414
  *
@@ -23989,8 +23785,6 @@ const composables = composablesImport, utils = utilsImport, types = typesImport,
23989
23785
  isCSSInjected: isCSSInjected,
23990
23786
  isDesignTokens: isDesignTokens,
23991
23787
  isValidCSSVariableName: isValidCSSVariableName,
23992
- loadThemeFromConfig: loadThemeFromConfig,
23993
- loadThemeFromConfigSync: loadThemeFromConfigSync,
23994
23788
  mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
23995
23789
  mergeCSSVars: mergeCSSVars,
23996
23790
  mergeTheme: mergeTheme,
@@ -23999,7 +23793,6 @@ const composables = composablesImport, utils = utilsImport, types = typesImport,
23999
23793
  removeCSS: removeCSS,
24000
23794
  removeCSSVariables: removeCSSVariables,
24001
23795
  removeTheme: removeTheme,
24002
- saveTheme: saveTheme,
24003
23796
  themePropertyToCSSVar: themePropertyToCSSVar,
24004
23797
  unregisterTheme: unregisterTheme,
24005
23798
  useComponentTheme: useComponentTheme,
@@ -24265,11 +24058,9 @@ exports.isDesignTokens = isDesignTokens, exports.isSlot = function(value) {
24265
24058
  * Merge multiple slot configurations
24266
24059
  * Later slots override earlier ones
24267
24060
  */ , exports.isValidCSSVariableName = isValidCSSVariableName, exports.isYouTubeUrl = isYouTubeUrl,
24268
- exports.loadAtomixConfig = loadAtomixConfig, exports.loadThemeFromConfig = loadThemeFromConfig,
24269
- exports.loadThemeFromConfigSync = loadThemeFromConfigSync, exports.mapSCSSTokensToCSSVars = mapSCSSTokensToCSSVars,
24270
- exports.mergeCSSVars = mergeCSSVars, exports.mergeClassNames = mergeClassNames,
24271
- exports.mergeComponentProps = mergeComponentProps, exports.mergePartStyles = mergePartStyles,
24272
- exports.mergeSlots = function(...slots) {
24061
+ exports.mapSCSSTokensToCSSVars = mapSCSSTokensToCSSVars, exports.mergeCSSVars = mergeCSSVars,
24062
+ exports.mergeClassNames = mergeClassNames, exports.mergeComponentProps = mergeComponentProps,
24063
+ exports.mergePartStyles = mergePartStyles, exports.mergeSlots = function(...slots) {
24273
24064
  const filtered = slots.filter((s => void 0 !== s));
24274
24065
  if (0 !== filtered.length) return 1 === filtered.length ? filtered[0] : _reduceInstanceProperty(filtered).call(filtered, ((acc, slot) => ({
24275
24066
  ...acc,
@@ -24293,42 +24084,8 @@ function(name, primaryColor, secondaryColor) {
24293
24084
  }
24294
24085
  });
24295
24086
  }, exports.registerTheme = registerTheme, exports.removeCSS = removeCSS, exports.removeCSSVariables = removeCSSVariables,
24296
- exports.removeTheme = removeTheme, exports.renderSlot = renderSlot, exports.resolveConfigPath = function() {
24297
- // Early return for browser environments - prevents any Node.js module access
24298
- // This check happens before any require() calls, preventing bundlers from analyzing them
24299
- if ("undefined" != typeof window || "undefined" == typeof process || !process.cwd) return null;
24300
- // Only attempt to load Node.js modules in Node.js runtime
24301
- // Use a lazy-loading pattern that prevents static analysis by bundlers
24302
- try {
24303
- // Create a function that only executes in Node.js runtime
24304
- // Use string-based module names to prevent static analysis by bundlers
24305
- const modules = (() => {
24306
- // These requires are only executed at runtime in Node.js environments
24307
- // They are marked as external in Rollup config and should not be bundled
24308
- // Using string concatenation and computed property access to prevent static analysis
24309
- if ("undefined" == typeof require) return null;
24310
- // Use a try-catch wrapper to safely access require
24311
- try {
24312
- // Build module names dynamically to prevent static analysis
24313
- const moduleNames = [ "fs", "path" ];
24314
- // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
24315
- return {
24316
- fs: require(moduleNames[0]),
24317
- path: require(moduleNames[1])
24318
- };
24319
- } catch {
24320
- return null;
24321
- }
24322
- })();
24323
- if (!modules) return null;
24324
- 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") ];
24325
- for (const configPath of possiblePaths) if (fs.existsSync(configPath)) return configPath;
24326
- } catch (error) {
24327
- // Silently fail in browser environments or when modules are unavailable
24328
- return null;
24329
- }
24330
- return null;
24331
- }, exports.saveTheme = saveTheme, exports.sliderConstants = sliderConstants, exports.supportsDarkMode = function(theme) {
24087
+ exports.removeTheme = removeTheme, exports.renderSlot = renderSlot, exports.sliderConstants = sliderConstants,
24088
+ exports.supportsDarkMode = function(theme) {
24332
24089
  var _context;
24333
24090
  return "dark" === theme.palette?.mode || !0 === theme.supportsDarkMode || Boolean((null == (_context = theme.a11y?.modes) ? void 0 : Function.call.bind(_includesInstanceProperty(_context), _context))?.("dark"));
24334
24091
  }, exports.theme = theme, exports.themePropertyToCSSVar = themePropertyToCSSVar,