@shohojdhara/atomix 0.5.0 → 0.5.2

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 (168) hide show
  1. package/atomix.config.ts +12 -0
  2. package/build-tools/webpack-loader.js +5 -4
  3. package/dist/atomix.css +230 -83
  4. package/dist/atomix.css.map +1 -1
  5. package/dist/atomix.min.css +1 -1
  6. package/dist/atomix.min.css.map +1 -1
  7. package/dist/build-tools/webpack-loader.js +5 -4
  8. package/dist/charts.d.ts +24 -23
  9. package/dist/charts.js +271 -369
  10. package/dist/charts.js.map +1 -1
  11. package/dist/config.d.ts +624 -0
  12. package/dist/config.js +59 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/core.d.ts +3 -2
  15. package/dist/core.js +342 -382
  16. package/dist/core.js.map +1 -1
  17. package/dist/forms.d.ts +4 -6
  18. package/dist/forms.js +233 -334
  19. package/dist/forms.js.map +1 -1
  20. package/dist/heavy.d.ts +11 -2
  21. package/dist/heavy.js +406 -445
  22. package/dist/heavy.js.map +1 -1
  23. package/dist/index.d.ts +109 -65
  24. package/dist/index.esm.js +654 -748
  25. package/dist/index.esm.js.map +1 -1
  26. package/dist/index.js +621 -717
  27. package/dist/index.js.map +1 -1
  28. package/dist/index.min.js +1 -1
  29. package/dist/index.min.js.map +1 -1
  30. package/dist/layout.js +59 -60
  31. package/dist/layout.js.map +1 -1
  32. package/dist/theme.js +4 -4
  33. package/dist/theme.js.map +1 -1
  34. package/package.json +24 -9
  35. package/scripts/atomix-cli.js +15 -1
  36. package/scripts/cli/__tests__/complexity-utils.test.js +24 -0
  37. package/scripts/cli/__tests__/detector.test.js +50 -0
  38. package/scripts/cli/__tests__/template-engine.test.js +23 -0
  39. package/scripts/cli/__tests__/test-setup.js +1 -133
  40. package/scripts/cli/commands/doctor.js +15 -3
  41. package/scripts/cli/commands/generate.js +113 -51
  42. package/scripts/cli/internal/ai-engine.js +30 -10
  43. package/scripts/cli/internal/complexity-utils.js +60 -0
  44. package/scripts/cli/internal/component-validator.js +49 -16
  45. package/scripts/cli/internal/generator.js +89 -36
  46. package/scripts/cli/internal/hook-generator.js +5 -2
  47. package/scripts/cli/internal/itcss-generator.js +16 -12
  48. package/scripts/cli/templates/next-templates.js +81 -30
  49. package/scripts/cli/templates/storybook-templates.js +12 -2
  50. package/scripts/cli/utils/detector.js +45 -7
  51. package/scripts/cli/utils/diagnostics.js +78 -0
  52. package/scripts/cli/utils/telemetry.js +13 -0
  53. package/src/components/Accordion/Accordion.stories.tsx +4 -0
  54. package/src/components/AtomixGlass/AtomixGlass.tsx +188 -128
  55. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +63 -91
  56. package/src/components/AtomixGlass/PerformanceDashboard.tsx +153 -201
  57. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +9 -6
  58. package/src/components/AtomixGlass/glass-utils.ts +51 -1
  59. package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +52 -46
  60. package/src/components/AtomixGlass/stories/Examples.stories.tsx +573 -236
  61. package/src/components/AtomixGlass/stories/Playground.stories.tsx +88 -41
  62. package/src/components/AtomixGlass/stories/argTypes.ts +19 -19
  63. package/src/components/AtomixGlass/stories/shared-components.tsx +7 -12
  64. package/src/components/AtomixGlass/stories/types.ts +3 -3
  65. package/src/components/Button/Button.tsx +114 -57
  66. package/src/components/Callout/Callout.tsx +4 -4
  67. package/src/components/Chart/ChartRenderer.tsx +1 -1
  68. package/src/components/Chart/DonutChart.tsx +11 -8
  69. package/src/components/EdgePanel/EdgePanel.tsx +119 -115
  70. package/src/components/Form/Select.tsx +4 -4
  71. package/src/components/List/List.tsx +4 -4
  72. package/src/components/Navigation/SideMenu/SideMenu.tsx +6 -6
  73. package/src/components/PhotoViewer/PhotoViewerImage.tsx +1 -1
  74. package/src/components/ProductReview/ProductReview.tsx +4 -2
  75. package/src/components/Rating/Rating.tsx +4 -2
  76. package/src/components/SectionIntro/SectionIntro.tsx +4 -2
  77. package/src/components/Steps/Steps.tsx +1 -1
  78. package/src/components/Tabs/Tabs.tsx +5 -5
  79. package/src/components/Testimonial/Testimonial.tsx +4 -2
  80. package/src/components/VideoPlayer/VideoPlayer.tsx +4 -2
  81. package/src/layouts/CssGrid/CssGrid.stories.tsx +464 -0
  82. package/src/layouts/CssGrid/CssGrid.tsx +215 -0
  83. package/src/layouts/CssGrid/index.ts +8 -0
  84. package/src/layouts/CssGrid/scripts/CssGrid.js +284 -0
  85. package/src/layouts/CssGrid/scripts/index.js +43 -0
  86. package/src/layouts/Grid/scripts/Container.js +139 -0
  87. package/src/layouts/Grid/scripts/Grid.js +184 -0
  88. package/src/layouts/Grid/scripts/GridCol.js +273 -0
  89. package/src/layouts/Grid/scripts/Row.js +154 -0
  90. package/src/layouts/Grid/scripts/index.js +48 -0
  91. package/src/layouts/MasonryGrid/MasonryGrid.tsx +71 -59
  92. package/src/lib/composables/atomix-glass/useGlassSize.ts +1 -1
  93. package/src/lib/composables/useAccordion.ts +5 -5
  94. package/src/lib/composables/useAtomixGlass.ts +111 -74
  95. package/src/lib/composables/useAtomixGlassStyles.ts +0 -2
  96. package/src/lib/composables/useBarChart.ts +2 -2
  97. package/src/lib/composables/useChart.ts +3 -2
  98. package/src/lib/composables/useChartToolbar.ts +48 -66
  99. package/src/lib/composables/useDataTable.ts +1 -1
  100. package/src/lib/composables/useDatePicker.ts +2 -2
  101. package/src/lib/composables/useEdgePanel.ts +45 -54
  102. package/src/lib/composables/useHeroBackgroundSlider.ts +5 -5
  103. package/src/lib/composables/usePhotoViewer.ts +2 -3
  104. package/src/lib/composables/usePieChart.ts +1 -1
  105. package/src/lib/composables/usePopover.ts +151 -139
  106. package/src/lib/composables/useSideMenu.ts +28 -41
  107. package/src/lib/composables/useSlider.ts +2 -6
  108. package/src/lib/composables/useTooltip.ts +2 -2
  109. package/src/lib/config/index.ts +39 -0
  110. package/src/lib/constants/components.ts +1 -0
  111. package/src/lib/theme/devtools/Comparator.tsx +1 -1
  112. package/src/lib/theme/devtools/Inspector.tsx +1 -1
  113. package/src/lib/theme/devtools/LiveEditor.tsx +1 -1
  114. package/src/lib/theme/runtime/ThemeProvider.tsx +1 -1
  115. package/src/lib/types/components.ts +1 -0
  116. package/src/styles/01-settings/_index.scss +1 -0
  117. package/src/styles/01-settings/_settings.atomix-glass.scss +174 -0
  118. package/src/styles/01-settings/_settings.masonry-grid.scss +42 -6
  119. package/src/styles/02-tools/_tools.glass.scss +6 -0
  120. package/src/styles/05-objects/_objects.masonry-grid.scss +162 -24
  121. package/src/styles/06-components/_components.atomix-glass.scss +160 -99
  122. package/scripts/cli/__tests__/README.md +0 -81
  123. package/scripts/cli/__tests__/basic.test.js +0 -116
  124. package/scripts/cli/__tests__/clean.test.js +0 -278
  125. package/scripts/cli/__tests__/component-generator.test.js +0 -332
  126. package/scripts/cli/__tests__/component-validator.test.js +0 -433
  127. package/scripts/cli/__tests__/generator.test.js +0 -613
  128. package/scripts/cli/__tests__/glass-motion.test.js +0 -256
  129. package/scripts/cli/__tests__/integration.test.js +0 -938
  130. package/scripts/cli/__tests__/migrate.test.js +0 -74
  131. package/scripts/cli/__tests__/security.test.js +0 -206
  132. package/scripts/cli/__tests__/theme-bridge.test.js +0 -507
  133. package/scripts/cli/__tests__/token-manager.test.js +0 -251
  134. package/scripts/cli/__tests__/token-provider.test.js +0 -361
  135. package/scripts/cli/__tests__/utils.test.js +0 -165
  136. package/src/components/AtomixGlass/stories/AnimationTests.stories.tsx +0 -95
  137. package/src/components/AtomixGlass/stories/CardExamples.stories.tsx +0 -212
  138. package/src/components/AtomixGlass/stories/Customization.stories.tsx +0 -131
  139. package/src/components/AtomixGlass/stories/DashboardExamples.stories.tsx +0 -348
  140. package/src/components/AtomixGlass/stories/EcommerceExamples.stories.tsx +0 -410
  141. package/src/components/AtomixGlass/stories/FormExamples.stories.tsx +0 -436
  142. package/src/components/AtomixGlass/stories/HeroExamples.stories.tsx +0 -264
  143. package/src/components/AtomixGlass/stories/InteractivePlayground.stories.tsx +0 -247
  144. package/src/components/AtomixGlass/stories/MobileUIExamples.stories.tsx +0 -418
  145. package/src/components/AtomixGlass/stories/ModalExamples.stories.tsx +0 -402
  146. package/src/components/AtomixGlass/stories/Modes.stories.tsx +0 -1082
  147. package/src/components/AtomixGlass/stories/Overview.stories.tsx +0 -497
  148. package/src/components/AtomixGlass/stories/Performance.stories.tsx +0 -103
  149. package/src/components/AtomixGlass/stories/PresetGallery.stories.tsx +0 -335
  150. package/src/components/AtomixGlass/stories/Shaders.stories.tsx +0 -395
  151. package/src/components/AtomixGlass/stories/WidgetExamples.stories.tsx +0 -441
  152. package/src/components/TypedButton/TypedButton.stories.tsx +0 -59
  153. package/src/components/TypedButton/TypedButton.tsx +0 -39
  154. package/src/components/TypedButton/index.ts +0 -2
  155. package/src/lib/composables/useBreadcrumb.ts +0 -81
  156. package/src/lib/composables/useChartInteractions.ts +0 -123
  157. package/src/lib/composables/useChartPerformance.ts +0 -347
  158. package/src/lib/composables/useDropdown.ts +0 -338
  159. package/src/lib/composables/useModal.ts +0 -110
  160. package/src/lib/composables/useTypedButton.ts +0 -66
  161. package/src/lib/hooks/usePerformanceMonitor.ts +0 -148
  162. package/src/lib/utils/displacement-generator.ts +0 -92
  163. package/src/lib/utils/memoryMonitor.ts +0 -191
  164. package/src/styles/01-settings/_settings.testtypecheck.scss +0 -53
  165. package/src/styles/01-settings/_settings.typedbutton.scss +0 -53
  166. package/src/styles/06-components/_components.testbutton.scss +0 -212
  167. package/src/styles/06-components/_components.testtypecheck.scss +0 -212
  168. package/src/styles/06-components/_components.typedbutton.scss +0 -212
