@shohojdhara/atomix 0.3.5 → 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 (182) hide show
  1. package/README.md +101 -199
  2. package/atomix.config.ts +241 -0
  3. package/dist/atomix.css +260 -179
  4. package/dist/atomix.css.map +1 -1
  5. package/dist/atomix.min.css +250 -179
  6. package/dist/atomix.min.css.map +1 -1
  7. package/dist/charts.js +69 -166
  8. package/dist/charts.js.map +1 -1
  9. package/dist/core.js +184 -263
  10. package/dist/core.js.map +1 -1
  11. package/dist/forms.js +55 -131
  12. package/dist/forms.js.map +1 -1
  13. package/dist/heavy.js +184 -263
  14. package/dist/heavy.js.map +1 -1
  15. package/dist/index.d.ts +1831 -1657
  16. package/dist/index.esm.js +4497 -4318
  17. package/dist/index.esm.js.map +1 -1
  18. package/dist/index.js +4510 -4328
  19. package/dist/index.js.map +1 -1
  20. package/dist/index.min.js +1 -1
  21. package/dist/index.min.js.map +1 -1
  22. package/dist/theme.d.ts +1431 -1472
  23. package/dist/theme.js +4175 -4138
  24. package/dist/theme.js.map +1 -1
  25. package/package.json +6 -20
  26. package/src/components/Accordion/Accordion.stories.tsx +50 -17
  27. package/src/components/AtomixGlass/AtomixGlass.tsx +128 -322
  28. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +12 -5
  29. package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +1 -32
  30. package/src/components/AtomixGlass/stories/Examples.stories.tsx +2 -2
  31. package/src/components/AtomixGlass/stories/shared-components.tsx +0 -31
  32. package/src/components/Avatar/Avatar.stories.tsx +7 -0
  33. package/src/components/Badge/Badge.stories.tsx +91 -13
  34. package/src/components/Block/Block.stories.tsx +7 -23
  35. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +7 -0
  36. package/src/components/Button/Button.stories.tsx +141 -22
  37. package/src/components/Button/Button.tsx +85 -167
  38. package/src/components/Button/ButtonGroup.stories.tsx +315 -0
  39. package/src/components/Button/ButtonGroup.tsx +67 -0
  40. package/src/components/Button/index.ts +2 -0
  41. package/src/components/Callout/Callout.stories.tsx +8 -6
  42. package/src/components/Card/Card.stories.tsx +82 -28
  43. package/src/components/Chart/AnimatedChart.tsx +0 -1
  44. package/src/components/Chart/AreaChart.tsx +0 -1
  45. package/src/components/Chart/BarChart.tsx +0 -1
  46. package/src/components/Chart/BubbleChart.tsx +0 -1
  47. package/src/components/Chart/CandlestickChart.tsx +0 -1
  48. package/src/components/Chart/Chart.stories.tsx +5 -7
  49. package/src/components/Chart/Chart.tsx +0 -16
  50. package/src/components/Chart/ChartRenderer.tsx +1 -1
  51. package/src/components/Chart/DonutChart.tsx +0 -1
  52. package/src/components/Chart/FunnelChart.tsx +0 -1
  53. package/src/components/Chart/GaugeChart.tsx +0 -1
  54. package/src/components/Chart/HeatmapChart.tsx +0 -1
  55. package/src/components/Chart/LineChart.tsx +0 -1
  56. package/src/components/Chart/MultiAxisChart.tsx +0 -1
  57. package/src/components/Chart/PieChart.tsx +0 -1
  58. package/src/components/Chart/RadarChart.tsx +0 -1
  59. package/src/components/Chart/ScatterChart.tsx +0 -1
  60. package/src/components/Chart/WaterfallChart.tsx +0 -1
  61. package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +7 -0
  62. package/src/components/DataTable/DataTable.stories.tsx +23 -16
  63. package/src/components/DatePicker/DatePicker.stories.tsx +27 -19
  64. package/src/components/Dropdown/Dropdown.stories.tsx +11 -19
  65. package/src/components/EdgePanel/EdgePanel.stories.tsx +1 -0
  66. package/src/components/Footer/Footer.stories.tsx +8 -6
  67. package/src/components/Footer/FooterLink.tsx +9 -2
  68. package/src/components/Form/Checkbox.stories.tsx +7 -0
  69. package/src/components/Form/Form.stories.tsx +7 -0
  70. package/src/components/Form/FormGroup.stories.tsx +9 -1
  71. package/src/components/Form/Input.stories.tsx +69 -16
  72. package/src/components/Form/Radio.stories.tsx +9 -1
  73. package/src/components/Form/Select.stories.tsx +9 -1
  74. package/src/components/Form/Textarea.stories.tsx +10 -2
  75. package/src/components/Hero/Hero.stories.tsx +7 -0
  76. package/src/components/List/List.stories.tsx +7 -0
  77. package/src/components/Messages/Messages.stories.tsx +8 -7
  78. package/src/components/Modal/Modal.stories.tsx +17 -6
  79. package/src/components/Navigation/Menu/Menu.stories.tsx +7 -0
  80. package/src/components/Navigation/Nav/Nav.stories.tsx +7 -0
  81. package/src/components/Navigation/Navbar/Navbar.stories.tsx +1 -0
  82. package/src/components/Navigation/SideMenu/SideMenu.stories.tsx +1 -1
  83. package/src/components/Pagination/Pagination.stories.tsx +188 -111
  84. package/src/components/Pagination/Pagination.tsx +83 -3
  85. package/src/components/PhotoViewer/PhotoViewer.stories.tsx +10 -5
  86. package/src/components/Popover/Popover.stories.tsx +191 -115
  87. package/src/components/ProductReview/ProductReview.stories.tsx +80 -58
  88. package/src/components/Progress/Progress.stories.tsx +79 -49
  89. package/src/components/Rating/Rating.stories.tsx +109 -84
  90. package/src/components/River/River.stories.tsx +194 -114
  91. package/src/components/SectionIntro/SectionIntro.stories.tsx +19 -9
  92. package/src/components/Slider/Slider.stories.tsx +7 -0
  93. package/src/components/Spinner/Spinner.stories.tsx +15 -11
  94. package/src/components/Steps/Steps.stories.tsx +132 -98
  95. package/src/components/Tabs/Tabs.stories.tsx +163 -112
  96. package/src/components/Testimonial/Testimonial.stories.tsx +114 -68
  97. package/src/components/Todo/Todo.stories.tsx +38 -12
  98. package/src/components/Toggle/Toggle.stories.tsx +61 -28
  99. package/src/components/Tooltip/Tooltip.stories.tsx +318 -200
  100. package/src/components/Upload/Upload.stories.tsx +122 -84
  101. package/src/components/VideoPlayer/VideoPlayer.stories.tsx +7 -24
  102. package/src/components/index.ts +1 -0
  103. package/src/lib/composables/useAtomixGlass.ts +9 -10
  104. package/src/lib/composables/useNavbar.ts +0 -10
  105. package/src/lib/config/loader.ts +4 -4
  106. package/src/lib/constants/components.ts +17 -0
  107. package/src/lib/hooks/useComponentCustomization.ts +1 -1
  108. package/src/lib/hooks/usePerformanceMonitor.ts +1 -1
  109. package/src/lib/hooks/useThemeTokens.ts +105 -0
  110. package/src/lib/theme/README.md +174 -0
  111. package/src/lib/theme/adapters/index.ts +31 -0
  112. package/src/lib/theme/adapters/themeAdapter.ts +287 -0
  113. package/src/lib/theme/config/__tests__/configLoader.test.ts +207 -0
  114. package/src/lib/theme/config/configLoader.ts +95 -0
  115. package/src/lib/theme/config/loader.ts +37 -54
  116. package/src/lib/theme/config/types.ts +2 -2
  117. package/src/lib/theme/config/validator.ts +15 -91
  118. package/src/lib/theme/{constants.ts → constants/constants.ts} +1 -19
  119. package/src/lib/theme/constants/index.ts +8 -0
  120. package/src/lib/theme/core/ThemeRegistry.ts +75 -266
  121. package/src/lib/theme/core/__tests__/createTheme.test.ts +132 -0
  122. package/src/lib/theme/core/composeTheme.ts +105 -0
  123. package/src/lib/theme/core/createTheme.ts +108 -0
  124. package/src/lib/theme/{createTheme.ts → core/createThemeObject.ts} +12 -8
  125. package/src/lib/theme/core/index.ts +19 -19
  126. package/src/lib/theme/devtools/Comparator.tsx +346 -22
  127. package/src/lib/theme/devtools/IMPROVEMENTS.md +139 -38
  128. package/src/lib/theme/devtools/Inspector.tsx +335 -51
  129. package/src/lib/theme/devtools/LiveEditor.tsx +478 -107
  130. package/src/lib/theme/devtools/Preview.tsx +471 -221
  131. package/src/lib/theme/{core → devtools}/ThemeValidator.ts +1 -1
  132. package/src/lib/theme/devtools/index.ts +14 -4
  133. package/src/lib/theme/devtools/useHistory.ts +130 -0
  134. package/src/lib/theme/{errors.ts → errors/errors.ts} +1 -1
  135. package/src/lib/theme/errors/index.ts +12 -0
  136. package/src/lib/theme/generators/cssFile.ts +79 -0
  137. package/src/lib/theme/generators/generateCSS.ts +89 -0
  138. package/src/lib/theme/generators/generateCSSNested.ts +130 -0
  139. package/src/lib/theme/{generateCSSVariables.ts → generators/generateCSSVariables.ts} +3 -13
  140. package/src/lib/theme/generators/index.ts +25 -0
  141. package/src/lib/theme/i18n/rtl.ts +5 -6
  142. package/src/lib/theme/index.ts +149 -19
  143. package/src/lib/theme/runtime/ThemeApplicator.ts +53 -112
  144. package/src/lib/theme/{ThemeContext.tsx → runtime/ThemeContext.tsx} +1 -1
  145. package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +5 -5
  146. package/src/lib/theme/runtime/ThemeProvider.tsx +266 -282
  147. package/src/lib/theme/runtime/index.ts +2 -2
  148. package/src/lib/theme/runtime/useTheme.ts +1 -2
  149. package/src/lib/theme/runtime/useThemeTokens.ts +131 -0
  150. package/src/lib/theme/test/testTheme.ts +385 -0
  151. package/src/lib/theme/tokens/index.ts +12 -0
  152. package/src/lib/theme/tokens/tokens.ts +721 -0
  153. package/src/lib/theme/types.ts +6 -42
  154. package/src/lib/theme/utils/componentTheming.ts +132 -0
  155. package/src/lib/theme/{utils.ts → utils/domUtils.ts} +2 -2
  156. package/src/lib/theme/utils/index.ts +11 -0
  157. package/src/lib/theme/utils/injectCSS.ts +90 -0
  158. package/src/lib/theme/utils/naming.ts +100 -0
  159. package/src/lib/theme/utils/themeHelpers.ts +78 -0
  160. package/src/lib/theme/{themeUtils.ts → utils/themeUtils.ts} +7 -7
  161. package/src/lib/theme-tools.ts +7 -8
  162. package/src/lib/types/components.ts +40 -130
  163. package/src/lib/utils/componentUtils.ts +2 -2
  164. package/src/lib/utils/memoryMonitor.ts +3 -3
  165. package/src/lib/utils/themeNaming.ts +135 -0
  166. package/src/styles/01-settings/_settings.design-tokens.scss +4 -1
  167. package/src/styles/02-tools/_tools.button.scss +66 -79
  168. package/src/styles/06-components/_components.atomix-glass.scss +13 -3
  169. package/src/styles/06-components/_components.pagination.scss +88 -0
  170. package/scripts/sync-theme-config.js +0 -309
  171. package/src/lib/theme/composeTheme.ts +0 -370
  172. package/src/lib/theme/core/ThemeCache.ts +0 -283
  173. package/src/lib/theme/core/ThemeEngine.test.ts +0 -146
  174. package/src/lib/theme/core/ThemeEngine.ts +0 -665
  175. package/src/lib/theme/createThemeFromConfig.ts +0 -132
  176. package/src/lib/theme/devtools/CLI.ts +0 -364
  177. package/src/lib/theme/runtime/ThemeManager.test.ts +0 -192
  178. package/src/lib/theme/runtime/ThemeManager.ts +0 -446
  179. package/src/styles/03-generic/_generated-root.css +0 -26
  180. package/src/themes/README.md +0 -442
  181. package/src/themes/themes.config.js +0 -68
  182. /package/src/lib/theme/{cssVariableMapper.ts → adapters/cssVariableMapper.ts} +0 -0
