@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/forms.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
 
3
- import React, { memo, forwardRef, useMemo, useState, useRef, useEffect, useCallback, useImperativeHandle, useContext, createContext } from "react";
3
+ import React, { memo, forwardRef, useId, useMemo, useState, useRef, useEffect, useCallback, useImperativeHandle, useContext, createContext } from "react";
4
4
 
5
5
  /**
6
6
  * Default theme colors for components
@@ -15,6 +15,7 @@ import React, { memo, forwardRef, useMemo, useState, useRef, useEffect, useCallb
15
15
  FILTER_OVERLAY_CLASS: "c-atomix-glass__filter-overlay",
16
16
  FILTER_SHADOW_CLASS: "c-atomix-glass__filter-shadow",
17
17
  CONTENT_CLASS: "c-atomix-glass__content",
18
+ BORDER_BACKDROP_CLASS: "c-atomix-glass__border-backdrop",
18
19
  BORDER_1_CLASS: "c-atomix-glass__border-1",
19
20
  BORDER_2_CLASS: "c-atomix-glass__border-2",
20
21
  HOVER_1_CLASS: "c-atomix-glass__hover-1",
@@ -360,7 +361,7 @@ import React, { memo, forwardRef, useMemo, useState, useRef, useEffect, useCallb
360
361
  default:
361
362
  return console.warn("AtomixGlass: Invalid displacement mode"), displacementMap;
362
363
  }
363
- }, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsx("svg", {
364
+ }, sharedShaderCache = new Map, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsx("svg", {
364
365
  style: {
365
366
  position: "absolute",
366
367
  width: "100%",
@@ -501,24 +502,17 @@ import React, { memo, forwardRef, useMemo, useState, useRef, useEffect, useCallb
501
502
  */ GlassFilterComponent.displayName = "GlassFilter";
502
503
 
503
504
  // Memoize component to prevent unnecessary re-renders
504
- 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));
505
-
506
- // Module-level counter for deterministic ID generation
507
- let idCounter = 0;
508
-
509
- // Module-level shared shader cache with LRU eviction
510
- 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 = {
505
+ 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 = {
511
506
  x: 0,
512
507
  y: 0
513
508
  }, 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 = {
514
509
  width: 0,
515
510
  height: 0
516
- }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1,
511
+ }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, isFixedOrSticky: isFixedOrSticky = !1,
517
512
  // Phase 1: Animation System props
518
513
  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) => {
519
- // Generate a stable, deterministic ID for SSR compatibility
520
- // Use a module-level counter that's consistent across server and client
521
- 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);
514
+ // React 18 useId — stable, unique, and SSR-safe (no module-level counter)
515
+ 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);
522
516
  // Lazy load shader utilities only when shader mode is needed
523
517
  useEffect((() => {
524
518
  "shader" === mode ?
@@ -541,9 +535,7 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
541
535
  // Create cache key from size and variant
542
536
  const cacheKey = `${glassSize.width}x${glassSize.height}-${shaderVariant}`, cachedUrl = (key => {
543
537
  const entry = sharedShaderCache.get(key);
544
- return entry ? (
545
- // Update access timestamp for LRU
546
- entry.timestamp = Date.now(), entry.url) : null;
538
+ return entry ? (entry.timestamp = Date.now(), entry.url) : null;
547
539
  })(cacheKey);
548
540
  // Check shared cache first
549
541
  if (cachedUrl) return void setShaderMapUrl(cachedUrl);
@@ -554,29 +546,24 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
554
546
  if (shaderUtilsRef.current) try {
555
547
  const {ShaderDisplacementGenerator: ShaderDisplacementGenerator, fragmentShaders: fragmentShaders} = shaderUtilsRef.current;
556
548
  shaderGeneratorRef.current?.destroy();
557
- const selectedShader = fragmentShaders[shaderVariant] || fragmentShaders.liquidGlass;
549
+ const selectedShader = fragmentShaders[shaderVariant] ?? fragmentShaders.liquidGlass;
558
550
  shaderGeneratorRef.current = new ShaderDisplacementGenerator({
559
551
  width: glassSize.width,
560
552
  height: glassSize.height,
561
553
  fragment: selectedShader
562
554
  }), shaderUpdateTimeoutRef.current = setTimeout((() => {
563
- const url = shaderGeneratorRef.current?.updateShader() || "";
555
+ const url = shaderGeneratorRef.current?.updateShader() ?? "";
564
556
  url && ((key, url) => {
565
- // Evict oldest entries if at capacity
566
557
  if (sharedShaderCache.size >= 15) {
567
558
  const entries = Array.from(sharedShaderCache.entries());
568
- // Sort by timestamp (oldest first)
569
- entries.sort(((a, b) => a[1].timestamp - b[1].timestamp));
570
- // Remove oldest entry
571
- const oldestEntry = entries[0];
572
- oldestEntry && sharedShaderCache.delete(oldestEntry[0]);
559
+ entries.sort(((a, b) => a[1].timestamp - b[1].timestamp));
560
+ const oldest = entries[0];
561
+ oldest && sharedShaderCache.delete(oldest[0]);
573
562
  }
574
563
  sharedShaderCache.set(key, {
575
564
  url: url,
576
565
  timestamp: Date.now()
577
- }),
578
- // Development mode: log cache size
579
- "undefined" != typeof process && "production" === process.env?.NODE_ENV || sharedShaderCache.size;
566
+ }), "undefined" != typeof process && "production" === process.env?.NODE_ENV || sharedShaderCache.size;
580
567
  })(cacheKey, url), setShaderMapUrl(url);
581
568
  }), 100);
582
569
  } catch (error) {
@@ -645,7 +632,6 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
645
632
  console.warn("AtomixGlassContainer: Error getting element bounds", error), setRectCache(null);
646
633
  }
647
634
  }), [ ref, glassSize ]);
