@shohojdhara/atomix 0.6.1 → 0.6.3

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 (67) hide show
  1. package/README.md +510 -106
  2. package/dist/atomix.css +30 -24
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +6 -6
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/atomix.umd.js +1 -1
  7. package/dist/atomix.umd.js.map +1 -1
  8. package/dist/atomix.umd.min.js +1 -1
  9. package/dist/charts.d.ts +11 -2
  10. package/dist/charts.js +294 -139
  11. package/dist/charts.js.map +1 -1
  12. package/dist/core.d.ts +14 -39
  13. package/dist/core.js +297 -145
  14. package/dist/core.js.map +1 -1
  15. package/dist/forms.d.ts +11 -1
  16. package/dist/forms.js +385 -185
  17. package/dist/forms.js.map +1 -1
  18. package/dist/heavy.d.ts +9 -0
  19. package/dist/heavy.js +297 -143
  20. package/dist/heavy.js.map +1 -1
  21. package/dist/index.d.ts +156 -164
  22. package/dist/index.esm.js +391 -203
  23. package/dist/index.esm.js.map +1 -1
  24. package/dist/index.js +391 -203
  25. package/dist/index.js.map +1 -1
  26. package/dist/index.min.js +1 -1
  27. package/dist/index.min.js.map +1 -1
  28. package/dist/theme.d.ts +14 -6
  29. package/dist/theme.js +2 -9
  30. package/dist/theme.js.map +1 -1
  31. package/package.json +26 -26
  32. package/src/components/AtomixGlass/AtomixGlass.tsx +1 -1
  33. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +8 -1
  34. package/src/components/AtomixGlass/deprecated/AtomixGlass.deprecated.tsx +390 -0
  35. package/src/components/AtomixGlass/glass-utils.ts +29 -0
  36. package/src/components/AtomixGlass/stories/Playground.stories.tsx +32 -1
  37. package/src/components/Button/Button.stories.tsx +1 -1
  38. package/src/components/Button/Button.tsx +6 -5
  39. package/src/components/Card/Card.tsx +2 -2
  40. package/src/components/Dropdown/Dropdown.tsx +1 -0
  41. package/src/components/EdgePanel/EdgePanel.tsx +1 -3
  42. package/src/components/Form/Select.test.tsx +75 -0
  43. package/src/components/Form/Select.tsx +348 -252
  44. package/src/components/Form/SelectOption.tsx +16 -10
  45. package/src/components/index.ts +1 -1
  46. package/src/layouts/CssGrid/index.ts +1 -0
  47. package/src/lib/composables/shared-mouse-tracker.ts +62 -6
  48. package/src/lib/composables/useAtomixGlass.ts +241 -139
  49. package/src/lib/composables/useAtomixGlassStyles.ts +201 -149
  50. package/src/lib/constants/components.ts +54 -35
  51. package/src/lib/theme/config/configLoader.ts +1 -1
  52. package/src/lib/theme/test/testTheme.ts +2 -2
  53. package/src/lib/theme/utils/themeUtils.ts +98 -110
  54. package/src/lib/types/components.ts +29 -65
  55. package/src/styles/01-settings/_settings.spacing.scss +6 -1
  56. package/src/styles/03-generic/_generic.reset.scss +1 -1
  57. package/src/styles/06-components/_components.atomix-glass.scss +20 -29
  58. package/src/styles/06-components/_components.data-table.scss +5 -4
  59. package/src/styles/06-components/_components.dynamic-background.scss +9 -8
  60. package/src/styles/06-components/_components.footer.scss +8 -7
  61. package/src/styles/06-components/_components.hero.scss +2 -2
  62. package/src/styles/06-components/_components.messages.scss +16 -16
  63. package/src/styles/06-components/_components.navbar.scss +2 -0
  64. package/src/styles/06-components/_components.select.scss +15 -2
  65. package/src/styles/06-components/_components.upload.scss +3 -3
  66. package/CHANGELOG.md +0 -165
  67. package/src/lib/theme/devtools/DesignTokensCustomizer.stories.tsx +0 -215
package/dist/index.js CHANGED
@@ -1750,12 +1750,23 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
1750
1750
  },
1751
1751
  DEFAULTS: {
1752
1752
  DISPLACEMENT_SCALE: 70,
1753
- BLUR_AMOUNT: 0,
1754
- SATURATION: 140,
1755
- ABERRATION_INTENSITY: 2,
1753
+ get BLUR_AMOUNT() {
1754
+ return .15 * this.DISPLACEMENT_SCALE;
1755
+ // Dynamically computed based on displacement
1756
+ },
1757
+ get SATURATION() {
1758
+ return 100 + .5 * this.DISPLACEMENT_SCALE;
1759
+ // Saturate relative to intensity
1760
+ },
1761
+ get ABERRATION_INTENSITY() {
1762
+ return .03 * this.DISPLACEMENT_SCALE;
1763
+ // Scale aberration with displacement
1764
+ },
1756
1765
  ELASTICITY: .15,
1757
- CORNER_RADIUS: 20,
1758
- // Default border-radius matching design system
1766
+ get CORNER_RADIUS() {
1767
+ return 16;
1768
+ // Use 16 to match SCSS design system (was 20)
1769
+ },
1759
1770
  PADDING: "0",
1760
1771
  MODE: "standard",
1761
1772
  OVER_LIGHT: !1,
@@ -1777,6 +1788,15 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
1777
1788
  MIN_BLUR: .1,
1778
1789
  MOUSE_INFLUENCE_DIVISOR: 100,
1779
1790
  EDGE_FADE_PIXELS: 2,
1791
+ // Elasticity physics constants
1792
+ ELASTICITY_TRANSLATION_FACTOR: .1,
1793
+ ELASTICITY_DISTANCE_THRESHOLD: 200,
1794
+ ELASTICITY_COMPRESSION_FACTOR: .3,
1795
+ ELASTICITY_STIFFNESS: .1,
1796
+ ELASTICITY_DAMPING: .76,
1797
+ ELASTICITY_VELOCITY_FACTOR: .65,
1798
+ ELASTICITY_STRETCH_RATIO: .45,
1799
+ ELASTICITY_MAGNIFICATION_BASE: 1.02,
1780
1800
  // Note: This default must match the SCSS variable --atomix-radius-md
1781
1801
  // @see src/styles/01-settings/_settings.global.scss
1782
1802
  DEFAULT_CORNER_RADIUS: 16,
@@ -1793,84 +1813,126 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
1793
1813
  // Base angle for border gradients (degrees)
1794
1814
  ANGLE_MULTIPLIER: 1.2,
1795
1815
  // Multiplier for mouse influence on angle
1816
+ VELOCITY_ANGLE_MULTIPLIER: 2.5,
1817
+ // How much velocity affects gradient rotation
1818
+ CHROMATIC_OFFSET: 1.5,
1819
+ // Degree offset for chromatic rim layers
1796
1820
  BORDER_STOP_1: {
1797
1821
  MIN: 10,
1798
1822
  // Minimum percentage for border stop 1
1799
1823
  BASE: 33,
1800
1824
  // Base percentage for border stop 1
1801
- MULTIPLIER: .3
1825
+ get MULTIPLIER() {
1826
+ return .009 * this.BASE;
1827
+ }
1802
1828
  },
1803
1829
  BORDER_STOP_2: {
1804
1830
  MAX: 90,
1805
1831
  // Maximum percentage for border stop 2
1806
1832
  BASE: 66,
1807
1833
  // Base percentage for border stop 2
1808
- MULTIPLIER: .4
1834
+ get MULTIPLIER() {
1835
+ return .006 * this.BASE;
1836
+ }
1809
1837
  },
1810
1838
  BORDER_OPACITY: {
1811
1839
  BASE_1: .12,
1812
1840
  // Base opacity for border gradient 1
1813
- BASE_2: .4,
1841
+ get BASE_2() {
1842
+ return 3.33 * this.BASE_1;
1843
+ },
1814
1844
  // Base opacity for border gradient 2
1815
- BASE_3: .32,
1845
+ get BASE_3() {
1846
+ return 2.66 * this.BASE_1;
1847
+ },
1816
1848
  // Base opacity for border gradient 3
1817
- BASE_4: .6,
1849
+ get BASE_4() {
1850
+ return 5 * this.BASE_1;
1851
+ },
1818
1852
  // Base opacity for border gradient 4
1819
- MULTIPLIER_LOW: .008,
1853
+ get MULTIPLIER_LOW() {
1854
+ return .066 * this.BASE_1;
1855
+ },
1820
1856
  // Low multiplier for mouse influence on opacity
1821
- MULTIPLIER_HIGH: .012
1857
+ get MULTIPLIER_HIGH() {
1858
+ return .1 * this.BASE_1;
1859
+ }
1822
1860
  },
1823
1861
  CENTER_POSITION: 50,
1824
1862
  // Center position percentage (50%)
1825
1863
  HOVER_POSITION: {
1826
1864
  DIVISOR_1: 2,
1827
1865
  // Divisor for hover 1 position calculation
1828
- DIVISOR_2: 1.5,
1866
+ get DIVISOR_2() {
1867
+ return .75 * this.DIVISOR_1;
1868
+ },
1829
1869
  // Divisor for hover 2 position calculation
1830
- MULTIPLIER_3: 1
1870
+ get MULTIPLIER_3() {
1871
+ return .5 * this.DIVISOR_1;
1872
+ }
1831
1873
  },
1832
- BASE_LAYER_MULTIPLIER: .5
1874
+ get BASE_LAYER_MULTIPLIER() {
1875
+ return .5;
1876
+ }
1833
1877
  },