package/dist/heavy.js CHANGED
@@ -460,9 +460,7 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
460
460
  })
461
461
  });
462
462
 
463
- /**
464
- * Badge-specific constants
465
- */ GlassFilterComponent.displayName = "GlassFilter";
463
+ GlassFilterComponent.displayName = "GlassFilter";
466
464
 
467
465
  // Memoize component to prevent unnecessary re-renders
468
466
  const GlassFilter = memo(GlassFilterComponent, ((prevProps, nextProps) => prevProps.id === nextProps.id && prevProps.displacementScale === nextProps.displacementScale && prevProps.aberrationIntensity === nextProps.aberrationIntensity && prevProps.mode === nextProps.mode && prevProps.shaderMapUrl === nextProps.shaderMapUrl && prevProps.blurAmount === nextProps.blurAmount)), sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({children: children, className: className = "", style: style, displacementScale: displacementScale = 25, blurAmount: blurAmount = .0625, saturation: saturation = 180, aberrationIntensity: aberrationIntensity = 2, mouseOffset: mouseOffset = {
@@ -475,10 +473,11 @@ const GlassFilter = memo(GlassFilterComponent, ((prevProps, nextProps) => prevP
475
473
  width: 0,
476
474
  height: 0
477
475
  }, onClick: onClick, mode: mode = "standard", effectiveDisableEffects: effectiveDisableEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", enableLiquidBlur: enableLiquidBlur = !1, elasticity: elasticity = 0, contentRef: contentRef}, ref) => {
478
- // Use React's useId() for SSR compatibility
479
- // Note: In Next.js, IDs may differ between server and client
480
- // We'll suppress hydration warnings on elements that use this ID
481
- const filterId = useId(), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null);
476
+ // Generate a stable, deterministic ID for SSR compatibility
477
+ // React's useId() should produce the same ID on server and client for the same
478
+ // component position in the tree. We use useState to ensure the ID is only
479
+ // generated once and remains stable across renders.
480
+ const baseId = useId(), [filterId] = useState((() => `atomix-glass-filter-${baseId.replace(/:/g, "-").replace(/^[^a-z]/i, "atomix-")}`)), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null);
482
481
  // Lazy load shader utilities only when shader mode is needed
483
482
  useEffect((() => {
484
483
  "shader" === mode ?
@@ -538,7 +537,7 @@ const GlassFilter = memo(GlassFilterComponent, ((prevProps, nextProps) => prevP
538
537
  timestamp: Date.now()
539
538
  }),
540
539
  // Development mode: log cache size
541
- "production" !== process.env.NODE_ENV && sharedShaderCache.size;
540
+ "undefined" != typeof process && "production" === process.env?.NODE_ENV || sharedShaderCache.size;
542
541
  })(cacheKey, url), setShaderMapUrl(url);
543
542
  };
544
543
  "undefined" != typeof requestIdleCallback ? requestIdleCallback(generate, {
@@ -851,9 +850,9 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
851
850
  childRadius > 0 && childRadius !== CONSTANTS.DEFAULT_CORNER_RADIUS && (extractedRadius = childRadius,
852
851
  extractionSource = "React children");
853
852
  }
854
- null !== extractedRadius && extractedRadius > 0 ? setDynamicCornerRadius(extractedRadius) : process.env.NODE_ENV;
853
+ null !== extractedRadius && extractedRadius > 0 ? setDynamicCornerRadius(extractedRadius) : "undefined" == typeof process || process.env;
855
854
  } catch (error) {
856
- "production" !== process.env.NODE_ENV && debugCornerRadius && console.error("[AtomixGlass] Error extracting corner radius:", error);
855
+ "undefined" != typeof process && "production" === process.env?.NODE_ENV || !debugCornerRadius || console.error("[AtomixGlass] Error extracting corner radius:", error);
857
856
  }
858
857
  };
859
858
  extractRadius();
@@ -928,7 +927,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
928
927
  // For image backgrounds, assume medium luminance
929
928
  totalLuminance += .5, validSamples++, hasValidBackground = !0);
