@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/core.js CHANGED
@@ -586,9 +586,7 @@ import * as PhosphorIcons from "@phosphor-icons/react";
586
586
  })
587
587
  });
588
588
 
589
- /**
590
- * Accordion-specific constants
591
- */ GlassFilterComponent.displayName = "GlassFilter";
589
+ GlassFilterComponent.displayName = "GlassFilter";
592
590
 
593
591
  // Memoize component to prevent unnecessary re-renders
594
592
  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 = {
@@ -601,10 +599,11 @@ const GlassFilter = memo(GlassFilterComponent, ((prevProps, nextProps) => prevP
601
599
  width: 0,
602
600
  height: 0
603
601
  }, onClick: onClick, mode: mode = "standard", effectiveDisableEffects: effectiveDisableEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", enableLiquidBlur: enableLiquidBlur = !1, elasticity: elasticity = 0, contentRef: contentRef}, ref) => {
604
- // Use React's useId() for SSR compatibility
605
- // Note: In Next.js, IDs may differ between server and client
606
- // We'll suppress hydration warnings on elements that use this ID
607
- const filterId = useId(), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null);
602
+ // Generate a stable, deterministic ID for SSR compatibility
603
+ // React's useId() should produce the same ID on server and client for the same
604
+ // component position in the tree. We use useState to ensure the ID is only
605
+ // generated once and remains stable across renders.
606
+ 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);
608
607
  // Lazy load shader utilities only when shader mode is needed
609
608
  useEffect((() => {
610
609
  "shader" === mode ?
@@ -664,7 +663,7 @@ const GlassFilter = memo(GlassFilterComponent, ((prevProps, nextProps) => prevP
664
663
  timestamp: Date.now()
665
664
  }),
666
665
  // Development mode: log cache size
667
- "production" !== process.env.NODE_ENV && sharedShaderCache.size;
666
+ "undefined" != typeof process && "production" === process.env?.NODE_ENV || sharedShaderCache.size;
668
667
  })(cacheKey, url), setShaderMapUrl(url);
669
668
  };
670
669
  "undefined" != typeof requestIdleCallback ? requestIdleCallback(generate, {
@@ -977,9 +976,9 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
977
976
  childRadius > 0 && childRadius !== CONSTANTS.DEFAULT_CORNER_RADIUS && (extractedRadius = childRadius,
978
977
  extractionSource = "React children");
979
978
  }
980
- null !== extractedRadius && extractedRadius > 0 ? setDynamicCornerRadius(extractedRadius) : process.env.NODE_ENV;
979
+ null !== extractedRadius && extractedRadius > 0 ? setDynamicCornerRadius(extractedRadius) : "undefined" == typeof process || process.env;
981
980
  } catch (error) {
982
- "production" !== process.env.NODE_ENV && debugCornerRadius && console.error("[AtomixGlass] Error extracting corner radius:", error);
981
+ "undefined" != typeof process && "production" === process.env?.NODE_ENV || !debugCornerRadius || console.error("[AtomixGlass] Error extracting corner radius:", error);
983
982
  }
984
983
  };
985
984
  extractRadius();
@@ -1054,7 +1053,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
1054
1053
  // For image backgrounds, assume medium luminance
1055
1054
  totalLuminance += .5, validSamples++, hasValidBackground = !0);
1056
1055
  } catch (styleError) {
1057
- process.env.NODE_ENV;
1056
+ "undefined" == typeof process || process.env;
1058
1057
  }
1059
1058
  // Move to parent element for next iteration
1060
1059
  if (!currentElement) break;
@@ -1093,7 +1092,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
1093
1092
  }
1094
1093
  } catch (error) {
1095
1094
  // Enhanced error logging with context
1096
- "development" === process.env.NODE_ENV && console.warn("AtomixGlass: Error detecting background brightness:", error);
1095
+ "undefined" != typeof process && "development" !== process.env?.NODE_ENV || console.warn("AtomixGlass: Error detecting background brightness:", error);
1097
1096
  const result = !1;
1098
1097
  if (element && element.parentElement) {
1099
1098
  const threshold = "object" == typeof overLight && null !== overLight && overLight.threshold || .7;
@@ -1150,7 +1149,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
1150
1149
  };
1151
1150
  // Calculate offset relative to this container
1152
1151
  // React 18 automatically batches these updates
1153
- setInternalMouseOffset(newOffset), setInternalGlobalMousePosition(globalPos), "production" !== process.env.NODE_ENV && enablePerformanceMonitoring && performance.now();
1152
+ setInternalMouseOffset(newOffset), setInternalGlobalMousePosition(globalPos), "undefined" != typeof process && "production" === process.env?.NODE_ENV || !enablePerformanceMonitoring || performance.now();
1154
1153
  }), [ mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveDisableEffects, enablePerformanceMonitoring ]);