1834
1878
  // Gradient opacity values for hover effects
1835
1879
  GRADIENT_OPACITY: {
1836
1880
  HOVER_1: {
1837
1881
  BLACK_START: .3,
1838
1882
  // Start opacity for black hover 1
1839
- BLACK_MID: .1,
1883
+ get BLACK_MID() {
1884
+ return this.BLACK_START / 3;
1885
+ },
1840
1886
  // Mid opacity for black hover 1
1841
1887
  BLACK_STOP: 30,
1842
1888
  // Stop percentage for black hover 1
1843
- BLACK_END: 60,
1889
+ get BLACK_END() {
1890
+ return 2 * this.BLACK_STOP;
1891
+ },
1844
1892
  // End percentage for black hover 1
1845
1893
  WHITE_START: .5,
1846
1894
  // Start opacity for white hover 1
1847
- WHITE_STOP: 50
1895
+ get WHITE_STOP() {
1896
+ return this.BLACK_END - 10;
1897
+ }
1848
1898
  },
1849
1899
  HOVER_2: {
1850
1900
  BLACK_START: .4,
1851
1901
  // Start opacity for black hover 2
1852
- BLACK_MID: .15,
1902
+ get BLACK_MID() {
1903
+ return .375 * this.BLACK_START;
1904
+ },
1853
1905
  // Mid opacity for black hover 2
1854
1906
  BLACK_STOP: 40,
1855
1907
  // Stop percentage for black hover 2
1856
- BLACK_END: 80,
1908
+ get BLACK_END() {
1909
+ return 2 * this.BLACK_STOP;
1910
+ },
1857
1911
  // End percentage for black hover 2
1858
1912
  WHITE_START: 1,
1859
1913
  // Start opacity for white hover 2
1860
- WHITE_STOP: 80
1914
+ get WHITE_STOP() {
1915
+ return this.BLACK_END;
1916
+ }
1861
1917
  },
1862
1918
  HOVER_3: {
1863
1919
  BLACK_START: .5,
1864
1920
  // Start opacity for black hover 3
1865
- BLACK_MID: .2,
1921
+ get BLACK_MID() {
1922
+ return .4 * this.BLACK_START;
1923
+ },
1866
1924
  // Mid opacity for black hover 3
1867
1925
  BLACK_STOP: 50,
1868
1926
  // Stop percentage for black hover 3
1869
- BLACK_END: 100,
1927
+ get BLACK_END() {
1928
+ return 2 * this.BLACK_STOP;
1929
+ },
1870
1930
  // End percentage for black hover 3
1871
1931
  WHITE_START: 1,
1872
1932
  // Start opacity for white hover 3
1873
- WHITE_STOP: 100
1933
+ get WHITE_STOP() {
1934
+ return this.BLACK_END;
1935
+ }
1874
1936
  }
1875
1937
  },
1876
1938
  // Base and overlay gradient constants
@@ -1879,34 +1941,54 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
1879
1941
  // Gradient angle in degrees
1880
1942
  BLACK_START_BASE: .15,
1881
1943
  // Base start opacity for black
1882
- BLACK_START_MULTIPLIER: .003,
1944
+ get BLACK_START_MULTIPLIER() {
1945
+ return .02 * this.BLACK_START_BASE;
1946
+ },
1883
1947
  // Multiplier for mouse X influence on start
1884
1948
  BLACK_MID_BASE: .1,
1885
1949
  // Base mid opacity for black
1886
- BLACK_MID_MULTIPLIER: .002,
1950
+ get BLACK_MID_MULTIPLIER() {
1951
+ return .02 * this.BLACK_MID_BASE;
1952
+ },
1887
1953
  // Multiplier for mouse Y influence on mid
1888
1954
  BLACK_MID_STOP: 50,
1889
1955
  // Mid stop percentage
1890
- BLACK_END_BASE: .18,
1956
+ get BLACK_END_BASE() {
1957
+ return 1.2 * this.BLACK_START_BASE;
1958
+ },
1891
1959
  // Base end opacity for black
1892
- BLACK_END_MULTIPLIER: .004,
1960
+ get BLACK_END_MULTIPLIER() {
1961
+ return .022 * this.BLACK_END_BASE;
1962
+ },
1893
1963
  // Multiplier for mouse X influence on end
1894
- WHITE_OPACITY: .1
1964
+ get WHITE_OPACITY() {
1965
+ return .666 * this.BLACK_START_BASE;
1966
+ }
1895
1967
  },
1896
1968
  OVERLAY_GRADIENT: {
1897
1969
  BLACK_START_BASE: .12,
1898
1970
  // Base start opacity for black overlay
1899
- BLACK_START_MULTIPLIER: .003,
1971
+ get BLACK_START_MULTIPLIER() {
1972
+ return .025 * this.BLACK_START_BASE;
1973
+ },
1900
1974
  // Multiplier for mouse X influence on start
1901
- BLACK_MID: .06,
1975
+ get BLACK_MID() {
1976
+ return .5 * this.BLACK_START_BASE;
1977
+ },
1902
1978
  // Mid opacity for black overlay
1903
1979
  BLACK_MID_STOP: 40,
1904
1980
  // Mid stop percentage
1905
- BLACK_END_BASE: .15,
1981
+ get BLACK_END_BASE() {
1982
+ return 1.25 * this.BLACK_START_BASE;
1983
+ },
1906
1984
  // Base end opacity for black overlay
1907
- BLACK_END_MULTIPLIER: .003,
1985
+ get BLACK_END_MULTIPLIER() {
1986
+ return .02 * this.BLACK_END_BASE;
1987
+ },
1908
1988
  // Multiplier for mouse Y influence on end
1909
- WHITE_OPACITY: .05
1989
+ get WHITE_OPACITY() {
1990
+ return .416 * this.BLACK_START_BASE;
1991
+ }
1910
1992
  },
1911
1993
  // Overlay highlight constants
1912
1994
  OVERLAY_HIGHLIGHT: {
@@ -1916,9 +1998,13 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
1916
1998
  // Y position percentage
1917
1999
  WHITE_OPACITY: .4,
1918
2000
  // White opacity in gradient
1919
- STOP: 60,
2001
+ get STOP() {
2002
+ return 150 * this.WHITE_OPACITY;
2003
+ },
1920
2004
  // Stop percentage
1921
- OPACITY_MULTIPLIER: .7
2005
+ get OPACITY_MULTIPLIER() {
2006
+ return 1.75 * this.WHITE_OPACITY;
2007
+ }
1922
2008
  },
1923
2009
  // Displacement and aberration multipliers
1924
2010
  MULTIPLIERS: {
@@ -2028,11 +2114,7 @@ function useAccordion(initialProps) {
2028
2114
  };
2029
2115
  }
2030
2116
 
2031
- const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateDistance = (pos1, pos2) => {
2032
- if (!pos1 || !pos2 || "number" != typeof pos1.x || "number" != typeof pos1.y || "number" != typeof pos2.x || "number" != typeof pos2.y) return 0;
2033
- const deltaX = pos1.x - pos2.x, deltaY = pos1.y - pos2.y;
2034
- return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
2035
- }, calculateElementCenter = rect => rect ? {
2117
+ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect => rect ? {
2036
2118
  x: rect.left + rect.width / 2,
2037
2119
  y: rect.top + rect.height / 2
2038
2120
  } : {
@@ -2104,7 +2186,16 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateDistance = (pos1, pos2)
2104
2186
  // Silently handle errors
2105
2187
  }
2106
2188
  return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
2107
- }, lerp$1 = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
2189
+ }, smoothstep = t => {
2190
+ const clamped = Math.max(0, Math.min(1, t));
2191
+ return clamped * clamped * (3 - 2 * clamped);
2192
+ }, lerp$1 = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), calculateSpring = (current, target, velocity, stiffness = .1, damping = .8) => {
2193
+ const newVelocity = (velocity + (target - current) * stiffness) * damping;
2194
+ return {
2195
+ value: current + newVelocity,
2196
+ velocity: newVelocity
2197
+ };
2198
+ }, getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
2108
2199
  switch (mode) {
2109
2200
  case "standard":
2110
2201
  return displacementMap;
@@ -2497,6 +2588,9 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
2497
2588
  }), jsxRuntime.jsx("div", {
2498
2589
  ref: contentRef,
2499
2590
  className: ATOMIX_GLASS.CONTENT_CLASS,
2591
+ style: {
2592
+ transform: "var(--atomix-glass-child-parallax, none)"
2593
+ },
2500
2594
  children: children
2501
2595
  }) ]
2502
2596
  })
@@ -2531,9 +2625,21 @@ class {
2531
2625
  y: this.lastEvent.clientY
2532
2626
  },