648
- // Pre-calculate static multipliers outside useMemo
649
635
  const liquidBlur = useMemo((() => {
650
636
  const defaultBlur = {
651
637
  baseBlur: blurAmount,
@@ -714,7 +700,6 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
714
700
  }), [ borderRadius, backdropStyle, mouseOffset, overLight, effectiveWithoutEffects, overLightConfig ]);
715
701
  return jsx("div", {
716
702
  ref: el => {
717
- // Apply force no-transition
718
703
  // Handle forwarded ref
719
704
  "function" == typeof ref ? ref(el) : ref && (ref.current = el);
720
705
  },
@@ -756,6 +741,7 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
756
741
  });
757
742
  }));
758
743
 
744
+ // ─── Blur multiplier constants (module-level, never change at runtime) ────────
759
745
  AtomixGlassContainer.displayName = "AtomixGlassContainer";
760
746
 
761
747
  // Singleton instance
@@ -956,8 +942,6 @@ class {
956
942
  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})`;
957
943
  // Container variables
958
944
  const style = containerElement.style;
959
- style.setProperty("--atomix-glass-container-width", isFixedOrSticky ? `${glassSize.width}` : "100%"),
960
- style.setProperty("--atomix-glass-container-height", isFixedOrSticky ? `${glassSize.height}` : "100%"),
961
945
  style.setProperty("--atomix-glass-container-padding", padding), style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
962
946
  style.setProperty("--atomix-glass-container-backdrop", backdropFilterString),
963
947
  // Shadows
@@ -1418,47 +1402,55 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
1418
1402
  return "undefined" == typeof process || process.env, finalConfig;
1419
1403
  }
1420
1404
  return "undefined" == typeof process || process.env, baseConfig;
1421
- }), [ 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 => {
1422
- if (externalGlobalMousePosition && externalMouseOffset) return;
1423
- if (effectiveWithoutEffects) return;
1424
- const container = mouseContainer?.current || glassRef.current;
1425
- if (!container) return;
1426
- // Use cached rect if available, otherwise get new one
1427
- let rect = cachedRectRef.current;
1428
- if (rect && 0 !== rect.width && 0 !== rect.height || (rect = container.getBoundingClientRect(),
1429
- cachedRectRef.current = rect), 0 === rect.width || 0 === rect.height) return;
1430
- const center = calculateElementCenter(rect);
1431
- // Write raw target — the lerp loop will smoothly pursue it
1432
- targetMouseOffsetRef.current = {
1433
- x: (globalPos.x - center.x) / rect.width * 100,
1434
- y: (globalPos.y - center.y) / rect.height * 100
1435
- }, targetGlobalMousePositionRef.current = globalPos;
1436
- }), [ mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects ]), startLerpLoop = useCallback((() => {
1405
+ }), [ 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((() => {
1406
+ lerpActiveRef.current = !1, null !== lerpRafRef.current && (cancelAnimationFrame(lerpRafRef.current),
1407
+ lerpRafRef.current = null);
1408
+ }), []), startLerpLoop = useCallback((() => {
1437
1409
  if (lerpActiveRef.current) return;
1438
1410
  lerpActiveRef.current = !0;
1439
1411
  const LERP_T = CONSTANTS.LERP_FACTOR, tick = () => {
1440
1412
  if (!lerpActiveRef.current) return;
1441
- // Add ref validity check to prevent memory leaks
1442
- if (!glassRef.current || !wrapperRef?.current) return void (lerpActiveRef.current = !1);
1413
+ if (!glassRef.current) return void (lerpActiveRef.current = !1);
1443
1414
  const cur = internalMouseOffsetRef.current, tgt = targetMouseOffsetRef.current, dx = tgt.x - cur.x, dy = tgt.y - cur.y;
1444
1415
  // If we're close enough, snap and park
1445
- if (Math.abs(dx) < .05 && Math.abs(dy) < .05) internalMouseOffsetRef.current = {
1416
+ if (Math.abs(dx) < .01 && Math.abs(dy) < .01) return internalMouseOffsetRef.current = {
1446
1417
  ...tgt
1447
1418
  }, internalGlobalMousePositionRef.current = {
1448
1419
  ...targetGlobalMousePositionRef.current
1449
- }; else {
1450
- internalMouseOffsetRef.current = {
1451
- x: lerp$1(cur.x, tgt.x, LERP_T),
1452
- y: lerp$1(cur.y, tgt.y, LERP_T)
1453
- };
1454
- const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
1455
- internalGlobalMousePositionRef.current = {
1456
- x: lerp$1(curG.x, tgtG.x, LERP_T),
1457
- y: lerp$1(curG.y, tgtG.y, LERP_T)
1458
- };
1459
- }
1460
- // Imperative style update with the smoothed values
1461
- updateAtomixGlassStyles(wrapperRef.current, glassRef.current, {
1420
+ },
1421
+ // Final update and stop
1422
+ updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
1423
+ mouseOffset: internalMouseOffsetRef.current,
1424
+ globalMousePosition: internalGlobalMousePositionRef.current,
1425
+ glassSize: glassSize,
1426
+ isHovered: isHovered,
1427
+ isActive: isActive,
1428
+ isOverLight: overLightConfig.isOverLight,
1429
+ baseOverLightConfig: overLightConfig,
1430
+ effectiveBorderRadius: effectiveBorderRadius,
1431
+ effectiveWithoutEffects: effectiveWithoutEffects,
1432
+ effectiveReducedMotion: effectiveReducedMotion,
1433
+ elasticity: elasticity,
1434
+ directionalScale: isActive && Boolean(onClick) ? "scale(0.96)" : "scale(1)",
1435
+ onClick: onClick,
1436
+ withLiquidBlur: withLiquidBlur,
1437
+ blurAmount: blurAmount,
1438
+ saturation: saturation,
1439
+ padding: padding,
1440
+ isFixedOrSticky: isFixedOrSticky
1441
+ }), void stopLerpLoop();
1442
+ // Smooth step
1443
+ internalMouseOffsetRef.current = {
1444
+ x: lerp$1(cur.x, tgt.x, LERP_T),
1445
+ y: lerp$1(cur.y, tgt.y, LERP_T)
1446
+ };
1447
+ const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
1448
+ internalGlobalMousePositionRef.current = {
1449
+ x: lerp$1(curG.x, tgtG.x, LERP_T),
1450
+ y: lerp$1(curG.y, tgtG.y, LERP_T)
1451
+ },
1452
+ // Imperative style update
1453
+ updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
1462
1454
  mouseOffset: internalMouseOffsetRef.current,
1463
1455
  globalMousePosition: internalGlobalMousePositionRef.current,
1464
1456
  glassSize: glassSize,
@@ -1481,10 +1473,24 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
1481
1473
  };
1482
1474
  // 0.08 – lower = more viscous
1483
1475
  lerpRafRef.current = requestAnimationFrame(tick);
1484
- }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding, isFixedOrSticky ]), stopLerpLoop = useCallback((() => {
1485
- lerpActiveRef.current = !1, null !== lerpRafRef.current && (cancelAnimationFrame(lerpRafRef.current),
1486
- lerpRafRef.current = null);
1487
- }), []);
1476
+ }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding, isFixedOrSticky, stopLerpLoop ]), handleGlobalMousePosition = useCallback((globalPos => {
1477
+ if (externalGlobalMousePosition && externalMouseOffset) return;
1478
+ if (effectiveWithoutEffects) return;
1479
+ const container = mouseContainer?.current || glassRef.current;
1480
+ if (!container) return;
1481
+ // Use cached rect if available, otherwise get new one
1482
+ let rect = cachedRectRef.current;
1483
+ if (rect && 0 !== rect.width && 0 !== rect.height || (rect = container.getBoundingClientRect(),
1484
+ cachedRectRef.current = rect), 0 === rect.width || 0 === rect.height) return;
1485
+ const center = calculateElementCenter(rect);
1486
+ // Write raw target — the lerp loop will smoothly pursue it
1487
+ targetMouseOffsetRef.current = {
1488
+ x: (globalPos.x - center.x) / rect.width * 100,
1489
+ y: (globalPos.y - center.y) / rect.height * 100
1490
+ }, targetGlobalMousePositionRef.current = globalPos,
1491
+ // Ensure the lerp loop is running to smoothly chase the new target
1492
+ lerpActiveRef.current || startLerpLoop();
1493
+ }), [ mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects, startLerpLoop ]);
1488
1494
  /**
1489
1495
  * Validate and clamp a numeric config value
1490
1496
  */
@@ -1493,7 +1499,7 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
1493
1499
  if (externalGlobalMousePosition && externalMouseOffset) return;
1494
1500
  if (effectiveWithoutEffects) return;
1495
1501
  const unsubscribe = globalMouseTracker.subscribe(handleGlobalMousePosition);
1496
- // Start the lerp loop — it will smoothly chase the target
1502
+ // Initial start
1497
1503
  startLerpLoop();
1498
1504
  const container = mouseContainer?.current || glassRef.current;
1499
1505
  let resizeObserver = null;
@@ -1506,7 +1512,7 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
1506
1512
  unsubscribe(), stopLerpLoop(), null !== updateRectRef.current && (cancelAnimationFrame(updateRectRef.current),
1507
1513
  updateRectRef.current = null), resizeObserver && resizeObserver.disconnect();
1508
1514
  };
1509
- }), [ handleGlobalMousePosition, startLerpLoop, stopLerpLoop, mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects ]),
1515
+ }), [ externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects, handleGlobalMousePosition, startLerpLoop, stopLerpLoop, mouseContainer, glassRef ]),
1510
1516
  // Also call updateStyles on other state changes (hover, active, etc)
1511
1517
  useEffect((() => {
1512
1518
  updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
@@ -1982,184 +1988,147 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
1982
1988
  /**
1983
1989
  * Get GPU memory info if available (Chrome DevTools only)
1984
1990
  */
1991
+ /** Map an FPS value to a semantic color token string. */
1992
+ const getQualityColor = quality => {
1993
+ switch (quality) {
1994
+ case "high":
1995
+ return "var(--atomix-color-success, #4ade80)";
1996
+
1997
+ case "medium":
1998
+ return "var(--atomix-color-warning, #fbbf24)";
1999
+
2000
+ case "low":
2001
+ return "var(--atomix-color-danger, #ef4444)";
2002
+
2003
+ default:
2004
+ return "#9ca3af";
2005
+ }
2006
+ }, getFpsLabel = fps => fps >= 58 ? "Optimal" : fps >= 45 ? "Warning" : "Critical";
2007
+
2008
+ /** Map a quality level string to a semantic color token string. */
2009
+ // Inject keyframes once
2010
+ if ("undefined" != typeof document) {
2011
+ const styleId = "perf-dashboard-keyframes";
2012
+ if (!document.getElementById(styleId)) {
2013
+ const styleEl = document.createElement("style");
2014
+ styleEl.id = styleId, styleEl.textContent = "\n@keyframes perf-dashboard-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n",
2015
+ document.head.appendChild(styleEl);
2016
+ }
2017
+ }
2018
+
1985
2019
  /**
1986
- * PerformanceDashboard - Real-time performance monitoring overlay
2020
+ * PerformanceDashboard - Real-time performance monitoring overlay.
1987
2021
  *
1988
- * Displays:
1989
- * - Current FPS with color coding
1990
- * - Frame time statistics
1991
- * - Quality level indicator
1992
- * - GPU memory usage (if available)
1993
- * - Auto-scaling status
1994
- */
1995
- const PerformanceDashboard = ({metrics: metrics, isVisible: isVisible = !0, onClose: onClose}) => {
1996
- // Get color for FPS display
1997
- const getFpsColor = fps => fps >= 58 ? "#4ade80" : // Green - good
1998
- fps >= 45 ? "#fbbf24" : "#ef4444" // Red - critical
1999
- , dashboardStyle = useMemo((() => ({
2000
- position: "fixed",
2001
- top: "16px",
2002
- right: "16px",
2003
- padding: "12px 16px",
2004
- backgroundColor: "rgba(17, 24, 39, 0.95)",
2005
- borderRadius: "8px",
2006
- boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
2007
- fontFamily: "monospace",
2008
- fontSize: "12px",
2009
- color: "#fff",
2010
- zIndex: 9999,
2011
- minWidth: "200px",
2012
- backdropFilter: "blur(8px)",
2013
- border: "1px solid rgba(255, 255, 255, 0.1)",
2014
- transition: "opacity 0.3s ease",
2015
- opacity: isVisible ? 1 : 0,
2016
- pointerEvents: isVisible ? "auto" : "none"
2017
- })), [ isVisible ]), headerStyle = useMemo((() => ({
2018
- display: "flex",
2019
- justifyContent: "space-between",
2020
- alignItems: "center",
2021
- marginBottom: "8px",
2022
- paddingBottom: "8px",
2023
- borderBottom: "1px solid rgba(255, 255, 255, 0.1)"
2024
- })), []), titleStyle = useMemo((() => ({
2025
- fontWeight: "bold",
2026
- fontSize: "13px",
2027
- color: "#fff"
2028
- })), []), closeButtonStyle = useMemo((() => ({
2029
- background: "transparent",
2030
- border: "none",
2031
- color: "#9ca3af",
2032
- cursor: "pointer",
2033
- fontSize: "16px",
2034
- padding: "0",
2035
- lineHeight: "1"
2036
- })), []), metricRowStyle = useMemo((() => ({
2037
- display: "flex",
2038
- justifyContent: "space-between",
2039
- alignItems: "center",
2040
- marginBottom: "6px"
2041
- })), []), labelStyle = useMemo((() => ({
2042
- color: "#9ca3af",
2043
- marginRight: "12px"
2044
- })), []), valueStyle = useMemo((() => ({
2045
- fontWeight: "bold"
2046
- })), []);
2047
- // Get quality level badge color
2048
- return isVisible ? jsxs("div", {
2049
- style: dashboardStyle,
2022
+ * Displays FPS, frame time, quality level, GPU memory, and auto-scaling status.
2023
+ * Rendered only when `debugPerformance={true}` on the parent `AtomixGlass`.
2024
+ */ const PerformanceDashboard = memo((({metrics: metrics, isVisible: isVisible = !0, onClose: onClose}) => {
2025
+ if (!isVisible) return null;
2026
+ const fpsColor = (fps = metrics.fps) >= 58 ? "var(--atomix-color-success, #4ade80)" : fps >= 45 ? "var(--atomix-color-warning, #fbbf24)" : "var(--atomix-color-danger, #ef4444)";
2027
+ var fps;
2028
+ const isCritical = metrics.fps < 45;
2029
+ return jsxs("div", {
2030
+ 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",
2031
+ style: {
2032
+ zIndex: 9999,
2033
+ minWidth: "12.5rem",
2034
+ // 200px
2035
+ backgroundColor: "rgba(17, 24, 39, 0.95)",
2036
+ backdropFilter: "blur(8px)",
2037
+ transition: "opacity 0.3s ease"
2038
+ },
2050
2039
  children: [ jsxs("div", {
2051
- style: headerStyle,
2040
+ className: "u-flex u-items-center u-justify-between u-mb-2 u-pb-2 u-border-b u-border-white-alpha-10",
2052
2041
  children: [ jsx("span", {
2053
- style: titleStyle,
2042
+ className: "u-text-sm u-font-bold u-text-white",
2054
2043
  children: "Performance Monitor"
2055
2044
  }), onClose && jsx("button", {
2056
- style: closeButtonStyle,
2045
+ 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",
2057
2046
  onClick: onClose,
2058
2047
  "aria-label": "Close performance dashboard",
2048
+ style: {
2049
+ transition: "color 0.2s ease"
2050
+ },
2059
2051
  children: "×"
2060
2052
  }) ]
2061
2053
  }), jsxs("div", {
2062
- style: metricRowStyle,
2054
+ className: "u-flex u-items-center u-justify-between u-mb-1-5",
2063
2055
  children: [ jsx("span", {
2064
- style: labelStyle,
2056
+ className: "u-text-gray-400 u-me-3",
2065
2057
  children: "FPS"
2066
2058
  }), jsx("span", {
2059
+ className: "u-font-bold",
2067
2060
  style: {
2068
- ...valueStyle,
2069
- color: getFpsColor(metrics.fps)
2061
+ color: fpsColor
2070
2062
  },
2071
2063
  children: Math.round(metrics.fps)
2072
2064
  }) ]
2073
2065
  }), jsxs("div", {
2074
- style: metricRowStyle,
2066
+ className: "u-flex u-items-center u-justify-between u-mb-1-5",
2075
2067
  children: [ jsx("span", {
2076
- style: labelStyle,
2068
+ className: "u-text-gray-400 u-me-3",
2077
2069
  children: "Frame Time"
2078
2070
  }), jsxs("span", {
2079
- style: valueStyle,
2071
+ className: "u-font-bold",
2080
2072
  children: [ metrics.frameTime.toFixed(2), "ms" ]
2081
2073
  }) ]
2082
2074
  }), jsxs("div", {
2083
- style: metricRowStyle,
2075
+ className: "u-flex u-items-center u-justify-between u-mb-1-5",
2084
2076
  children: [ jsx("span", {
2085
- style: labelStyle,
2077
+ className: "u-text-gray-400 u-me-3",
2086
2078
  children: "Quality"
2087
2079
  }), jsx("span", {
2080
+ className: "u-font-bold u-text-uppercase",
2088
2081
  style: {
2089
- ...valueStyle,
2090
- color: (quality => {
2091
- switch (quality) {
2092
- case "high":
2093
- return "#4ade80";
2094
-
2095
- case "medium":
2096
- return "#fbbf24";
2097
-
2098
- case "low":
2099
- return "#ef4444";
2100
-
2101
- default:
2102
- return "#9ca3af";
2103
- }
2104
- })(metrics.qualityLevel),
2105
- textTransform: "uppercase",
2106
- fontSize: "11px"
2082
+ fontSize: "0.6875rem",
2083
+ // 11px
2084
+ color: getQualityColor(metrics.qualityLevel)
2107
2085
  },
2108
2086
  children: metrics.qualityLevel
2109
2087
  }) ]
2110
2088
  }), metrics.gpuMemory && jsxs("div", {
2111
- style: metricRowStyle,
2089
+ className: "u-flex u-items-center u-justify-between u-mb-1-5",
2112
2090
  children: [ jsx("span", {
2113
- style: labelStyle,
2091
+ className: "u-text-gray-400 u-me-3",
2114
2092
  children: "GPU Memory"
2115
2093
  }), jsxs("span", {
2116
- style: valueStyle,
2094
+ className: "u-font-bold",
2117
2095
  children: [ "~", Math.round(metrics.gpuMemory / 1024), "MB" ]
2118
2096
  }) ]
2119
2097
  }), metrics.isAutoScaling && jsx("div", {
2098
+ className: "u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10 u-text-center",
2120
2099
  style: {
2121
- marginTop: "8px",
2122
- paddingTop: "8px",
2123
- borderTop: "1px solid rgba(255, 255, 255, 0.1)",
2124
- fontSize: "10px",
2125
- color: "#6b7280",
2126
- textAlign: "center"
2100
+ fontSize: "0.625rem",
2101
+ // 10px
2102
+ color: "#6b7280"
2127
2103
  },
2128
2104
  children: "Auto-scaling active"
2129
2105
  }), jsxs("div", {
2130
- style: {
2131
- marginTop: "8px",
2132
- paddingTop: "8px",
2133
- borderTop: "1px solid rgba(255, 255, 255, 0.1)",
2134
- display: "flex",
2135
- alignItems: "center",
2136
- gap: "6px"
2137
- },
2106
+ className: "u-flex u-items-center u-gap-2 u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10",
2138
2107
  children: [ jsx("div", {
2108
+ className: "u-rounded-full",
2139
2109
  style: {
2140
- width: "8px",
2141
- height: "8px",
2142
- borderRadius: "50%",
2143
- backgroundColor: getFpsColor(metrics.fps),
2144
- animation: metrics.fps < 45 ? "pulse 1s infinite" : "none"
2110
+ width: "0.5rem",
2111
+ height: "0.5rem",
2112
+ flexShrink: 0,
2113
+ backgroundColor: fpsColor,
2114
+ ...isCritical && {
2115
+ animation: "perf-dashboard-pulse 1s infinite"
2116
+ }
2145
2117
  }
2146
2118
  }), jsx("span", {
2119
+ className: "u-text-xs",
2147
2120
  style: {
2148
- fontSize: "10px",
2149
- color: metrics.fps >= 58 ? "#4ade80" : metrics.fps >= 45 ? "#fbbf24" : "#ef4444"
2121
+ fontSize: "0.625rem",
2122
+ // 10px
2123
+ color: fpsColor
2150
2124
  },
2151
- children: metrics.fps >= 58 ? "Optimal" : metrics.fps >= 45 ? "Warning" : "Critical"
2125
+ children: getFpsLabel(metrics.fps)
2152
2126
  }) ]
2153
2127
  }) ]
2154
- }) : null;
2155
- };
2128
+ });
2129
+ }));
2156
2130
 
2157
- // Add pulse animation for critical FPS
2158
- if ("undefined" != typeof document) {
2159
- const styleSheet = document.createElement("style");
2160
- styleSheet.textContent = "\n @keyframes pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n ",
2161
- document.head.appendChild(styleSheet);
2162
- }
2131
+ PerformanceDashboard.displayName = "PerformanceDashboard";
2163
2132
 
2164
2133
  /**
2165
2134
  * Mobile optimization presets
@@ -2170,7 +2139,8 @@ if ("undefined" != typeof document) {
2170
2139
  /**
2171
2140
  * Performance preset - Maximum FPS, reduced quality
2172
2141
  * Best for low-end devices or when battery saving is priority
2173
- */ const PERFORMANCE_PRESET = {
2142
+ */
2143
+ const PERFORMANCE_PRESET = {
2174
2144
  distortionOctaves: 2,
2175
2145
  // Minimal FBM layers
2176
2146
  displacementScale: 50,
@@ -2279,95 +2249,21 @@ if ("undefined" != typeof document) {
2279
2249
  saturation: 70
2280
2250
  }
2281
2251
  }
2282
- };
2283
-
2284
- /**
2285
- * Balanced preset - Good quality with reasonable performance
2286
- * Default preset for most mobile devices
2287
- */
2288
- /**
2289
- * AtomixGlass - A high-performance glass morphism component with liquid distortion effects
2290
- *
2291
- * Features:
2292
- * - Hardware-accelerated glass effects with SVG filters
2293
- * - Mouse-responsive liquid distortion
2294
- * - Dynamic border-radius extraction from children CSS properties
2295
- * - Automatic light/dark theme detection via overLight prop
2296
- * - Accessibility and performance optimizations
2297
- * - Multiple displacement modes (standard, polar, prominent, shader)
2298
- * - Design token integration for consistent theming
2299
- * - Focus ring support for keyboard navigation
2300
- * - Responsive breakpoints for mobile optimization
2301
- * - Enhanced ARIA attributes for screen readers
2302
- * - Time-based animation system with FBM distortion
2303
- * - Device preset optimization for performance/quality balance
2304
- *
2305
- * Design System Compliance:
2306
- * - Uses design tokens for opacity, spacing, and colors
2307
- * - Follows BEM methodology for class naming
2308
- * - Implements focus-ring mixin for accessibility
2309
- * - Supports reduced motion and high contrast preferences
2310
- *
2311
- * @example
2312
- * // Basic usage with dynamic border-radius extraction
2313
- * <AtomixGlass>
2314
- * <div style={{ borderRadius: '12px' }}>Content with 12px radius</div>
2315
- * </AtomixGlass>
2316
- *
2317
- * @example
2318
- * // Manual border-radius override
2319
- * <AtomixGlass borderRadius={20}>
2320
- * <div>Content with 20px glass radius</div>
2321
- * </AtomixGlass>
2322
- *
2323
- * @example
2324
- * // Interactive glass with click handler
2325
- * <AtomixGlass onClick={() => console.log('Clicked')} aria-label="Glass card">
2326
- * <div>Clickable content</div>
2327
- * </AtomixGlass>
2328
- *
2329
- * @example
2330
- * // OverLight - Boolean mode (explicit control)
2331
- * <AtomixGlass overLight={true}>
2332
- * <div>Content on light background</div>
2333
- * </AtomixGlass>
2334
- *
2335
- * @example
2336
- * // OverLight - Auto-detection mode
2337
- * <AtomixGlass overLight="auto">
2338
- * <div>Content with auto-detected background</div>
2339
- * </AtomixGlass>
2340
- *
2341
- * @example
2342
- * // OverLight - Object config with custom settings
2343
- * <AtomixGlass
2344
- * overLight={{
2345
- * threshold: 0.8,
2346
- * opacity: 0.6,
2347
- * contrast: 1.8,
2348
- * brightness: 1.0,
2349
- * saturationBoost: 1.5
2350
- * }}
2351
- * >
2352
- * <div>Content with custom overLight config</div>
2353
- * </AtomixGlass>
2354
- *
2355
- * @example
2356
- * // Debug mode for overLight detection
2357
- * <AtomixGlass overLight="auto" debugOverLight={true}>
2358
- * <div>Content with debug logging enabled</div>
2359
- * </AtomixGlass>
2360
- *
2361
- * @example
2362
- * // Performance-optimized for mobile devices
2363
- * <AtomixGlass devicePreset="performance" disableResponsiveBreakpoints={false}>
2364
- * <div>Mobile-optimized glass effect</div>
2365
- * </AtomixGlass>
2366
- */
2367
- 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}) {
2368
- 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({
2252
+ }, 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) {
2253
+ const glassRef = useRef(null), contentRef = useRef(null), internalWrapperRef = useRef(null), mergedRef = useMemo((() =>
2254
+ // Helper to merge refs
2255
+ function(...refs) {
2256
+ return node => {
2257
+ refs.forEach((ref => {
2258
+ "function" == typeof ref ? ref(node) : null != ref && (ref.current = node);
2259
+ }));
2260
+ };
2261
+ }
2262
+ // Internal implementation with forwardRef
2263
+ (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({
2369
2264
  glassRef: glassRef,
2370
2265
  contentRef: contentRef,
2266
+ wrapperRef: internalWrapperRef,
2371
2267
  borderRadius: borderRadius,
2372
2268
  globalMousePosition: externalGlobalMousePosition,
2373
2269
  mouseOffset: externalMouseOffset,
@@ -2396,7 +2292,6 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
2396
2292
  distortionGain: distortionGain,
2397
2293
  distortionQuality: distortionQuality
2398
2294
  });
2399
- // Re-calculate only when devicePreset changes
2400
2295
  // Responsive breakpoint system - automatically adjusts parameters based on viewport
2401
2296
  !
2402
2297
  /**
@@ -2586,11 +2481,10 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
2586
2481
  },
2587
2482
  breakpoints: MOBILE_OPTIMIZED_BREAKPOINTS,
2588
2483
  enabled: !disableResponsiveBreakpoints && "undefined" != typeof window,
2589
- // Enable unless disabled
2590
2484
  debug: !1
2591
2485
  });
2592
2486
  // Performance monitoring - tracks FPS, frame time, memory usage
2593
- const {metrics: performanceMetrics, recommendedQuality: recommendedQuality, isUnderperforming: isUnderperforming, setQualityLevel: setQualityLevel, toggleMonitoring: toggleMonitoring} =
2487
+ const {metrics: performanceMetrics, toggleMonitoring: toggleMonitoring} =
2594
2488
  /**
2595
2489
  * Performance Monitor Hook
2596
2490
  *
@@ -2754,17 +2648,17 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
2754
2648
  toggleMonitoring: toggleMonitoring
2755
2649
  };
2756
2650
  }({
2757
- enabled: !1,
2758
- // We'll toggle manually based on prop
2651
+ enabled: debugPerformance,
2652
+ // Enable when debugPerformance is true
2759
2653
  debug: !1,
2760
2654
  showOverlay: !1
2761
2655
  });
2762
- // Auto-start performance monitoring if enabled (only in development)
2656
+ // Auto-start performance monitoring when debugPerformance is enabled
2763
2657
  React.useEffect((() => {
2764
- "development" === process.env.NODE_ENV && window?.enablePerformanceMonitoring && toggleMonitoring();
2658
+ debugPerformance && toggleMonitoring();
2765
2659
  // eslint-disable-next-line react-hooks/exhaustive-deps
2766
- }), []);
2767
- // Only run once on mount
2660
+ }), [ debugPerformance ]);
2661
+ // Re-run when debugPerformance changes
2768
2662
  const isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, rootLayoutStyle = useMemo((() => {
2769
2663
  if (!isFixedOrSticky) return {};
2770
2664
  const {position: p, top: t, left: l, right: r, bottom: b} = restStyle;
@@ -2792,34 +2686,30 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
2792
2686
  if (isFixedOrSticky) {
2793
2687
  const {position: _p, top: _t, left: _l, right: _r, bottom: _b, ...visualStyle} = restStyle;
2794
2688
  return {
2795
- ...visualStyle,
2796
- ...!effectiveWithoutEffects && {
2797
- transform: transformStyle
2798
- }
2689
+ ...visualStyle
2799
2690
  };
2800
2691
  }
2801
2692
  return {
2802
- ...restStyle,
2803
- ...!effectiveWithoutEffects && {
2804
- transform: transformStyle
2805
- }
2693
+ ...restStyle
2806
2694
  };
2807
- }), [ isFixedOrSticky, restStyle, effectiveWithoutEffects, transformStyle ]);
2695
+ }), [ isFixedOrSticky, restStyle ]);
2808
2696
  // Build className with state modifiers
2809
2697
  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((() => ({
2810
2698
  position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
2811
- top: isFixedOrSticky ? 0 : restStyle.top || 0,
2812
- left: isFixedOrSticky ? 0 : restStyle.left || 0
2813
- })), [ isFixedOrSticky, restStyle.position, restStyle.top, restStyle.left ]), adjustedSize = useMemo((() => {
2699
+ top: isFixedOrSticky ? restStyle.top ?? 0 : 0,
2700
+ left: isFixedOrSticky ? restStyle.left ?? 0 : 0,
2701
+ right: isFixedOrSticky ? restStyle.right ?? "auto" : "auto",
2702
+ bottom: isFixedOrSticky ? restStyle.bottom ?? "auto" : "auto"
2703
+ })), [ isFixedOrSticky, restStyle.position, restStyle.top, restStyle.left, restStyle.right, restStyle.bottom ]), adjustedSize = useMemo((() => {
2814
2704
  // Keep a reference to positionStyles to avoid unused-variable lint,
2815
2705
  // but sizing is driven by explicit width/height or measured size.
2816
2706
  positionStyles.position;
2817
- 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;
2707
+ 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;
2818
2708
  return {
2819
2709
  width: resolveLength(effectiveWidth, glassSize.width),
2820
2710
  height: resolveLength(effectiveHeight, glassSize.height)
2821
2711
  };
2822
- }), [ width, height, restStyle.width, restStyle.height, positionStyles.position, glassSize.width, glassSize.height ]), gradientValues = useMemo((() => {
2712
+ }), [ width, height, restStyle.width, restStyle.height, positionStyles.position, glassSize.width, glassSize.height, isFixedOrSticky ]), gradientValues = useMemo((() => {
2823
2713
  const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT;
2824
2714
  return {
2825
2715
  borderGradientAngle: GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER,
@@ -2849,33 +2739,32 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
2849
2739
  absMx: absMx,
2850
2740
  absMy: absMy
2851
2741
  };
2852
- }), [ mouseOffset.x, mouseOffset.y ]), opacityValues = useMemo((() => {
2853
- const overLightOpacity = overLightConfig.opacity;
2854
- return {
2855
- hover1: isHovered || isActive ? .5 : 0,
2856
- hover2: isActive ? .5 : 0,
2857
- hover3: isHovered ? .4 : isActive ? .8 : 0,
2858
- base: isOverLight ? overLightOpacity || .4 : 0,
2859
- over: isOverLight ? 1.1 * (overLightOpacity || .4) : 0
2860
- };
2861
- }), [ isHovered, isActive, isOverLight, overLightConfig.opacity ]), glassVars = useMemo((() => {
2862
- 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;
2742
+ }), [ 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((() => ({
2743
+ hover1: isHovered || isActive ? .5 : 0,
2744
+ hover2: isActive ? .5 : 0,
2745
+ hover3: isHovered ? .4 : isActive ? .8 : 0,
2746
+ base: isOverLight ? clampedOverLightOpacity || .4 : 0,
2747
+ over: isOverLight ? 1.1 * (clampedOverLightOpacity || .4) : 0
2748
+ })), [ isHovered, isActive, isOverLight, clampedOverLightOpacity ]), glassVars = useMemo((() => {
2749
+ 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;
2863
2750
  return {
2864
2751
  ...void 0 !== customZIndex && {
2865
2752
  "--atomix-glass-base-z-index": customZIndex
2866
2753
  },
2867
2754
  "--atomix-glass-radius": `${effectiveBorderRadius}px`,
2868
2755
  "--atomix-glass-transform": transformStyle || "none",
2869
- // Internal decorative layers are positioned relative to the root;
2870
- "--atomix-glass-position": rootLayoutStyle.position,
2871
- "--atomix-glass-top": `${isFixedOrSticky ? rootLayoutStyle.top : 0}px`,
2872
- "--atomix-glass-left": `${isFixedOrSticky ? rootLayoutStyle.left : 0}px`,
2756
+ "--atomix-glass-container-position": `${isFixedOrSticky ? rootLayoutStyle.position : positionStyles.position}`,
2757
+ "--atomix-glass-position": `${isFixedOrSticky ? rootLayoutStyle.position : positionStyles.position}`,
2758
+ "--atomix-glass-top": `${isFixedOrSticky ? restStyle.top ?? 0 : 0}px`,
2759
+ "--atomix-glass-left": `${isFixedOrSticky ? restStyle.left ?? 0 : 0}px`,
2760
+ "--atomix-glass-right": isFixedOrSticky ? restStyle.right ?? "auto" : "auto",
2761
+ "--atomix-glass-bottom": isFixedOrSticky ? restStyle.bottom ?? "auto" : "auto",
2873
2762
  "--atomix-glass-width": adjustedSize.width,
2874
2763
  "--atomix-glass-height": adjustedSize.height,
2875
- "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
2764
+ "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.125rem)",
2876
2765
  "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay",
2877
- "--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%)`,
2878
- "--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%)`,
2766
+ "--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%)`,
2767
+ "--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%)`,
2879
2768
  "--atomix-glass-hover-1-opacity": opacityValues.hover1,