930
929
  } catch (styleError) {
931
- process.env.NODE_ENV;
930
+ "undefined" == typeof process || process.env;
932
931
  }
933
932
  // Move to parent element for next iteration
934
933
  if (!currentElement) break;
@@ -967,7 +966,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
967
966
  }
968
967
  } catch (error) {
969
968
  // Enhanced error logging with context
970
- "development" === process.env.NODE_ENV && console.warn("AtomixGlass: Error detecting background brightness:", error);
969
+ "undefined" != typeof process && "development" !== process.env?.NODE_ENV || console.warn("AtomixGlass: Error detecting background brightness:", error);
971
970
  const result = !1;
972
971
  if (element && element.parentElement) {
973
972
  const threshold = "object" == typeof overLight && null !== overLight && overLight.threshold || .7;
@@ -1024,7 +1023,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
1024
1023
  };
1025
1024
  // Calculate offset relative to this container
1026
1025
  // React 18 automatically batches these updates
1027
- setInternalMouseOffset(newOffset), setInternalGlobalMousePosition(globalPos), "production" !== process.env.NODE_ENV && enablePerformanceMonitoring && performance.now();
1026
+ setInternalMouseOffset(newOffset), setInternalGlobalMousePosition(globalPos), "undefined" != typeof process && "production" === process.env?.NODE_ENV || !enablePerformanceMonitoring || performance.now();
1028
1027
  }), [ mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveDisableEffects, enablePerformanceMonitoring ]);
1029
1028
  // Subscribe to shared mouse tracker