2533
2627
  // Notify all subscribers
2534
- this.listeners.forEach((callback => {
2628
+ this.listeners.forEach((listener => {
2535
2629
  try {
2536
- callback(this.position);
2630
+ // If the listener has an element, calculate distance-based attenuation
2631
+ if (listener.element) {
2632
+ const elementRect = listener.element.getBoundingClientRect(), elementCenter = {
2633
+ x: elementRect.left + elementRect.width / 2,
2634
+ y: elementRect.top + elementRect.height / 2
2635
+ }, distance = this.calculateDistance(this.position, elementCenter), maxDistance = listener.maxDistance || 300, attenuation = Math.max(0, 1 - distance / maxDistance), attenuatedRelativePosition = {
2636
+ x: (this.position.x - elementCenter.x) / elementRect.width * 100 * attenuation,
2637
+ y: (this.position.y - elementCenter.y) / elementRect.height * 100 * attenuation
2638
+ };
2639
+ listener.callback(attenuatedRelativePosition);
2640
+ } else
2641
+ // Send original position for listeners without distance-based attenuation
2642
+ listener.callback(this.position);
2537
2643
  } catch (error) {
2538
2644
  console.error("GlobalMouseTracker: Error in subscriber callback", error);
2539
2645
  }
@@ -2544,10 +2650,17 @@ class {
2544
2650
  /**
2545
2651
  * Subscribe to mouse position updates
2546
2652
  * @param callback Function to call when mouse position changes
2653
+ * @param element Optional element for distance-based attenuation
2654
+ * @param maxDistance Optional maximum distance for full effect
2547
2655
  * @returns Unsubscribe function
2548
- */ subscribe(callback) {
2656
+ */ subscribe(callback, element, maxDistance) {
2657
+ const listener = {
2658
+ callback: callback,
2659
+ element: element,
2660
+ maxDistance: maxDistance
2661
+ };
2549
2662
  // Return unsubscribe function
2550
- return this.listeners.add(callback),
2663
+ return this.listeners.add(listener),
2551
2664
  // Start tracking if this is the first subscriber
2552
2665
  1 === this.listeners.size && this.startTracking(),
2553
2666
  // Immediately notify with current position
@@ -2558,9 +2671,13 @@ class {
2558
2671
  /**
2559
2672
  * Unsubscribe from mouse position updates
2560
2673
  */ unsubscribe(callback) {
2561
- this.listeners.delete(callback),
2674
+ // Find and remove the listener with the given callback
2675
+ for (const listener of this.listeners) if (listener.callback === callback) {
2676
+ this.listeners.delete(listener);
2677
+ break;
2678
+ }
2562
2679
  // Stop tracking if no more subscribers
2563
- 0 === this.listeners.size && this.stopTracking();
2680
+ 0 === this.listeners.size && this.stopTracking();
2564
2681
  }
2565
2682
  /**
2566
2683
  * Start tracking mouse movement
@@ -2579,6 +2696,12 @@ class {
2579
2696
  null !== this.rafId && (cancelAnimationFrame(this.rafId), this.rafId = null), this.lastEvent = null);
2580
2697
  }
2581
2698
  /**
2699
+ * Calculate distance between two points
2700
+ */ calculateDistance(point1, point2) {
2701
+ const dx = point1.x - point2.x, dy = point1.y - point2.y;
2702
+ return Math.sqrt(dx * dx + dy * dy);
2703
+ }
2704
+ /**
2582
2705
  * Get current mouse position (synchronous)
2583
2706
  */ getPosition() {
2584
2707
  return {
@@ -2592,51 +2715,26 @@ class {
2592
2715
  }
2593
2716
  }, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
2594
2717
  if (!wrapperElement && !containerElement) return;
2595
- const {mouseOffset: mouseOffset, globalMousePosition: globalMousePosition, glassSize: glassSize, isHovered: isHovered, isActive: isActive, isOverLight: isOverLight, baseOverLightConfig: baseOverLightConfig, effectiveBorderRadius: effectiveBorderRadius, effectiveWithoutEffects: effectiveWithoutEffects, effectiveReducedMotion: effectiveReducedMotion, elasticity: elasticity, directionalScale: directionalScale, onClick: onClick, withLiquidBlur: withLiquidBlur, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, isFixedOrSticky: isFixedOrSticky = !1} = params, mouseInfluence = calculateMouseInfluence(mouseOffset), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1, overLightConfig = {
2718
+ if (!validateGlassSize(params.glassSize)) return;
2719
+ const {mouseOffset: mouseOffset, globalMousePosition: globalMousePosition, glassSize: glassSize, isHovered: isHovered, isActive: isActive, isOverLight: isOverLight, baseOverLightConfig: baseOverLightConfig, effectiveBorderRadius: effectiveBorderRadius, effectiveWithoutEffects: effectiveWithoutEffects, effectiveReducedMotion: effectiveReducedMotion, elasticity: elasticity, elasticTranslation: elasticTranslation, elasticVelocity: elasticVelocity, mouseVelocity: mouseVelocity, directionalScale: directionalScale, scaleBase: scaleBase, onClick: onClick, withLiquidBlur: withLiquidBlur, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, isFixedOrSticky: isFixedOrSticky = !1} = params, mouseInfluence = calculateMouseInfluence(mouseOffset), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1, overLightConfig = {
2596
2720
  opacity: baseOverLightConfig.opacity * hoverIntensity * activeIntensity,
2597
2721
  contrast: Math.min(1.6, baseOverLightConfig.contrast + .1 * mouseInfluence),
2598
2722
  brightness: Math.min(1.1, baseOverLightConfig.brightness + .05 * mouseInfluence),
2599
2723
  shadowIntensity: Math.min(1.2, Math.max(.5, baseOverLightConfig.shadowIntensity + .2 * mouseInfluence)),
2600
2724
  borderOpacity: Math.min(1, Math.max(.3, baseOverLightConfig.borderOpacity + .1 * mouseInfluence)),
2601
2725
  saturationBoost: baseOverLightConfig.saturationBoost
2602
- };
2603
- // Calculate mouse influence
2604
- let computedDirectionalScale = directionalScale, elasticTranslation = {
2726
+ }, scaleX = directionalScale.x * scaleBase, scaleY = directionalScale.y * scaleBase, transformStyle = effectiveWithoutEffects ? `scale(${scaleBase})` : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) scaleX(${scaleX}) scaleY(${scaleY})`, stretchMagnitude = ((pos1, pos2) => {
2727
+ if (!pos1 || !pos2 || "number" != typeof pos1.x || "number" != typeof pos1.y || "number" != typeof pos2.x || "number" != typeof pos2.y) return 0;
2728
+ const deltaX = pos1.x - pos2.x, deltaY = pos1.y - pos2.y;
2729
+ return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
2730
+ })({
2605
2731
  x: 0,
2606
2732
  y: 0
2607
- };
2608
- // Calculate elastic translation and directional scale
2609
- if (!effectiveWithoutEffects && wrapperElement) {
2610
- const rect = wrapperElement.getBoundingClientRect(), center = calculateElementCenter(rect);
2611
- // Mouse presence and edge distance logic
2612
- if (globalMousePosition.x && globalMousePosition.y && validateGlassSize(glassSize)) {
2613
- const deltaX = globalMousePosition.x - center.x, deltaY = globalMousePosition.y - center.y, edgeDistanceX = Math.max(0, Math.abs(deltaX) - glassSize.width / 2), edgeDistanceY = Math.max(0, Math.abs(deltaY) - glassSize.height / 2), edgeDistance = calculateDistance({
2614
- x: edgeDistanceX,
2615
- y: edgeDistanceY
2616
- }, {
2617
- x: 0,
2618
- y: 0
2619
- }), rawT = edgeDistance > ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE ? 0 : 1 - edgeDistance / ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE, fadeInFactor = (t => {
2620
- const clamped = Math.max(0, Math.min(1, t));
2621
- return clamped * clamped * (3 - 2 * clamped);
2622
- })(rawT);
2623
- // Directional scale
2624
- if (elasticTranslation = {
2625
- x: deltaX * elasticity * .1 * fadeInFactor,
2626
- y: deltaY * elasticity * .1 * fadeInFactor
2627
- }, !isOverLight && edgeDistance <= ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE) {
2628
- const centerDistance = calculateDistance(globalMousePosition, center);
2629
- if (centerDistance > 0) {
2630
- const normalizedX = deltaX / centerDistance, normalizedY = deltaY / centerDistance, stretchIntensity = Math.min(centerDistance / 300, 1) * elasticity * rawT, scaleX = 1 + Math.abs(normalizedX) * stretchIntensity * .3 - Math.abs(normalizedY) * stretchIntensity * .15, scaleY = 1 + Math.abs(normalizedY) * stretchIntensity * .3 - Math.abs(normalizedX) * stretchIntensity * .15, softScaleX = 1 - softClamp(Math.max(0, 1 - scaleX), .2), softScaleY = 1 - softClamp(Math.max(0, 1 - scaleY), .2);
2631
- computedDirectionalScale = `scaleX(${Math.max(.85, softScaleX)}) scaleY(${Math.max(.85, softScaleY)})`;
2632
- }
2633
- }
2634
- }
2635
- }
2636
- const transformStyle = effectiveWithoutEffects ? isActive && Boolean(onClick) ? "scale(0.98)" : "scale(1)" : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) ${isActive && Boolean(onClick) ? "scale(0.96)" : computedDirectionalScale}`;
2637
- // Update Wrapper Styles (glassVars)
2638
- if (wrapperElement) {
2639
- const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, borderGradientAngle = GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER, borderStop1 = Math.max(GRADIENT.BORDER_STOP_1.MIN, GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER), borderStop2 = Math.min(GRADIENT.BORDER_STOP_2.MAX, GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER), borderOpacities = [ GRADIENT.BORDER_OPACITY.BASE_1 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, GRADIENT.BORDER_OPACITY.BASE_2 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH, GRADIENT.BORDER_OPACITY.BASE_3 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, GRADIENT.BORDER_OPACITY.BASE_4 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH ], configBorderOpacity = overLightConfig.borderOpacity, whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, hoverPositions = {
2733
+ }, elasticTranslation), tensionFactor = smoothstep(stretchMagnitude / 80), lightingContrast = Math.min(1.8, overLightConfig.contrast + .2 * tensionFactor), lightingBrightness = Math.min(1.2, overLightConfig.brightness + .1 * tensionFactor);
2734
+ // Calculate mouse influence
2735
+ // Update Wrapper Styles (glassVars)
2736
+ if (wrapperElement) {
2737
+ const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, velocityRotation = (mouseVelocity.x + elasticVelocity.x) * (GRADIENT.VELOCITY_ANGLE_MULTIPLIER || 2.5), borderGradientAngle = GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER + velocityRotation, chromaticOffset = GRADIENT.CHROMATIC_OFFSET || 1.5, angleR = borderGradientAngle - chromaticOffset, angleB = borderGradientAngle + chromaticOffset, borderStop1 = Math.max(GRADIENT.BORDER_STOP_1.MIN, GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER), borderStop2 = Math.min(GRADIENT.BORDER_STOP_2.MAX, GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER), tensionGlow = 1 + .5 * tensionFactor, borderOpacities = [ (GRADIENT.BORDER_OPACITY.BASE_1 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW) * tensionGlow, (GRADIENT.BORDER_OPACITY.BASE_2 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH) * tensionGlow, (GRADIENT.BORDER_OPACITY.BASE_3 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW) * tensionGlow, (GRADIENT.BORDER_OPACITY.BASE_4 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH) * tensionGlow ], configBorderOpacity = overLightConfig.borderOpacity, whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, hoverPositions = {
2640
2738
  hover1: {
2641
2739
  x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
2642
2740
  y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1
@@ -2659,10 +2757,16 @@ class {
2659
2757
  base: isOverLight ? overLightConfig.opacity : 0,
2660
2758
  over: isOverLight ? 1.1 * overLightConfig.opacity : 0
2661
2759
  }, style = wrapperElement.style;
2662
- style.setProperty("--atomix-glass-transform", transformStyle || "none"),
2663
- // Gradients
2664
- style.setProperty("--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%)`),
2665
- style.setProperty("--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%)`),
2760
+ style.setProperty("--atomix-glass-transform", transformStyle || "none");
2761
+ // Parallax for content (liquid refraction feel)
2762
+ const parallaxFactor = .38 + .12 * tensionFactor;
2763
+ style.setProperty("--atomix-glass-child-parallax", `translate(${elasticTranslation.x * -parallaxFactor}px, ${elasticTranslation.y * -parallaxFactor}px)`),
2764
+ style.setProperty("--atomix-glass-contrast", lightingContrast.toString()), style.setProperty("--atomix-glass-brightness", lightingBrightness.toString()),
2765
+ // ── Chromatic Rim Lighting ──────────────────────────────────────
2766
+ // Layer 1: Core White/Blue highlight
2767
+ style.setProperty("--atomix-glass-border-gradient-1", `linear-gradient(${angleB}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[0] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[1] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`),
2768
+ // Layer 2: Subtle Red/Warm highlight (offset angle)
2769
+ style.setProperty("--atomix-glass-border-gradient-2", `linear-gradient(${angleR}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[2] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[3] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`),
2666
2770
  // Hover gradients
2667
2771
  style.setProperty("--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}%)`),
2668
2772
  style.setProperty("--atomix-glass-hover-2-gradient", isOverLight ? `radial-gradient(circle at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_STOP}%)`),
@@ -2690,7 +2794,7 @@ class {
2690
2794
  flowBlur: blurAmount * FLOW_BLUR_MULTIPLIER
2691
2795
  };
2692
2796
  if (withLiquidBlur && rect) {
2693
- const mouseInfluence = calculateMouseInfluence(mouseOffset), maxBlur = blurAmount * MAX_BLUR_RELATIVE, baseBlur = Math.min(maxBlur, blurAmount + mouseInfluence * blurAmount * MOUSE_INFLUENCE_BLUR_FACTOR), edgeIntensity = mouseInfluence * EDGE_INTENSITY_MOUSE_FACTOR, edgeBlur = Math.min(maxBlur, baseBlur * (.8 + .4 * edgeIntensity)), centerIntensity = mouseInfluence * CENTER_INTENSITY_MOUSE_FACTOR, centerBlur = Math.min(maxBlur, baseBlur * (.3 + .3 * centerIntensity)), flowBlur = Math.min(maxBlur, baseBlur * FLOW_BLUR_MULTIPLIER);
2797
+ const mouseInfluence = calculateMouseInfluence(mouseOffset), maxBlur = blurAmount * MAX_BLUR_RELATIVE, baseBlur = softClamp(blurAmount + mouseInfluence * blurAmount * MOUSE_INFLUENCE_BLUR_FACTOR, maxBlur), edgeBlur = softClamp(baseBlur * (.8 + mouseInfluence * EDGE_INTENSITY_MOUSE_FACTOR * .4), maxBlur), centerBlur = softClamp(baseBlur * (.3 + mouseInfluence * CENTER_INTENSITY_MOUSE_FACTOR * .3), maxBlur), flowBlur = softClamp(baseBlur * FLOW_BLUR_MULTIPLIER, maxBlur);
2694
2798
  liquidBlur = {
2695
2799
  baseBlur: clampBlur(baseBlur),
2696
2800
  edgeBlur: clampBlur(edgeBlur),
@@ -2699,9 +2803,10 @@ class {
2699
2803
  };
2700
2804
  }
2701
2805
  // Backdrop filter
2702
- let backdropFilterString = `blur(${blurAmount}px) saturate(${saturation}%) contrast(1.05) brightness(1.05)`;
2703
- const dynamicSaturation = saturation + 20 * (liquidBlur.baseBlur || 0), area = rect ? rect.width * rect.height : 0;
2704
- 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})`;
2806
+ const dynamicSaturation = saturation + 40 * tensionFactor + 15 * (liquidBlur.baseBlur || 0);
2807
+ let backdropFilterString = "";
2808
+ const area = rect ? rect.width * rect.height : 0;
2809
+ 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, 250)}%) contrast(${lightingContrast}) brightness(${lightingBrightness})` : `blur(${clampBlur(.4 * liquidBlur.baseBlur + .25 * liquidBlur.edgeBlur + .15 * liquidBlur.centerBlur + .2 * liquidBlur.flowBlur)}px) saturate(${Math.min(dynamicSaturation, 250)}%) contrast(${lightingContrast}) brightness(${lightingBrightness})`;
2705
2810
  // Container variables
2706
2811
  const style = containerElement.style;
2707
2812
  style.setProperty("--atomix-glass-container-padding", padding), style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
@@ -2863,7 +2968,8 @@ const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new Weak
2863
2968
  * Composable hook for AtomixGlass component logic
2864
2969
  * Manages all state, calculations, and event handlers
2865
2970
  */
2866
- function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef: wrapperRef, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, elasticity: elasticity = .05, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, children: children, blurAmount: blurAmount, saturation: saturation, padding: padding, withLiquidBlur: withLiquidBlur, isFixedOrSticky: isFixedOrSticky = !1, withTimeAnimation:
2971
+ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef: wrapperRef, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, children: children, blurAmount: blurAmount, saturation: saturation, padding: padding, withLiquidBlur: withLiquidBlur, isFixedOrSticky: isFixedOrSticky = !1, priority: priority = 1, withTimeAnimation:
2972
+ // Default priority
2867
2973
  // Phase 1: Animation System Props
2868
2974
  withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: animationSpeed = ATOMIX_GLASS.DEFAULTS.ANIMATION_SPEED, withMultiLayerDistortion: withMultiLayerDistortion = ATOMIX_GLASS.DEFAULTS.WITH_MULTI_LAYER_DISTORTION, distortionOctaves: distortionOctaves = ATOMIX_GLASS.DEFAULTS.DISTORTION_OCTAVES, distortionLacunarity: distortionLacunarity = ATOMIX_GLASS.DEFAULTS.DISTORTION_LACUNARITY, distortionGain: distortionGain = ATOMIX_GLASS.DEFAULTS.DISTORTION_GAIN, distortionQuality: distortionQuality = ATOMIX_GLASS.DEFAULTS.DISTORTION_QUALITY}) {
2869
2975
  // State
@@ -2879,7 +2985,24 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2879
2985
  }), targetGlobalMousePositionRef = React.useRef({
2880
2986
  x: 0,
2881
2987
  y: 0
2882
- }), lerpRafRef = React.useRef(null), lerpActiveRef = React.useRef(!1), [dynamicBorderRadius, setDynamicCornerRadius] = React.useState(CONSTANTS.DEFAULT_CORNER_RADIUS), [userPrefersReducedMotion, setUserPrefersReducedMotion] = React.useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = React.useState(!1), [detectedOverLight, setDetectedOverLight] = React.useState(!1), animationFrameIdRef = React.useRef(null), animationStartTimeRef = React.useRef(0), elapsedTimeRef = React.useRef(0), shaderTimeRef = React.useRef(0), fbmConfig = React.useMemo((() => {
2988
+ }), lerpRafRef = React.useRef(null), lerpActiveRef = React.useRef(!1), [dynamicBorderRadius, setDynamicCornerRadius] = React.useState(CONSTANTS.DEFAULT_CORNER_RADIUS), elasticTranslationRef = React.useRef({
2989
+ x: 0,
2990
+ y: 0
2991
+ }), elasticVelocityRef = React.useRef({
2992
+ x: 0,
2993
+ y: 0
2994
+ }), directionalScaleRef = React.useRef({
2995
+ x: 1,
2996
+ y: 1
2997
+ }), scaleVelocityRef = React.useRef({
2998
+ x: 0,
2999
+ y: 0
3000
+ });
3001
+ React.useRef(0);
3002
+ const mouseVelocityRef = React.useRef({
3003
+ x: 0,
3004
+ y: 0
3005
+ }), [userPrefersReducedMotion, setUserPrefersReducedMotion] = React.useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = React.useState(!1), [detectedOverLight, setDetectedOverLight] = React.useState(!1), animationFrameIdRef = React.useRef(null), animationStartTimeRef = React.useRef(0), elapsedTimeRef = React.useRef(0), shaderTimeRef = React.useRef(0), fbmConfig = React.useMemo((() => {
2883
3006
  // If quality preset is provided, use it as base
2884
3007
  const preset = (quality = distortionQuality, ATOMIX_GLASS.CONSTANTS.DISTORTION_QUALITY_PRESETS[quality]);
2885
3008
  // Override with custom values if provided
@@ -3164,57 +3287,85 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
3164
3287
  return "undefined" == typeof process || process.env, finalConfig;
3165
3288
  }
3166
3289
  return "undefined" == typeof process || process.env, baseConfig;
3167
- }), [ overLight, getEffectiveOverLight, isHovered, isActive, validateConfigValue, debugOverLight ]), transformStyle = React.useMemo((() => effectiveWithoutEffects || isActive && Boolean(onClick) ? "scale(0.98)" : "scale(1)"), [ effectiveWithoutEffects, isActive, onClick ]), updateRectRef = React.useRef(null), stopLerpLoop = React.useCallback((() => {
3290
+ }), [ overLight, getEffectiveOverLight, isHovered, isActive, validateConfigValue, debugOverLight ]), transformStyle = React.useMemo((() => effectiveWithoutEffects || isActive && Boolean(onClick) ? "scale(0.99)" : "scale(1)"), [ effectiveWithoutEffects, isActive, onClick ]), updateRectRef = React.useRef(null), stopLerpLoop = React.useCallback((() => {
3168
3291
  lerpActiveRef.current = !1, null !== lerpRafRef.current && (cancelAnimationFrame(lerpRafRef.current),
3169
3292
  lerpRafRef.current = null);
3170
3293
  }), []), startLerpLoop = React.useCallback((() => {
3171
3294
  if (lerpActiveRef.current) return;
3172
- lerpActiveRef.current = !0;
3173
- const LERP_T = CONSTANTS.LERP_FACTOR, tick = () => {
3295
+ lerpActiveRef.current = !0, CONSTANTS.LERP_FACTOR;
3296
+ // 0.08 lower = more viscous
3297
+ const tick = () => {
3174
3298
  if (!lerpActiveRef.current) return;
3175
3299
  if (!glassRef.current) return void (lerpActiveRef.current = !1);
3176
- const cur = internalMouseOffsetRef.current, tgt = targetMouseOffsetRef.current, dx = tgt.x - cur.x, dy = tgt.y - cur.y;
3177
- // If we're close enough, snap and park
3178
- if (Math.abs(dx) < .01 && Math.abs(dy) < .01) return internalMouseOffsetRef.current = {
3179
- ...tgt
3180
- }, internalGlobalMousePositionRef.current = {
3181
- ...targetGlobalMousePositionRef.current
3182
- },
3183
- // Final update and stop
3184
- updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
3185
- mouseOffset: internalMouseOffsetRef.current,
3186
- globalMousePosition: internalGlobalMousePositionRef.current,
3187
- glassSize: glassSize,
3188
- isHovered: isHovered,
3189
- isActive: isActive,
3190
- isOverLight: overLightConfig.isOverLight,
3191
- baseOverLightConfig: overLightConfig,
3192
- effectiveBorderRadius: effectiveBorderRadius,
3193
- effectiveWithoutEffects: effectiveWithoutEffects,
3194
- effectiveReducedMotion: effectiveReducedMotion,
3195
- elasticity: elasticity,
3196
- directionalScale: isActive && Boolean(onClick) ? "scale(0.96)" : "scale(1)",
3197
- onClick: onClick,
3198
- withLiquidBlur: withLiquidBlur,
3199
- blurAmount: blurAmount,
3200
- saturation: saturation,
3201
- padding: padding,
3202
- isFixedOrSticky: isFixedOrSticky
3203
- }), void stopLerpLoop();
3204
- // Smooth step
3205
- internalMouseOffsetRef.current = {
3206
- x: lerp$1(cur.x, tgt.x, LERP_T),
3207
- y: lerp$1(cur.y, tgt.y, LERP_T)
3300
+ const cur = internalMouseOffsetRef.current, tgt = targetMouseOffsetRef.current, springX = calculateSpring(cur.x, tgt.x, mouseVelocityRef.current.x, CONSTANTS.LERP_FACTOR, CONSTANTS.ELASTICITY_DAMPING), springY = calculateSpring(cur.y, tgt.y, mouseVelocityRef.current.y, CONSTANTS.LERP_FACTOR, CONSTANTS.ELASTICITY_DAMPING);
3301
+ internalMouseOffsetRef.current = {
3302
+ x: springX.value,
3303
+ y: springY.value
3304
+ }, mouseVelocityRef.current = {
3305
+ x: springX.velocity,
3306
+ y: springY.velocity
3208
3307
  };
3209
3308
  const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
3210
3309
  internalGlobalMousePositionRef.current = {
3211
- x: lerp$1(curG.x, tgtG.x, LERP_T),
3212
- y: lerp$1(curG.y, tgtG.y, LERP_T)
3310
+ x: lerp$1(curG.x, tgtG.x, CONSTANTS.LERP_FACTOR),
3311
+ y: lerp$1(curG.y, tgtG.y, CONSTANTS.LERP_FACTOR)
3312
+ };
3313
+ // ── Calculate Elastic Physics ─────────────────────────────────────
3314
+ let targetElasticTranslation = {
3315
+ x: 0,
3316
+ y: 0
3317
+ }, targetScale = {
3318
+ x: 1,
3319
+ y: 1
3320
+ };
3321
+ if (!effectiveWithoutEffects && glassRef.current) {
3322
+ const rect = cachedRectRef.current || glassRef.current.getBoundingClientRect(), center = calculateElementCenter(rect), globalPos = internalGlobalMousePositionRef.current;
3323
+ if (globalPos.x && globalPos.y) {
3324
+ const deltaX = globalPos.x - center.x, deltaY = globalPos.y - center.y, edgeDistanceX = Math.max(0, Math.abs(deltaX) - rect.width / 2), edgeDistanceY = Math.max(0, Math.abs(deltaY) - rect.height / 2), edgeDistance = Math.sqrt(edgeDistanceX * edgeDistanceX + edgeDistanceY * edgeDistanceY), activationZone = CONSTANTS.ACTIVATION_ZONE, rawT = edgeDistance > activationZone ? 0 : 1 - edgeDistance / activationZone, fadeInFactor = smoothstep(rawT);
3325
+ // Scale stretch logic (liquid surface tension)
3326
+ if (targetElasticTranslation = {
3327
+ x: deltaX * elasticity * CONSTANTS.ELASTICITY_TRANSLATION_FACTOR * fadeInFactor,
3328
+ y: deltaY * elasticity * CONSTANTS.ELASTICITY_TRANSLATION_FACTOR * fadeInFactor
3329
+ }, edgeDistance <= activationZone) {
3330
+ const centerDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
3331
+ if (centerDistance > 0) {
3332
+ const nx = deltaX / centerDistance, ny = deltaY / centerDistance, stretchIntensity = Math.min(centerDistance / 350, 1) * elasticity * rawT, mag = 1 + .06 * stretchIntensity;
3333
+ targetScale = {
3334
+ x: mag + Math.abs(nx) * stretchIntensity * CONSTANTS.ELASTICITY_STRETCH_RATIO,
3335
+ y: mag + Math.abs(ny) * stretchIntensity * CONSTANTS.ELASTICITY_STRETCH_RATIO
3336
+ },
3337
+ // Maintain liquid volume by compressing the perpendicular axis
3338
+ targetScale.x -= Math.abs(ny) * stretchIntensity * .15, targetScale.y -= Math.abs(nx) * stretchIntensity * .15;
3339
+ }
3340
+ }
3341
+ }
3342
+ }
3343
+ // Integrate Elastic Translation Spring
3344
+ const springTX = calculateSpring(elasticTranslationRef.current.x, targetElasticTranslation.x, elasticVelocityRef.current.x, CONSTANTS.ELASTICITY_STIFFNESS, CONSTANTS.ELASTICITY_DAMPING), springTY = calculateSpring(elasticTranslationRef.current.y, targetElasticTranslation.y, elasticVelocityRef.current.y, CONSTANTS.ELASTICITY_STIFFNESS, CONSTANTS.ELASTICITY_DAMPING);
3345
+ elasticTranslationRef.current = {
3346
+ x: springTX.value,
3347
+ y: springTY.value
3348
+ }, elasticVelocityRef.current = {
3349
+ x: springTX.velocity,
3350
+ y: springTY.velocity
3351
+ };
3352
+ // Integrate Scale Spring
3353
+ const springSX = calculateSpring(directionalScaleRef.current.x, targetScale.x, scaleVelocityRef.current.x, CONSTANTS.ELASTICITY_STIFFNESS, CONSTANTS.ELASTICITY_DAMPING), springSY = calculateSpring(directionalScaleRef.current.y, targetScale.y, scaleVelocityRef.current.y, CONSTANTS.ELASTICITY_STIFFNESS, CONSTANTS.ELASTICITY_DAMPING);
3354
+ directionalScaleRef.current = {
3355
+ x: springSX.value,
3356
+ y: springSY.value
3357
+ }, scaleVelocityRef.current = {
3358
+ x: springSX.velocity,
3359
+ y: springSY.velocity
3213
3360
  },
3214
3361
  // Imperative style update
3215
3362
  updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
3216
3363
  mouseOffset: internalMouseOffsetRef.current,
3217
3364
  globalMousePosition: internalGlobalMousePositionRef.current,
3365
+ elasticTranslation: elasticTranslationRef.current,
3366
+ elasticVelocity: elasticVelocityRef.current,
3367
+ mouseVelocity: mouseVelocityRef.current,
3368
+ directionalScale: directionalScaleRef.current,
3218
3369
  glassSize: glassSize,
3219
3370
  isHovered: isHovered,
3220
3371
  isActive: isActive,
@@ -3224,17 +3375,16 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
3224
3375
  effectiveWithoutEffects: effectiveWithoutEffects,
3225
3376
  effectiveReducedMotion: effectiveReducedMotion,
3226
3377
  elasticity: elasticity,
3227
- directionalScale: isActive && Boolean(onClick) ? "scale(0.96)" : "scale(1)",
3378
+ scaleBase: isActive && Boolean(onClick) ? .99 : 1,
3228
3379
  onClick: onClick,
3229
3380
  withLiquidBlur: withLiquidBlur,
3230
3381
  blurAmount: blurAmount,
3231
3382
  saturation: saturation,
3232
3383
  padding: padding,
3233
3384
  isFixedOrSticky: isFixedOrSticky
3234
- }), lerpRafRef.current = requestAnimationFrame(tick);
3385
+ }), Math.abs(mouseVelocityRef.current.x) < .001 && Math.abs(mouseVelocityRef.current.y) < .001 && Math.abs(elasticVelocityRef.current.x) < .001 && Math.abs(elasticVelocityRef.current.y) < .001 && Math.abs(scaleVelocityRef.current.x) < .001 && Math.abs(scaleVelocityRef.current.y) < .001 && Math.abs(internalMouseOffsetRef.current.x - targetMouseOffsetRef.current.x) < .001 && Math.abs(internalMouseOffsetRef.current.y - targetMouseOffsetRef.current.y) < .001 ? stopLerpLoop() : lerpRafRef.current = requestAnimationFrame(tick);
3235
3386
  };
3236
- // 0.08 – lower = more viscous
3237
- lerpRafRef.current = requestAnimationFrame(tick);
3387
+ lerpRafRef.current = requestAnimationFrame(tick);
3238
3388
  }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding, isFixedOrSticky, stopLerpLoop ]), handleGlobalMousePosition = React.useCallback((globalPos => {
3239
3389
  if (externalGlobalMousePosition && externalMouseOffset) return;
3240
3390
  if (effectiveWithoutEffects) return;
@@ -3260,7 +3410,8 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
3260
3410
  React.useEffect((() => {
3261
3411
  if (externalGlobalMousePosition && externalMouseOffset) return;
3262
3412
  if (effectiveWithoutEffects) return;
3263
- const unsubscribe = globalMouseTracker.subscribe(handleGlobalMousePosition);
3413
+ const unsubscribe = globalMouseTracker.subscribe(handleGlobalMousePosition, glassRef.current || void 0, 300);
3414
+ // 300px max distance for full effect
3264
3415
  // Initial start
3265
3416
  startLerpLoop();
3266
3417
  const container = mouseContainer?.current || glassRef.current;
@@ -3280,6 +3431,11 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
3280
3431
  updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
3281
3432
  mouseOffset: externalMouseOffset || internalMouseOffsetRef.current,
3282
3433
  globalMousePosition: externalGlobalMousePosition || internalGlobalMousePositionRef.current,
3434
+ elasticTranslation: elasticTranslationRef.current,
3435
+ elasticVelocity: elasticVelocityRef.current,
3436
+ mouseVelocity: mouseVelocityRef.current,
3437
+ directionalScale: directionalScaleRef.current,
3438
+ scaleBase: isActive && Boolean(onClick) ? .96 : 1,
3283
3439
  glassSize: glassSize,
3284
3440
  isHovered: isHovered,
3285
3441
  isActive: isActive,
@@ -3289,7 +3445,6 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
3289
3445
  effectiveWithoutEffects: effectiveWithoutEffects,
3290
3446
  effectiveReducedMotion: effectiveReducedMotion,
3291
3447
  elasticity: elasticity,
3292
- directionalScale: isActive && Boolean(onClick) ? "scale(0.96)" : "scale(1)",
3293
3448
  onClick: onClick,
3294
3449
  withLiquidBlur: withLiquidBlur,
3295
3450
  blurAmount: blurAmount,
@@ -4255,7 +4410,7 @@ function getDevicePreset(presetName) {
4255
4410
  "aria-label": ariaLabel,
4256
4411
  "aria-describedby": ariaDescribedBy,
4257
4412
  "aria-disabled": !(!onClick || !effectiveWithoutEffects) || !onClick && void 0,
4258
- "aria-pressed": void 0,
4413
+ "aria-pressed": onClick ? isActive : void 0,
4259
4414
  onKeyDown: onClick ? handleKeyDown : void 0,
4260
4415
  children: [ jsxRuntime.jsx(AtomixGlassContainer, {
4261
4416
  ref: glassRef,
@@ -5426,10 +5581,10 @@ function renderSlot(slot, props, fallback) {
5426
5581
  children: renderSlot(slots?.spinner, {
5427
5582
  className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.SPINNER_ELEMENT),
5428
5583
  size: spinnerSize,
5429
- variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
5584
+ variant: "link" === variant || "ghost" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "danger" : variant
5430
5585
  }, jsxRuntime.jsx(Spinner, {
5431
5586
  size: spinnerSize,
5432
- variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
5587
+ variant: "link" === variant || "ghost" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "danger" : variant
5433
5588
  }))
5434
5589
  }), iconElement && !loading && jsxRuntime.jsx("span", {
5435
5590
  className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.ICON_ELEMENT),
@@ -5518,8 +5673,7 @@ function renderSlot(slot, props, fallback) {
5518
5673
  const defaultGlassProps = {
5519
5674
  displacementScale: 20,
5520
5675
  blurAmount: 0,
5521
- saturation: 200,
5522
- elasticity: 0
5676
+ saturation: 200
5523
5677
  }, glassProps = !0 === glass ? defaultGlassProps : {
5524
5678
  ...defaultGlassProps,
5525
5679
  ...glass
@@ -5950,7 +6104,6 @@ className: className = "", style: style, ...rest}, ref) => {
5950
6104
  const glassProps = !0 === glass ? {} : glass;
5951
6105
  return jsxRuntime.jsx(AtomixGlass, {
5952
6106
  ...glassProps,
5953
- elasticity: 0,
5954
6107
  children: anchorElement
5955
6108
  });
5956
6109
  }
@@ -5966,7 +6119,6 @@ className: className = "", style: style, ...rest}, ref) => {
5966
6119
  const glassProps = !0 === glass ? {} : glass;
5967
6120
  return jsxRuntime.jsx(AtomixGlass, {
5968
6121
  ...glassProps,
5969
- elasticity: 0,
5970
6122
  children: divElement
5971
6123
  });
5972
6124
  }
@@ -12209,9 +12361,7 @@ const EdgePanelComponentBase = ({title: title, children: children, position: pos
12209
12361
  // The original code returned null if !isOpenState && isOpen === false.
12210
12362
  // Let's keep that logic.
12211
12363
  if (!isOpenState && !1 === isOpen) return null;
12212
- const defaultGlassProps = {
12213
- elasticity: 0
12214
- }, glassProps = !0 === glass ? defaultGlassProps : {
12364
+ const defaultGlassProps = {}, glassProps = !0 === glass ? defaultGlassProps : {
12215
12365
  ...defaultGlassProps,
12216
12366
  ...glass
12217
12367
  }, panelContent = React__default.default.Children.toArray(children).some((child => {
@@ -13587,26 +13737,25 @@ var composablesImport = Object.freeze({
13587
13737
  useTodo: useTodo
13588
13738
  });
13589
13739
 
13590
- const SelectContext = React.createContext(null), SelectOption = React.memo((({value: value, children: children, disabled: disabled = !1, className: className = "", style: style}) => {
13591
- const context = React.useContext(SelectContext), label = "string" == typeof children ? children : value;
13592
- // We assume children is the label if it's a string, or we need a way to get label.
13593
- // For simplicity, we use children as label for registration if it's a string.
13594
- if (React.useEffect((() => {
13740
+ const SelectContext = React.createContext(null), SelectOption = React.memo((({value: value, label: label, children: children, disabled: disabled = !1, className: className = "", style: style}) => {
13741
+ const context = React.useContext(SelectContext), displayLabel = label || ("string" == typeof children ? children : value);
13742
+ if (React.useEffect((() => {
13595
13743
  if (context) return context.registerOption({
13596
13744
  value: value,
13597
- label: label,
13745
+ label: displayLabel,
13598
13746
  disabled: disabled
13599
13747
  }), () => {
13600
13748
  context.unregisterOption(value);
13601
13749
  };
13602
- }), [ context, value, label, disabled ]), !context) return console.warn("SelectOption must be used within a Select component"),
13750
+ }), [ context, value, displayLabel, disabled ]), !context) return console.warn("SelectOption must be used within a Select component"),
13603
13751
  null;
13604
- const {selectedValue: selectedValue, onSelect: onSelect} = context, isSelected = Array.isArray(selectedValue) ? _includesInstanceProperty(selectedValue).call(selectedValue, value) : selectedValue === value;
13752
+ const {selectedValue: selectedValue, onSelect: onSelect, focusedValue: focusedValue, id: id} = context, isSelected = Array.isArray(selectedValue) ? _includesInstanceProperty(selectedValue).call(selectedValue, value) : selectedValue === value, isFocused = focusedValue === value;
13605
13753
  return jsxRuntime.jsx("li", {
13606
- className: `${SELECT.CLASSES.SELECT_ITEM} ${className}`.trim(),
13754
+ id: id ? `${id}-opt-${value}` : void 0,
13755
+ className: `${SELECT.CLASSES.SELECT_ITEM} ${isFocused ? "is-focused" : ""} ${isSelected ? "is-selected" : ""} ${className}`.trim(),
13607
13756
  "data-value": value,
13608
13757
  onClick: e => {
13609
- e.preventDefault(), e.stopPropagation(), disabled || onSelect(value, label);
13758
+ e.preventDefault(), e.stopPropagation(), disabled || onSelect(value, displayLabel);
13610
13759
  },
13611
13760
  style: style,
13612
13761
  role: "option",
@@ -13626,7 +13775,7 @@ const SelectContext = React.createContext(null), SelectOption = React.memo((({
13626
13775
  tabIndex: -1
13627
13776
  }), jsxRuntime.jsx("div", {
13628
13777
  className: "c-select__item-label",
13629
- children: children
13778
+ children: children || displayLabel
13630
13779
  }) ]
13631
13780
  })
13632
13781
  });
@@ -13649,18 +13798,18 @@ const SelectComponentBase = ({options: options, value: value, onChange: onChange
13649
13798
  disabled: disabled,
13650
13799
  invalid: invalid,
13651
13800
  valid: valid
13652
- }), [isOpen, setIsOpen] = React.useState(!1), [selectedLabel, setSelectedLabel] = React.useState(placeholder), dropdownRef = React.useRef(null), panelRef = React.useRef(null), bodyRef = React.useRef(null), nativeSelectRef = React.useRef(null), [registeredOptions, setRegisteredOptions] = React.useState([]), registerOption = React.useCallback((option => {
13801
+ }), [isOpen, setIsOpen] = React.useState(!1), [focusedIndex, setFocusedIndex] = React.useState(-1), dropdownRef = React.useRef(null), panelRef = React.useRef(null), bodyRef = React.useRef(null), nativeSelectRef = React.useRef(null), [registeredOptions, setRegisteredOptions] = React.useState([]), registerOption = React.useCallback((option => {
13653
13802
  setRegisteredOptions((prev => prev.some((o => o.value === option.value)) ? prev : [ ...prev, option ]));
13654
13803
  }), []), unregisterOption = React.useCallback((value => {
13655
13804
  setRegisteredOptions((prev => prev.filter((o => o.value !== value))));
13656
- }), []), hasOptionsProp = options && options.length > 0, activeOptions = hasOptionsProp ? options : registeredOptions;
13657
- // Update selected label when value changes
13658
- React.useEffect((() => {
13659
- if (value) {
13805
+ }), []), hasOptionsProp = options && options.length > 0, activeOptions = hasOptionsProp ? options : registeredOptions, selectedLabel = React.useMemo((() => {
13806
+ if (multiple && Array.isArray(value)) return 0 === value.length ? placeholder : activeOptions.filter((opt => _includesInstanceProperty(value).call(value, opt.value))).map((opt => opt.label)).join(", ");
13807
+ if (value && "string" == typeof value) {
13660
13808
  const selectedOption = activeOptions.find((opt => opt.value === value));
13661
- selectedOption && setSelectedLabel(selectedOption.label);
13662
- } else setSelectedLabel(placeholder);
13663
- }), [ value, activeOptions, placeholder ]),
13809
+ return selectedOption ? selectedOption.label : placeholder;
13810
+ }
13811
+ return placeholder;
13812
+ }), [ value, activeOptions, placeholder, multiple ]);
13664
13813
  // Handle click outside to close dropdown
13665
13814
  React.useEffect((() => {
13666
13815
  const handleClickOutside = event => {
@@ -13673,31 +13822,54 @@ const SelectComponentBase = ({options: options, value: value, onChange: onChange
13673
13822
  }), []);
13674
13823
  // Toggle dropdown
13675
13824
  const handleToggle = () => {
13676
- disabled || (!isOpen && bodyRef.current && panelRef.current ? bodyRef.current.style.height = `${panelRef.current.clientHeight}px` : bodyRef.current && (bodyRef.current.style.height = "0px"),
13677
- setIsOpen(!isOpen));
13678
- }, handleItemClick = React.useCallback((option => {
13679
- if (setSelectedLabel(option.label), setIsOpen(!1), bodyRef.current && (bodyRef.current.style.height = "0px"),
13680
- nativeSelectRef.current && (nativeSelectRef.current.value = option.value), onChange) {
13681
- // Create a synthetic event
13682
- const event = {
13683
- target: {
13684
- name: name,
13685
- value: option.value
13686
- }
13687
- };
13688
- onChange(event);
13825
+ if (!disabled) {
13826
+ const nextOpen = !isOpen;
13827
+ if (nextOpen && bodyRef.current && panelRef.current)
13828
+ // Set focused index to current selection or first item
13829
+ if (bodyRef.current.style.height = `${panelRef.current.clientHeight}px`, value && !multiple && "string" == typeof value) {
13830
+ const index = activeOptions.findIndex((opt => opt.value === value));
13831
+ setFocusedIndex(index >= 0 ? index : 0);
13832
+ } else if (multiple && Array.isArray(value) && value.length > 0) {
13833
+ const index = activeOptions.findIndex((opt => _includesInstanceProperty(value).call(value, opt.value)));
13834
+ setFocusedIndex(index >= 0 ? index : 0);
13835
+ } else setFocusedIndex(0); else bodyRef.current && (bodyRef.current.style.height = "0px",
13836
+ setFocusedIndex(-1));
13837
+ setIsOpen(nextOpen);
13689
13838
  }
13690
- }), [ onChange, name ]), onSelect = React.useCallback(((val, label) => {
13839
+ }, handleItemClick = React.useCallback((option => {
13840
+ let newValue;
13841
+ if (multiple) {
13842
+ const currentValues = Array.isArray(value) ? value : value ? [ value ] : [];
13843
+ newValue = _includesInstanceProperty(currentValues).call(currentValues, option.value) ? currentValues.filter((v => v !== option.value)) : [ ...currentValues, option.value ];
13844
+ } else newValue = option.value, setIsOpen(!1), bodyRef.current && (bodyRef.current.style.height = "0px");
13845
+ onChange && (
13846
+ // Sync native select before firing onChange
13847
+ nativeSelectRef.current && (multiple && Array.isArray(newValue) ? Array.from(nativeSelectRef.current.options).forEach((opt => {
13848
+ opt.selected = _includesInstanceProperty(newValue).call(newValue, opt.value);
13849
+ })) : "string" == typeof newValue && (nativeSelectRef.current.value = newValue)),
13850
+ onChange({
13851
+ target: {
13852
+ name: name,
13853
+ value: newValue
13854
+ }
13855
+ }));
13856
+ }), [ onChange, name, multiple, value ]), onSelect = React.useCallback(((val, label) => {
13691
13857
  handleItemClick({
13692
13858
  value: val,
13693
13859
  label: label
13694
13860
  });
13695
- }), [ handleItemClick ]), contextValue = React__default.default.useMemo((() => ({
13861
+ }), [ handleItemClick ]), focusedValue = React.useMemo((() => {
13862
+ if (focusedIndex >= 0 && focusedIndex < activeOptions.length) return activeOptions[focusedIndex]?.value;
13863
+ }), [ focusedIndex, activeOptions ]), focusedOptionId = React.useMemo((() => {
13864
+ if (isOpen && focusedValue) return `${id || "select"}-opt-${focusedValue}`;
13865
+ }), [ isOpen, focusedValue, id ]), contextValue = React__default.default.useMemo((() => ({
13696
13866
  registerOption: registerOption,
13697
13867
  unregisterOption: unregisterOption,
13698
13868
  selectedValue: value,
13699
- onSelect: onSelect
13700
- })), [ registerOption, unregisterOption, value, onSelect ]), selectContent = jsxRuntime.jsx(SelectContext.Provider, {
13869
+ onSelect: onSelect,
13870
+ focusedValue: focusedValue,
13871
+ id: id || "select"
13872
+ })), [ registerOption, unregisterOption, value, onSelect, focusedValue, id ]), selectContent = jsxRuntime.jsx(SelectContext.Provider, {
13701
13873
  value: contextValue,
13702
13874
  children: jsxRuntime.jsxs("div", {
13703
13875
  className: `${selectClass} ${isOpen ? SELECT.CLASSES.IS_OPEN : ""}`,
@@ -13745,7 +13917,12 @@ const SelectComponentBase = ({options: options, value: value, onChange: onChange
13745
13917
  if (!disabled) switch (event.key) {
13746
13918
  case "Enter":
13747
13919
  case " ":
13748
- event.preventDefault(), handleToggle();
13920
+ if (event.preventDefault(), isOpen) {
13921
+ if (focusedIndex >= 0 && focusedIndex < activeOptions.length) {
13922
+ const option = activeOptions[focusedIndex];
13923
+ option && !option.disabled && handleItemClick(option);
13924
+ }
13925
+ } else handleToggle();
13749
13926
  break;
13750
13927
 
13751
13928
  case "Escape":
@@ -13753,8 +13930,23 @@ const SelectComponentBase = ({options: options, value: value, onChange: onChange
13753
13930
  break;
13754
13931
 
13755
13932
  case "ArrowDown":
13933
+ event.preventDefault(), isOpen ? setFocusedIndex((prev => prev < activeOptions.length - 1 ? prev + 1 : prev)) : handleToggle();
13934
+ break;
13935
+
13756
13936
  case "ArrowUp":
13757
- isOpen || (event.preventDefault(), handleToggle());
13937
+ event.preventDefault(), isOpen ? setFocusedIndex((prev => prev > 0 ? prev - 1 : 0)) : handleToggle();
13938
+ break;
13939
+
13940
+ case "Home":
13941
+ isOpen && (event.preventDefault(), setFocusedIndex(0));
13942
+ break;
13943
+
13944
+ case "End":
13945
+ isOpen && (event.preventDefault(), setFocusedIndex(activeOptions.length - 1));
13946
+ break;
13947
+
13948
+ case "Tab":
13949
+ isOpen && (setIsOpen(!1), bodyRef.current && (bodyRef.current.style.height = "0px"));
13758
13950
  }
13759
13951
  },
13760
13952
  "aria-disabled": disabled,
@@ -13763,7 +13955,11 @@ const SelectComponentBase = ({options: options, value: value, onChange: onChange
13763
13955
  "aria-haspopup": "listbox",
13764
13956
  "aria-expanded": isOpen,
13765
13957
  "aria-controls": id ? `${id}-listbox` : void 0,
13766
- children: selectedLabel
13958
+ "aria-activedescendant": focusedOptionId,
13959
+ children: jsxRuntime.jsx("div", {
13960
+ className: "c-select__selected-text",
13961
+ children: selectedLabel
13962
+ })
13767
13963
  }), jsxRuntime.jsx("i", {
13768
13964
  className: `${SELECT.CLASSES.ICON_CARET} ${SELECT.CLASSES.TOGGLE_ICON}`
13769
13965
  }), jsxRuntime.jsx("div", {
@@ -13781,11 +13977,13 @@ const SelectComponentBase = ({options: options, value: value, onChange: onChange
13781
13977
  id: id ? `${id}-listbox` : void 0,
13782
13978
  "aria-labelledby": id,
13783
13979
  children: hasOptionsProp ? options.map(((option, index) => jsxRuntime.jsx("li", {
13784
- className: SELECT.CLASSES.SELECT_ITEM,
13980
+ id: `${id || "select"}-opt-${option.value}`,
13981
+ className: `${SELECT.CLASSES.SELECT_ITEM} ${focusedIndex === index ? "is-focused" : ""} ${multiple && Array.isArray(value) && _includesInstanceProperty(value).call(value, option.value) || value === option.value ? "is-selected" : ""}`,
13785
13982
  "data-value": option.value,
13786
13983
  onClick: () => !option.disabled && handleItemClick(option),
13984
+ onMouseEnter: () => setFocusedIndex(index),
13787
13985
  role: "option",
13788
- "aria-selected": value === option.value,
13986
+ "aria-selected": multiple && Array.isArray(value) && _includesInstanceProperty(value).call(value, option.value) || value === option.value,
13789
13987
  "aria-disabled": option.disabled,
13790
13988
  children: jsxRuntime.jsxs("label", {
13791
13989
  htmlFor: `SelectItem${index}`,
@@ -13794,7 +13992,7 @@ const SelectComponentBase = ({options: options, value: value, onChange: onChange
13794
13992
  type: "checkbox",
13795
13993
  id: `SelectItem${index}`,
13796
13994
  className: "c-checkbox__input c-select__item-input",
13797
- checked: value === option.value,
13995
+ checked: multiple && Array.isArray(value) && _includesInstanceProperty(value).call(value, option.value) || value === option.value,
13798
13996
  readOnly: !0,
13799
13997
  disabled: option.disabled
13800
13998
  }), jsxRuntime.jsx("div", {
@@ -13813,10 +14011,7 @@ const SelectComponentBase = ({options: options, value: value, onChange: onChange
13813
14011
  // Default glass settings for select components
13814
14012
  const defaultGlassProps = {
13815
14013
  displacementScale: 60,
13816
- blurAmount: 1,
13817
- saturation: 180,
13818
- aberrationIntensity: .2,
13819
- borderRadius: 12,
14014
+ blurAmount: 10,
13820
14015
  mode: "shader"
13821
14016
  }, glassProps = !0 === glass ? defaultGlassProps : {
13822
14017
  ...defaultGlassProps,
@@ -22040,7 +22235,7 @@ class ThemeLogger {
22040
22235
  document.body && document.body.setAttribute(dataAttribute, themeName),
22041
22236
  // Also set on documentElement for broader compatibility
22042
22237
  document.documentElement.setAttribute(dataAttribute, themeName));
22043
- }, isValidThemeName = themeName => !(!themeName || "string" != typeof themeName) && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(themeName), createLocalStorageAdapter = () => ({
22238
+ }, getSystemTheme = () => isServer() ? "light" : window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light", isValidThemeName = themeName => !(!themeName || "string" != typeof themeName) && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(themeName), createLocalStorageAdapter = () => ({
22044
22239
  getItem: key => {
22045
22240
  if (isServer()) return null;
22046
22241
  try {
@@ -22081,6 +22276,7 @@ class ThemeLogger {
22081
22276
  applyThemeAttributes: applyThemeAttributes,
22082
22277
  buildThemePath: buildThemePath,
22083
22278
  createLocalStorageAdapter: createLocalStorageAdapter,
22279
+ getSystemTheme: getSystemTheme,
22084
22280
  isBrowser: isBrowser,
22085
22281
  isServer: isServer,
22086
22282
  isValidThemeName: isValidThemeName,
@@ -22185,14 +22381,6 @@ class ThemeLogger {
22185
22381
  return "undefined" == typeof window ? "light" : localStorage.getItem(storageKey) || "light";
22186
22382
  }
22187
22383
 
22188
- /**
22189
- * Get system theme preference
22190
- *
22191
- * @returns 'dark' if system prefers dark mode, 'light' otherwise
22192
- */ function getSystemTheme() {
22193
- return "undefined" == typeof window ? "light" : window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
22194
- }
22195
-
22196
22384
  /**
22197
22385
  * Initialize theme based on saved preference or system preference
22198
22386
  *