2880
2769
  "--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}%)`,
2881
2770
  "--atomix-glass-hover-2-opacity": opacityValues.hover2,
@@ -2889,13 +2778,14 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
2889
2778
  "--atomix-glass-overlay-highlight-opacity": opacityValues.over * ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER,
2890
2779
  "--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}%)`
2891
2780
  };
2892
- }), [ gradientValues, opacityValues, effectiveBorderRadius, transformStyle, adjustedSize, isOverLight, overLightConfig.borderOpacity, customZIndex, rootLayoutStyle, isFixedOrSticky ]), renderBackgroundLayer = layerType => jsx("div", {
2781
+ }), [ 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", {
2893
2782
  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(" ")
2894
2783
  });
2895
2784
  // Calculate position and size styles for internal layers
2896
2785
  // When root is fixed/sticky, internal layers use absolute (relative to root)
2897
2786
  return jsxs("div", {
2898
2787
  ...rest,
2788
+ ref: mergedRef,
2899
2789
  className: componentClassName,
2900
2790
  style: {
2901
2791
  ...glassVars
@@ -2905,17 +2795,14 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
2905
2795
  "aria-label": ariaLabel,
2906
2796
  "aria-describedby": ariaDescribedBy,
2907
2797
  "aria-disabled": !(!onClick || !effectiveWithoutEffects) || !onClick && void 0,
2908
- "aria-pressed": !(!onClick || !isActive) || !onClick && void 0,
2798
+ "aria-pressed": void 0,
2909
2799
  onKeyDown: onClick ? handleKeyDown : void 0,
2910
2800
  children: [ jsx(AtomixGlassContainer, {
2911
2801
  ref: glassRef,
2912
2802
  contentRef: contentRef,
2913
2803
  className: className,
2914
2804
  style: {
2915
- ...restStyle,
2916
- ...!isFixedOrSticky && {
2917
- position: "relative"
2918
- }
2805
+ ...restStyle
2919
2806
  },
2920
2807
  borderRadius: effectiveBorderRadius,
2921
2808
  displacementScale: effectiveWithoutEffects ? 0 : "shader" === mode ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_DISPLACEMENT : isOverLight ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.OVER_LIGHT_DISPLACEMENT : displacementScale,
@@ -2951,6 +2838,7 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
2951
2838
  effectiveReducedMotion: effectiveReducedMotion,
2952
2839
  shaderVariant: shaderVariant,
2953
2840
  withLiquidBlur: withLiquidBlur,
2841
+ isFixedOrSticky: isFixedOrSticky,
2954
2842
  // Phase 1: Animation System props
2955
2843
  shaderTime: getShaderTime(),
2956
2844
  withTimeAnimation: withTimeAnimation,
@@ -2979,6 +2867,8 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
2979
2867
  }) ]
2980
2868
  }), withBorder && jsxs(Fragment, {
2981
2869
  children: [ jsx("span", {
2870
+ className: ATOMIX_GLASS.BORDER_BACKDROP_CLASS
2871
+ }), jsx("span", {
2982
2872
  className: ATOMIX_GLASS.BORDER_1_CLASS
2983
2873
  }), jsx("span", {
2984
2874
  className: ATOMIX_GLASS.BORDER_2_CLASS
@@ -2989,9 +2879,18 @@ function AtomixGlass({children: children, displacementScale: displacementScale =
2989
2879
  onClose: () => {}
2990
2880
  }) ]
2991
2881
  });
2992
- }
2882
+ }));
2883
+
2884
+ /**
2885
+ * Balanced preset - Good quality with reasonable performance
2886
+ * Default preset for most mobile devices
2887
+ */ AtomixGlassInner.displayName = "AtomixGlass";
2993
2888
 