package/dist/charts.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
 
3
- import React, { useState, useRef, useEffect, useCallback, useMemo, memo, forwardRef, createContext, useContext } from "react";
3
+ import React, { useState, useRef, useEffect, useCallback, useMemo, memo, forwardRef, useId, createContext, useContext } from "react";
4
4
 
5
5
  import * as PhosphorIcons from "@phosphor-icons/react";
6
6
 
@@ -470,6 +470,7 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
470
470
  FILTER_OVERLAY_CLASS: "c-atomix-glass__filter-overlay",
471
471
  FILTER_SHADOW_CLASS: "c-atomix-glass__filter-shadow",
472
472
  CONTENT_CLASS: "c-atomix-glass__content",
473
+ BORDER_BACKDROP_CLASS: "c-atomix-glass__border-backdrop",
473
474
  BORDER_1_CLASS: "c-atomix-glass__border-1",
474
475
  BORDER_2_CLASS: "c-atomix-glass__border-2",
475
476
  HOVER_1_CLASS: "c-atomix-glass__hover-1",
@@ -767,8 +768,11 @@ function useChart(initialProps) {
767
768
  }), animationFrameRef = useRef(null);
768
769
  // Default chart properties
769
770
  // Cleanup animation frame on unmount
770
- useEffect((() => () => {
771
- animationFrameRef.current && cancelAnimationFrame(animationFrameRef.current);
771
+ useEffect((() => {
772
+ const currentRef = animationFrameRef.current;
773
+ return () => {
774
+ currentRef && cancelAnimationFrame(currentRef);
775
+ };
772
776
  }), []);
773
777
  /**
774
778
  * Point interaction handlers
@@ -1669,7 +1673,7 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateDistance = (pos1, pos2)
1669
1673
  default:
1670
1674
  return console.warn("AtomixGlass: Invalid displacement mode"), displacementMap;
1671
1675
  }
1672
- }, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsx("svg", {
1676
+ }, sharedShaderCache = new Map, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsx("svg", {
1673
1677
  style: {
1674
1678
  position: "absolute",
1675
1679
  width: "100%",
@@ -1810,24 +1814,17 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateDistance = (pos1, pos2)
1810
1814
  */ GlassFilterComponent.displayName = "GlassFilter";
1811
1815
 
1812
1816
  // Memoize component to prevent unnecessary re-renders
1813
- 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));
1814
-
1815
- // Module-level counter for deterministic ID generation
1816
- let idCounter = 0;
1817
-
1818
- // Module-level shared shader cache with LRU eviction
1819
- const 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 = {
1817
+ 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)), AtomixGlassContainer = forwardRef((({children: children, className: className = "", style: style, displacementScale: displacementScale = 25, blurAmount: blurAmount = .0625, saturation: saturation = 180, aberrationIntensity: aberrationIntensity = 2, mouseOffset: mouseOffset = {
1820
1818
  x: 0,
1821
1819
  y: 0
1822
1820
  }, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0, padding: padding = "0 0", glassSize: glassSize = {
1823
1821
  width: 0,
1824
1822
  height: 0
1825
- }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1,
1823
+ }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, isFixedOrSticky: isFixedOrSticky = !1,
1826
1824
  // Phase 1: Animation System props
1827
1825
  shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", contentRef: contentRef}, ref) => {
1828
- // Generate a stable, deterministic ID for SSR compatibility
1829
- // Use a module-level counter that's consistent across server and client
1830
- const filterId = useMemo((() => "atomix-glass-filter-" + ++idCounter), []), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null), shaderUpdateTimeoutRef = useRef(null), animationFrameRef = useRef(null);
1826
+ // React 18 useId — stable, unique, and SSR-safe (no module-level counter)
1827
+ const rawId = useId(), filterId = useMemo((() => `atomix-glass-filter-${rawId.replace(/:/g, "")}`), [ rawId ]), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null), shaderUpdateTimeoutRef = useRef(null), animationFrameRef = useRef(null);
1831
1828
  // Lazy load shader utilities only when shader mode is needed
1832
1829
  useEffect((() => {
1833
1830
  "shader" === mode ?
@@ -1850,9 +1847,7 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
1850
1847
  // Create cache key from size and variant
1851
1848
  const cacheKey = `${glassSize.width}x${glassSize.height}-${shaderVariant}`, cachedUrl = (key => {
1852
1849
  const entry = sharedShaderCache.get(key);
1853
- return entry ? (
1854
- // Update access timestamp for LRU
1855
- entry.timestamp = Date.now(), entry.url) : null;
1850
+ return entry ? (entry.timestamp = Date.now(), entry.url) : null;
1856
1851
  })(cacheKey);
1857
1852
  // Check shared cache first
1858
1853
  if (cachedUrl) return void setShaderMapUrl(cachedUrl);
@@ -1863,29 +1858,24 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
1863
1858
  if (shaderUtilsRef.current) try {
1864
1859
  const {ShaderDisplacementGenerator: ShaderDisplacementGenerator, fragmentShaders: fragmentShaders} = shaderUtilsRef.current;
1865
1860
  shaderGeneratorRef.current?.destroy();
1866
- const selectedShader = fragmentShaders[shaderVariant] || fragmentShaders.liquidGlass;
1861
+ const selectedShader = fragmentShaders[shaderVariant] ?? fragmentShaders.liquidGlass;
1867
1862
  shaderGeneratorRef.current = new ShaderDisplacementGenerator({
1868
1863
  width: glassSize.width,
1869
1864
  height: glassSize.height,
1870
1865
  fragment: selectedShader
1871
1866
  }), shaderUpdateTimeoutRef.current = setTimeout((() => {
1872
- const url = shaderGeneratorRef.current?.updateShader() || "";
1867
+ const url = shaderGeneratorRef.current?.updateShader() ?? "";
1873
1868
  url && ((key, url) => {
1874
- // Evict oldest entries if at capacity
1875
1869
  if (sharedShaderCache.size >= 15) {
1876
1870
  const entries = Array.from(sharedShaderCache.entries());
1877
- // Sort by timestamp (oldest first)
1878
- entries.sort(((a, b) => a[1].timestamp - b[1].timestamp));
1879
- // Remove oldest entry
1880
- const oldestEntry = entries[0];
1881
- oldestEntry && sharedShaderCache.delete(oldestEntry[0]);
1871
+ entries.sort(((a, b) => a[1].timestamp - b[1].timestamp));
1872
+ const oldest = entries[0];
1873
+ oldest && sharedShaderCache.delete(oldest[0]);
1882
1874
  }
1883
1875
  sharedShaderCache.set(key, {
1884
1876
  url: url,
1885
1877
  timestamp: Date.now()
1886
- }),
1887
- // Development mode: log cache size
1888
- "undefined" != typeof process && "production" === process.env?.NODE_ENV || sharedShaderCache.size;
1878
+ }), "undefined" != typeof process && "production" === process.env?.NODE_ENV || sharedShaderCache.size;
1889
1879
  })(cacheKey, url), setShaderMapUrl(url);
1890
1880
  }), 100);
1891
1881
  } catch (error) {
@@ -1954,7 +1944,6 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
1954
1944
  console.warn("AtomixGlassContainer: Error getting element bounds", error), setRectCache(null);
1955
1945
  }
1956
1946
  }), [ ref, glassSize ]);