1155
1154
  // Subscribe to shared mouse tracker
1156
1155
  useEffect((() => {
@@ -1290,10 +1289,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
1290
1289
  saturationBoost: validatedSaturationBoost + .4 * mouseInfluence
1291
1290
  };
1292
1291
  // Validate and apply object config values with proper clamping
1293
- return process.env.NODE_ENV, finalConfig;
1292
+ return "undefined" == typeof process || process.env, finalConfig;
1294
1293
  }
1295
1294
  // Debug logging for non-object configs
1296
- return process.env.NODE_ENV, baseConfig;
1295
+ return "undefined" == typeof process || process.env, baseConfig;
1297
1296
  }), [ 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 => {
1298
1297
  !onClick || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), onClick());
1299
1298
  }), [ onClick ]), handleMouseMove = useCallback((_e => {}), []);
@@ -1404,7 +1403,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
1404
1403
  * <div>Content with debug logging enabled</div>
1405
1404
  * </AtomixGlass>
1406
1405
  */ 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}) {
1407
- 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({
1406
+ 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({
1408
1407
  glassRef: glassRef,
1409
1408
  contentRef: contentRef,
1410
1409
  cornerRadius: cornerRadius,
@@ -1421,128 +1420,51 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
1421
1420
  debugOverLight: debugOverLight,
1422
1421
  enablePerformanceMonitoring: enablePerformanceMonitoring,
1423
1422
  children: children
1424
- }), isOverLight = overLightConfig.isOverLight, shouldRenderOverLightLayers = enableOverLightLayers && isOverLight;
1425
- // Read CSS custom properties once on mount and cache them
1426
- useEffect((() => {
1427
- if ("undefined" != typeof window && glassRef.current && !opacityCacheRef.current) try {
1428
- 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) => {
1429
- if (!value) return defaultValue;
1430
- const parsed = parseFloat(value);
1431
- return isNaN(parsed) ? defaultValue : parsed;
1432
- };
1433
- opacityCacheRef.current = {
1434
- opacity50: parseOpacity(opacity50Value, .5),
1435
- opacity40: parseOpacity(opacity40Value, .4),
1436
- opacity80: parseOpacity(opacity80Value, .8),
1437
- opacity0: parseOpacity(opacity0Value, 0)
1438
- };
1439
- } catch (error) {
1440
- // Fallback to defaults if reading fails
1441
- opacityCacheRef.current = {
1442
- opacity50: .5,
1443
- opacity40: .4,
1444
- opacity80: .8,
1445
- opacity0: 0
1446
- };
1447
- }
1448
- }), []);
1449
- // Calculate base style with transforms (only dynamic values)
1450
- const baseStyle = useMemo((() => ({
1423
+ }), isOverLight = overLightConfig.isOverLight, shouldRenderOverLightLayers = enableOverLightLayers && isOverLight, baseStyle = {
1451
1424
  ...style,
1452
1425
  ...0 !== elasticity && !effectiveDisableEffects && {
1453
1426
  transform: transformStyle
1454
1427
  }
1455
- })), [ 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((() => ({
1456
- position: baseStylePosition || "absolute",
1457
- top: baseStyleTop || 0,
1458
- left: baseStyleLeft || 0
1459
- })), [ baseStylePosition, baseStyleTop, baseStyleLeft ]), baseStyleWidth = baseStyle.width, baseStyleHeight = baseStyle.height, glassSizeWidth = glassSize.width, glassSizeHeight = glassSize.height, adjustedSize = useMemo((() => ({
1460
- width: "fixed" !== baseStylePosition ? "100%" : baseStyleWidth || Math.max(glassSizeWidth, 0),
1461
- height: "fixed" !== baseStylePosition ? "100%" : baseStyleHeight || Math.max(glassSizeHeight, 0)
1462
- })), [ baseStylePosition, baseStyleWidth, baseStyleHeight, glassSizeWidth, glassSizeHeight ]), mouseOffsetX = mouseOffset.x, mouseOffsetY = mouseOffset.y, GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, gradientCalculations = useMemo((() => {
1463
- 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;
1464
- return {
1465
- isOverLight: isOverLight,
1466
- mx: mx,
1467
- my: my,
1468
- borderGradientAngle: borderGradientAngle,
1469
- borderStop1: borderStop1,
1470
- borderStop2: borderStop2,
1471
- borderOpacity1: borderOpacity1,
1472
- borderOpacity2: borderOpacity2,
1473
- borderOpacity3: borderOpacity3,
1474
- borderOpacity4: borderOpacity4,
1475
- hover1X: hover1X,
1476
- hover1Y: hover1Y,
1477
- hover2X: hover2X,
1478
- hover2Y: hover2Y,
1479
- hover3X: hover3X,
1480
- hover3Y: hover3Y,
1481
- baseX: baseX,
1482
- baseY: baseY
1483
- };
1484
- }), [ mouseOffsetX, mouseOffsetY, isOverLight ]), overLightOpacity = overLightConfig.opacity, opacityValues = useMemo((() => {
1485
- // Use cached values if available, otherwise fallback to defaults
1486
- const opacity50 = opacityCacheRef.current?.opacity50 ?? .5, opacity40 = opacityCacheRef.current?.opacity40 ?? .4, opacity80 = opacityCacheRef.current?.opacity80 ?? .8, opacity0 = opacityCacheRef.current?.opacity0 ?? 0;
1487
- // Dynamic multiplier for overlay
1488
- return {
1489
- hover1: isHovered || isActive ? opacity50 : opacity0,
1490
- hover2: isActive ? opacity50 : opacity0,
1491
- hover3: isHovered ? opacity40 : isActive ? opacity80 : opacity0,
1492
- base: isOverLight ? overLightOpacity || opacity40 : opacity0,
1493
- over: isOverLight ? 1.1 * (overLightOpacity || opacity40) : opacity0
1494
- };
1495
- }), [ 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((() => {
1496
- // RGB color values for rgba() functions
1497
- // Note: CSS doesn't support rgba(var(--rgb), opacity) syntax, so we use direct values
1498
- // These values align with design tokens: --atomix-white-rgb and --atomix-black-rgb
1499
- // The actual RGB values are defined in SCSS and should match these fallbacks
1500
- // TODO: Consider reading from CSS custom properties if browser support improves
1501
- const whiteColor = "255, 255, 255";
1502
- // Matches --atomix-white-rgb design token
1503
- // Matches --atomix-black-rgb design token
1504
- return {
1505
- // Standard CSS custom properties for dynamic values
1506
- "--atomix-glass-radius": `${effectiveCornerRadius}px`,
1507
- "--atomix-glass-transform": baseStyleTransform || "none",
1508
- "--atomix-glass-position": positionStylesPosition,
1509
- "--atomix-glass-top": "fixed" !== positionStylesTop ? `${positionStylesTop}px` : "0",
1510
- "--atomix-glass-left": "fixed" !== positionStylesLeft ? `${positionStylesLeft}px` : "0",
1511
- "--atomix-glass-width": "fixed" !== baseStylePosition ? adjustedSizeWidth : `${adjustedSizeWidth}px`,
1512
- "--atomix-glass-height": "fixed" !== baseStylePosition ? adjustedSizeHeight : `${adjustedSizeHeight}px`,
1513
- // Border width: Use spacing token for consistency
1514
- "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
1515
- "--atomix-glass-blend-mode": gradientIsOverLight ? "multiply" : "overlay",
1516
- // Dynamic gradients and backgrounds
1517
- // Note: RGB values use design token-aligned constants (white: 255,255,255; black: 0,0,0)
1518
- "--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%)`,
1519
- "--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%)`,
1520
- "--atomix-glass-hover-1-opacity": opacityValuesHover1,
1521
- "--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}%)`,
1522
- "--atomix-glass-hover-2-opacity": opacityValuesHover2,
1523
- "--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}%)`,
1524
- "--atomix-glass-hover-3-opacity": opacityValuesHover3,
1525
- "--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}%)`,
1526
- "--atomix-glass-base-opacity": opacityValuesBase,
1527
- "--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})`,
1528
- "--atomix-glass-overlay-opacity": opacityValuesOver,
1529
- "--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})`
1530
- };
1531
- }), [
1532
- // Position styles - only specific properties
1533
- positionStylesPosition, positionStylesTop, positionStylesLeft,
1534
- // Adjusted size - only specific properties
1535
- adjustedSizeWidth, adjustedSizeHeight,
1536
- // Base style - only transform property
1537
- baseStyleTransform, baseStylePosition,
1538
- // Other values
1539
- effectiveCornerRadius, effectiveReducedMotion,
1540
- // Gradient calculations - extracted properties
1541
- gradientIsOverLight, gradientMx, gradientMy, gradientBorderGradientAngle, gradientBorderStop1, gradientBorderStop2, gradientBorderOpacity1, gradientBorderOpacity2, gradientBorderOpacity3, gradientBorderOpacity4, gradientHover1X, gradientHover1Y, gradientHover2X, gradientHover2Y, gradientHover3X, gradientHover3Y, gradientBaseX, gradientBaseY,
1542
- // Opacity values - extracted properties
1543
- opacityValuesHover1, opacityValuesHover2, opacityValuesHover3, opacityValuesBase, opacityValuesOver ]);
1544
- // Build className with state modifiers
1545
- return jsxs("div", {
1428
+ }, 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 = {
1429
+ position: style.position || "absolute",
1430
+ top: style.top || 0,
1431
+ left: style.left || 0
1432
+ }, adjustedSize = {
1433
+ width: "fixed" !== style.position ? "100%" : style.width ? style.width : Math.max(glassSize.width, 0),
1434
+ height: "fixed" !== style.position ? "100%" : style.height ? style.height : Math.max(glassSize.height, 0)
1435
+ }, 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 = {
1436
+ hover1: isHovered || isActive ? .5 : 0,
1437
+ hover2: isActive ? .5 : 0,
1438
+ hover3: isHovered ? .4 : isActive ? .8 : 0,
1439
+ base: isOverLight ? overLightOpacity || .4 : 0,
1440
+ over: isOverLight ? 1.1 * (overLightOpacity || .4) : 0
1441
+ }, whiteColor = "255, 255, 255", glassVars = {
1442
+ // Standard CSS custom properties for dynamic values
1443
+ "--atomix-glass-radius": `${effectiveCornerRadius}px`,
1444
+ "--atomix-glass-transform": transformStyle || "none",
1445
+ "--atomix-glass-position": positionStyles.position,
1446
+ "--atomix-glass-top": "fixed" !== positionStyles.top ? `${positionStyles.top}px` : "0",
1447
+ "--atomix-glass-left": "fixed" !== positionStyles.left ? `${positionStyles.left}px` : "0",
1448
+ "--atomix-glass-width": "fixed" !== style.position ? adjustedSize.width : `${adjustedSize.width}px`,
1449
+ "--atomix-glass-height": "fixed" !== style.position ? adjustedSize.height : `${adjustedSize.height}px`,
1450
+ // Border width: Use spacing token for consistency
1451
+ "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
1452
+ "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay",
1453
+ // Dynamic gradients and backgrounds
1454
+ "--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%)`,
1455
+ "--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%)`,
1456
+ "--atomix-glass-hover-1-opacity": opacityValues.hover1,
1457
+ "--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}%)`,
1458
+ "--atomix-glass-hover-2-opacity": opacityValues.hover2,
1459
+ "--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}%)`,
1460
+ "--atomix-glass-hover-3-opacity": opacityValues.hover3,
1461
+ "--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}%)`,
1462
+ "--atomix-glass-base-opacity": opacityValues.base,
1463
+ "--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})`,
1464
+ "--atomix-glass-overlay-opacity": opacityValues.over,
1465
+ "--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})`
1466
+ };
1467
+ return jsxs("div", {
1546
1468
  className: componentClassName,
1547
1469
  style: glassVars,
1548
1470
  role: role || (onClick ? "button" : void 0),
@@ -2063,69 +1985,103 @@ const sizeMap = {
2063
1985
  * Icon component that displays a Phosphor icon
2064
1986
  */ Icon.displayName = "Icon";
2065
1987
 
1988
+ /**
1989
+ * Theme Naming Utility
1990
+ *
1991
+ * Provides consistent naming conventions for CSS classes, CSS variables,
1992
+ * and JavaScript properties throughout the theme system.
1993
+ */
1994
+ class ThemeNaming {
1995
+ /**
1996
+ * Set the global prefix for all theme tokens
1997
+ * @param newPrefix - New prefix to use
1998
+ */
1999
+ static setPrefix(newPrefix) {
2000
+ this.prefix = newPrefix;
2001
+ }
2002
+ /**
2003
+ * Get the current prefix
2004
+ */ static getPrefix() {
2005
+ return this.prefix;
2006
+ }
2007
+ /**
2008
+ * Convert camelCase to kebab-case for CSS variables
2009
+ * @param str - String to convert
2010
+ */ static camelToKebab(str) {
2011
+ return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").toLowerCase();
2012
+ }
2013
+ /**
2014
+ * Convert kebab-case to camelCase for JavaScript properties
2015
+ * @param str - String to convert
2016
+ */ static kebabToCamel(str) {
2017
+ return str.replace(/-([a-z])/g, (g => g[1].toUpperCase()));
2018
+ }
2019
+ /**
2020
+ * Create a CSS variable name
2021
+ * @param token - Token name in camelCase
2022
+ */ static cssVar(token) {
2023
+ return `--${this.prefix}-${this.camelToKebab(token)}`;
2024
+ }
2025
+ /**
2026
+ * Create a BEM CSS class name
2027
+ * @param block - Block name
2028
+ * @param element - Element name (optional)
2029
+ * @param modifier - Modifier name (optional)
2030
+ */ static bemClass(block, element, modifier) {
2031
+ let className = `c-${block}`;
2032
+ return element && (className += `__${element}`), modifier && (className += `--${modifier}`),
2033
+ className;
2034
+ }
2035
+ /**
2036
+ * Create a variant class name
2037
+ * @param component - Component name
2038
+ * @param variant - Variant name
2039
+ */ static variantClass(component, variant) {
2040
+ return `c-${component}--${variant}`;
2041
+ }
2042
+ /**
2043
+ * Create a size class name
2044
+ * @param component - Component name
2045
+ * @param size - Size name
2046
+ */ static sizeClass(component, size) {
2047
+ return `c-${component}--${size}`;
2048
+ }
2049
+ /**
2050
+ * Create a state class name
2051
+ * @param component - Component name
2052
+ * @param state - State name
2053
+ */ static stateClass(component, state) {
2054
+ return `c-${component}--${state}`;
2055
+ }
2056
+ /**
2057
+ * Create a utility class name
2058
+ * @param utility - Utility name
2059
+ */ static utilityClass(utility) {
2060
+ return `u-${utility}`;
2061
+ }
2062
+ /**
2063
+ * Create a layout class name
2064
+ * @param layout - Layout name
2065
+ */ static layoutClass(layout) {
2066
+ return `l-${layout}`;
2067
+ }
2068
+ /**
2069
+ * Create an object class name
2070
+ * @param object - Object name
2071
+ */ static objectClass(object) {
2072
+ return `o-${object}`;
2073
+ }
2074
+ }
2075
+
2076
+ ThemeNaming.prefix = "atomix";
2077
+
2066
2078
  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) => {
2067
- const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement = useMemo((() => loading ? null : iconName ? jsx(Icon, {
2079
+ const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement = iconName ? jsx(Icon, {
2068
2080
  name: iconName,
2069
2081
  size: iconSize
2070
- }) : icon), [ icon, iconName, iconSize, loading ]), {generateButtonClass: generateButtonClass, handleClick: handleClick} =
2071
- /**
2072
- * Button state and functionality
2073
- * @param initialProps - Initial button properties
2074
- * @returns Button state and methods
2075
- */
2076
- function(initialProps) {
2077
- // Default button properties
2078
- const defaultProps = {
2079
- variant: "primary",
2080
- size: "md",
2081
- disabled: !1,
2082
- rounded: !1,
2083
- loading: !1,
2084
- fullWidth: !1,
2085
- block: !1,
2086
- active: !1,
2087
- selected: !1,
2088
- ...initialProps
2089
- };
2090
- /**
2091
- * Generate button class based on properties
2092
- * @param props - Button properties
2093
- * @returns Class string
2094
- */ return {
2095
- defaultProps: defaultProps,
2096
- generateButtonClass: props => {
2097
- 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 : "";
2098
- return [ BUTTON.BASE_CLASS, `c-btn--${variant}`, sizeClass, iconOnlyClass, roundedClass, disabledClass, glassClass, loadingClass, fullWidthClass, blockClass, activeClass, selectedClass, className ].filter(Boolean).join(" ");
2099
- },
2100
- handleClick: handler => event => {
2101
- defaultProps.disabled || defaultProps.loading || !handler || handler(event);
2102
- }
2103
- };
2104
- }({
2105
- variant: variant,
2106
- size: size,
2107
- disabled: isDisabled,
2108
- rounded: rounded,
2109
- glass: glass,
2110
- loading: loading,
2111
- fullWidth: fullWidth,
2112
- block: block,
2113
- active: active,
2114
- selected: selected
2115
- }), buttonClass = useMemo((() => generateButtonClass({
2116
- variant: variant,
2117
- size: size,
2118
- disabled: isDisabled,
2119
- rounded: rounded,
2120
- iconOnly: iconOnly,
2121
- glass: glass,
2122
- loading: loading,
2123
- fullWidth: fullWidth,
2124
- block: block,
2125
- active: active,
2126
- selected: selected,
2127
- className: className
2128
- })), [ variant, size, isDisabled, rounded, iconOnly, glass, loading, fullWidth, block, active, selected, className, generateButtonClass ]), handleClickEvent = useCallback((event => {
2082
+ }) : icon;
2083
+ // Determine if we should render as a link
2084
+ 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 => {
2129
2085
  isDisabled ? event.preventDefault() : onClick?.(event);
2130
2086
  }), [ isDisabled, onClick ]), handleMouseEnter = useCallback((event => {
2131
2087
  isDisabled || onHover?.(event);
@@ -2133,28 +2089,23 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
2133
2089
  isDisabled || onFocus?.(event);
2134
2090
  }), [ isDisabled, onFocus ]), handleBlurEvent = useCallback((event => {
2135
2091
  isDisabled || onBlur?.(event);
2136
- }), [ 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((() => {
2137
- const iconSpan = iconElement && jsx("span", {
2138
- className: BUTTON.ICON_CLASS,
2139
- "aria-hidden": "true",
2140
- children: iconElement
2141
- }), spinnerElement = loading && jsx("span", {
2142
- className: BUTTON.SPINNER_CLASS,
2092
+ }), [ isDisabled, onBlur ]), buttonText = loading && loadingText ? loadingText : label || children, spinnerSize = "sm" === size ? "sm" : "lg" === size ? "md" : "sm", buttonContent = jsxs(Fragment, {
2093
+ children: [ loading && jsx("span", {
2094
+ className: ThemeNaming.bemClass("btn", "spinner"),
2143
2095
  "aria-hidden": "true",
2144
2096
  children: jsx(Spinner, {
2145
2097
  size: spinnerSize,
2146
2098
  variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
2147
2099
  })
2148
- }), labelElement = !iconOnly && buttonText && jsx("span", {
2149
- className: BUTTON.LABEL_CLASS,
2100
+ }), iconElement && !loading && jsx("span", {
2101
+ className: ThemeNaming.bemClass("btn", "icon"),
2102
+ "aria-hidden": "true",
2103
+ children: iconElement
2104
+ }), !iconOnly && buttonText && jsx("span", {
2105
+ className: ThemeNaming.bemClass("btn", "label"),
2150
2106
  children: buttonText
2151
- });
2152
- return jsxs(Fragment, "end" === iconPosition ? {
2153
- children: [ labelElement, spinnerElement, iconSpan ]
2154
- } : {
2155
- children: [ spinnerElement, iconSpan, labelElement ]
2156
- });
2157
- }), [ iconElement, iconPosition, iconOnly, buttonText, loading, spinnerSize, variant ]), buttonProps = useMemo((() => ({
2107
+ }) ]
2108
+ }), buttonProps = {
2158
2109
  ref: ref,
2159
2110
  className: buttonClass,
2160
2111
  type: "button" !== Component || shouldRenderAsLink ? void 0 : type,
@@ -2172,8 +2123,16 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
2172
2123
  tabIndex: void 0 !== tabIndex ? tabIndex : isDisabled ? -1 : 0,
2173
2124
  style: style,
2174
2125
  ...props
2175
- })), [ ref, buttonClass, Component, type, handleClickEvent, handleMouseEnter, handleFocusEvent, handleBlurEvent, isDisabled, loading, ariaLabel, iconOnly, label, children, ariaDescribedBy, ariaExpanded, ariaControls, tabIndex, style, props ]);
2176
- // Determine if we should render as a link
2126
+ }, defaultGlassProps = {
2127
+ displacementScale: 20,
2128
+ blurAmount: 0,
2129
+ saturation: 200,
2130
+ elasticity: 0
2131
+ }, glassProps = !0 === glass ? defaultGlassProps : {
2132
+ ...defaultGlassProps,
2133
+ ...glass
2134
+ };
2135
+ // Handle click with loading check
2177
2136
  // Render as anchor if href is provided
2178
2137
  if (shouldRenderAsLink) {
2179
2138
  const {ref: _, ...buttonPropsWithoutRef} = buttonProps, anchorButtonProps = {
@@ -2193,22 +2152,10 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
2193
2152
  ...linkProps,
2194
2153
  children: buttonContent
2195
2154
  });
2196
- if (glass) {
2197
- const defaultGlassProps = {
2198
- displacementScale: 20,
2199
- blurAmount: 0,
2200
- saturation: 200,
2201
- elasticity: 0
2202
- }, glassProps = !0 === glass ? defaultGlassProps : {
2203
- ...defaultGlassProps,
2204
- ...glass
2205
- };
2206
- return jsx(AtomixGlass, {
2207
- ...glassProps,
2208
- children: linkElement
2209
- });
2210
- }
2211
- return linkElement;
2155
+ return glass ? jsx(AtomixGlass, {
2156
+ ...glassProps,
2157
+ children: linkElement
2158
+ }) : linkElement;
2212
2159
  }
2213
2160
  // Fallback to regular anchor tag
2214
2161
  const anchorElement = jsx("a", {
@@ -2219,46 +2166,20 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
2219
2166
  rel: "_blank" === target ? "noopener noreferrer" : void 0,
2220
2167
  children: buttonContent
2221
2168
  });
2222
- if (glass) {
2223
- const defaultGlassProps = {
2224
- displacementScale: 20,
2225
- blurAmount: 0,
2226
- saturation: 200,
2227
- elasticity: 0
2228
- }, glassProps = !0 === glass ? defaultGlassProps : {
2229
- ...defaultGlassProps,
2230
- ...glass
2231
- };
2232
- return jsx(AtomixGlass, {
2233
- ...glassProps,
2234
- children: anchorElement
2235
- });
2236
- }
2237
- return anchorElement;
2238
- }
2239
- // Default button rendering
2240
- if (glass) {
2241
- const defaultGlassProps = {
2242
- displacementScale: 20,
2243
- blurAmount: 0,
2244
- saturation: 200,
2245
- elasticity: 0
2246
- }, glassProps = !0 === glass ? defaultGlassProps : {
2247
- ...defaultGlassProps,
2248
- ...glass
2249
- };
2250
- return jsx(AtomixGlass, {
2169
+ return glass ? jsx(AtomixGlass, {
2251
2170
  ...glassProps,
2252
- children: jsx(Component, {
2253
- ...buttonProps,
2254
- children: buttonContent
2255
- })
2256
- });
2171
+ children: anchorElement
2172
+ }) : anchorElement;
2257
2173
  }
2258
- return jsx(Component, {
2174
+ // Default button rendering
2175
+ const buttonElement = jsx(Component, {
2259
2176
  ...buttonProps,
2260
2177
  children: buttonContent
2261
2178
  });
2179
+ return glass ? jsx(AtomixGlass, {
2180
+ ...glassProps,
2181
+ children: buttonElement
2182
+ }) : buttonElement;
2262
2183
  })));
2263
2184
 
2264
2185
  Button.displayName = "Button";