2994
- const Checkbox = React.memo( forwardRef((({label: label, checked: checked, onChange: onChange, className: className = "", style: style, disabled: disabled = !1, required: required = !1, id: id, name: name, value: value, invalid: invalid = !1, valid: valid = !1, indeterminate: indeterminate = !1, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, onClick: onClick, glass: glass, ...props}, ref) => {
2889
+ /**
2890
+ * AtomixGlass - wrapped with React.memo to prevent unnecessary re-renders.
2891
+ * Ref is forwarded to the root `<div>` element.
2892
+ */
2893
+ const AtomixGlass = memo(AtomixGlassInner), Checkbox = React.memo( forwardRef((({label: label, checked: checked, onChange: onChange, className: className = "", style: style, disabled: disabled = !1, required: required = !1, id: id, name: name, value: value, invalid: invalid = !1, valid: valid = !1, indeterminate: indeterminate = !1, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, onClick: onClick, glass: glass, ...props}, ref) => {
2995
2894
  // Local ref to handle indeterminate state
2996
2895
  const localRef = useRef(null);
2997
2896
  // Merge refs
@@ -3422,7 +3321,7 @@ SelectOption.displayName = "SelectOption";
3422
3321
  /**
3423
3322
  * Select - A component for dropdown selection
3424
3323
  */
3425
- const Select = memo((({options: options, value: value, onChange: onChange, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder = "Select an option", className: className = "", style: style, disabled: disabled = !1, required: required = !1, id: id, name: name, size: size = "md", invalid: invalid = !1, valid: valid = !1, multiple: multiple = !1, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, glass: glass, children: children}) => {
3324
+ const SelectComponentBase = ({options: options, value: value, onChange: onChange, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder = "Select an option", className: className = "", style: style, disabled: disabled = !1, required: required = !1, id: id, name: name, size: size = "md", invalid: invalid = !1, valid: valid = !1, multiple: multiple = !1, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, glass: glass, children: children}) => {
3426
3325
  const {generateSelectClass: generateSelectClass} =
3427
3326
  /**
3428
3327
  * Select state and functionality
@@ -3646,7 +3545,7 @@ const Select = memo((({options: options, value: value, onChange: onChange, onBl
3646
3545
  });
3647
3546
  }
3648
3547
  return selectContent;
3649
- }));
3548
+ }, Select = memo(SelectComponentBase);
3650
3549
 
3651
3550
  Select.displayName = "Select", Select.Option = SelectOption;
3652
3551