1957
- // Pre-calculate static multipliers outside useMemo
1958
1947
  const liquidBlur = useMemo((() => {
1959
1948
  const defaultBlur = {
1960
1949
  baseBlur: blurAmount,
@@ -2023,7 +2012,6 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
2023
2012
  }), [ borderRadius, backdropStyle, mouseOffset, overLight, effectiveWithoutEffects, overLightConfig ]);
2024
2013
  return jsx("div", {
2025
2014
  ref: el => {
2026
- // Apply force no-transition
2027
2015
  // Handle forwarded ref
2028
2016
  "function" == typeof ref ? ref(el) : ref && (ref.current = el);
2029
2017
  },
@@ -2065,6 +2053,7 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
2065
2053
  });
2066
2054
  }));
2067
2055
 
2056
+ // ─── Blur multiplier constants (module-level, never change at runtime) ────────
2068
2057
  AtomixGlassContainer.displayName = "AtomixGlassContainer";
2069
2058
 
2070
2059
  // Singleton instance
@@ -2265,8 +2254,6 @@ class {
2265
2254
  backdropFilterString = !withLiquidBlur || effectiveReducedMotion || effectiveWithoutEffects || area > 18e4 ? `blur(${clampBlur(Math.max(liquidBlur.baseBlur, .8 * liquidBlur.edgeBlur, 1.1 * liquidBlur.centerBlur, .9 * liquidBlur.flowBlur))}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig.contrast}) brightness(${overLightConfig.brightness})` : `blur(${clampBlur(.4 * liquidBlur.baseBlur + .25 * liquidBlur.edgeBlur + .15 * liquidBlur.centerBlur + .2 * liquidBlur.flowBlur)}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig.contrast}) brightness(${overLightConfig.brightness})`;
2266
2255
  // Container variables
2267
2256
  const style = containerElement.style;
2268
- style.setProperty("--atomix-glass-container-width", isFixedOrSticky ? `${glassSize.width}` : "100%"),
2269
- style.setProperty("--atomix-glass-container-height", isFixedOrSticky ? `${glassSize.height}` : "100%"),
2270
2257
  style.setProperty("--atomix-glass-container-padding", padding), style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
2271
2258
  style.setProperty("--atomix-glass-container-backdrop", backdropFilterString),
2272
2259
  // Shadows
@@ -2727,47 +2714,55 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2727
2714
  return "undefined" == typeof process || process.env, finalConfig;
2728
2715
  }
2729
2716
  return "undefined" == typeof process || process.env, baseConfig;
2730
- }), [ overLight, getEffectiveOverLight, isHovered, isActive, validateConfigValue, debugOverLight ]), transformStyle = useMemo((() => effectiveWithoutEffects || isActive && Boolean(onClick) ? "scale(0.98)" : "scale(1)"), [ effectiveWithoutEffects, isActive, onClick ]), updateRectRef = useRef(null), handleGlobalMousePosition = useCallback((globalPos => {
2731
- if (externalGlobalMousePosition && externalMouseOffset) return;
2732
- if (effectiveWithoutEffects) return;
2733
- const container = mouseContainer?.current || glassRef.current;
2734
- if (!container) return;
2735
- // Use cached rect if available, otherwise get new one
2736
- let rect = cachedRectRef.current;
2737
- if (rect && 0 !== rect.width && 0 !== rect.height || (rect = container.getBoundingClientRect(),
2738
- cachedRectRef.current = rect), 0 === rect.width || 0 === rect.height) return;
2739
- const center = calculateElementCenter(rect);
2740
- // Write raw target — the lerp loop will smoothly pursue it
2741
- targetMouseOffsetRef.current = {
2742
- x: (globalPos.x - center.x) / rect.width * 100,
2743
- y: (globalPos.y - center.y) / rect.height * 100
2744
- }, targetGlobalMousePositionRef.current = globalPos;
2745
- }), [ mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects ]), startLerpLoop = useCallback((() => {
2717
+ }), [ overLight, getEffectiveOverLight, isHovered, isActive, validateConfigValue, debugOverLight ]), transformStyle = useMemo((() => effectiveWithoutEffects || isActive && Boolean(onClick) ? "scale(0.98)" : "scale(1)"), [ effectiveWithoutEffects, isActive, onClick ]), updateRectRef = useRef(null), stopLerpLoop = useCallback((() => {
2718
+ lerpActiveRef.current = !1, null !== lerpRafRef.current && (cancelAnimationFrame(lerpRafRef.current),
2719
+ lerpRafRef.current = null);
2720
+ }), []), startLerpLoop = useCallback((() => {
2746
2721
  if (lerpActiveRef.current) return;
2747
2722
  lerpActiveRef.current = !0;
2748
2723
  const LERP_T = CONSTANTS.LERP_FACTOR, tick = () => {
2749
2724
  if (!lerpActiveRef.current) return;
2750
- // Add ref validity check to prevent memory leaks
2751
- if (!glassRef.current || !wrapperRef?.current) return void (lerpActiveRef.current = !1);
2725
+ if (!glassRef.current) return void (lerpActiveRef.current = !1);
2752
2726
  const cur = internalMouseOffsetRef.current, tgt = targetMouseOffsetRef.current, dx = tgt.x - cur.x, dy = tgt.y - cur.y;
2753
2727
  // If we're close enough, snap and park
2754
- if (Math.abs(dx) < .05 && Math.abs(dy) < .05) internalMouseOffsetRef.current = {
2728
+ if (Math.abs(dx) < .01 && Math.abs(dy) < .01) return internalMouseOffsetRef.current = {
2755
2729
  ...tgt
2756
2730
  }, internalGlobalMousePositionRef.current = {
2757
2731
  ...targetGlobalMousePositionRef.current
2758
- }; else {
2759
- internalMouseOffsetRef.current = {
2760
- x: lerp$1(cur.x, tgt.x, LERP_T),
2761
- y: lerp$1(cur.y, tgt.y, LERP_T)
2762
- };
2763
- const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
2764
- internalGlobalMousePositionRef.current = {
2765
- x: lerp$1(curG.x, tgtG.x, LERP_T),
2766
- y: lerp$1(curG.y, tgtG.y, LERP_T)
2767
- };
2768
- }
2769
- // Imperative style update with the smoothed values
2770
- updateAtomixGlassStyles(wrapperRef.current, glassRef.current, {
2732
+ },
2733
+ // Final update and stop
2734
+ updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
2735
+ mouseOffset: internalMouseOffsetRef.current,
2736
+ globalMousePosition: internalGlobalMousePositionRef.current,
2737
+ glassSize: glassSize,
2738
+ isHovered: isHovered,
2739
+ isActive: isActive,
2740
+ isOverLight: overLightConfig.isOverLight,
2741
+ baseOverLightConfig: overLightConfig,
2742
+ effectiveBorderRadius: effectiveBorderRadius,
2743
+ effectiveWithoutEffects: effectiveWithoutEffects,
2744
+ effectiveReducedMotion: effectiveReducedMotion,
2745
+ elasticity: elasticity,
2746
+ directionalScale: isActive && Boolean(onClick) ? "scale(0.96)" : "scale(1)",
2747
+ onClick: onClick,
2748
+ withLiquidBlur: withLiquidBlur,
2749
+ blurAmount: blurAmount,
2750
+ saturation: saturation,
2751
+ padding: padding,
2752
+ isFixedOrSticky: isFixedOrSticky
2753
+ }), void stopLerpLoop();
2754
+ // Smooth step
2755
+ internalMouseOffsetRef.current = {
2756
+ x: lerp$1(cur.x, tgt.x, LERP_T),
2757
+ y: lerp$1(cur.y, tgt.y, LERP_T)
2758
+ };
2759
+ const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
2760
+ internalGlobalMousePositionRef.current = {
2761
+ x: lerp$1(curG.x, tgtG.x, LERP_T),
2762
+ y: lerp$1(curG.y, tgtG.y, LERP_T)
2763
+ },
2764
+ // Imperative style update
2765
+ updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
2771
2766
  mouseOffset: internalMouseOffsetRef.current,
2772
2767
  globalMousePosition: internalGlobalMousePositionRef.current,
2773
2768
  glassSize: glassSize,
@@ -2790,10 +2785,24 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2790
2785
  };
2791
2786
  // 0.08 – lower = more viscous
2792
2787
  lerpRafRef.current = requestAnimationFrame(tick);
2793
- }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding, isFixedOrSticky ]), stopLerpLoop = useCallback((() => {
2794
- lerpActiveRef.current = !1, null !== lerpRafRef.current && (cancelAnimationFrame(lerpRafRef.current),
2795
- lerpRafRef.current = null);
2796
- }), []);
2788
+ }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding, isFixedOrSticky, stopLerpLoop ]), handleGlobalMousePosition = useCallback((globalPos => {
2789
+ if (externalGlobalMousePosition && externalMouseOffset) return;
2790
+ if (effectiveWithoutEffects) return;
2791
+ const container = mouseContainer?.current || glassRef.current;
2792
+ if (!container) return;
2793
+ // Use cached rect if available, otherwise get new one
2794
+ let rect = cachedRectRef.current;
2795
+ if (rect && 0 !== rect.width && 0 !== rect.height || (rect = container.getBoundingClientRect(),
2796
+ cachedRectRef.current = rect), 0 === rect.width || 0 === rect.height) return;
2797
+ const center = calculateElementCenter(rect);
2798
+ // Write raw target — the lerp loop will smoothly pursue it
2799
+ targetMouseOffsetRef.current = {
2800
+ x: (globalPos.x - center.x) / rect.width * 100,
2801
+ y: (globalPos.y - center.y) / rect.height * 100
2802
+ }, targetGlobalMousePositionRef.current = globalPos,
2803
+ // Ensure the lerp loop is running to smoothly chase the new target
2804
+ lerpActiveRef.current || startLerpLoop();
2805
+ }), [ mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects, startLerpLoop ]);
2797
2806
  /**
2798
2807
  * Validate and clamp a numeric config value
2799
2808
  */