1030
1029
  useEffect((() => {
@@ -1164,10 +1163,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
1164
1163
  saturationBoost: validatedSaturationBoost + .4 * mouseInfluence
1165
1164
  };
1166
1165
  // Validate and apply object config values with proper clamping
1167
- return process.env.NODE_ENV, finalConfig;
1166
+ return "undefined" == typeof process || process.env, finalConfig;
1168
1167
  }
1169
1168
  // Debug logging for non-object configs
1170
- return process.env.NODE_ENV, baseConfig;
1169
+ return "undefined" == typeof process || process.env, baseConfig;
1171
1170
  }), [ overLight, getEffectiveOverLight, mouseOffset, isHovered, isActive, validateConfigValue, debugOverLight ]), handleMouseEnter = useCallback((() => setIsHovered(!0)), []), handleMouseLeave = useCallback((() => setIsHovered(!1)), []), handleMouseDown = useCallback((() => setIsActive(!0)), []), handleMouseUp = useCallback((() => setIsActive(!1)), []), handleKeyDown = useCallback((e => {
1172
1171
  !onClick || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), onClick());
1173
1172
  }), [ onClick ]), handleMouseMove = useCallback((_e => {}), []);
@@ -1278,7 +1277,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
1278
1277
  * <div>Content with debug logging enabled</div>
1279
1278
  * </AtomixGlass>
1280
1279
  */ 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}) {
1281
- const glassRef = useRef(null), contentRef = useRef(null), opacityCacheRef = 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({
1280
+ const glassRef = useRef(null), contentRef = useRef(null), {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveCornerRadius: effectiveCornerRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveDisableEffects: effectiveDisableEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
1282
1281
  glassRef: glassRef,
1283
1282
  contentRef: contentRef,
1284
1283
  cornerRadius: cornerRadius,
@@ -1295,128 +1294,51 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
1295
1294
  debugOverLight: debugOverLight,
1296
1295
  enablePerformanceMonitoring: enablePerformanceMonitoring,
1297
1296
  children: children
1298
- }), isOverLight = overLightConfig.isOverLight, shouldRenderOverLightLayers = enableOverLightLayers && isOverLight;
1299
- // Read CSS custom properties once on mount and cache them
1300
- useEffect((() => {
1301
- if ("undefined" != typeof window && glassRef.current && !opacityCacheRef.current) try {
1302
- const computedStyle = window.getComputedStyle(glassRef.current), 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) => {
1303
- if (!value) return defaultValue;
1304
- const parsed = parseFloat(value);
1305
- return isNaN(parsed) ? defaultValue : parsed;
1306
- };
1307
- opacityCacheRef.current = {
1308
- opacity50: parseOpacity(opacity50Value, .5),
1309
- opacity40: parseOpacity(opacity40Value, .4),
1310
- opacity80: parseOpacity(opacity80Value, .8),
1311
- opacity0: parseOpacity(opacity0Value, 0)
1312
- };
1313
- } catch (error) {
1314
- // Fallback to defaults if reading fails
1315
- opacityCacheRef.current = {
1316
- opacity50: .5,
1317
- opacity40: .4,
1318
- opacity80: .8,
1319
- opacity0: 0
1320
- };
1321
- }
1322
- }), []);
1323
- // Calculate base style with transforms (only dynamic values)
1324
- const baseStyle = useMemo((() => ({
1297
+ }), isOverLight = overLightConfig.isOverLight, shouldRenderOverLightLayers = enableOverLightLayers && isOverLight, baseStyle = {
1325
1298
  ...style,
1326
1299
  ...0 !== elasticity && !effectiveDisableEffects && {
1327
1300
  transform: transformStyle
1328
1301
  }
1329
- })), [ style, transformStyle, effectiveDisableEffects, elasticity ]), componentClassName = useMemo((() => [ ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`, effectiveDisableEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`, className ].filter(Boolean).join(" ")), [ effectiveReducedMotion, effectiveHighContrast, effectiveDisableEffects, className ]), baseStylePosition = baseStyle.position, baseStyleTop = baseStyle.top, baseStyleLeft = baseStyle.left, positionStyles = useMemo((() => ({
1330
- position: baseStylePosition || "absolute",
1331
- top: baseStyleTop || 0,
1332
- left: baseStyleLeft || 0
1333
- })), [ baseStylePosition, baseStyleTop, baseStyleLeft ]), baseStyleWidth = baseStyle.width, baseStyleHeight = baseStyle.height, glassSizeWidth = glassSize.width, glassSizeHeight = glassSize.height, adjustedSize = useMemo((() => ({
1334
- width: "fixed" !== baseStylePosition ? "100%" : baseStyleWidth || Math.max(glassSizeWidth, 0),
1335
- height: "fixed" !== baseStylePosition ? "100%" : baseStyleHeight || Math.max(glassSizeHeight, 0)
1336
- })), [ baseStylePosition, baseStyleWidth, baseStyleHeight, glassSizeWidth, glassSizeHeight ]), mouseOffsetX = mouseOffset.x, mouseOffsetY = mouseOffset.y, GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, gradientCalculations = useMemo((() => {
1337
- 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;
1338
- return {
1339
- isOverLight: isOverLight,
1340
- mx: mx,
1341
- my: my,
1342
- borderGradientAngle: borderGradientAngle,
1343
- borderStop1: borderStop1,
1344
- borderStop2: borderStop2,
1345
- borderOpacity1: borderOpacity1,
1346
- borderOpacity2: borderOpacity2,
1347
- borderOpacity3: borderOpacity3,
1348
- borderOpacity4: borderOpacity4,
1349
- hover1X: hover1X,
1350
- hover1Y: hover1Y,
1351
- hover2X: hover2X,
1352
- hover2Y: hover2Y,
1353
- hover3X: hover3X,
1354
- hover3Y: hover3Y,
1355
- baseX: baseX,
1356
- baseY: baseY
1357
- };
1358
- }), [ mouseOffsetX, mouseOffsetY, isOverLight ]), overLightOpacity = overLightConfig.opacity, opacityValues = useMemo((() => {
1359
- // Use cached values if available, otherwise fallback to defaults
1360
- const opacity50 = opacityCacheRef.current?.opacity50 ?? .5, opacity40 = opacityCacheRef.current?.opacity40 ?? .4, opacity80 = opacityCacheRef.current?.opacity80 ?? .8, opacity0 = opacityCacheRef.current?.opacity0 ?? 0;
1361
- // Dynamic multiplier for overlay
1362
- return {
1363
- hover1: isHovered || isActive ? opacity50 : opacity0,
1364
- hover2: isActive ? opacity50 : opacity0,
1365
- hover3: isHovered ? opacity40 : isActive ? opacity80 : opacity0,
1366
- base: isOverLight ? overLightOpacity || opacity40 : opacity0,
1367
- over: isOverLight ? 1.1 * (overLightOpacity || opacity40) : opacity0
1368
- };
1369
- }), [ isHovered, isActive, isOverLight, overLightOpacity ]), gradientIsOverLight = gradientCalculations.isOverLight, gradientMx = gradientCalculations.mx, gradientMy = gradientCalculations.my, gradientBorderGradientAngle = gradientCalculations.borderGradientAngle, gradientBorderStop1 = gradientCalculations.borderStop1, gradientBorderStop2 = gradientCalculations.borderStop2, gradientBorderOpacity1 = gradientCalculations.borderOpacity1, gradientBorderOpacity2 = gradientCalculations.borderOpacity2, gradientBorderOpacity3 = gradientCalculations.borderOpacity3, gradientBorderOpacity4 = gradientCalculations.borderOpacity4, gradientHover1X = gradientCalculations.hover1X, gradientHover1Y = gradientCalculations.hover1Y, gradientHover2X = gradientCalculations.hover2X, gradientHover2Y = gradientCalculations.hover2Y, gradientHover3X = gradientCalculations.hover3X, gradientHover3Y = gradientCalculations.hover3Y, gradientBaseX = gradientCalculations.baseX, gradientBaseY = gradientCalculations.baseY, positionStylesPosition = positionStyles.position, positionStylesTop = positionStyles.top, positionStylesLeft = positionStyles.left, adjustedSizeWidth = adjustedSize.width, adjustedSizeHeight = adjustedSize.height, baseStyleTransform = baseStyle.transform, opacityValuesHover1 = opacityValues.hover1, opacityValuesHover2 = opacityValues.hover2, opacityValuesHover3 = opacityValues.hover3, opacityValuesBase = opacityValues.base, opacityValuesOver = opacityValues.over, glassVars = useMemo((() => {
1370
- // RGB color values for rgba() functions
1371
- // Note: CSS doesn't support rgba(var(--rgb), opacity) syntax, so we use direct values
1372
- // These values align with design tokens: --atomix-white-rgb and --atomix-black-rgb
1373
- // The actual RGB values are defined in SCSS and should match these fallbacks
1374
- // TODO: Consider reading from CSS custom properties if browser support improves
1375
- const whiteColor = "255, 255, 255";
1376
- // Matches --atomix-white-rgb design token
1377
- // Matches --atomix-black-rgb design token
1378
- return {
1379
- // Standard CSS custom properties for dynamic values
1380
- "--atomix-glass-radius": `${effectiveCornerRadius}px`,
1381
- "--atomix-glass-transform": baseStyleTransform || "none",
1382
- "--atomix-glass-position": positionStylesPosition,
1383
- "--atomix-glass-top": "fixed" !== positionStylesTop ? `${positionStylesTop}px` : "0",
1384
- "--atomix-glass-left": "fixed" !== positionStylesLeft ? `${positionStylesLeft}px` : "0",
1385
- "--atomix-glass-width": "fixed" !== baseStylePosition ? adjustedSizeWidth : `${adjustedSizeWidth}px`,
1386
- "--atomix-glass-height": "fixed" !== baseStylePosition ? adjustedSizeHeight : `${adjustedSizeHeight}px`,
1387
- // Border width: Use spacing token for consistency
1388
- "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
1389
- "--atomix-glass-blend-mode": gradientIsOverLight ? "multiply" : "overlay",
1390
- // Dynamic gradients and backgrounds
1391
- // Note: RGB values use design token-aligned constants (white: 255,255,255; black: 0,0,0)
1392
- "--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%)`,
1393
- "--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%)`,
1394
- "--atomix-glass-hover-1-opacity": opacityValuesHover1,
1395
- "--atomix-glass-hover-1-gradient": gradientIsOverLight ? `radial-gradient(circle at ${gradientHover1X}% ${gradientHover1Y}%, 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 ${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}%)`,
1396
- "--atomix-glass-hover-2-opacity": opacityValuesHover2,
1397
- "--atomix-glass-hover-2-gradient": gradientIsOverLight ? `radial-gradient(circle at ${gradientHover2X}% ${gradientHover2Y}%, 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 ${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}%)`,
1398
- "--atomix-glass-hover-3-opacity": opacityValuesHover3,
1399
- "--atomix-glass-hover-3-gradient": gradientIsOverLight ? `radial-gradient(circle at ${gradientHover3X}% ${gradientHover3Y}%, 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 ${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}%)`,
1400
- "--atomix-glass-base-opacity": opacityValuesBase,
1401
- "--atomix-glass-base-gradient": gradientIsOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + gradientMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(0, 0, 0, ${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(0, 0, 0, ${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})`,
1402
- "--atomix-glass-overlay-opacity": opacityValuesOver,
1403
- "--atomix-glass-overlay-gradient": gradientIsOverLight ? `radial-gradient(circle at ${gradientBaseX}% ${gradientBaseY}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + Math.abs(gradientMx) * 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(gradientMy) * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`
1404
- };
1405
- }), [
1406
- // Position styles - only specific properties
1407
- positionStylesPosition, positionStylesTop, positionStylesLeft,
1408
- // Adjusted size - only specific properties
1409
- adjustedSizeWidth, adjustedSizeHeight,
1410
- // Base style - only transform property
1411
- baseStyleTransform, baseStylePosition,
1412
- // Other values
1413
- effectiveCornerRadius, effectiveReducedMotion,
1414
- // Gradient calculations - extracted properties
1415
- gradientIsOverLight, gradientMx, gradientMy, gradientBorderGradientAngle, gradientBorderStop1, gradientBorderStop2, gradientBorderOpacity1, gradientBorderOpacity2, gradientBorderOpacity3, gradientBorderOpacity4, gradientHover1X, gradientHover1Y, gradientHover2X, gradientHover2Y, gradientHover3X, gradientHover3Y, gradientBaseX, gradientBaseY,
1416
- // Opacity values - extracted properties
1417
- opacityValuesHover1, opacityValuesHover2, opacityValuesHover3, opacityValuesBase, opacityValuesOver ]);
1418
- // Build className with state modifiers
1419
- return jsxs("div", {
1302
+ }, 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 = {
1303
+ position: style.position || "absolute",
1304
+ top: style.top || 0,
1305
+ left: style.left || 0
1306
+ }, adjustedSize = {
1307
+ width: "fixed" !== style.position ? "100%" : style.width ? style.width : Math.max(glassSize.width, 0),
1308
+ height: "fixed" !== style.position ? "100%" : style.height ? style.height : Math.max(glassSize.height, 0)
1309
+ }, 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 = {
1310
+ hover1: isHovered || isActive ? .5 : 0,
1311
+ hover2: isActive ? .5 : 0,
1312
+ hover3: isHovered ? .4 : isActive ? .8 : 0,
1313
+ base: isOverLight ? overLightOpacity || .4 : 0,
1314
+ over: isOverLight ? 1.1 * (overLightOpacity || .4) : 0
1315
+ }, whiteColor = "255, 255, 255", glassVars = {
1316
+ // Standard CSS custom properties for dynamic values
1317
+ "--atomix-glass-radius": `${effectiveCornerRadius}px`,
1318
+ "--atomix-glass-transform": transformStyle || "none",
1319
+ "--atomix-glass-position": positionStyles.position,
1320
+ "--atomix-glass-top": "fixed" !== positionStyles.top ? `${positionStyles.top}px` : "0",
1321
+ "--atomix-glass-left": "fixed" !== positionStyles.left ? `${positionStyles.left}px` : "0",
1322
+ "--atomix-glass-width": "fixed" !== style.position ? adjustedSize.width : `${adjustedSize.width}px`,
1323
+ "--atomix-glass-height": "fixed" !== style.position ? adjustedSize.height : `${adjustedSize.height}px`,
1324
+ // Border width: Use spacing token for consistency
1325
+ "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
1326
+ "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay",
1327
+ // Dynamic gradients and backgrounds
1328
+ "--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%)`,
1329
+ "--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%)`,
1330
+ "--atomix-glass-hover-1-opacity": opacityValues.hover1,
1331
+ "--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}%)`,
1332
+ "--atomix-glass-hover-2-opacity": opacityValues.hover2,
1333
+ "--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}%)`,
1334
+ "--atomix-glass-hover-3-opacity": opacityValues.hover3,
1335
+ "--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}%)`,
1336
+ "--atomix-glass-base-opacity": opacityValues.base,
1337
+ "--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})`,
1338
+ "--atomix-glass-overlay-opacity": opacityValues.over,
1339
+ "--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})`
1340
+ };
1341
+ return jsxs("div", {
1420
1342
  className: componentClassName,
1421
1343
  style: glassVars,
1422
1344
  role: role || (onClick ? "button" : void 0),
@@ -3219,69 +3141,103 @@ const sizeMap = {
3219
3141
  * Icon component that displays a Phosphor icon
3220
3142
  */ Icon.displayName = "Icon";
3221
3143
 
3144
+ /**
3145
+ * Theme Naming Utility
3146
+ *
3147
+ * Provides consistent naming conventions for CSS classes, CSS variables,
3148
+ * and JavaScript properties throughout the theme system.
3149
+ */
3150
+ class ThemeNaming {
3151
+ /**
3152
+ * Set the global prefix for all theme tokens
3153
+ * @param newPrefix - New prefix to use
3154
+ */
3155
+ static setPrefix(newPrefix) {
3156
+ this.prefix = newPrefix;
3157
+ }
3158
+ /**
3159
+ * Get the current prefix
3160
+ */ static getPrefix() {
3161
+ return this.prefix;
3162
+ }
3163
+ /**
3164
+ * Convert camelCase to kebab-case for CSS variables
3165
+ * @param str - String to convert
3166
+ */ static camelToKebab(str) {
3167
+ return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").toLowerCase();
3168
+ }
3169
+ /**
3170
+ * Convert kebab-case to camelCase for JavaScript properties
3171
+ * @param str - String to convert
3172
+ */ static kebabToCamel(str) {
3173
+ return str.replace(/-([a-z])/g, (g => g[1].toUpperCase()));
3174
+ }
3175
+ /**
3176
+ * Create a CSS variable name
3177
+ * @param token - Token name in camelCase
3178
+ */ static cssVar(token) {
3179
+ return `--${this.prefix}-${this.camelToKebab(token)}`;
3180
+ }
3181
+ /**
3182
+ * Create a BEM CSS class name
3183
+ * @param block - Block name
3184
+ * @param element - Element name (optional)
3185
+ * @param modifier - Modifier name (optional)
3186
+ */ static bemClass(block, element, modifier) {
3187
+ let className = `c-${block}`;
3188
+ return element && (className += `__${element}`), modifier && (className += `--${modifier}`),
3189
+ className;
3190
+ }
3191
+ /**
3192
+ * Create a variant class name
3193
+ * @param component - Component name
3194
+ * @param variant - Variant name
3195
+ */ static variantClass(component, variant) {
3196
+ return `c-${component}--${variant}`;
3197
+ }
3198
+ /**
3199
+ * Create a size class name
3200
+ * @param component - Component name
3201
+ * @param size - Size name
3202
+ */ static sizeClass(component, size) {
3203
+ return `c-${component}--${size}`;
3204
+ }
3205
+ /**
3206
+ * Create a state class name
3207
+ * @param component - Component name
3208
+ * @param state - State name
3209
+ */ static stateClass(component, state) {
3210
+ return `c-${component}--${state}`;
3211
+ }
3212
+ /**
3213
+ * Create a utility class name
3214
+ * @param utility - Utility name
3215
+ */ static utilityClass(utility) {
3216
+ return `u-${utility}`;
3217
+ }
3218
+ /**
3219
+ * Create a layout class name
3220
+ * @param layout - Layout name
3221
+ */ static layoutClass(layout) {
3222
+ return `l-${layout}`;
3223
+ }
3224
+ /**
3225
+ * Create an object class name
3226
+ * @param object - Object name
3227
+ */ static objectClass(object) {
3228
+ return `o-${object}`;
3229
+ }
3230
+ }
3231
+
3232
+ ThemeNaming.prefix = "atomix";
3233
+
3222
3234
  const Button = React.memo( forwardRef((({label: label, children: children, onClick: onClick, variant: variant = "primary", size: size = "md", disabled: disabled = !1, loading: loading = !1, loadingText: loadingText, icon: icon, iconName: iconName, iconSize: iconSize = "sm", iconPosition: iconPosition = "start", iconOnly: iconOnly = !1, rounded: rounded = !1, fullWidth: fullWidth = !1, block: block = !1, active: active = !1, selected: selected = !1, type: type = "button", className: className = "", as: Component = "button", href: href, target: target, glass: glass, onHover: onHover, onFocus: onFocus, onBlur: onBlur, ariaLabel: ariaLabel, ariaDescribedBy: ariaDescribedBy, ariaExpanded: ariaExpanded, ariaControls: ariaControls, tabIndex: tabIndex, style: style, LinkComponent: LinkComponent, ...props}, ref) => {
3223
- const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement = useMemo((() => loading ? null : iconName ? jsx(Icon, {
3235
+ const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement = iconName ? jsx(Icon, {
3224
3236
  name: iconName,
3225
3237
  size: iconSize
3226
- }) : icon), [ icon, iconName, iconSize, loading ]), {generateButtonClass: generateButtonClass, handleClick: handleClick} =
3227
- /**
3228
- * Button state and functionality
3229
- * @param initialProps - Initial button properties
3230
- * @returns Button state and methods
3231
- */
3232
- function(initialProps) {
3233
- // Default button properties
3234
- const defaultProps = {
3235
- variant: "primary",
3236
- size: "md",
3237
- disabled: !1,
3238
- rounded: !1,
3239
- loading: !1,
3240
- fullWidth: !1,
3241
- block: !1,
3242
- active: !1,
3243
- selected: !1,
3244
- ...initialProps
3245
- };
3246
- /**
3247
- * Generate button class based on properties
3248
- * @param props - Button properties
3249
- * @returns Class string
3250
- */ return {
3251
- defaultProps: defaultProps,
3252
- generateButtonClass: props => {
3253
- const {variant: variant = defaultProps.variant, size: size = defaultProps.size, disabled: disabled = defaultProps.disabled, rounded: rounded = defaultProps.rounded, iconOnly: iconOnly = !1, glass: glass = defaultProps.glass, loading: loading = defaultProps.loading, fullWidth: fullWidth = defaultProps.fullWidth, block: block = defaultProps.block, active: active = defaultProps.active, selected: selected = defaultProps.selected, className: className = ""} = props, sizeClass = "md" === size ? "" : `c-btn--${size}`, iconOnlyClass = iconOnly ? "c-btn--icon" : "", roundedClass = rounded ? "c-btn--rounded" : "", disabledClass = disabled ? "c-btn--disabled" : "", glassClass = glass ? "c-btn--glass" : "", loadingClass = loading ? BUTTON.CLASSES.LOADING : "", fullWidthClass = fullWidth ? BUTTON.CLASSES.FULL_WIDTH : "", blockClass = block ? BUTTON.CLASSES.BLOCK : "", activeClass = active ? BUTTON.CLASSES.ACTIVE : "", selectedClass = selected ? BUTTON.CLASSES.SELECTED : "";
3254
- return [ BUTTON.BASE_CLASS, `c-btn--${variant}`, sizeClass, iconOnlyClass, roundedClass, disabledClass, glassClass, loadingClass, fullWidthClass, blockClass, activeClass, selectedClass, className ].filter(Boolean).join(" ");
3255
- },
3256
- handleClick: handler => event => {
3257
- defaultProps.disabled || defaultProps.loading || !handler || handler(event);
3258
- }
3259
- };
3260
- }({
3261
- variant: variant,
3262
- size: size,
3263
- disabled: isDisabled,
3264
- rounded: rounded,
3265
- glass: glass,
3266
- loading: loading,
3267
- fullWidth: fullWidth,
3268
- block: block,
3269
- active: active,
3270
- selected: selected
3271
- }), buttonClass = useMemo((() => generateButtonClass({
3272
- variant: variant,
3273
- size: size,
3274
- disabled: isDisabled,
3275
- rounded: rounded,
3276
- iconOnly: iconOnly,
3277
- glass: glass,
3278
- loading: loading,
3279
- fullWidth: fullWidth,
3280
- block: block,
3281
- active: active,
3282
- selected: selected,
3283
- className: className
3284
- })), [ variant, size, isDisabled, rounded, iconOnly, glass, loading, fullWidth, block, active, selected, className, generateButtonClass ]), handleClickEvent = useCallback((event => {
3238
+ }) : icon;
3239
+ // Determine if we should render as a link
3240
+ const buttonClass = [ BUTTON.BASE_CLASS, ThemeNaming.variantClass("btn", variant), "md" !== size ? ThemeNaming.sizeClass("btn", size) : "", iconOnly ? ThemeNaming.stateClass("btn", "icon") : "", rounded ? ThemeNaming.stateClass("btn", "rounded") : "", isDisabled ? ThemeNaming.stateClass("btn", "disabled") : "", glass ? ThemeNaming.stateClass("btn", "glass") : "", loading ? BUTTON.CLASSES.LOADING : "", fullWidth ? BUTTON.CLASSES.FULL_WIDTH : "", block ? BUTTON.CLASSES.BLOCK : "", active ? BUTTON.CLASSES.ACTIVE : "", selected ? BUTTON.CLASSES.SELECTED : "", className ].filter(Boolean).join(" "), handleClickEvent = useCallback((event => {
3285
3241
  isDisabled ? event.preventDefault() : onClick?.(event);
3286
3242
  }), [ isDisabled, onClick ]), handleMouseEnter = useCallback((event => {
3287
3243
  isDisabled || onHover?.(event);
@@ -3289,28 +3245,23 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
3289
3245
  isDisabled || onFocus?.(event);
3290
3246
  }), [ isDisabled, onFocus ]), handleBlurEvent = useCallback((event => {
3291
3247
  isDisabled || onBlur?.(event);
3292
- }), [ isDisabled, onBlur ]), buttonText = useMemo((() => loading && loadingText ? loadingText : label || children), [ loading, loadingText, label, children ]), spinnerSize = useMemo((() => "sm" === size ? "sm" : "lg" === size ? "md" : "sm"), [ size ]), buttonContent = useMemo((() => {
3293
- const iconSpan = iconElement && jsx("span", {
3294
- className: BUTTON.ICON_CLASS,
3295
- "aria-hidden": "true",
3296
- children: iconElement
3297
- }), spinnerElement = loading && jsx("span", {
3298
- className: BUTTON.SPINNER_CLASS,
3248
+ }), [ isDisabled, onBlur ]), buttonText = loading && loadingText ? loadingText : label || children, spinnerSize = "sm" === size ? "sm" : "lg" === size ? "md" : "sm", buttonContent = jsxs(Fragment, {
3249
+ children: [ loading && jsx("span", {
3250
+ className: ThemeNaming.bemClass("btn", "spinner"),
3299
3251
  "aria-hidden": "true",
3300
3252
  children: jsx(Spinner, {
3301
3253
  size: spinnerSize,
3302
3254
  variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
3303
3255
  })
3304
- }), labelElement = !iconOnly && buttonText && jsx("span", {
3305
- className: BUTTON.LABEL_CLASS,
3256
+ }), iconElement && !loading && jsx("span", {
3257
+ className: ThemeNaming.bemClass("btn", "icon"),
3258
+ "aria-hidden": "true",
3259
+ children: iconElement
3260
+ }), !iconOnly && buttonText && jsx("span", {
3261
+ className: ThemeNaming.bemClass("btn", "label"),
3306
3262
  children: buttonText
3307
- });
3308
- return jsxs(Fragment, "end" === iconPosition ? {
3309
- children: [ labelElement, spinnerElement, iconSpan ]
3310
- } : {
3311
- children: [ spinnerElement, iconSpan, labelElement ]
3312
- });
3313
- }), [ iconElement, iconPosition, iconOnly, buttonText, loading, spinnerSize, variant ]), buttonProps = useMemo((() => ({
3263
+ }) ]
3264
+ }), buttonProps = {
3314
3265
  ref: ref,
3315
3266
  className: buttonClass,
3316
3267
  type: "button" !== Component || shouldRenderAsLink ? void 0 : type,
@@ -3328,8 +3279,16 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
3328
3279
  tabIndex: void 0 !== tabIndex ? tabIndex : isDisabled ? -1 : 0,
3329
3280
  style: style,
3330
3281
  ...props
3331
- })), [ ref, buttonClass, Component, type, handleClickEvent, handleMouseEnter, handleFocusEvent, handleBlurEvent, isDisabled, loading, ariaLabel, iconOnly, label, children, ariaDescribedBy, ariaExpanded, ariaControls, tabIndex, style, props ]);
3332
- // Determine if we should render as a link
3282
+ }, defaultGlassProps = {
3283
+ displacementScale: 20,
3284
+ blurAmount: 0,
3285
+ saturation: 200,
3286
+ elasticity: 0
3287
+ }, glassProps = !0 === glass ? defaultGlassProps : {
3288
+ ...defaultGlassProps,
3289
+ ...glass
3290
+ };
3291
+ // Handle click with loading check
3333
3292
  // Render as anchor if href is provided
3334
3293
  if (shouldRenderAsLink) {
3335
3294
  const {ref: _, ...buttonPropsWithoutRef} = buttonProps, anchorButtonProps = {
@@ -3349,22 +3308,10 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
3349
3308
  ...linkProps,
3350
3309
  children: buttonContent
3351
3310
  });
3352
- if (glass) {
3353
- const defaultGlassProps = {
3354
- displacementScale: 20,
3355
- blurAmount: 0,
3356
- saturation: 200,
3357
- elasticity: 0
3358
- }, glassProps = !0 === glass ? defaultGlassProps : {
3359
- ...defaultGlassProps,
3360
- ...glass
3361
- };
3362
- return jsx(AtomixGlass, {
3363
- ...glassProps,
3364
- children: linkElement
3365
- });
3366
- }
3367
- return linkElement;
3311
+ return glass ? jsx(AtomixGlass, {
3312
+ ...glassProps,
3313
+ children: linkElement
3314
+ }) : linkElement;
3368
3315
  }
3369
3316
  // Fallback to regular anchor tag
3370
3317
  const anchorElement = jsx("a", {
@@ -3375,46 +3322,20 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
3375
3322
  rel: "_blank" === target ? "noopener noreferrer" : void 0,
3376
3323
  children: buttonContent
3377
3324
  });
3378
- if (glass) {
3379
- const defaultGlassProps = {
3380
- displacementScale: 20,
3381
- blurAmount: 0,
3382
- saturation: 200,
3383
- elasticity: 0
3384
- }, glassProps = !0 === glass ? defaultGlassProps : {
3385
- ...defaultGlassProps,
3386
- ...glass
3387
- };
3388
- return jsx(AtomixGlass, {
3389
- ...glassProps,
3390
- children: anchorElement
3391
- });
3392
- }
3393
- return anchorElement;
3394
- }
3395
- // Default button rendering
3396
- if (glass) {
3397
- const defaultGlassProps = {
3398
- displacementScale: 20,
3399
- blurAmount: 0,
3400
- saturation: 200,
3401
- elasticity: 0
3402
- }, glassProps = !0 === glass ? defaultGlassProps : {
3403
- ...defaultGlassProps,
3404
- ...glass
3405
- };
3406
- return jsx(AtomixGlass, {
3325
+ return glass ? jsx(AtomixGlass, {
3407
3326
  ...glassProps,
3408
- children: jsx(Component, {
3409
- ...buttonProps,
3410
- children: buttonContent
3411
- })
3412
- });
3327
+ children: anchorElement
3328
+ }) : anchorElement;
3413
3329
  }
3414
- return jsx(Component, {
3330
+ // Default button rendering
3331
+ const buttonElement = jsx(Component, {
3415
3332
  ...buttonProps,
3416
3333
  children: buttonContent
3417
3334
  });
3335
+ return glass ? jsx(AtomixGlass, {
3336
+ ...glassProps,
3337
+ children: buttonElement
3338
+ }) : buttonElement;
3418
3339
  })));
3419
3340
 
3420
3341
  Button.displayName = "Button";