@@ -2802,7 +2811,7 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2802
2811
  if (externalGlobalMousePosition && externalMouseOffset) return;
2803
2812
  if (effectiveWithoutEffects) return;
2804
2813
  const unsubscribe = globalMouseTracker.subscribe(handleGlobalMousePosition);
2805
- // Start the lerp loop — it will smoothly chase the target
2814
+ // Initial start
2806
2815
  startLerpLoop();
2807
2816
  const container = mouseContainer?.current || glassRef.current;
2808
2817
  let resizeObserver = null;
@@ -2815,7 +2824,7 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2815
2824
  unsubscribe(), stopLerpLoop(), null !== updateRectRef.current && (cancelAnimationFrame(updateRectRef.current),
2816
2825
  updateRectRef.current = null), resizeObserver && resizeObserver.disconnect();
2817
2826
  };
2818
- }), [ handleGlobalMousePosition, startLerpLoop, stopLerpLoop, mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects ]),
2827
+ }), [ externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects, handleGlobalMousePosition, startLerpLoop, stopLerpLoop, mouseContainer, glassRef ]),
2819
2828
  // Also call updateStyles on other state changes (hover, active, etc)
2820
2829
  useEffect((() => {
2821
2830
  updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
@@ -3007,184 +3016,147 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
3007
3016
  /**
3008
3017
  * Get GPU memory info if available (Chrome DevTools only)
3009
3018
  */
3019
+ /** Map an FPS value to a semantic color token string. */
3020
+ const getQualityColor = quality => {
3021
+ switch (quality) {
3022
+ case "high":
3023
+ return "var(--atomix-color-success, #4ade80)";
3024
+
3025
+ case "medium":
3026
+ return "var(--atomix-color-warning, #fbbf24)";
3027
+
3028
+ case "low":
3029
+ return "var(--atomix-color-danger, #ef4444)";
3030
+
3031
+ default:
3032
+ return "#9ca3af";
3033
+ }
3034
+ }, getFpsLabel = fps => fps >= 58 ? "Optimal" : fps >= 45 ? "Warning" : "Critical";
3035
+
3036
+ /** Map a quality level string to a semantic color token string. */
3037
+ // Inject keyframes once
3038
+ if ("undefined" != typeof document) {
3039
+ const styleId = "perf-dashboard-keyframes";
3040
+ if (!document.getElementById(styleId)) {
3041
+ const styleEl = document.createElement("style");
3042
+ styleEl.id = styleId, styleEl.textContent = "\n@keyframes perf-dashboard-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n",
3043
+ document.head.appendChild(styleEl);
3044
+ }
3045
+ }
3046
+
3010
3047
  /**
3011
- * PerformanceDashboard - Real-time performance monitoring overlay
3048
+ * PerformanceDashboard - Real-time performance monitoring overlay.
3012
3049
  *
3013
- * Displays:
3014
- * - Current FPS with color coding
3015
- * - Frame time statistics
3016
- * - Quality level indicator
3017
- * - GPU memory usage (if available)
3018
- * - Auto-scaling status
3019
- */
3020
- const PerformanceDashboard = ({metrics: metrics, isVisible: isVisible = !0, onClose: onClose}) => {
3021
- // Get color for FPS display
3022
- const getFpsColor = fps => fps >= 58 ? "#4ade80" : // Green - good
3023
- fps >= 45 ? "#fbbf24" : "#ef4444" // Red - critical
3024
- , dashboardStyle = useMemo((() => ({
3025
- position: "fixed",
3026
- top: "16px",
3027
- right: "16px",
3028
- padding: "12px 16px",
3029
- backgroundColor: "rgba(17, 24, 39, 0.95)",
3030
- borderRadius: "8px",
3031
- boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
3032
- fontFamily: "monospace",
3033
- fontSize: "12px",
3034
- color: "#fff",
3035
- zIndex: 9999,
3036
- minWidth: "200px",
3037
- backdropFilter: "blur(8px)",
3038
- border: "1px solid rgba(255, 255, 255, 0.1)",
3039
- transition: "opacity 0.3s ease",
3040
- opacity: isVisible ? 1 : 0,
3041
- pointerEvents: isVisible ? "auto" : "none"
3042
- })), [ isVisible ]), headerStyle = useMemo((() => ({
3043
- display: "flex",
3044
- justifyContent: "space-between",
3045
- alignItems: "center",
3046
- marginBottom: "8px",
3047
- paddingBottom: "8px",
3048
- borderBottom: "1px solid rgba(255, 255, 255, 0.1)"
3049
- })), []), titleStyle = useMemo((() => ({
3050
- fontWeight: "bold",
3051
- fontSize: "13px",
3052
- color: "#fff"
3053
- })), []), closeButtonStyle = useMemo((() => ({
3054
- background: "transparent",
3055
- border: "none",
3056
- color: "#9ca3af",
3057
- cursor: "pointer",
3058
- fontSize: "16px",
3059
- padding: "0",
3060
- lineHeight: "1"
3061
- })), []), metricRowStyle = useMemo((() => ({
3062
- display: "flex",
3063
- justifyContent: "space-between",
3064
- alignItems: "center",
3065
- marginBottom: "6px"
3066
- })), []), labelStyle = useMemo((() => ({
3067
- color: "#9ca3af",
3068
- marginRight: "12px"
3069
- })), []), valueStyle = useMemo((() => ({
3070
- fontWeight: "bold"
3071
- })), []);
3072
- // Get quality level badge color
3073
- return isVisible ? jsxs("div", {
3074
- style: dashboardStyle,
3050
+ * Displays FPS, frame time, quality level, GPU memory, and auto-scaling status.
3051
+ * Rendered only when `debugPerformance={true}` on the parent `AtomixGlass`.
3052
+ */ const PerformanceDashboard = memo((({metrics: metrics, isVisible: isVisible = !0, onClose: onClose}) => {
3053
+ if (!isVisible) return null;
3054
+ const fpsColor = (fps = metrics.fps) >= 58 ? "var(--atomix-color-success, #4ade80)" : fps >= 45 ? "var(--atomix-color-warning, #fbbf24)" : "var(--atomix-color-danger, #ef4444)";
3055
+ var fps;
3056
+ const isCritical = metrics.fps < 45;
3057
+ return jsxs("div", {
3058
+ className: "c-perf-dashboard u-position-fixed u-top-4 u-end-4 u-p-3 u-px-4 u-text-xs u-font-mono u-text-white u-rounded-md u-border u-border-white-alpha-10 u-shadow-lg",
3059
+ style: {
3060
+ zIndex: 9999,
3061
+ minWidth: "12.5rem",
3062
+ // 200px
3063
+ backgroundColor: "rgba(17, 24, 39, 0.95)",
3064
+ backdropFilter: "blur(8px)",
3065
+ transition: "opacity 0.3s ease"
3066
+ },
3075
3067
  children: [ jsxs("div", {
3076
- style: headerStyle,
3068
+ className: "u-flex u-items-center u-justify-between u-mb-2 u-pb-2 u-border-b u-border-white-alpha-10",
3077
3069
  children: [ jsx("span", {
3078
- style: titleStyle,
3070
+ className: "u-text-sm u-font-bold u-text-white",
3079
3071
  children: "Performance Monitor"
3080
3072
  }), onClose && jsx("button", {
3081
- style: closeButtonStyle,
3073
+ className: "u-bg-transparent u-border-none u-p-0 u-line-height-1 u-text-base u-text-gray-400 u-cursor-pointer hover:u-text-white",
3082
3074
  onClick: onClose,
3083
3075
  "aria-label": "Close performance dashboard",
3076
+ style: {
3077
+ transition: "color 0.2s ease"
3078
+ },
3084
3079
  children: "×"
3085
3080
  }) ]
3086
3081
  }), jsxs("div", {
3087
- style: metricRowStyle,
3082
+ className: "u-flex u-items-center u-justify-between u-mb-1-5",
3088
3083
  children: [ jsx("span", {
3089
- style: labelStyle,
3084
+ className: "u-text-gray-400 u-me-3",
3090
3085
  children: "FPS"
3091
3086
  }), jsx("span", {
3087
+ className: "u-font-bold",
3092
3088
  style: {
3093
- ...valueStyle,
3094
- color: getFpsColor(metrics.fps)
3089
+ color: fpsColor
3095
3090
  },
3096
3091
  children: Math.round(metrics.fps)
3097
3092
  }) ]
3098
3093
  }), jsxs("div", {
3099
- style: metricRowStyle,
3094
+ className: "u-flex u-items-center u-justify-between u-mb-1-5",
3100
3095
  children: [ jsx("span", {
3101
- style: labelStyle,
3096
+ className: "u-text-gray-400 u-me-3",
3102
3097
  children: "Frame Time"
3103
3098
  }), jsxs("span", {
3104
- style: valueStyle,
3099
+ className: "u-font-bold",
3105
3100
  children: [ metrics.frameTime.toFixed(2), "ms" ]
3106
3101
  }) ]
3107
3102
  }), jsxs("div", {
3108
- style: metricRowStyle,
3103
+ className: "u-flex u-items-center u-justify-between u-mb-1-5",
3109
3104
  children: [ jsx("span", {
3110
- style: labelStyle,
3105
+ className: "u-text-gray-400 u-me-3",
3111
3106
  children: "Quality"
3112
3107
  }), jsx("span", {
3108
+ className: "u-font-bold u-text-uppercase",
3113
3109
  style: {
3114
- ...valueStyle,
3115
- color: (quality => {
3116
- switch (quality) {
3117
- case "high":
3118
- return "#4ade80";
3119
-
3120
- case "medium":
3121
- return "#fbbf24";
3122
-
3123
- case "low":
3124
- return "#ef4444";
3125
-
3126
- default:
3127
- return "#9ca3af";
3128
- }
3129
- })(metrics.qualityLevel),
3130
- textTransform: "uppercase",
3131
- fontSize: "11px"
3110
+ fontSize: "0.6875rem",
3111
+ // 11px
3112
+ color: getQualityColor(metrics.qualityLevel)
3132
3113
  },
3133
3114
  children: metrics.qualityLevel
3134
3115
  }) ]
3135
3116
  }), metrics.gpuMemory && jsxs("div", {
3136
- style: metricRowStyle,
3117
+ className: "u-flex u-items-center u-justify-between u-mb-1-5",
3137
3118
  children: [ jsx("span", {
3138
- style: labelStyle,
3119
+ className: "u-text-gray-400 u-me-3",
3139
3120
  children: "GPU Memory"
3140
3121
  }), jsxs("span", {
3141
- style: valueStyle,
3122
+ className: "u-font-bold",
3142
3123
  children: [ "~", Math.round(metrics.gpuMemory / 1024), "MB" ]
3143
3124
  }) ]
3144
3125
  }), metrics.isAutoScaling && jsx("div", {
3126
+ className: "u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10 u-text-center",
3145
3127
  style: {
3146
- marginTop: "8px",
3147
- paddingTop: "8px",
3148
- borderTop: "1px solid rgba(255, 255, 255, 0.1)",
3149
- fontSize: "10px",
3150
- color: "#6b7280",
3151
- textAlign: "center"
3128
+ fontSize: "0.625rem",
3129
+ // 10px
3130
+ color: "#6b7280"
3152
3131
  },
3153
3132
  children: "Auto-scaling active"
3154
3133
  }), jsxs("div", {
3155
- style: {
3156
- marginTop: "8px",
3157
- paddingTop: "8px",
3158
- borderTop: "1px solid rgba(255, 255, 255, 0.1)",
3159
- display: "flex",
3160
- alignItems: "center",
3161
- gap: "6px"
3162
- },
3134
+ className: "u-flex u-items-center u-gap-2 u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10",
3163
3135
  children: [ jsx("div", {
3136
+ className: "u-rounded-full",
3164
3137
  style: {
3165
- width: "8px",
3166
- height: "8px",
3167
- borderRadius: "50%",
3168
- backgroundColor: getFpsColor(metrics.fps),
3169
- animation: metrics.fps < 45 ? "pulse 1s infinite" : "none"
3138
+ width: "0.5rem",
3139
+ height: "0.5rem",
3140
+ flexShrink: 0,
3141
+ backgroundColor: fpsColor,
3142
+ ...isCritical && {
3143
+ animation: "perf-dashboard-pulse 1s infinite"
3144
+ }
3170
3145
  }
3171
3146
  }), jsx("span", {
3147
+ className: "u-text-xs",
3172
3148
  style: {
3173
- fontSize: "10px",
3174
- color: metrics.fps >= 58 ? "#4ade80" : metrics.fps >= 45 ? "#fbbf24" : "#ef4444"
3149
+ fontSize: "0.625rem",
3150
+ // 10px
3151
+ color: fpsColor
3175
3152
  },
3176
- children: metrics.fps >= 58 ? "Optimal" : metrics.fps >= 45 ? "Warning" : "Critical"
3153
+ children: getFpsLabel(metrics.fps)
3177
3154
  }) ]
3178
3155
  }) ]
3179
- }) : null;
3180
- };
3156
+ });
3157
+ }));
3181
3158
 
3182
- // Add pulse animation for critical FPS
3183
- if ("undefined" != typeof document) {
3184
- const styleSheet = document.createElement("style");
3185
- styleSheet.textContent = "\n @keyframes pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n ",
3186
- document.head.appendChild(styleSheet);
3187
- }
3159
+ PerformanceDashboard.displayName = "PerformanceDashboard";
3188
3160
 
3189
3161
  /**
3190
3162
  * Mobile optimization presets
@@ -3195,7 +3167,8 @@ if ("undefined" != typeof document) {
3195
3167
  /**
3196
3168
  * Performance preset - Maximum FPS, reduced quality
3197
3169
  * Best for low-end devices or when battery saving is priority
3198
- */ const PERFORMANCE_PRESET = {
3170
+ */
3171
+ const PERFORMANCE_PRESET = {
3199
3172
  distortionOctaves: 2,
3200
3173
  // Minimal FBM layers
3201
3174
  displacementScale: 50,
@@ -3304,95 +3277,21 @@ if ("undefined" != typeof document) {
3304
3277
  saturation: 70
3305
3278
  }
3306
3279
  }
3307
- };
3308
-
3309
- /**
3310
- * Balanced preset - Good quality with reasonable performance
3311
- * Default preset for most mobile devices
3312
- */
3313
- /**
3314
- * AtomixGlass - A high-performance glass morphism component with liquid distortion effects
3315
- *
3316
- * Features:
3317
- * - Hardware-accelerated glass effects with SVG filters
3318
- * - Mouse-responsive liquid distortion
3319
- * - Dynamic border-radius extraction from children CSS properties
3320
- * - Automatic light/dark theme detection via overLight prop
3321
- * - Accessibility and performance optimizations
3322
- * - Multiple displacement modes (standard, polar, prominent, shader)
3323
- * - Design token integration for consistent theming
3324
- * - Focus ring support for keyboard navigation
3325
- * - Responsive breakpoints for mobile optimization
3326
- * - Enhanced ARIA attributes for screen readers
3327
- * - Time-based animation system with FBM distortion
3328
- * - Device preset optimization for performance/quality balance
3329
- *
3330
- * Design System Compliance:
3331
- * - Uses design tokens for opacity, spacing, and colors
3332
- * - Follows BEM methodology for class naming
3333
- * - Implements focus-ring mixin for accessibility
3334
- * - Supports reduced motion and high contrast preferences
3335
- *
3336
- * @example
3337
- * // Basic usage with dynamic border-radius extraction
3338
- * <AtomixGlass>
3339
- * <div style={{ borderRadius: '12px' }}>Content with 12px radius</div>
3340
- * </AtomixGlass>
3341
- *
3342
- * @example
3343
- * // Manual border-radius override
3344
- * <AtomixGlass borderRadius={20}>
3345
- * <div>Content with 20px glass radius</div>
3346
- * </AtomixGlass>
3347
- *
3348
- * @example
3349
- * // Interactive glass with click handler
3350
- * <AtomixGlass onClick={() => console.log('Clicked')} aria-label="Glass card">
3351
- * <div>Clickable content</div>
3352
- * </AtomixGlass>
3353
- *
3354
- * @example
3355
- * // OverLight - Boolean mode (explicit control)
3356
- * <AtomixGlass overLight={true}>
3357
- * <div>Content on light background</div>
3358
- * </AtomixGlass>
3359
- *
3360
- * @example
3361
- * // OverLight - Auto-detection mode
3362
- * <AtomixGlass overLight="auto">
3363
- * <div>Content with auto-detected background</div>
3364
- * </AtomixGlass>
3365
- *
3366
- * @example
3367
- * // OverLight - Object config with custom settings
3368
- * <AtomixGlass
3369
- * overLight={{
3370
- * threshold: 0.8,
3371
- * opacity: 0.6,
3372
- * contrast: 1.8,
3373
- * brightness: 1.0,
3374
- * saturationBoost: 1.5
3375
- * }}
3376
- * >
3377
- * <div>Content with custom overLight config</div>
3378
- * </AtomixGlass>
3379
- *
3380
- * @example
3381
- * // Debug mode for overLight detection
3382
- * <AtomixGlass overLight="auto" debugOverLight={true}>
3383
- * <div>Content with debug logging enabled</div>
3384
- * </AtomixGlass>
3385
- *
3386
- * @example
3387
- * // Performance-optimized for mobile devices
3388
- * <AtomixGlass devicePreset="performance" disableResponsiveBreakpoints={false}>
3389
- * <div>Mobile-optimized glass effect</div>
3390
- * </AtomixGlass>
3391
- */
3392
- 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, borderRadius: borderRadius, 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, withoutEffects: withoutEffects = !1, withLiquidBlur: withLiquidBlur = !1, withBorder: withBorder = !0, withOverLightLayers: withOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS, debugPerformance: debugPerformance = !1, debugOverLight: debugOverLight = !1, height: height, width: width, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", devicePreset: devicePreset = "balanced", disableResponsiveBreakpoints: disableResponsiveBreakpoints = !1, ...rest}) {
3393
- const glassRef = useRef(null), contentRef = useRef(null), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = "fixed" === restStyle.position || "sticky" === restStyle.position, {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveBorderRadius: effectiveBorderRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveWithoutEffects: effectiveWithoutEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, getShaderTime: getShaderTime, applyTimeBasedDistortion: applyTimeBasedDistortion, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
3280
+ }, AtomixGlassInner = forwardRef((function({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, borderRadius: borderRadius, 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, withoutEffects: withoutEffects = !1, withLiquidBlur: withLiquidBlur = !1, withBorder: withBorder = !0, withOverLightLayers: withOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS, debugPerformance: debugPerformance = !1, debugOverLight: debugOverLight = !1, height: height, width: width, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", devicePreset: devicePreset = "balanced", disableResponsiveBreakpoints: disableResponsiveBreakpoints = !1, isFixedOrSticky: propsIsFixedOrSticky, ...rest}, ref) {
3281
+ const glassRef = useRef(null), contentRef = useRef(null), internalWrapperRef = useRef(null), mergedRef = useMemo((() =>
3282
+ // Helper to merge refs
3283
+ function(...refs) {
3284
+ return node => {
3285
+ refs.forEach((ref => {
3286
+ "function" == typeof ref ? ref(node) : null != ref && (ref.current = node);
3287
+ }));
3288
+ };
3289
+ }
3290
+ // Internal implementation with forwardRef
3291
+ (ref, internalWrapperRef)), [ ref ]), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = propsIsFixedOrSticky || "fixed" === restStyle.position || "sticky" === restStyle.position, {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveBorderRadius: effectiveBorderRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveWithoutEffects: effectiveWithoutEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, getShaderTime: getShaderTime, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
3394
3292
  glassRef: glassRef,
3395
3293
  contentRef: contentRef,
3294
+ wrapperRef: internalWrapperRef,
3396
3295
  borderRadius: borderRadius,
3397
3296
  globalMousePosition: externalGlobalMousePosition,
3398
3297
  mouseOffset: externalMouseOffset,
@@ -3421,7 +3320,6 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
3421
3320
  distortionGain: distortionGain,
3422
3321
  distortionQuality: distortionQuality
3423
3322
  });
3424
- // Re-calculate only when devicePreset changes
3425
3323
  // Responsive breakpoint system - automatically adjusts parameters based on viewport
3426
3324
  !
3427
3325
  /**
@@ -3611,11 +3509,10 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
3611
3509
  },
3612
3510
  breakpoints: MOBILE_OPTIMIZED_BREAKPOINTS,
3613
3511
  enabled: !disableResponsiveBreakpoints && "undefined" != typeof window,
3614
- // Enable unless disabled
3615
3512
  debug: !1
3616
3513
  });
3617
3514
  // Performance monitoring - tracks FPS, frame time, memory usage
3618
- const {metrics: performanceMetrics, recommendedQuality: recommendedQuality, isUnderperforming: isUnderperforming, setQualityLevel: setQualityLevel, toggleMonitoring: toggleMonitoring} =
3515
+ const {metrics: performanceMetrics, toggleMonitoring: toggleMonitoring} =
3619
3516
  /**
3620
3517
  * Performance Monitor Hook
3621
3518
  *
@@ -3779,17 +3676,17 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
3779
3676
  toggleMonitoring: toggleMonitoring
3780
3677
  };
3781
3678
  }({
3782
- enabled: !1,
3783
- // We'll toggle manually based on prop
3679
+ enabled: debugPerformance,
3680
+ // Enable when debugPerformance is true
3784
3681
  debug: !1,
3785
3682
  showOverlay: !1
3786
3683
  });
3787
- // Auto-start performance monitoring if enabled (only in development)
3684
+ // Auto-start performance monitoring when debugPerformance is enabled
3788
3685
  React.useEffect((() => {
3789
- "development" === process.env.NODE_ENV && window?.enablePerformanceMonitoring && toggleMonitoring();
3686
+ debugPerformance && toggleMonitoring();
3790
3687
  // eslint-disable-next-line react-hooks/exhaustive-deps
3791
- }), []);
3792
- // Only run once on mount
3688
+ }), [ debugPerformance ]);
3689
+ // Re-run when debugPerformance changes
3793
3690
  const isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, rootLayoutStyle = useMemo((() => {
3794
3691
  if (!isFixedOrSticky) return {};
3795
3692
  const {position: p, top: t, left: l, right: r, bottom: b} = restStyle;
@@ -3817,34 +3714,30 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
3817
3714
  if (isFixedOrSticky) {
3818
3715
  const {position: _p, top: _t, left: _l, right: _r, bottom: _b, ...visualStyle} = restStyle;
3819
3716
  return {
3820
- ...visualStyle,
3821
- ...!effectiveWithoutEffects && {
3822
- transform: transformStyle
3823
- }
3717
+ ...visualStyle
3824
3718
  };
3825
3719
  }
3826
3720
  return {
3827
- ...restStyle,
3828
- ...!effectiveWithoutEffects && {
3829
- transform: transformStyle
3830
- }
3721
+ ...restStyle
3831
3722
  };
3832
- }), [ isFixedOrSticky, restStyle, effectiveWithoutEffects, transformStyle ]);
3723
+ }), [ isFixedOrSticky, restStyle ]);
3833
3724
  // Build className with state modifiers
3834
3725
  const componentClassName = [ ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`, effectiveWithoutEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`, className ].filter(Boolean).join(" "), positionStyles = useMemo((() => ({
3835
3726
  position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
3836
- top: isFixedOrSticky ? 0 : restStyle.top || 0,
3837
- left: isFixedOrSticky ? 0 : restStyle.left || 0
3838
- })), [ isFixedOrSticky, restStyle.position, restStyle.top, restStyle.left ]), adjustedSize = useMemo((() => {
3727
+ top: isFixedOrSticky ? restStyle.top ?? 0 : 0,
3728
+ left: isFixedOrSticky ? restStyle.left ?? 0 : 0,
3729
+ right: isFixedOrSticky ? restStyle.right ?? "auto" : "auto",
3730
+ bottom: isFixedOrSticky ? restStyle.bottom ?? "auto" : "auto"
3731
+ })), [ isFixedOrSticky, restStyle.position, restStyle.top, restStyle.left, restStyle.right, restStyle.bottom ]), adjustedSize = useMemo((() => {
3839
3732
  // Keep a reference to positionStyles to avoid unused-variable lint,
3840
3733
  // but sizing is driven by explicit width/height or measured size.
3841
3734
  positionStyles.position;
3842
- const resolveLength = (value, measured) => void 0 !== value ? "number" == typeof value ? `${value}px` : value : measured > 0 ? `${measured}px` : "100%", effectiveWidth = width ?? restStyle.width, effectiveHeight = height ?? restStyle.height;
3735
+ const resolveLength = (value, measured) => void 0 !== value && isFixedOrSticky ? "number" == typeof value ? `${value}px` : value : measured > 0 && isFixedOrSticky ? `${measured}px` : "100%", effectiveWidth = width ?? restStyle.width, effectiveHeight = height ?? restStyle.height;
3843
3736
  return {
3844
3737
  width: resolveLength(effectiveWidth, glassSize.width),
3845
3738
  height: resolveLength(effectiveHeight, glassSize.height)
3846
3739
  };
3847
- }), [ width, height, restStyle.width, restStyle.height, positionStyles.position, glassSize.width, glassSize.height ]), gradientValues = useMemo((() => {
3740
+ }), [ width, height, restStyle.width, restStyle.height, positionStyles.position, glassSize.width, glassSize.height, isFixedOrSticky ]), gradientValues = useMemo((() => {
3848
3741
  const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT;
3849
3742
  return {
3850
3743
  borderGradientAngle: GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER,
@@ -3874,33 +3767,32 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
3874
3767
  absMx: absMx,
3875
3768
  absMy: absMy
3876
3769
  };
3877
- }), [ mouseOffset.x, mouseOffset.y ]), opacityValues = useMemo((() => {
3878
- const overLightOpacity = overLightConfig.opacity;
3879
- return {
3880
- hover1: isHovered || isActive ? .5 : 0,
3881
- hover2: isActive ? .5 : 0,
3882
- hover3: isHovered ? .4 : isActive ? .8 : 0,
3883
- base: isOverLight ? overLightOpacity || .4 : 0,
3884
- over: isOverLight ? 1.1 * (overLightOpacity || .4) : 0
3885
- };
3886
- }), [ isHovered, isActive, isOverLight, overLightConfig.opacity ]), glassVars = useMemo((() => {
3887
- const whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, {borderGradientAngle: borderGradientAngle, borderStop1: borderStop1, borderStop2: borderStop2, borderOpacities: borderOpacities, hoverPositions: hoverPositions, basePosition: basePosition, mx: mx, my: my, absMx: absMx, absMy: absMy} = gradientValues, configBorderOpacity = overLightConfig?.borderOpacity ?? 1;
3770
+ }), [ mouseOffset.x, mouseOffset.y ]), clampedOverLightOpacity = Math.max(0, Math.min(1, overLightConfig?.opacity ?? .4)), clampedBorderOpacity = Math.max(0, Math.min(1, overLightConfig?.borderOpacity ?? 1)), opacityValues = useMemo((() => ({
3771
+ hover1: isHovered || isActive ? .5 : 0,
3772
+ hover2: isActive ? .5 : 0,
3773
+ hover3: isHovered ? .4 : isActive ? .8 : 0,
3774
+ base: isOverLight ? clampedOverLightOpacity || .4 : 0,
3775
+ over: isOverLight ? 1.1 * (clampedOverLightOpacity || .4) : 0
3776
+ })), [ isHovered, isActive, isOverLight, clampedOverLightOpacity ]), glassVars = useMemo((() => {
3777
+ const whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, {borderGradientAngle: borderGradientAngle, borderStop1: borderStop1, borderStop2: borderStop2, borderOpacities: borderOpacities, hoverPositions: hoverPositions, basePosition: basePosition, mx: mx, my: my, absMx: absMx, absMy: absMy} = gradientValues;
3888
3778
  return {
3889
3779
  ...void 0 !== customZIndex && {
3890
3780
  "--atomix-glass-base-z-index": customZIndex
3891
3781
  },
3892
3782
  "--atomix-glass-radius": `${effectiveBorderRadius}px`,
3893
3783
  "--atomix-glass-transform": transformStyle || "none",
3894
- // Internal decorative layers are positioned relative to the root;
3895
- "--atomix-glass-position": rootLayoutStyle.position,
3896
- "--atomix-glass-top": `${isFixedOrSticky ? rootLayoutStyle.top : 0}px`,
3897
- "--atomix-glass-left": `${isFixedOrSticky ? rootLayoutStyle.left : 0}px`,
3784
+ "--atomix-glass-container-position": `${isFixedOrSticky ? rootLayoutStyle.position : positionStyles.position}`,
3785
+ "--atomix-glass-position": `${isFixedOrSticky ? rootLayoutStyle.position : positionStyles.position}`,
3786
+ "--atomix-glass-top": `${isFixedOrSticky ? restStyle.top ?? 0 : 0}px`,
3787
+ "--atomix-glass-left": `${isFixedOrSticky ? restStyle.left ?? 0 : 0}px`,
3788
+ "--atomix-glass-right": isFixedOrSticky ? restStyle.right ?? "auto" : "auto",
3789
+ "--atomix-glass-bottom": isFixedOrSticky ? restStyle.bottom ?? "auto" : "auto",
3898
3790
  "--atomix-glass-width": adjustedSize.width,
3899
3791
  "--atomix-glass-height": adjustedSize.height,
3900
- "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
3792
+ "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.125rem)",
3901
3793
  "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay",
3902
- "--atomix-glass-border-gradient-1": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[0] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[1] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
3903
- "--atomix-glass-border-gradient-2": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[2] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[3] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
3794
+ "--atomix-glass-border-gradient-1": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[0] ?? 1) * clampedBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[1] ?? 1) * clampedBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
3795
+ "--atomix-glass-border-gradient-2": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[2] ?? 1) * clampedBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[3] ?? 1) * clampedBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
3904
3796
  "--atomix-glass-hover-1-opacity": opacityValues.hover1,
3905
3797
  "--atomix-glass-hover-1-gradient": isOverLight ? `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_STOP}%)`,
3906
3798
  "--atomix-glass-hover-2-opacity": opacityValues.hover2,
@@ -3914,13 +3806,14 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
3914
3806
  "--atomix-glass-overlay-highlight-opacity": opacityValues.over * ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER,
3915
3807
  "--atomix-glass-overlay-highlight-bg": `radial-gradient(circle at ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_X}% ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_Y}%, rgba(255, 255, 255, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.WHITE_OPACITY}) 0%, transparent ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.STOP}%)`
3916
3808
  };
3917
- }), [ gradientValues, opacityValues, effectiveBorderRadius, transformStyle, adjustedSize, isOverLight, overLightConfig.borderOpacity, customZIndex, rootLayoutStyle, isFixedOrSticky ]), renderBackgroundLayer = layerType => jsx("div", {
3809
+ }), [ gradientValues, opacityValues, effectiveBorderRadius, transformStyle, adjustedSize, isOverLight, clampedBorderOpacity, customZIndex, isFixedOrSticky, positionStyles.position, rootLayoutStyle.position, restStyle.top, restStyle.left, restStyle.right, restStyle.bottom ]), renderBackgroundLayer = layerType => jsx("div", {
3918
3810
  className: [ ATOMIX_GLASS.BACKGROUND_LAYER_CLASS, "dark" === layerType ? ATOMIX_GLASS.BACKGROUND_LAYER_DARK_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_BLACK_CLASS, isOverLight ? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS ].filter(Boolean).join(" ")
3919
3811
  });
3920
3812
  // Calculate position and size styles for internal layers
3921
3813
  // When root is fixed/sticky, internal layers use absolute (relative to root)
3922
3814
  return jsxs("div", {
3923
3815
  ...rest,
3816
+ ref: mergedRef,
3924
3817
  className: componentClassName,
3925
3818
  style: {
3926
3819
  ...glassVars
@@ -3930,17 +3823,14 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
3930
3823
  "aria-label": ariaLabel,
3931
3824
  "aria-describedby": ariaDescribedBy,
3932
3825
  "aria-disabled": !(!onClick || !effectiveWithoutEffects) || !onClick && void 0,
3933
- "aria-pressed": !(!onClick || !isActive) || !onClick && void 0,
3826
+ "aria-pressed": void 0,
3934
3827
  onKeyDown: onClick ? handleKeyDown : void 0,
3935
3828
  children: [ jsx(AtomixGlassContainer, {
3936
3829
  ref: glassRef,
3937
3830
  contentRef: contentRef,
3938
3831
  className: className,
3939
3832
  style: {
3940
- ...restStyle,
3941
- ...!isFixedOrSticky && {
3942
- position: "relative"
3943
- }
3833
+ ...restStyle
3944
3834
  },
3945
3835
  borderRadius: effectiveBorderRadius,
3946
3836
  displacementScale: effectiveWithoutEffects ? 0 : "shader" === mode ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_DISPLACEMENT : isOverLight ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.OVER_LIGHT_DISPLACEMENT : displacementScale,
@@ -3976,6 +3866,7 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
3976
3866
  effectiveReducedMotion: effectiveReducedMotion,
3977
3867
  shaderVariant: shaderVariant,
3978
3868
  withLiquidBlur: withLiquidBlur,
3869
+ isFixedOrSticky: isFixedOrSticky,
3979
3870
  // Phase 1: Animation System props
3980
3871
  shaderTime: getShaderTime(),
3981
3872
  withTimeAnimation: withTimeAnimation,
@@ -4004,6 +3895,8 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
4004
3895
  }) ]
4005
3896
  }), withBorder && jsxs(Fragment, {
4006
3897
  children: [ jsx("span", {
3898
+ className: ATOMIX_GLASS.BORDER_BACKDROP_CLASS
3899
+ }), jsx("span", {
4007
3900
  className: ATOMIX_GLASS.BORDER_1_CLASS
4008
3901
  }), jsx("span", {
4009
3902
  className: ATOMIX_GLASS.BORDER_2_CLASS
@@ -4014,9 +3907,18 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
4014
3907
  onClose: () => {}
4015
3908
  }) ]
4016
3909
  });
4017
- }
3910
+ }));
4018
3911
 
4019
- const ChartContext = createContext(null), Chart = memo( forwardRef((({children: children, type: type = "line", size: size = "md", variant: variant = "primary", title: title, subtitle: subtitle, loading: loading = !1, error: error, className: className = "", "aria-label": ariaLabel, onFullscreen: onFullscreen, onExport: onExport, onRefresh: onRefresh, showToolbar: showToolbar = !1, enableFullscreen: enableFullscreen = !1, enableExport: enableExport = !1, enableRefresh: enableRefresh = !1, exportFormats: exportFormats = [ "png", "svg", "csv" ], datasets: datasets, config: config,
3912
+ /**
3913
+ * Balanced preset - Good quality with reasonable performance
3914
+ * Default preset for most mobile devices
3915
+ */ AtomixGlassInner.displayName = "AtomixGlass";
3916
+
3917
+ /**
3918
+ * AtomixGlass - wrapped with React.memo to prevent unnecessary re-renders.
3919
+ * Ref is forwarded to the root `<div>` element.
3920
+ */
3921
+ const AtomixGlass = memo(AtomixGlassInner), ChartContext = createContext(null), Chart = memo( forwardRef((({children: children, type: type = "line", size: size = "md", variant: variant = "primary", title: title, subtitle: subtitle, loading: loading = !1, error: error, className: className = "", "aria-label": ariaLabel, onFullscreen: onFullscreen, onExport: onExport, onRefresh: onRefresh, showToolbar: showToolbar = !1, enableFullscreen: enableFullscreen = !1, enableExport: enableExport = !1, enableRefresh: enableRefresh = !1, exportFormats: exportFormats = [ "png", "svg", "csv" ], datasets: datasets, config: config,
4020
3922
  // Destructure non-DOM props to prevent passing to DOM element
4021
3923
  toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, customToolbarGroups: customToolbarGroups, data: data, showLegend: showLegend, interactive: interactive, fullscreen: fullscreen, onDataPointClick: onDataPointClick, onLegendItemClick: onLegendItemClick, glass: glass, ...props}, ref) => {
4022
3924
  const [isFullscreen, setIsFullscreen] = useState(!1), [isExporting, setIsExporting] = useState(!1), chartContainerRef = useRef(null), [zoomLevel, setZoomLevel] = useState(1), [panOffset, setPanOffset] = useState({
@@ -4119,8 +4021,8 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
4119
4021
  }), [ chartType ]), finalDefaults = useMemo((() => ({
4120
4022
  ...getChartDefaults(),
4121
4023
  ...defaults
4122
- })), [ getChartDefaults, defaults ]), enhancedHandlers = {
4123
- onRefresh: useCallback((() => {
4024
+ })), [ getChartDefaults, defaults ]), enhancedHandlers = useMemo((() => ({
4025
+ onRefresh: () => {
4124
4026
  setState((prev => ({
4125
4027
  ...prev,
4126
4028
  isRefreshing: !0
@@ -4130,8 +4032,8 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
4130
4032
  isRefreshing: !1
4131
4033
  })));
4132
4034
  }), 1e3);
4133
- }), [ handlers.onRefresh ]),
4134
- onExport: useCallback((async format => {
4035
+ },
4036
+ onExport: async format => {
4135
4037
  setState((prev => ({
4136
4038
  ...prev,
4137
4039
  isExporting: !0
@@ -4144,70 +4046,70 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
4144
4046
  isExporting: !1
4145
4047
  })));
4146
4048
  }
4147
- }), [ handlers.onExport ]),
4148
- onFullscreen: useCallback((isFullscreen => {
4049
+ },
4050
+ onFullscreen: isFullscreen => {
4149
4051
  setState((prev => ({
4150
4052
  ...prev,
4151
4053
  isFullscreen: isFullscreen
4152
4054
  }))), handlers.onFullscreen?.(isFullscreen);
4153
- }), [ handlers.onFullscreen ]),
4154
- onZoomIn: useCallback((() => {
4055
+ },
4056
+ onZoomIn: () => {
4155
4057
  setState((prev => ({
4156
4058
  ...prev,
4157
4059
  zoomLevel: Math.min(1.2 * prev.zoomLevel, 5)
4158
4060
  }))), handlers.onZoomIn?.();
4159
- }), [ handlers.onZoomIn ]),
4160
- onZoomOut: useCallback((() => {
4061
+ },
4062
+ onZoomOut: () => {
4161
4063
  setState((prev => ({
4162
4064
  ...prev,
4163
4065
  zoomLevel: Math.max(prev.zoomLevel / 1.2, .2)
4164
4066
  }))), handlers.onZoomOut?.();
4165
- }), [ handlers.onZoomOut ]),
4166
- onZoomReset: useCallback((() => {
4067
+ },
4068
+ onZoomReset: () => {
4167
4069
  setState((prev => ({
4168
4070
  ...prev,
4169
4071
  zoomLevel: 1
4170
4072
  }))), handlers.onZoomReset?.();
4171
- }), [ handlers.onZoomReset ]),
4172
- onPanToggle: useCallback((enabled => {
4073
+ },
4074
+ onPanToggle: enabled => {
4173
4075
  setState((prev => ({
4174
4076
  ...prev,
4175
4077
  panEnabled: enabled
4176
4078
  }))), handlers.onPanToggle?.(enabled);
4177
- }), [ handlers.onPanToggle ]),
4178
- onReset: useCallback((() => {
4079
+ },
4080
+ onReset: () => {
4179
4081
  setState((prev => ({
4180
4082
  ...prev,
4181
4083
  zoomLevel: 1,
4182
4084
  panEnabled: !1
4183
4085
  }))), handlers.onReset?.();
4184
- }), [ handlers.onReset ]),
4185
- onGridToggle: useCallback((show => {
4086
+ },
4087
+ onGridToggle: show => {
4186
4088
  setState((prev => ({
4187
4089
  ...prev,
4188
4090
  showGrid: show
4189
4091
  }))), handlers.onGridToggle?.(show);
4190
- }), [ handlers.onGridToggle ]),
4191
- onLegendToggle: useCallback((show => {
4092
+ },
4093
+ onLegendToggle: show => {
4192
4094
  setState((prev => ({
4193
4095
  ...prev,
4194
4096
  showLegend: show
4195
4097
  }))), handlers.onLegendToggle?.(show);
4196
- }), [ handlers.onLegendToggle ]),
4197
- onTooltipsToggle: useCallback((show => {
4098
+ },
4099
+ onTooltipsToggle: show => {
4198
4100
  setState((prev => ({
4199
4101
  ...prev,
4200
4102
  showTooltips: show
4201
4103
  }))), handlers.onTooltipsToggle?.(show);
4202
- }), [ handlers.onTooltipsToggle ]),
4203
- onAnimationsToggle: useCallback((enabled => {
4104
+ },
4105
+ onAnimationsToggle: enabled => {
4204
4106
  setState((prev => ({
4205
4107
  ...prev,
4206
4108
  animationsEnabled: enabled
4207
4109
  }))), handlers.onAnimationsToggle?.(enabled);
4208
- }), [ handlers.onAnimationsToggle ]),
4209
- onSettings: useCallback((() => {}), [])
4210
- }, generateToolbarGroups = useCallback((() => {
4110
+ },
4111
+ onSettings: () => {}
4112
+ })), [ handlers ]), generateToolbarGroups = useCallback((() => {
4211
4113
  const groups = [], dataActions = [];
4212
4114
  // Data actions group
4213
4115
  finalDefaults.refresh && dataActions.push({
@@ -4332,7 +4234,7 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
4332
4234
  actions: customActions
4333
4235
  });
4334
4236
  return groups;
4335
- }), [ chartType, finalDefaults, state, enhancedHandlers, customActions, customGroups ]);
4237
+ }), [ finalDefaults, state, enhancedHandlers, customActions, customGroups ]);
4336
4238
  // Keyboard shortcuts
4337
4239
  return useEffect((() => {
4338
4240
  const handleKeyDown = event => {
@@ -4924,7 +4826,7 @@ const ChartRenderer = memo( forwardRef((({datasets: datasets = [], config: conf
4924
4826
  announcement: announcement,
4925
4827
  focusedPoint: focusedPoint,
4926
4828
  getAccessibleDescription: () => "Chart description"
4927
- })), [ announcement, focusedPoint ]), transform = useMemo((() => chartContext ? `translate(${chartContext.panOffset.x}px, ${chartContext.panOffset.y}px) scale(${chartContext.zoomLevel})` : ""), [ chartContext?.panOffset.x, chartContext?.panOffset.y, chartContext?.zoomLevel ]), chartData = useMemo((() => {
4829
+ })), [ announcement, focusedPoint ]), transform = useMemo((() => chartContext ? `translate(${chartContext.panOffset.x}px, ${chartContext.panOffset.y}px) scale(${chartContext.zoomLevel})` : ""), [ chartContext ]), chartData = useMemo((() => {
4928
4830
  // Return null if dimensions not ready to prevent calculation with invalid dimensions
4929
4831
  if (!isInitialized || 0 === dimensions.width || 0 === dimensions.height) return null;
4930
4832
  const scales = calculateScales(processedData, dimensions.width, dimensions.height, void 0, config);
@@ -5341,7 +5243,7 @@ const BarChart = memo( forwardRef((({datasets: datasets = [], config: config =
5341
5243
  opacity: .4
5342
5244
  } ]
5343
5245
  };
5344
- })) : []), [ options.useGradients ]), formatValue = useCallback((value => options.valueFormatter ? options.valueFormatter(value) : value.toString()), [ options.valueFormatter ]);
5246
+ })) : []), [ options.useGradients ]), formatValue = useCallback((value => options.valueFormatter ? options.valueFormatter(value) : value.toString()), [ options ]);
5345
5247
  return {
5346
5248
  // State
5347
5249
  hoveredBar: hoveredBar,
@@ -5367,7 +5269,7 @@ const BarChart = memo( forwardRef((({datasets: datasets = [], config: config =
5367
5269
  y: horizontal ? y + height / 2 : y - 5
5368
5270
  };
5369
5271
  }
5370
- }), [ options.dataLabelPosition ]),
5272
+ }), [ options ]),
5371
5273
  // Handlers
5372
5274
  handleBarHover: handleBarHover,
5373
5275
  handleBarLeave: handleBarLeave,
@@ -5671,13 +5573,13 @@ const DonutChart = memo( forwardRef((({datasets: datasets = [], config: config
5671
5573
  roundedCorners: !0
5672
5574
  }, onDataPointClick: onDataPointClick, ...props}, ref) => {
5673
5575
  // Use the first dataset for donut chart
5674
- const dataset = datasets.length > 0 ? datasets[0] : {
5576
+ const dataset = useMemo((() => datasets.length > 0 ? datasets[0] : {
5675
5577
  label: "",
5676
5578
  data: []
5677
- }, chartData = useMemo((() => {
5579
+ }), [ datasets ]), chartData = useMemo((() => {
5678
5580
  if (!dataset?.data?.length) return null;
5679
5581
  // Filter out invalid data points
5680
- const validDataPoints = dataset?.data?.filter((point => "number" == typeof point.value && !isNaN(point.value) && isFinite(point.value) && point.value > 0));
5582
+ const validDataPoints = (dataset?.data || []).filter((point => "number" == typeof point.value && !isNaN(point.value) && isFinite(point.value) && point.value > 0));
5681
5583
  return validDataPoints.length ? {
5682
5584
  validDataPoints: validDataPoints
5683
5585
  } : null;
@@ -6636,7 +6538,7 @@ const PieChart = memo( forwardRef((({datasets: datasets = [], config: config =
6636
6538
  const parts = [];
6637
6539
  return !1 !== options.showLabels && parts.push(slice.label), options.showPercentages && parts.push(`${Math.round(slice.percentage)}%`),
6638
6540
  options.showValues && parts.push(slice.value.toString()), parts.join(" - ");
6639
- }), [ options.labelFormatter, options.showLabels, options.showPercentages, options.showValues ]), getSliceTransform = useCallback(((slice, isHovered) => isHovered && options.enableHoverEffects && options.hoverOffset ? `translate(${Math.cos(slice.midAngle) * options.hoverOffset}, ${Math.sin(slice.midAngle) * options.hoverOffset})` : ""), [ options.enableHoverEffects, options.hoverOffset ]), isSliceSelected = useCallback((index => selectedSlices.has(index)), [ selectedSlices ]);
6541
+ }), [ options ]), getSliceTransform = useCallback(((slice, isHovered) => isHovered && options.enableHoverEffects && options.hoverOffset ? `translate(${Math.cos(slice.midAngle) * options.hoverOffset}, ${Math.sin(slice.midAngle) * options.hoverOffset})` : ""), [ options.enableHoverEffects, options.hoverOffset ]), isSliceSelected = useCallback((index => selectedSlices.has(index)), [ selectedSlices ]);
6640
6542
  return {
6641
6543
  // Data
6642
6544
  processedData: processedData,