@shohojdhara/atomix 0.6.4 → 0.6.6

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 (83) hide show
  1. package/dist/atomix.css +117 -38
  2. package/dist/atomix.css.map +1 -1
  3. package/dist/atomix.min.css +1 -1
  4. package/dist/atomix.min.css.map +1 -1
  5. package/dist/atomix.umd.js +1 -1
  6. package/dist/atomix.umd.js.map +1 -1
  7. package/dist/atomix.umd.min.js +1 -1
  8. package/dist/charts.d.ts +30 -1
  9. package/dist/charts.js +625 -846
  10. package/dist/charts.js.map +1 -1
  11. package/dist/core.d.ts +30 -1
  12. package/dist/core.js +659 -873
  13. package/dist/core.js.map +1 -1
  14. package/dist/forms.d.ts +30 -1
  15. package/dist/forms.js +1171 -1402
  16. package/dist/forms.js.map +1 -1
  17. package/dist/heavy.d.ts +31 -89
  18. package/dist/heavy.js +975 -1195
  19. package/dist/heavy.js.map +1 -1
  20. package/dist/index.d.ts +383 -140
  21. package/dist/index.esm.js +1567 -1679
  22. package/dist/index.esm.js.map +1 -1
  23. package/dist/index.js +1556 -1667
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.min.js +1 -1
  26. package/dist/index.min.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/components/Accordion/Accordion.tsx +2 -5
  29. package/src/components/AtomixGlass/AtomixGlass.test.tsx +14 -16
  30. package/src/components/AtomixGlass/AtomixGlass.tsx +137 -364
  31. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +32 -251
  32. package/src/components/AtomixGlass/GlassFilter.tsx +62 -68
  33. package/src/components/AtomixGlass/README.md +2 -1
  34. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +19 -18
  35. package/src/components/AtomixGlass/glass-border-styles.test.ts +58 -0
  36. package/src/components/AtomixGlass/glass-border-styles.ts +136 -0
  37. package/src/components/AtomixGlass/glass-utils.ts +456 -22
  38. package/src/components/AtomixGlass/shader-utils.ts +19 -77
  39. package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +158 -537
  40. package/src/components/AtomixGlass/stories/Border.stories.tsx +149 -0
  41. package/src/components/AtomixGlass/stories/Examples.stories.tsx +229 -89
  42. package/src/components/AtomixGlass/stories/Playground.stories.tsx +29 -340
  43. package/src/components/AtomixGlass/stories/argTypes.ts +30 -13
  44. package/src/components/AtomixGlass/stories/premium-presets.ts +206 -0
  45. package/src/components/AtomixGlass/stories/shared-components.tsx +52 -8
  46. package/src/components/Badge/Badge.tsx +4 -4
  47. package/src/components/Button/Button.tsx +2 -6
  48. package/src/components/Callout/Callout.test.tsx +4 -3
  49. package/src/components/Callout/Callout.tsx +2 -5
  50. package/src/components/Dropdown/Dropdown.tsx +3 -7
  51. package/src/components/Form/Checkbox.tsx +2 -8
  52. package/src/components/Form/Input.tsx +2 -9
  53. package/src/components/Form/Radio.tsx +2 -9
  54. package/src/components/Form/Select.test.tsx +6 -6
  55. package/src/components/Form/Select.tsx +2 -7
  56. package/src/components/Form/Textarea.stories.tsx +5 -5
  57. package/src/components/Form/Textarea.tsx +2 -9
  58. package/src/components/Messages/Messages.tsx +2 -8
  59. package/src/components/Modal/Modal.tsx +4 -5
  60. package/src/components/Navigation/Nav/Nav.tsx +2 -6
  61. package/src/components/Navigation/Navbar/Navbar.tsx +2 -9
  62. package/src/components/Navigation/SideMenu/SideMenu.tsx +2 -6
  63. package/src/components/Pagination/Pagination.tsx +2 -10
  64. package/src/components/Popover/Popover.tsx +2 -9
  65. package/src/components/Progress/Progress.tsx +2 -7
  66. package/src/components/Rating/Rating.tsx +2 -10
  67. package/src/components/Spinner/Spinner.tsx +2 -7
  68. package/src/components/Steps/Steps.tsx +2 -10
  69. package/src/components/Tabs/Tabs.tsx +2 -9
  70. package/src/components/Toggle/Toggle.tsx +2 -10
  71. package/src/components/Tooltip/Tooltip.tsx +2 -5
  72. package/src/lib/composables/useAtomixGlass.ts +42 -143
  73. package/src/lib/composables/useAtomixGlassStyles.ts +61 -77
  74. package/src/lib/composables/usePerformanceMonitor.ts +5 -66
  75. package/src/lib/constants/components.ts +363 -46
  76. package/src/lib/types/components.ts +33 -1
  77. package/src/styles/01-settings/_settings.atomix-glass.scss +66 -28
  78. package/src/styles/02-tools/_tools.button.scss +51 -42
  79. package/src/styles/02-tools/_tools.glass.scss +45 -3
  80. package/src/styles/06-components/_components.atomix-glass.scss +116 -79
  81. package/src/components/AtomixGlass/PerformanceDashboard.tsx +0 -171
  82. package/src/components/AtomixGlass/animation-system.ts +0 -578
  83. package/src/components/AtomixGlass/deprecated/AtomixGlass.deprecated.tsx +0 -390
package/dist/index.esm.js CHANGED
@@ -1687,6 +1687,268 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
1687
1687
  NEWSLETTER_BUTTON_TEXT: "Subscribe",
1688
1688
  BACK_TO_TOP_TEXT: "Back to Top"
1689
1689
  }
1690
+ }, GLASS_DEFAULTS = {
1691
+ /**
1692
+ * Button — compact interactive element.
1693
+ * Low displacement + no blur override so the backdrop token handles frosting.
1694
+ * Zero elasticity: the button itself handles press/hover feedback.
1695
+ */
1696
+ BUTTON: {
1697
+ displacementScale: 16,
1698
+ saturation: 180,
1699
+ elasticity: 0
1700
+ },
1701
+ /**
1702
+ * Badge — pill-shaped tag. Tiny surface, minimal distortion.
1703
+ * borderRadius is set dynamically at runtime; this serves as a safe fallback.
1704
+ */
1705
+ BADGE: {
1706
+ displacementScale: 14,
1707
+ borderRadius: 16,
1708
+ elasticity: 0
1709
+ },
1710
+ /**
1711
+ * Accordion — block-level content container.
1712
+ * Gentle displacement; zero elasticity so open/close animation isn't jittery.
1713
+ */
1714
+ ACCORDION: {
1715
+ displacementScale: 18,
1716
+ elasticity: 0
1717
+ },
1718
+ /**
1719
+ * Callout — notification / alert banner.
1720
+ * Slightly more frosted than Accordion to give it visual priority.
1721
+ */
1722
+ CALLOUT: {
1723
+ displacementScale: 22,
1724
+ borderRadius: 8,
1725
+ elasticity: 0
1726
+ },
1727
+ /**
1728
+ * Dropdown — floating menu. Small surface, should feel light and airy.
1729
+ * No blur override — rely on the backdrop token.
1730
+ */
1731
+ DROPDOWN: {
1732
+ displacementScale: 16,
1733
+ elasticity: 0
1734
+ },
1735
+ /**
1736
+ * EdgePanel — full-height side drawer.
1737
+ * Empty config: the panel inherits all ATOMIX_GLASS.DEFAULTS.
1738
+ * borderRadius and size are managed by the panel's own SCSS.
1739
+ */
1740
+ EDGE_PANEL: {},
1741
+ /**
1742
+ * Modal — full-screen overlay dialog. Shader mode for premium refraction.
1743
+ * displacementScale omitted — set dynamically from modal content height at runtime.
1744
+ * elasticity: 0 — modals should not wobble when the user interacts with them.
1745
+ */
1746
+ MODAL: {
1747
+ blurAmount: 28,
1748
+ elasticity: 0,
1749
+ mode: "shader",
1750
+ shaderMode: "premiumGlass"
1751
+ },
1752
+ /**
1753
+ * Navbar — sticky / fixed navigation bar spanning full width.
1754
+ * Shader gives the top edge a polished lens look.
1755
+ * borderRadius: 0 — navbars run edge-to-edge.
1756
+ * elasticity: 0 — no wobble on a fixed chrome element.
1757
+ */
1758
+ NAVBAR: {
1759
+ displacementScale: 24,
1760
+ blurAmount: 24,
1761
+ borderRadius: 0,
1762
+ elasticity: 0,
1763
+ mode: "shader",
1764
+ shaderVariant: "premiumGlass"
1765
+ },
1766
+ /**
1767
+ * Nav (inline nav list) — narrower than a full Navbar, standard mode is
1768
+ * enough. Rounded corners to match typical pill / tab nav designs.
1769
+ */
1770
+ NAV: {
1771
+ displacementScale: 24,
1772
+ blurAmount: 20,
1773
+ borderRadius: 8,
1774
+ elasticity: 0,
1775
+ mode: "shader"
1776
+ },
1777
+ /**
1778
+ * SideMenu — persistent sidebar navigation.
1779
+ * Moderate displacement; shader for depth. Zero elasticity.
1780
+ */
1781
+ SIDE_MENU: {
1782
+ displacementScale: 24,
1783
+ blurAmount: 24,
1784
+ borderRadius: 0,
1785
+ elasticity: 0,
1786
+ mode: "shader"
1787
+ },
1788
+ /**
1789
+ * Popover — small floating card above content.
1790
+ * Shader mode + aberration for the characteristic lens fringe.
1791
+ * Low displacement so the content remains readable.
1792
+ */
1793
+ POPOVER: {
1794
+ displacementScale: 22,
1795
+ blurAmount: 20,
1796
+ saturation: 180,
1797
+ aberrationIntensity: .35,
1798
+ borderRadius: 12,
1799
+ elasticity: 0,
1800
+ mode: "shader"
1801
+ },
1802
+ /**
1803
+ * Tooltip — tiny single-line label.
1804
+ * Higher displacement than other small elements because tooltips float
1805
+ * freely and the distortion reads as depth. No shader (too small to matter).
1806
+ */
1807
+ TOOLTIP: {
1808
+ displacementScale: 18,
1809
+ blurAmount: 16,
1810
+ elasticity: 0
1811
+ },
1812
+ /**
1813
+ * Tabs — tabbed content panel. Shader for the nav strip refraction.
1814
+ */
1815
+ TABS: {
1816
+ displacementScale: 24,
1817
+ blurAmount: 20,
1818
+ saturation: 180,
1819
+ aberrationIntensity: .35,
1820
+ borderRadius: 12,
1821
+ elasticity: 0,
1822
+ mode: "shader"
1823
+ },
1824
+ /**
1825
+ * Toggle — switch control. Compact, pill shape.
1826
+ * Relies on borderRadius from the component's own SCSS.
1827
+ */
1828
+ TOGGLE: {
1829
+ displacementScale: 16,
1830
+ elasticity: 0
1831
+ },
1832
+ /**
1833
+ * Form inputs (Input, Textarea, Select, Checkbox, Radio).
1834
+ * Unified glass feel for all form controls — subtle displacement,
1835
+ * rounded corners matching the $input-border-radius token (≈ 6px).
1836
+ */
1837
+ INPUT: {
1838
+ displacementScale: 18,
1839
+ borderRadius: 6,
1840
+ elasticity: 0
1841
+ },
1842
+ TEXTAREA: {
1843
+ displacementScale: 18,
1844
+ borderRadius: 6,
1845
+ elasticity: 0
1846
+ },
1847
+ SELECT: {
1848
+ displacementScale: 18,
1849
+ borderRadius: 6,
1850
+ elasticity: 0
1851
+ },
1852
+ CHECKBOX: {
1853
+ displacementScale: 14,
1854
+ borderRadius: 4,
1855
+ elasticity: 0
1856
+ },
1857
+ RADIO: {
1858
+ displacementScale: 14,
1859
+ borderRadius: 99,
1860
+ elasticity: 0
1861
+ },
1862
+ /**
1863
+ * Pagination — row of page buttons.
1864
+ * Thin, horizontal strip; low displacement so numbers stay legible.
1865
+ */
1866
+ PAGINATION: {
1867
+ displacementScale: 18,
1868
+ borderRadius: 8,
1869
+ elasticity: 0
1870
+ },
1871
+ /**
1872
+ * Progress — horizontal bar track.
1873
+ * Very low displacement — the bar should not distort.
1874
+ */
1875
+ PROGRESS: {
1876
+ displacementScale: 10,
1877
+ borderRadius: 99,
1878
+ elasticity: 0
1879
+ },
1880
+ /**
1881
+ * Rating — star picker.
1882
+ * Compact inline element; minimal glass, no shader needed.
1883
+ */
1884
+ RATING: {
1885
+ displacementScale: 16,
1886
+ elasticity: 0
1887
+ },
1888
+ /**
1889
+ * Spinner — loading indicator.
1890
+ * Barely-there glass; the spinner itself provides visual interest.
1891
+ */
1892
+ SPINNER: {
1893
+ displacementScale: 12,
1894
+ elasticity: 0
1895
+ },
1896
+ /**
1897
+ * Steps — horizontal / vertical stepper.
1898
+ * Moderate displacement so the connector lines remain crisp.
1899
+ */
1900
+ STEPS: {
1901
+ displacementScale: 22,
1902
+ borderRadius: 8,
1903
+ elasticity: 0
1904
+ },
1905
+ /**
1906
+ * Messages / chat bubbles.
1907
+ * Rounded pill-like bubbles; gentle glass to aid readability.
1908
+ */
1909
+ MESSAGES: {
1910
+ displacementScale: 20,
1911
+ borderRadius: 16,
1912
+ elasticity: 0
1913
+ }
1914
+ }, GLASS_BORDER_GRADIENT = {
1915
+ BASE_ANGLE: 135,
1916
+ ANGLE_MULTIPLIER: .5,
1917
+ VELOCITY_ANGLE_MULTIPLIER: .5,
1918
+ CHROMATIC_OFFSET: 1.5,
1919
+ STOP_1: {
1920
+ MIN: 10,
1921
+ BASE: 33,
1922
+ get MULTIPLIER() {
1923
+ return .009 * this.BASE;
1924
+ }
1925
+ },
1926
+ STOP_2: {
1927
+ MAX: 90,
1928
+ BASE: 66,
1929
+ get MULTIPLIER() {
1930
+ return .006 * this.BASE;
1931
+ }
1932
+ },
1933
+ OPACITY: {
1934
+ /** Matches $glass-border-1-opacity (0.08) */
1935
+ BASE_1: .08,
1936
+ get BASE_2() {
1937
+ return 3.33 * this.BASE_1;
1938
+ },
1939
+ get BASE_3() {
1940
+ return 2.66 * this.BASE_1;
1941
+ },
1942
+ get BASE_4() {
1943
+ return 5 * this.BASE_1;
1944
+ },
1945
+ get MULTIPLIER_LOW() {
1946
+ return .066 * this.BASE_1;
1947
+ },
1948
+ get MULTIPLIER_HIGH() {
1949
+ return .1 * this.BASE_1;
1950
+ }
1951
+ }
1690
1952
  }, ATOMIX_GLASS = {
1691
1953
  BASE_CLASS: "c-atomix-glass",
1692
1954
  CONTAINER_CLASS: "c-atomix-glass__container",
@@ -1698,6 +1960,22 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
1698
1960
  BORDER_BACKDROP_CLASS: "c-atomix-glass__border-backdrop",
1699
1961
  BORDER_1_CLASS: "c-atomix-glass__border-1",
1700
1962
  BORDER_2_CLASS: "c-atomix-glass__border-2",
1963
+ /** Centralized liquid glass rim configuration */
1964
+ BORDER: {
1965
+ WIDTH_CSS_VAR: "--atomix-glass-border-width",
1966
+ DEFAULT_WIDTH: "0.5px",
1967
+ GRADIENT_CSS_VARS: {
1968
+ GRADIENT_1: "--atomix-glass-border-gradient-1",
1969
+ GRADIENT_2: "--atomix-glass-border-gradient-2"
1970
+ },
1971
+ GRADIENT: GLASS_BORDER_GRADIENT,
1972
+ OVER_LIGHT: {
1973
+ opacity: .7
1974
+ },
1975
+ DARK: {
1976
+ opacity: .35
1977
+ }
1978
+ },
1701
1979
  HOVER_1_CLASS: "c-atomix-glass__hover-1",
1702
1980
  HOVER_2_CLASS: "c-atomix-glass__hover-2",
1703
1981
  HOVER_3_CLASS: "c-atomix-glass__hover-3",
@@ -1726,25 +2004,22 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
1726
2004
  SHADER: "c-atomix-glass--shader"
1727
2005
  },
1728
2006
  DEFAULTS: {
1729
- DISPLACEMENT_SCALE: 70,
2007
+ /** Subtle refraction — Apple UI chrome avoids heavy liquid distortion */
2008
+ DISPLACEMENT_SCALE: 28,
1730
2009
  get BLUR_AMOUNT() {
1731
- return .15 * this.DISPLACEMENT_SCALE;
1732
- // Dynamically computed based on displacement
1733
- },
1734
- get SATURATION() {
1735
- return 100 + .5 * this.DISPLACEMENT_SCALE;
1736
- // Saturate relative to intensity
1737
- },
2010
+ // Apple Music sidebar / player bar: ~20–40px frost (see $glass-backdrop-filter)
2011
+ return Math.max(20, .72 * this.DISPLACEMENT_SCALE);
2012
+ },
2013
+ /** Fixed 180% matches Apple's saturate(180%) backdrop recipe */
2014
+ SATURATION: 180,
1738
2015
  get ABERRATION_INTENSITY() {
1739
- return .03 * this.DISPLACEMENT_SCALE;
1740
- // Scale aberration with displacement
1741
- },
1742
- ELASTICITY: .15,
2016
+ return .02 * this.DISPLACEMENT_SCALE;
2017
+ },
2018
+ ELASTICITY: .05,
1743
2019
  get CORNER_RADIUS() {
1744
2020
  return 16;
1745
2021
  // Use 16 to match SCSS design system (was 20)
1746
2022
  },
1747
- PADDING: "0",
1748
2023
  MODE: "standard",
1749
2024
  OVER_LIGHT: !1,
1750
2025
  ENABLE_OVER_LIGHT_LAYERS: !0,
@@ -1760,19 +2035,29 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
1760
2035
  },
1761
2036
  CONSTANTS: {
1762
2037
  ACTIVATION_ZONE: 200,
1763
- LERP_FACTOR: .08,
2038
+ LERP_FACTOR: .05,
2039
+ // Lower = more viscous, liquid-smooth tracking (Apple feel)
1764
2040
  SMOOTHSTEP_POWER: 2.5,
1765
2041
  MIN_BLUR: .1,
1766
2042
  MOUSE_INFLUENCE_DIVISOR: 100,
1767
2043
  EDGE_FADE_PIXELS: 2,
1768
- // Elasticity physics constants
1769
- ELASTICITY_TRANSLATION_FACTOR: .1,
2044
+ // Interaction intensity multipliers shared by the hook and the imperative style updater
2045
+ INTERACTION: {
2046
+ HOVER_INTENSITY: 1.4,
2047
+ ACTIVE_INTENSITY: 1.6
2048
+ },
2049
+ // Elasticity physics constants — Apple-tuned: soft springs, fast settling, minimal stretch
2050
+ ELASTICITY_TRANSLATION_FACTOR: .06,
2051
+ // Subtler elastic shift (was 0.1)
1770
2052
  ELASTICITY_DISTANCE_THRESHOLD: 200,
1771
2053
  ELASTICITY_COMPRESSION_FACTOR: .3,
1772
- ELASTICITY_STIFFNESS: .1,
1773
- ELASTICITY_DAMPING: .76,
2054
+ ELASTICITY_STIFFNESS: .06,
2055
+ // Softer springs = gentler motion (was 0.1)
2056
+ ELASTICITY_DAMPING: .88,
2057
+ // Fast settling, no wobble (was 0.76)
1774
2058
  ELASTICITY_VELOCITY_FACTOR: .65,
1775
- ELASTICITY_STRETCH_RATIO: .45,
2059
+ ELASTICITY_STRETCH_RATIO: .25,
2060
+ // Less visible surface tension stretch (was 0.45)
1776
2061
  ELASTICITY_MAGNIFICATION_BASE: 1.02,
1777
2062
  // Note: This default must match the SCSS variable --atomix-radius-md
1778
2063
  // @see src/styles/01-settings/_settings.global.scss
@@ -1786,55 +2071,16 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
1786
2071
  },
1787
2072
  // Gradient calculation constants
1788
2073
  GRADIENT: {
1789
- BASE_ANGLE: 135,
1790
- // Base angle for border gradients (degrees)
1791
- ANGLE_MULTIPLIER: 1.2,
1792
- // Multiplier for mouse influence on angle
1793
- VELOCITY_ANGLE_MULTIPLIER: 2.5,
1794
- // How much velocity affects gradient rotation
1795
- CHROMATIC_OFFSET: 1.5,
1796
- // Degree offset for chromatic rim layers
1797
- BORDER_STOP_1: {
1798
- MIN: 10,
1799
- // Minimum percentage for border stop 1
1800
- BASE: 33,
1801
- // Base percentage for border stop 1
1802
- get MULTIPLIER() {
1803
- return .009 * this.BASE;
1804
- }
1805
- },
1806
- BORDER_STOP_2: {
1807
- MAX: 90,
1808
- // Maximum percentage for border stop 2
1809
- BASE: 66,
1810
- // Base percentage for border stop 2
1811
- get MULTIPLIER() {
1812
- return .006 * this.BASE;
1813
- }
1814
- },
1815
- BORDER_OPACITY: {
1816
- BASE_1: .12,
1817
- // Base opacity for border gradient 1
1818
- get BASE_2() {
1819
- return 3.33 * this.BASE_1;
1820
- },
1821
- // Base opacity for border gradient 2
1822
- get BASE_3() {
1823
- return 2.66 * this.BASE_1;
1824
- },
1825
- // Base opacity for border gradient 3
1826
- get BASE_4() {
1827
- return 5 * this.BASE_1;
1828
- },
1829
- // Base opacity for border gradient 4
1830
- get MULTIPLIER_LOW() {
1831
- return .066 * this.BASE_1;
1832
- },
1833
- // Low multiplier for mouse influence on opacity
1834
- get MULTIPLIER_HIGH() {
1835
- return .1 * this.BASE_1;
1836
- }
1837
- },
2074
+ BASE_ANGLE: GLASS_BORDER_GRADIENT.BASE_ANGLE,
2075
+ ANGLE_MULTIPLIER: GLASS_BORDER_GRADIENT.ANGLE_MULTIPLIER,
2076
+ VELOCITY_ANGLE_MULTIPLIER: GLASS_BORDER_GRADIENT.VELOCITY_ANGLE_MULTIPLIER,
2077
+ CHROMATIC_OFFSET: GLASS_BORDER_GRADIENT.CHROMATIC_OFFSET,
2078
+ /** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.STOP_1 */
2079
+ BORDER_STOP_1: GLASS_BORDER_GRADIENT.STOP_1,
2080
+ /** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.STOP_2 */
2081
+ BORDER_STOP_2: GLASS_BORDER_GRADIENT.STOP_2,
2082
+ /** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.OPACITY */
2083
+ BORDER_OPACITY: GLASS_BORDER_GRADIENT.OPACITY,
1838
2084
  CENTER_POSITION: 50,
1839
2085
  // Center position percentage (50%)
1840
2086
  HOVER_POSITION: {
@@ -1867,8 +2113,8 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
1867
2113
  return 2 * this.BLACK_STOP;
1868
2114
  },
1869
2115
  // End percentage for black hover 1
1870
- WHITE_START: .5,
1871
- // Start opacity for white hover 1
2116
+ WHITE_START: .35,
2117
+ // Gentler hover flash Apple hover is barely visible
1872
2118
  get WHITE_STOP() {
1873
2119
  return this.BLACK_END - 10;
1874
2120
  }
@@ -1886,8 +2132,8 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
1886
2132
  return 2 * this.BLACK_STOP;
1887
2133
  },
1888
2134
  // End percentage for black hover 2
1889
- WHITE_START: 1,
1890
- // Start opacity for white hover 2
2135
+ WHITE_START: .7,
2136
+ // Gentler hover flash
1891
2137
  get WHITE_STOP() {
1892
2138
  return this.BLACK_END;
1893
2139
  }
@@ -1905,8 +2151,8 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
1905
2151
  return 2 * this.BLACK_STOP;
1906
2152
  },
1907
2153
  // End percentage for black hover 3
1908
- WHITE_START: 1,
1909
- // Start opacity for white hover 3
2154
+ WHITE_START: .7,
2155
+ // Gentler hover flash
1910
2156
  get WHITE_STOP() {
1911
2157
  return this.BLACK_END;
1912
2158
  }
@@ -1916,13 +2162,13 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
1916
2162
  BASE_GRADIENT: {
1917
2163
  ANGLE: 135,
1918
2164
  // Gradient angle in degrees
1919
- BLACK_START_BASE: .15,
2165
+ BLACK_START_BASE: .1,
1920
2166
  // Base start opacity for black
1921
2167
  get BLACK_START_MULTIPLIER() {
1922
2168
  return .02 * this.BLACK_START_BASE;
1923
2169
  },
1924
2170
  // Multiplier for mouse X influence on start
1925
- BLACK_MID_BASE: .1,
2171
+ BLACK_MID_BASE: .07,
1926
2172
  // Base mid opacity for black
1927
2173
  get BLACK_MID_MULTIPLIER() {
1928
2174
  return .02 * this.BLACK_MID_BASE;
@@ -1943,7 +2189,7 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
1943
2189
  }
1944
2190
  },
1945
2191
  OVERLAY_GRADIENT: {
1946
- BLACK_START_BASE: .12,
2192
+ BLACK_START_BASE: .08,
1947
2193
  // Base start opacity for black overlay
1948
2194
  get BLACK_START_MULTIPLIER() {
1949
2195
  return .025 * this.BLACK_START_BASE;
@@ -1967,14 +2213,14 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
1967
2213
  return .416 * this.BLACK_START_BASE;
1968
2214
  }
1969
2215
  },
1970
- // Overlay highlight constants
2216
+ // Overlay highlight constants — Apple places specular at the top-center
1971
2217
  OVERLAY_HIGHLIGHT: {
1972
- POSITION_X: 20,
1973
- // X position percentage
1974
- POSITION_Y: 20,
1975
- // Y position percentage
1976
- WHITE_OPACITY: .4,
1977
- // White opacity in gradient
2218
+ POSITION_X: 50,
2219
+ // Centered horizontal — Apple's top-center specular
2220
+ POSITION_Y: 5,
2221
+ // Very top — catches light like a curved glass surface
2222
+ WHITE_OPACITY: .28,
2223
+ // Softer specular visible but not glaring
1978
2224
  get STOP() {
1979
2225
  return 150 * this.WHITE_OPACITY;
1980
2226
  },
@@ -1995,6 +2241,10 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
1995
2241
  SATURATION: {
1996
2242
  HIGH_CONTRAST: 200
1997
2243
  },
2244
+ // Container shadows — hairline inner catch + soft floating lift (Apple player bar)
2245
+ CONTAINER_SHADOW: {
2246
+ LIGHT: "inset 0 0.5px 0 rgba(255, 255, 255, 0.32), inset 0 1px 2px rgba(255, 255, 255, 0.06), 0 4px 16px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.08)"
2247
+ },
1998
2248
  // Phase 1: Animation System Constants
1999
2249
  ANIMATION: {
2000
2250
  // Breathing effect timing (in milliseconds)
@@ -2091,135 +2341,488 @@ function useAccordion(initialProps) {
2091
2341
  };
2092
2342
  }
2093
2343
 
2094
- const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect => rect ? {
2095
- x: rect.left + rect.width / 2,
2096
- y: rect.top + rect.height / 2
2097
- } : {
2098
- x: 0,
2099
- y: 0
2100
- }, calculateMouseInfluence = mouseOffset => {
2101
- if (!mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y) return 0;
2102
- // Bounded calculation — keeps the glass effect subtle and stable
2103
- const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$2.MOUSE_INFLUENCE_DIVISOR;
2104
- return Math.min(.8, influence);
2105
- // Tighter cap to prevent blur/filter blow-out
2106
- }, clampBlur = value => "number" != typeof value || isNaN(value) ? CONSTANTS$2.MIN_BLUR : Math.max(CONSTANTS$2.MIN_BLUR, Math.min(50, value)), validateGlassSize = size => size && "number" == typeof size.width && "number" == typeof size.height && size.width > 0 && size.height > 0 && size.width <= CONSTANTS$2.MAX_SIZE && size.height <= CONSTANTS$2.MAX_SIZE, parseBorderRadiusValue = value => {
2107
- if ("number" == typeof value) return Math.max(0, value);
2108
- if ("string" != typeof value || !value.trim()) return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
2109
- const trimmedValue = value.trim();
2110
- // Handle px values
2111
- if (trimmedValue.endsWith("px")) {
2112
- const parsed = parseFloat(trimmedValue);
2113
- return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, parsed);
2114
- }
2115
- // Handle rem values (assume 16px = 1rem)
2116
- if (trimmedValue.endsWith("rem")) {
2117
- const parsed = parseFloat(trimmedValue);
2118
- return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
2119
- }
2120
- // Handle em values (assume 16px = 1em for simplicity)
2121
- if (trimmedValue.endsWith("em")) {
2122
- const parsed = parseFloat(trimmedValue);
2123
- return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
2124
- }
2125
- // Handle percentage (convert to approximate px value, assuming 200px container)
2126
- if (trimmedValue.endsWith("%")) {
2127
- const parsed = parseFloat(trimmedValue);
2128
- return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, parsed / 100 * 200);
2129
- }
2130
- // Handle unitless numbers
2131
- const numValue = parseFloat(trimmedValue);
2132
- return isNaN(numValue) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, numValue);
2133
- }, extractBorderRadiusFromElement = element => {
2134
- if (!element || !element.props) return null;
2135
- // Check inline styles first (highest priority)
2136
- if (element.props.style) {
2137
- const radiusFromStyle = (style => {
2138
- if (!style) return null;
2139
- // Check various border-radius properties
2140
- const borderRadius = style.borderRadius || style.borderTopLeftRadius || style.borderTopRightRadius || style.borderBottomLeftRadius || style.borderBottomRightRadius;
2141
- return void 0 !== borderRadius ? parseBorderRadiusValue(borderRadius) : null;
2142
- })(element.props.style);
2143
- if (null !== radiusFromStyle && radiusFromStyle > 0) return radiusFromStyle;
2144
- }
2145
- // If element has children, recursively check them
2146
- if (element.props.children) {
2147
- const childRadius = extractBorderRadiusFromChildren(element.props.children);
2148
- if (childRadius > 0 && childRadius !== CONSTANTS$2.DEFAULT_CORNER_RADIUS) return childRadius;
2149
- }
2150
- return null;
2151
- }, extractBorderRadiusFromChildren = children => {
2152
- if (!children) return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
2153
- try {
2154
- const childArray = React.Children.toArray(children);
2155
- for (let i = 0; i < childArray.length; i++) {
2156
- const child = childArray[i];
2157
- if ( React.isValidElement(child)) {
2158
- const radius = extractBorderRadiusFromElement(child);
2159
- if (null !== radius) return radius;
2344
+ var aCallable = aCallable$3, toObject = toObject$2, IndexedObject = indexedObject, lengthOfArrayLike = lengthOfArrayLike$2, $TypeError = TypeError, REDUCE_EMPTY = "Reduce of empty array with no initial value", createMethod = function(IS_RIGHT) {
2345
+ return function(that, callbackfn, argumentsLength, memo) {
2346
+ var O = toObject(that), self = IndexedObject(O), length = lengthOfArrayLike(O);
2347
+ if (aCallable(callbackfn), 0 === length && argumentsLength < 2) throw new $TypeError(REDUCE_EMPTY);
2348
+ var index = IS_RIGHT ? length - 1 : 0, i = IS_RIGHT ? -1 : 1;
2349
+ if (argumentsLength < 2) for (;;) {
2350
+ if (index in self) {
2351
+ memo = self[index], index += i;
2352
+ break;
2160
2353
  }
2354
+ if (index += i, IS_RIGHT ? index < 0 : length <= index) throw new $TypeError(REDUCE_EMPTY);
2161
2355
  }
2162
- } catch (error) {
2163
- // Silently handle errors
2164
- }
2165
- return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
2166
- }, smoothstep = t => {
2167
- const clamped = Math.max(0, Math.min(1, t));
2168
- return clamped * clamped * (3 - 2 * clamped);
2169
- }, 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) => {
2170
- const newVelocity = (velocity + (target - current) * stiffness) * damping;
2171
- return {
2172
- value: current + newVelocity,
2173
- velocity: newVelocity
2356
+ for (;IS_RIGHT ? index >= 0 : length > index; index += i) index in self && (memo = callbackfn(memo, self[index], index, O));
2357
+ return memo;
2174
2358
  };
2175
- }, getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
2176
- switch (mode) {
2177
- case "standard":
2178
- return displacementMap;
2359
+ }, arrayReduce = {
2360
+ // `Array.prototype.reduce` method
2361
+ // https://tc39.es/ecma262/#sec-array.prototype.reduce
2362
+ left: createMethod(!1),
2363
+ // `Array.prototype.reduceRight` method
2364
+ // https://tc39.es/ecma262/#sec-array.prototype.reduceright
2365
+ right: createMethod(!0)
2366
+ }, fails = fails$9, globalThis$1 = globalThis_1, userAgent = environmentUserAgent, classof = classofRaw$2, userAgentStartsWith = function(string) {
2367
+ return userAgent.slice(0, string.length) === string;
2368
+ }, environment = userAgentStartsWith("Bun/") ? "BUN" : userAgentStartsWith("Cloudflare-Workers") ? "CLOUDFLARE" : userAgentStartsWith("Deno/") ? "DENO" : userAgentStartsWith("Node.js/") ? "NODE" : globalThis$1.Bun && "string" == typeof Bun.version ? "BUN" : globalThis$1.Deno && "object" == typeof Deno.version ? "DENO" : "process" === classof(globalThis$1.process) ? "NODE" : globalThis$1.window && globalThis$1.document ? "BROWSER" : "REST", $reduce = arrayReduce.left;
2179
2369
 
2180
- case "polar":
2181
- return polarDisplacementMap;
2370
+ // `Array.prototype.reduce` method
2371
+ // https://tc39.es/ecma262/#sec-array.prototype.reduce
2372
+ _export({
2373
+ target: "Array",
2374
+ proto: !0,
2375
+ forced: !("NODE" === environment) && environmentV8Version > 79 && environmentV8Version < 83 || !function(METHOD_NAME, argument) {
2376
+ var method = [][METHOD_NAME];
2377
+ return !!method && fails((function() {
2378
+ // eslint-disable-next-line no-useless-call -- required for testing
2379
+ method.call(null, argument || function() {
2380
+ return 1;
2381
+ }, 1);
2382
+ }));
2383
+ }("reduce")
2384
+ }, {
2385
+ reduce: function(callbackfn /* , initialValue */) {
2386
+ var length = arguments.length;
2387
+ return $reduce(this, callbackfn, length, length > 1 ? arguments[1] : void 0);
2388
+ }
2389
+ });
2182
2390
 
2183
- case "prominent":
2184
- return prominentDisplacementMap;
2391
+ var reduce$3 = getBuiltInPrototypeMethod$3("Array", "reduce"), isPrototypeOf = objectIsPrototypeOf, method = reduce$3, ArrayPrototype = Array.prototype;
2185
2392
 
2186
- case "shader":
2187
- return shaderMapUrl || displacementMap;
2393
+ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
2394
+ var own = it.reduce;
2395
+ return it === ArrayPrototype || isPrototypeOf(ArrayPrototype, it) && own === ArrayPrototype.reduce ? method : own;
2396
+ }));
2188
2397
 
2189
- default:
2190
- return console.warn("AtomixGlass: Invalid displacement mode"), displacementMap;
2191
- }
2192
- }, sharedShaderCache = new Map, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsx("svg", {
2193
- style: {
2194
- position: "absolute",
2195
- width: "100%",
2196
- height: "100%",
2197
- inset: 0
2198
- },
2199
- "aria-hidden": "true",
2200
- children: jsxs("defs", {
2201
- children: [ jsxs("radialGradient", {
2202
- id: `${id}-edge-mask`,
2203
- cx: "50%",
2204
- cy: "50%",
2205
- r: "50%",
2206
- children: [ jsx("stop", {
2207
- offset: "0%",
2208
- stopColor: "black",
2209
- stopOpacity: "0"
2210
- }), jsx("stop", {
2211
- offset: `${Math.max(30, 80 - 2 * aberrationIntensity)}%`,
2212
- stopColor: "black",
2213
- stopOpacity: "0"
2214
- }), jsx("stop", {
2215
- offset: "100%",
2216
- stopColor: "white",
2217
- stopOpacity: "1"
2218
- }) ]
2219
- }), jsxs("filter", {
2220
- id: id,
2221
- x: "-35%",
2222
- y: "-35%",
2398
+ /**
2399
+ * Map SCSS tokens to CSS custom properties
2400
+ *
2401
+ * @example
2402
+ * const tokens = { '$primary-color': '#7AFFD7', '$spacing-md': '16px' }
2403
+ * const vars = mapSCSSTokensToCSSVars(tokens)
2404
+ * // Returns: { '--primary-color': '#7AFFD7', '--spacing-md': '16px' }
2405
+ */ function mapSCSSTokensToCSSVars(tokens, options = {}) {
2406
+ const vars = {}, {prefix: prefix = "atomix", separator: separator = "-"} = options;
2407
+ return Object.entries(tokens).forEach((([key, value]) => {
2408
+ // Remove $ prefix from SCSS variables
2409
+ const normalizedKey = (key.startsWith("$") ? key.slice(1) : key).replace(/_/g, separator);
2410
+ // Convert underscores to separators
2411
+ vars[`--${prefix}${separator}${normalizedKey}`] = String(value);
2412
+ })), vars;
2413
+ }
2414
+
2415
+ /**
2416
+ * Apply CSS variables to an element
2417
+ *
2418
+ * @param vars - CSS variables to apply
2419
+ * @param element - Target element (defaults to document.documentElement)
2420
+ */ function applyCSSVariables(vars, element) {
2421
+ if ("undefined" == typeof window) return;
2422
+ // SSR safety
2423
+ const target = element || document.documentElement;
2424
+ Object.entries(vars).forEach((([key, value]) => {
2425
+ target.style.setProperty(key, String(value));
2426
+ }));
2427
+ }
2428
+
2429
+ /**
2430
+ * Remove CSS variables from an element
2431
+ *
2432
+ * @param varNames - Variable names to remove
2433
+ * @param element - Target element (defaults to document.documentElement)
2434
+ */ function removeCSSVariables(varNames, element) {
2435
+ if ("undefined" == typeof window) return;
2436
+ // SSR safety
2437
+ const target = element || document.documentElement;
2438
+ varNames.forEach((varName => {
2439
+ target.style.removeProperty(varName);
2440
+ }));
2441
+ }
2442
+
2443
+ /**
2444
+ * Get CSS variable value from an element
2445
+ *
2446
+ * @param varName - Variable name to get
2447
+ * @param element - Target element (defaults to document.documentElement)
2448
+ * @returns Variable value or null if not found
2449
+ */ function getCSSVariable(varName, element) {
2450
+ if ("undefined" == typeof window) return null;
2451
+ // SSR safety
2452
+ const target = element || document.documentElement;
2453
+ return getComputedStyle(target).getPropertyValue(varName).trim() || null;
2454
+ }
2455
+
2456
+ /**
2457
+ * Convert CSS variable object to inline style object
2458
+ *
2459
+ * @example
2460
+ * const vars = { '--atomix-button-bg': '#000' }
2461
+ * const style = cssVarsToStyle(vars)
2462
+ * // Returns: { '--atomix-button-bg': '#000' } as React.CSSProperties
2463
+ */ function cssVarsToStyle(vars) {
2464
+ var _context;
2465
+ return _reduceInstanceProperty(_context = Object.entries(vars)).call(_context, ((acc, [key, value]) => (acc[key] = "number" == typeof value ? `${value}px` : value,
2466
+ acc)), {});
2467
+ }
2468
+
2469
+ /**
2470
+ * Merge multiple CSS variable objects
2471
+ * Later objects override earlier ones
2472
+ */ function mergeCSSVars(...varObjects) {
2473
+ return _reduceInstanceProperty(varObjects).call(varObjects, ((acc, vars) => (vars && Object.assign(acc, vars),
2474
+ acc)), {});
2475
+ }
2476
+
2477
+ /**
2478
+ * Validate CSS variable name format
2479
+ */ function isValidCSSVariableName(name) {
2480
+ return /^--[a-z0-9-]+$/.test(name);
2481
+ }
2482
+
2483
+ /**
2484
+ * Extract component name from CSS variable name
2485
+ *
2486
+ * @example
2487
+ * extractComponentName('--atomix-button-bg')
2488
+ * // Returns: 'button'
2489
+ */ function extractComponentName(varName, prefix = "atomix") {
2490
+ const regex = new RegExp(`^--${prefix}-([a-z0-9]+)-`), match = varName.match(regex);
2491
+ return match ? match[1] ?? null : null;
2492
+ }
2493
+
2494
+ /**
2495
+ * Component Utilities
2496
+ *
2497
+ * Helper functions for component development with the new customization system
2498
+ */
2499
+ /**
2500
+ * Merge multiple class names
2501
+ */ function mergeClassNames(...classes) {
2502
+ return classes.filter(Boolean).join(" ");
2503
+ }
2504
+
2505
+ /**
2506
+ * Apply part styles to element props
2507
+ */ function applyPartStyles(baseProps, partStyles) {
2508
+ return partStyles ? {
2509
+ ...baseProps,
2510
+ className: mergeClassNames(baseProps.className, partStyles.className),
2511
+ style: {
2512
+ ...baseProps.style,
2513
+ ...partStyles.style
2514
+ }
2515
+ } : baseProps;
2516
+ }
2517
+
2518
+ /**
2519
+ * Create style object from CSS variables
2520
+ */ function createCSSVarStyle(cssVars, baseStyle) {
2521
+ return cssVars ? {
2522
+ ...cssVarsToStyle(cssVars),
2523
+ ...baseStyle
2524
+ } : baseStyle || {};
2525
+ }
2526
+
2527
+ function mergeComponentProps(baseProps, customization) {
2528
+ const {className: className, style: style, cssVars: cssVars, parts: parts} = customization, cssVarStyle = cssVars ? cssVarsToStyle(cssVars) : {};
2529
+ // Merge CSS variables into style
2530
+ return {
2531
+ ...baseProps,
2532
+ className: mergeClassNames(baseProps.className, className),
2533
+ style: {
2534
+ ...cssVarStyle,
2535
+ ...baseProps.style,
2536
+ ...style
2537
+ }
2538
+ };
2539
+ }
2540
+
2541
+ /**
2542
+ * Get part styles from parts object
2543
+ */ function getPartStyles(parts, partName) {
2544
+ return parts?.[partName];
2545
+ }
2546
+
2547
+ /**
2548
+ * Create element props with part styles
2549
+ */ function createPartProps(baseClassName, partStyles, additionalProps) {
2550
+ return {
2551
+ ...additionalProps,
2552
+ className: mergeClassNames(baseClassName, partStyles?.className),
2553
+ style: {
2554
+ ...partStyles?.style,
2555
+ ...additionalProps?.style
2556
+ }
2557
+ };
2558
+ }
2559
+
2560
+ /**
2561
+ * Check if component has customization
2562
+ */ function hasCustomization(props) {
2563
+ return Boolean(props.parts || props.cssVars || props.slots);
2564
+ }
2565
+
2566
+ /**
2567
+ * Create data attributes for debugging
2568
+ */ function createDebugAttrs(componentName, variant) {
2569
+ return "undefined" == typeof process || "development" !== process.env?.NODE_ENV ? {} : {
2570
+ "data-component": componentName,
2571
+ ...variant && {
2572
+ "data-variant": variant
2573
+ }
2574
+ };
2575
+ }
2576
+
2577
+ /**
2578
+ * Generate a UUID v4
2579
+ */ function generateUUID() {
2580
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c => {
2581
+ const r = 16 * Math.random() | 0;
2582
+ return ("x" === c ? r : 3 & r | 8).toString(16);
2583
+ }));
2584
+ }
2585
+
2586
+ /**
2587
+ * Check if a URL is a YouTube URL
2588
+ */ function isYouTubeUrl(url) {
2589
+ return /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+/.test(url);
2590
+ }
2591
+
2592
+ /**
2593
+ * Extract YouTube video ID from URL
2594
+ */ function extractYouTubeId(url) {
2595
+ if (!isYouTubeUrl(url)) return null;
2596
+ const patterns = [ /(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([^&\n?#]+)/, /youtube\.com\/.*[?&]v=([^&\n?#]+)/ ];
2597
+ for (const pattern of patterns) {
2598
+ const match = url.match(pattern);
2599
+ if (match && match[1]) return match[1];
2600
+ }
2601
+ return null;
2602
+ }
2603
+
2604
+ /**
2605
+ * Utility to merge multiple React refs into one
2606
+ */ function setRef(ref, value) {
2607
+ "function" == typeof ref ? ref(value) : ref && (
2608
+ // This is safe because we're checking that ref exists first
2609
+ ref.current = value);
2610
+ }
2611
+
2612
+ /**
2613
+ * Combines two React refs into a single ref function
2614
+ * This is used when you need to use and forward a ref at the same time
2615
+ */ function useForkRef(refA, refB) {
2616
+ return React.useMemo((() => null == refA && null == refB ? null : refValue => {
2617
+ setRef(refA, refValue), setRef(refB, refValue);
2618
+ }), [ refA, refB ]);
2619
+ }
2620
+
2621
+ const {CONSTANTS: CONSTANTS$3} = ATOMIX_GLASS, calculateElementCenter = rect => rect ? {
2622
+ x: rect.left + rect.width / 2,
2623
+ y: rect.top + rect.height / 2
2624
+ } : {
2625
+ x: 0,
2626
+ y: 0
2627
+ }, calculateMouseInfluence = mouseOffset => {
2628
+ if (!mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y) return 0;
2629
+ // Clamp influence to keep mouse response subtle and stable.
2630
+ const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$3.MOUSE_INFLUENCE_DIVISOR;
2631
+ return Math.min(.8, influence);
2632
+ // Tighter cap to prevent blur/filter blow-out
2633
+ }, clampBlur = value => "number" != typeof value || isNaN(value) ? CONSTANTS$3.MIN_BLUR : Math.max(CONSTANTS$3.MIN_BLUR, Math.min(50, value)), validateGlassSize = size => size && "number" == typeof size.width && "number" == typeof size.height && size.width > 0 && size.height > 0 && size.width <= CONSTANTS$3.MAX_SIZE && size.height <= CONSTANTS$3.MAX_SIZE, parseBorderRadiusValue = value => {
2634
+ if ("number" == typeof value) return Math.max(0, value);
2635
+ if ("string" != typeof value || !value.trim()) return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
2636
+ const trimmedValue = value.trim();
2637
+ // Handle px values
2638
+ if (trimmedValue.endsWith("px")) {
2639
+ const parsed = parseFloat(trimmedValue);
2640
+ return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, parsed);
2641
+ }
2642
+ // Handle rem values (assume 16px = 1rem)
2643
+ if (trimmedValue.endsWith("rem")) {
2644
+ const parsed = parseFloat(trimmedValue);
2645
+ return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
2646
+ }
2647
+ // Handle em values (assume 16px = 1em for simplicity)
2648
+ if (trimmedValue.endsWith("em")) {
2649
+ const parsed = parseFloat(trimmedValue);
2650
+ return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
2651
+ }
2652
+ // Handle percentage (convert to approximate px value, assuming 200px container)
2653
+ if (trimmedValue.endsWith("%")) {
2654
+ const parsed = parseFloat(trimmedValue);
2655
+ return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, parsed / 100 * 200);
2656
+ }
2657
+ // Handle unitless numbers
2658
+ const numValue = parseFloat(trimmedValue);
2659
+ return isNaN(numValue) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, numValue);
2660
+ }, extractBorderRadiusFromElement = element => {
2661
+ if (!element || !element.props) return null;
2662
+ // Check inline styles first (highest priority)
2663
+ if (element.props.style) {
2664
+ const radiusFromStyle = (style => {
2665
+ if (!style) return null;
2666
+ // Check various border-radius properties
2667
+ const borderRadius = style.borderRadius || style.borderTopLeftRadius || style.borderTopRightRadius || style.borderBottomLeftRadius || style.borderBottomRightRadius;
2668
+ return void 0 !== borderRadius ? parseBorderRadiusValue(borderRadius) : null;
2669
+ })(element.props.style);
2670
+ if (null !== radiusFromStyle && radiusFromStyle > 0) return radiusFromStyle;
2671
+ }
2672
+ // If element has children, recursively check them
2673
+ if (element.props.children) {
2674
+ const childRadius = extractBorderRadiusFromChildren(element.props.children);
2675
+ if (childRadius > 0 && childRadius !== CONSTANTS$3.DEFAULT_CORNER_RADIUS) return childRadius;
2676
+ }
2677
+ return null;
2678
+ }, extractBorderRadiusFromChildren = children => {
2679
+ if (!children) return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
2680
+ try {
2681
+ const childArray = React.Children.toArray(children);
2682
+ for (let i = 0; i < childArray.length; i++) {
2683
+ const child = childArray[i];
2684
+ if ( React.isValidElement(child)) {
2685
+ const radius = extractBorderRadiusFromElement(child);
2686
+ if (null !== radius) return radius;
2687
+ }
2688
+ }
2689
+ } catch (error) {
2690
+ // Silently handle errors
2691
+ }
2692
+ return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
2693
+ }, smoothstep = t => {
2694
+ const clamped = Math.max(0, Math.min(1, t));
2695
+ return clamped * clamped * (3 - 2 * clamped);
2696
+ }, lerp = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), clamp = (value, min, max) => "number" != typeof value || isNaN(value) ? min : Math.max(min, Math.min(max, value)), smoothstepEdge = (edge0, edge1, x) => "number" != typeof edge0 || "number" != typeof edge1 || "number" != typeof x ? 0 : smoothstep((x - edge0) / (edge1 - edge0)), easeInOutCubic = t => {
2697
+ if ("number" != typeof t || isNaN(t)) return 0;
2698
+ const clamped = Math.max(0, Math.min(1, t));
2699
+ return clamped < .5 ? 4 * clamped * clamped * clamped : 1 - Math.pow(-2 * clamped + 2, 3) / 2;
2700
+ }, easeOutQuart = t => {
2701
+ if ("number" != typeof t || isNaN(t)) return 0;
2702
+ const clamped = Math.max(0, Math.min(1, t));
2703
+ return 1 - Math.pow(1 - clamped, 4);
2704
+ }, vec2Length = (x, y) => {
2705
+ if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
2706
+ const maxComponent = Math.max(Math.abs(x), Math.abs(y));
2707
+ if (0 === maxComponent) return 0;
2708
+ const scaledX = x / maxComponent, scaledY = y / maxComponent;
2709
+ return maxComponent * Math.sqrt(scaledX * scaledX + scaledY * scaledY);
2710
+ }, getInteractionIntensity = (isHovered, isActive) => ({
2711
+ hoverIntensity: isHovered ? CONSTANTS$3.INTERACTION.HOVER_INTENSITY : 1,
2712
+ activeIntensity: isActive ? CONSTANTS$3.INTERACTION.ACTIVE_INTENSITY : 1
2713
+ })
2714
+ /**
2715
+ * Spring-damper integration helper
2716
+ * Calculates the next value based on velocity, stiffness, and damping.
2717
+ */ , calculateSpring = (current, target, velocity, stiffness = .1, damping = .8) => {
2718
+ const newVelocity = (velocity + (target - current) * stiffness) * damping;
2719
+ return {
2720
+ value: current + newVelocity,
2721
+ velocity: newVelocity
2722
+ };
2723
+ };
2724
+
2725
+ /**
2726
+ * Calculate element center from bounding rect
2727
+ */
2728
+ /**
2729
+ * Normalizes a layout inset for use in CSS custom properties.
2730
+ *
2731
+ * @param value - Raw inset from `style` (number, px string, or `auto`).
2732
+ * @param fallback - Value used when `value` is undefined.
2733
+ */
2734
+ function formatGlassInsetValue(value, fallback = "auto") {
2735
+ return void 0 === value ? "number" == typeof fallback ? `${fallback}px` : String(fallback) : "auto" === value ? "auto" : "number" == typeof value ? `${value}px` : value;
2736
+ }
2737
+
2738
+ /**
2739
+ * Determines whether the glass should use fixed/sticky layout semantics.
2740
+ *
2741
+ * @param explicit - Value of the `isFixedOrSticky` prop.
2742
+ * @param position - `position` from the consumer `style` object.
2743
+ */
2744
+ /** Coerces a value to a finite number, returning `fallback` when invalid. */
2745
+ function toSafeNumber(value, fallback = 0) {
2746
+ return "number" != typeof value || isNaN(value) ? fallback : value;
2747
+ }
2748
+
2749
+ /**
2750
+ * Calculates the target frame rate for shader time-animation loops.
2751
+ *
2752
+ * Balances visual quality against distortion complexity and `animationSpeed`.
2753
+ */
2754
+ /**
2755
+ * Computes per-channel displacement scale for the SVG chromatic-aberration filter.
2756
+ */
2757
+ function getChromaticDisplacementScale(mode, displacementScale, aberrationIntensity, channelFactor) {
2758
+ return displacementScale * (("shader" === mode ? 1 : -1) - aberrationIntensity * channelFactor);
2759
+ }
2760
+
2761
+ /**
2762
+ * Get displacement map URL based on mode
2763
+ */ const getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
2764
+ switch (mode) {
2765
+ case "standard":
2766
+ return displacementMap;
2767
+
2768
+ case "polar":
2769
+ return polarDisplacementMap;
2770
+
2771
+ case "prominent":
2772
+ return prominentDisplacementMap;
2773
+
2774
+ case "shader":
2775
+ return shaderMapUrl || displacementMap;
2776
+
2777
+ default:
2778
+ return console.warn("AtomixGlass: Invalid displacement mode"), displacementMap;
2779
+ }
2780
+ }, sharedShaderCache = new Map, CHROMATIC_CHANNELS = [ {
2781
+ result: "RED_DISPLACED",
2782
+ channelResult: "RED_CHANNEL",
2783
+ aberrationFactor: 0,
2784
+ colorMatrix: "1 0 0 0 0\n0 0 0 0 0\n0 0 0 0 0\n0 0 0 1 0"
2785
+ }, {
2786
+ result: "GREEN_DISPLACED",
2787
+ channelResult: "GREEN_CHANNEL",
2788
+ aberrationFactor: .02,
2789
+ colorMatrix: "0 0 0 0 0\n0 1 0 0 0\n0 0 0 0 0\n0 0 0 1 0"
2790
+ }, {
2791
+ result: "BLUE_DISPLACED",
2792
+ channelResult: "BLUE_CHANNEL",
2793
+ aberrationFactor: .03,
2794
+ colorMatrix: "0 0 0 0 0\n0 0 0 0 0\n0 0 1 0 0\n0 0 0 1 0"
2795
+ } ], FILTER_SVG_STYLE = {
2796
+ position: "absolute",
2797
+ width: "100%",
2798
+ height: "100%",
2799
+ inset: 0
2800
+ }, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsx("svg", {
2801
+ style: FILTER_SVG_STYLE,
2802
+ "aria-hidden": "true",
2803
+ children: jsxs("defs", {
2804
+ children: [ jsxs("radialGradient", {
2805
+ id: `${id}-edge-mask`,
2806
+ cx: "50%",
2807
+ cy: "50%",
2808
+ r: "50%",
2809
+ children: [ jsx("stop", {
2810
+ offset: "0%",
2811
+ stopColor: "black",
2812
+ stopOpacity: "0"
2813
+ }), jsx("stop", {
2814
+ offset: `${Math.max(30, 80 - 2 * aberrationIntensity)}%`,
2815
+ stopColor: "black",
2816
+ stopOpacity: "0"
2817
+ }), jsx("stop", {
2818
+ offset: "100%",
2819
+ stopColor: "white",
2820
+ stopOpacity: "1"
2821
+ }) ]
2822
+ }), jsxs("filter", {
2823
+ id: id,
2824
+ x: "-35%",
2825
+ y: "-35%",
2223
2826
  width: "170%",
2224
2827
  height: "170%",
2225
2828
  colorInterpolationFilters: "sRGB",
@@ -2249,43 +2852,21 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect =>
2249
2852
  dx: "0",
2250
2853
  dy: "0",
2251
2854
  result: "CENTER_ORIGINAL"
2252
- }), jsx("feDisplacementMap", {
2253
- in: "SourceGraphic",
2254
- in2: "DISPLACEMENT_MAP",
2255
- scale: displacementScale * ("shader" === mode ? 1 : -1),
2256
- xChannelSelector: "R",
2257
- yChannelSelector: "B",
2258
- result: "RED_DISPLACED"
2259
- }), jsx("feColorMatrix", {
2260
- in: "RED_DISPLACED",
2261
- type: "matrix",
2262
- values: "1 0 0 0 0\n 0 0 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0",
2263
- result: "RED_CHANNEL"
2264
- }), jsx("feDisplacementMap", {
2265
- in: "SourceGraphic",
2266
- in2: "DISPLACEMENT_MAP",
2267
- scale: displacementScale * (("shader" === mode ? 1 : -1) - .02 * aberrationIntensity),
2268
- xChannelSelector: "R",
2269
- yChannelSelector: "B",
2270
- result: "GREEN_DISPLACED"
2271
- }), jsx("feColorMatrix", {
2272
- in: "GREEN_DISPLACED",
2273
- type: "matrix",
2274
- values: "0 0 0 0 0\n 0 1 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0",
2275
- result: "GREEN_CHANNEL"
2276
- }), jsx("feDisplacementMap", {
2277
- in: "SourceGraphic",
2278
- in2: "DISPLACEMENT_MAP",
2279
- scale: displacementScale * (("shader" === mode ? 1 : -1) - .03 * aberrationIntensity),
2280
- xChannelSelector: "R",
2281
- yChannelSelector: "B",
2282
- result: "BLUE_DISPLACED"
2283
- }), jsx("feColorMatrix", {
2284
- in: "BLUE_DISPLACED",
2285
- type: "matrix",
2286
- values: "0 0 0 0 0\n 0 0 0 0 0\n 0 0 1 0 0\n 0 0 0 1 0",
2287
- result: "BLUE_CHANNEL"
2288
- }), jsx("feBlend", {
2855
+ }), CHROMATIC_CHANNELS.map((channel => jsxs(React.Fragment, {
2856
+ children: [ jsx("feDisplacementMap", {
2857
+ in: "SourceGraphic",
2858
+ in2: "DISPLACEMENT_MAP",
2859
+ scale: getChromaticDisplacementScale(mode, displacementScale, aberrationIntensity, channel.aberrationFactor),
2860
+ xChannelSelector: "R",
2861
+ yChannelSelector: "B",
2862
+ result: channel.result
2863
+ }), jsx("feColorMatrix", {
2864
+ in: channel.result,
2865
+ type: "matrix",
2866
+ values: channel.colorMatrix,
2867
+ result: channel.channelResult
2868
+ }) ]
2869
+ }, channel.channelResult))), jsx("feBlend", {
2289
2870
  in: "GREEN_CHANNEL",
2290
2871
  in2: "BLUE_CHANNEL",
2291
2872
  mode: "screen",
@@ -2326,21 +2907,22 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect =>
2326
2907
  });
2327
2908
 
2328
2909
  /**
2329
- * Calculate distance between two points
2910
+ * Module-level LRU cache for shader displacement maps.
2911
+ *
2912
+ * Shared across all `AtomixGlassContainer` instances so identical size and
2913
+ * variant combinations are generated once.
2330
2914
  */ GlassFilterComponent.displayName = "GlassFilter";
2331
2915
 
2332
- // Memoize component to prevent unnecessary re-renders
2916
+ /** Shallow prop comparison to avoid redundant SVG filter regeneration. */
2333
2917
  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 = {
2334
2918
  x: 0,
2335
2919
  y: 0
2336
- }, 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 = {
2920
+ }, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0, glassSize: glassSize = {
2337
2921
  width: 0,
2338
2922
  height: 0
2339
- }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, isFixedOrSticky: isFixedOrSticky = !1,
2340
- // Phase 1: Animation System props
2341
- 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) => {
2923
+ }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, isFixedOrSticky: isFixedOrSticky = !1, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", contentRef: contentRef}, ref) => {
2342
2924
  // React 18 useId — stable, unique, and SSR-safe (no module-level counter)
2343
- 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);
2925
+ const rawId = useId(), filterId = useMemo((() => `atomix-glass-filter-${rawId.replace(/:/g, "")}`), [ rawId ]), containerRef = useForkRef(ref, null), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null), shaderUpdateTimeoutRef = useRef(null), animationFrameRef = useRef(null);
2344
2926
  // Lazy load shader utilities only when shader mode is needed
2345
2927
  useEffect((() => {
2346
2928
  "shader" === mode ?
@@ -2418,15 +3000,23 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
2418
3000
  shaderGeneratorRef.current = null;
2419
3001
  }
2420
3002
  };
2421
- }), [ mode, glassSize, shaderVariant ]),
2422
- // Phase 1: Time-Based Animation Loop - Continuous shader regeneration
2423
- useEffect((() => {
3003
+ }), [ mode, glassSize, shaderVariant ]), useEffect((() => {
2424
3004
  // Only run animations in shader mode with time animation enabled
2425
3005
  if ("shader" !== mode || !withTimeAnimation || effectiveReducedMotion || effectiveWithoutEffects)
2426
3006
  // Cancel any existing animation frame
2427
3007
  return void (null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
2428
3008
  animationFrameRef.current = null));
2429
- const baseFps = "ultra" === distortionQuality ? 60 : "high" === distortionQuality ? 30 : "medium" === distortionQuality ? 24 : 20, effectiveSpeed = Math.max(.5, Math.min(2, animationSpeed || 1)), complexity = withMultiLayerDistortion ? Math.max(1, (distortionOctaves || 3) / 3 + .25 * Math.max(0, (distortionLacunarity || 2) - 2) + Math.max(0, (distortionGain || .5) - .5)) : 1, frameInterval = 1e3 / Math.max(12, Math.min(60, Math.round(baseFps * effectiveSpeed / complexity)));
3009
+ const targetFps = function(options) {
3010
+ const {distortionQuality: distortionQuality, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5} = options, baseFps = "ultra" === distortionQuality ? 60 : "high" === distortionQuality ? 30 : "medium" === distortionQuality ? 24 : 20, effectiveSpeed = Math.max(.5, Math.min(2, animationSpeed)), complexity = withMultiLayerDistortion ? Math.max(1, distortionOctaves / 3 + .25 * Math.max(0, distortionLacunarity - 2) + Math.max(0, distortionGain - .5)) : 1;
3011
+ return Math.max(12, Math.min(60, Math.round(baseFps * effectiveSpeed / complexity)));
3012
+ }({
3013
+ distortionQuality: distortionQuality,
3014
+ animationSpeed: animationSpeed,
3015
+ withMultiLayerDistortion: withMultiLayerDistortion,
3016
+ distortionOctaves: distortionOctaves,
3017
+ distortionLacunarity: distortionLacunarity,
3018
+ distortionGain: distortionGain
3019
+ }), frameInterval = 1e3 / targetFps;
2430
3020
  let lastUpdate = 0, isCancelled = !1;
2431
3021
  const animate = currentTime => {
2432
3022
  if (!isCancelled) {
@@ -2450,88 +3040,21 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
2450
3040
  };
2451
3041
  }), [ mode, withTimeAnimation, animationSpeed, displacementScale, withMultiLayerDistortion, distortionOctaves, distortionLacunarity, distortionGain, distortionQuality, effectiveReducedMotion, effectiveWithoutEffects, glassSize ]);
2452
3042
  // Removed forced reflow to avoid layout thrash and potential feedback sizing loops
2453
- const [rectCache, setRectCache] = useState(null);
2454
- useEffect((() => {
2455
- if (!ref || "function" == typeof ref) return;
2456
- const element = ref.current;
2457
- if (element) try {
2458
- setRectCache(element.getBoundingClientRect());
2459
- } catch (error) {
2460
- console.warn("AtomixGlassContainer: Error getting element bounds", error), setRectCache(null);
2461
- }
2462
- }), [ ref, glassSize ]);
2463
- const liquidBlur = useMemo((() => {
2464
- const defaultBlur = {
2465
- baseBlur: blurAmount,
2466
- edgeBlur: 1.25 * blurAmount,
2467
- centerBlur: 1.1 * blurAmount,
2468
- flowBlur: 1.2 * blurAmount
2469
- };
2470
- // Enhanced validation for liquid blur
2471
- if (!withLiquidBlur || !rectCache || !mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y || isNaN(mouseOffset.x) || isNaN(mouseOffset.y)) return defaultBlur;
2472
- try {
2473
- const mouseInfluence = calculateMouseInfluence(mouseOffset), maxBlur = 2 * blurAmount, baseBlur = Math.min(maxBlur, blurAmount + mouseInfluence * blurAmount * .15), edgeIntensity = .15 * mouseInfluence, edgeBlur = Math.min(maxBlur, baseBlur * (.8 + .4 * edgeIntensity)), centerIntensity = .1 * mouseInfluence, centerBlur = Math.min(maxBlur, baseBlur * (.3 + .3 * centerIntensity)), flowBlur = Math.min(maxBlur, 1.2 * baseBlur);
2474
- // NOTE: hover/active multipliers intentionally omitted here —
2475
- // they belong on opacity layers, not the blur filter itself.
2476
- return {
2477
- baseBlur: clampBlur(baseBlur),
2478
- edgeBlur: clampBlur(edgeBlur),
2479
- centerBlur: clampBlur(centerBlur),
2480
- flowBlur: clampBlur(flowBlur)
2481
- };
2482
- } catch (error) {
2483
- return console.warn("AtomixGlassContainer: Error calculating liquid blur", error),
2484
- defaultBlur;
2485
- }
2486
- }), [ withLiquidBlur, blurAmount, mouseOffset, rectCache ]), backdropStyle = useMemo((() => {
2487
- try {
2488
- const dynamicSaturation = saturation + 20 * (liquidBlur.baseBlur || 0), validatedBaseBlur = "number" != typeof liquidBlur.baseBlur || isNaN(liquidBlur.baseBlur) ? 0 : liquidBlur.baseBlur, validatedEdgeBlur = "number" != typeof liquidBlur.edgeBlur || isNaN(liquidBlur.edgeBlur) ? 0 : liquidBlur.edgeBlur, validatedCenterBlur = "number" != typeof liquidBlur.centerBlur || isNaN(liquidBlur.centerBlur) ? 0 : liquidBlur.centerBlur, validatedFlowBlur = "number" != typeof liquidBlur.flowBlur || isNaN(liquidBlur.flowBlur) ? 0 : liquidBlur.flowBlur, area = rectCache ? rectCache.width * rectCache.height : 0;
2489
- // Validate blur values before using them
2490
- return !withLiquidBlur || effectiveReducedMotion || effectiveWithoutEffects || area > 18e4 ? {
2491
- backdropFilter: `blur(${clampBlur(Math.max(validatedBaseBlur, .8 * validatedEdgeBlur, 1.1 * validatedCenterBlur, .9 * validatedFlowBlur))}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig?.contrast || 1.05}) brightness(${overLightConfig?.brightness || 1.05})`
2492
- } : {
2493
- backdropFilter: `blur(${clampBlur(.4 * validatedBaseBlur + .25 * validatedEdgeBlur + .15 * validatedCenterBlur + .2 * validatedFlowBlur)}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig?.contrast || 1}) brightness(${overLightConfig?.brightness || 1})`
2494
- };
2495
- // Single-pass fallback: stronger radius to match perceived blur of multi-pass
2496
- } catch (error) {
2497
- return console.warn("AtomixGlassContainer: Error calculating backdrop style", error),
2498
- {
2499
- backdropFilter: `blur(${blurAmount}px) saturate(${saturation}%) contrast(1.05) brightness(1.05)`
2500
- };
2501
- }
2502
- }), [ liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion, effectiveWithoutEffects, withLiquidBlur, overLightConfig ]), containerVars = useMemo((() => {
3043
+ const containerVars = useMemo((() => {
2503
3044
  try {
2504
- // Safe extraction of mouse offset values
2505
- const mx = mouseOffset && "number" == typeof mouseOffset.x && !isNaN(mouseOffset.x) ? mouseOffset.x : 0, my = mouseOffset && "number" == typeof mouseOffset.y && !isNaN(mouseOffset.y) ? mouseOffset.y : 0;
2506
3045
  return {
2507
- "--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px`,
2508
- "--atomix-glass-container-backdrop": backdropStyle?.backdropFilter || "none",
2509
- "--atomix-glass-container-shadow": overLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${(.4 + .002 * mx) * (overLightConfig?.shadowIntensity || 1)})`, `inset 0 -1px 0 rgba(0, 0, 0, ${(.2 + .001 * Math.abs(my)) * (overLightConfig?.shadowIntensity || 1)})`, `inset 0 0 20px rgba(0, 0, 0, ${(.08 + .001 * Math.abs(mx + my)) * (overLightConfig?.shadowIntensity || 1)})`, `0 2px 12px rgba(0, 0, 0, ${(.12 + .002 * Math.abs(my)) * (overLightConfig?.shadowIntensity || 1)})` ].join(", ") : "0 0 20px rgba(0, 0, 0, 0.15) inset, 0 4px 8px rgba(0, 0, 0, 0.08) inset",
2510
- "--atomix-glass-container-shadow-opacity": effectiveWithoutEffects ? 0 : 1,
2511
- // Background and shadow values use design token-aligned RGB values
2512
- "--atomix-glass-container-bg": overLight ? `linear-gradient(${180 + .5 * mx}deg, rgba(255, 255, 255, 0.1) 0%, transparent 20%, transparent 80%, rgba(0, 0, 0, 0.05) 100%)` : "none",
2513
- "--atomix-glass-container-text-shadow": overLight ? "0px 1px 2px rgba(255, 255, 255, 0.15)" : "0px 2px 12px rgba(0, 0, 0, 0.4)",
2514
- "--atomix-glass-container-box-shadow": overLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)"
3046
+ "--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px`
2515
3047
  };
2516
3048
  } catch (error) {
2517
3049
  return console.warn("AtomixGlassContainer: Error generating container variables", error),
2518
3050
  {
2519
- "--atomix-glass-container-padding": "0 0",
2520
- "--atomix-glass-container-radius": "0px",
2521
- "--atomix-glass-container-backdrop": "none",
2522
- "--atomix-glass-container-shadow": "none",
2523
- "--atomix-glass-container-shadow-opacity": 1,
2524
- "--atomix-glass-container-bg": "none",
2525
- "--atomix-glass-container-text-shadow": "none"
3051
+ "--atomix-glass-container-radius": "0px"
2526
3052
  };
2527
3053
  }
2528
- }), [ borderRadius, backdropStyle, mouseOffset, overLight, effectiveWithoutEffects, overLightConfig ]);
3054
+ }), [ borderRadius ]);
2529
3055
  return jsx("div", {
2530
- ref: el => {
2531
- // Handle forwarded ref
2532
- "function" == typeof ref ? ref(el) : ref && (ref.current = el);
2533
- },
2534
- className: `${ATOMIX_GLASS.CONTAINER_CLASS} ${className} ${isActive ? ATOMIX_GLASS.CLASSES.ACTIVE : ""} ${overLight ? ATOMIX_GLASS.CLASSES.OVER_LIGHT : ""}`,
3056
+ ref: containerRef,
3057
+ className: mergeClassNames(ATOMIX_GLASS.CONTAINER_CLASS, className, isActive && ATOMIX_GLASS.CLASSES.ACTIVE, overLight && ATOMIX_GLASS.CLASSES.OVER_LIGHT),
2535
3058
  style: {
2536
3059
  ...style,
2537
3060
  ...containerVars
@@ -2549,8 +3072,8 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
2549
3072
  blurAmount: blurAmount,
2550
3073
  mode: mode,
2551
3074
  id: filterId,
2552
- displacementScale: "number" != typeof displacementScale || isNaN(displacementScale) ? 0 : displacementScale,
2553
- aberrationIntensity: "number" != typeof aberrationIntensity || isNaN(aberrationIntensity) ? 0 : aberrationIntensity,
3075
+ displacementScale: toSafeNumber(displacementScale),
3076
+ aberrationIntensity: toSafeNumber(aberrationIntensity),
2554
3077
  shaderMapUrl: shaderMapUrl
2555
3078
  }), jsx("div", {
2556
3079
  className: ATOMIX_GLASS.FILTER_OVERLAY_CLASS,
@@ -2572,8 +3095,12 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
2572
3095
  });
2573
3096
  }));
2574
3097
 
2575
- // ─── Blur multiplier constants (module-level, never change at runtime) ────────
2576
- AtomixGlassContainer.displayName = "AtomixGlassContainer";
3098
+ /**
3099
+ * Internal glass surface that owns backdrop-filter, SVG distortion, and content.
3100
+ *
3101
+ * Layout and stacking styles are applied via the `style` prop from the parent.
3102
+ * The root wrapper supplies CSS custom properties only.
3103
+ */ AtomixGlassContainer.displayName = "AtomixGlassContainer";
2577
3104
 
2578
3105
  // Singleton instance
2579
3106
  const globalMouseTracker = new
@@ -2688,28 +3215,32 @@ class {
2688
3215
  */ getSubscriberCount() {
2689
3216
  return this.listeners.size;
2690
3217
  }
2691
- }, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
3218
+ }, {BORDER: BORDER, CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, BORDER_GRADIENT = BORDER.GRADIENT, WHITE = CONSTANTS$2.PALETTE.WHITE, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
2692
3219
  if (!wrapperElement && !containerElement) return;
2693
3220
  if (!validateGlassSize(params.glassSize)) return;
2694
- 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 = {
3221
+ 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, isFixedOrSticky: isFixedOrSticky = !1, borderAnimated: borderAnimated = !0, borderOpacityMultiplier: borderOpacityMultiplier = 1} = params, mouseInfluence = calculateMouseInfluence(mouseOffset), {hoverIntensity: hoverIntensity, activeIntensity: activeIntensity} = getInteractionIntensity(isHovered, isActive), overLightConfig = {
2695
3222
  opacity: baseOverLightConfig.opacity * hoverIntensity * activeIntensity,
2696
3223
  contrast: Math.min(1.6, baseOverLightConfig.contrast + .1 * mouseInfluence),
2697
3224
  brightness: Math.min(1.1, baseOverLightConfig.brightness + .05 * mouseInfluence),
2698
3225
  shadowIntensity: Math.min(1.2, Math.max(.5, baseOverLightConfig.shadowIntensity + .2 * mouseInfluence)),
2699
3226
  borderOpacity: Math.min(1, Math.max(.3, baseOverLightConfig.borderOpacity + .1 * mouseInfluence)),
2700
3227
  saturationBoost: baseOverLightConfig.saturationBoost
2701
- }, 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) => {
2702
- if (!pos1 || !pos2 || "number" != typeof pos1.x || "number" != typeof pos1.y || "number" != typeof pos2.x || "number" != typeof pos2.y) return 0;
2703
- const deltaX = pos1.x - pos2.x, deltaY = pos1.y - pos2.y;
2704
- return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
2705
- })({
2706
- x: 0,
2707
- y: 0
2708
- }, elasticTranslation), tensionFactor = smoothstep(stretchMagnitude / 80), lightingContrast = Math.min(1.8, overLightConfig.contrast + .2 * tensionFactor), lightingBrightness = Math.min(1.2, overLightConfig.brightness + .1 * tensionFactor);
3228
+ }, scaleX = directionalScale.x * scaleBase, scaleY = directionalScale.y * scaleBase, transformStyle = effectiveWithoutEffects ? `scale(${scaleBase})` : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) scaleX(${scaleX}) scaleY(${scaleY})`, tensionFactor =
3229
+ /**
3230
+ * Computes tension factor from elastic translation magnitude (0–1).
3231
+ */
3232
+ function(elasticTranslation) {
3233
+ const magnitude = Math.hypot(elasticTranslation.x, elasticTranslation.y);
3234
+ return smoothstep(magnitude / 80);
3235
+ }
3236
+ /**
3237
+ * Updates the styles of the AtomixGlass wrapper and container elements imperatively
3238
+ * to avoid React re-renders on mouse movement.
3239
+ */ (elasticTranslation), lightingContrast = Math.min(1.8, overLightConfig.contrast + .2 * tensionFactor), lightingBrightness = Math.min(1.2, overLightConfig.brightness + .1 * tensionFactor);
2709
3240
  // Calculate mouse influence
2710
3241
  // Update Wrapper Styles (glassVars)
2711
3242
  if (wrapperElement) {
2712
- 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 = {
3243
+ const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, hoverPositions = {
2713
3244
  hover1: {
2714
3245
  x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
2715
3246
  y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1
@@ -2726,28 +3257,55 @@ class {
2726
3257
  x: GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER,
2727
3258
  y: GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER
2728
3259
  }, opacityValues = {
2729
- hover1: isHovered || isActive ? .5 : 0,
2730
- hover2: isActive ? .5 : 0,
2731
- hover3: isHovered ? .4 : isActive ? .8 : 0,
2732
- base: isOverLight ? overLightConfig.opacity : 0,
2733
- over: isOverLight ? 1.1 * overLightConfig.opacity : 0
3260
+ // hover-1: ambient highlight glow present on hover and during press
3261
+ hover1: isHovered || isActive ? 1 : 0,
3262
+ // hover-2: press depth shadow only fires on active (mousedown)
3263
+ hover2: isActive ? 1 : 0,
3264
+ // hover-3: global soft-light surface shift half-strength on hover, full on press
3265
+ hover3: isActive ? 1 : isHovered ? .55 : 0,
3266
+ // Dark chrome: faint smoky tint; over-light keeps stronger fill
3267
+ base: isOverLight ? overLightConfig.opacity : .14,
3268
+ over: isOverLight ? 1.1 * overLightConfig.opacity : .1
2734
3269
  }, style = wrapperElement.style;
2735
3270
  style.setProperty("--atomix-glass-transform", transformStyle || "none");
2736
3271
  // Parallax for content (liquid refraction feel)
2737
3272
  const parallaxFactor = .38 + .12 * tensionFactor;
2738
3273
  style.setProperty("--atomix-glass-child-parallax", `translate(${elasticTranslation.x * -parallaxFactor}px, ${elasticTranslation.y * -parallaxFactor}px)`),
2739
- style.setProperty("--atomix-glass-contrast", lightingContrast.toString()), style.setProperty("--atomix-glass-brightness", lightingBrightness.toString()),
3274
+ style.setProperty("--atomix-glass-contrast", lightingContrast.toString()), style.setProperty("--atomix-glass-brightness", lightingBrightness.toString());
2740
3275
  // ── Chromatic Rim Lighting ──────────────────────────────────────
2741
- // Layer 1: Core White/Blue highlight
2742
- 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%)`),
2743
- // Layer 2: Subtle Red/Warm highlight (offset angle)
2744
- 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%)`),
2745
- // Hover gradients
2746
- 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}%)`),
2747
- 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}%)`),
2748
- style.setProperty("--atomix-glass-hover-3-gradient", isOverLight ? `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_STOP}%)`),
2749
- style.setProperty("--atomix-glass-base-gradient", isOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + mx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + my * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + absMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`),
2750
- style.setProperty("--atomix-glass-overlay-gradient", isOverLight ? `radial-gradient(circle at ${basePosition.x}% ${basePosition.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + absMx * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + absMy * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`),
3276
+ const borderVars = ATOMIX_GLASS.BORDER.GRADIENT_CSS_VARS;
3277
+ if (borderAnimated && !effectiveWithoutEffects) {
3278
+ const borderCssVars =
3279
+ /**
3280
+ * Builds animated chromatic rim CSS variables for border layers 1 and 2.
3281
+ * When empty, SCSS static conic/linear fallbacks apply.
3282
+ */
3283
+ function(params) {
3284
+ const {mouseOffset: mouseOffset, mouseVelocity: mouseVelocity, elasticVelocity: elasticVelocity, borderOpacity: borderOpacity, opacityMultiplier: opacityMultiplier = 1, tensionFactor: tensionFactor = 0} = params, mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), velocityRotation = (mouseVelocity.x + elasticVelocity.x) * BORDER_GRADIENT.VELOCITY_ANGLE_MULTIPLIER, borderGradientAngle = BORDER_GRADIENT.BASE_ANGLE + mx * BORDER_GRADIENT.ANGLE_MULTIPLIER + velocityRotation, chromaticOffset = BORDER_GRADIENT.CHROMATIC_OFFSET, angleR = borderGradientAngle - chromaticOffset, angleB = borderGradientAngle + chromaticOffset, borderStop1 = Math.max(BORDER_GRADIENT.STOP_1.MIN, BORDER_GRADIENT.STOP_1.BASE + my * BORDER_GRADIENT.STOP_1.MULTIPLIER), borderStop2 = Math.min(BORDER_GRADIENT.STOP_2.MAX, BORDER_GRADIENT.STOP_2.BASE + my * BORDER_GRADIENT.STOP_2.MULTIPLIER), tensionGlow = 1 + .5 * tensionFactor, opacities = BORDER_GRADIENT.OPACITY, borderOpacities = [ (opacities.BASE_1 + absMx * opacities.MULTIPLIER_LOW) * tensionGlow, (opacities.BASE_2 + absMx * opacities.MULTIPLIER_HIGH) * tensionGlow, (opacities.BASE_3 + absMx * opacities.MULTIPLIER_LOW) * tensionGlow, (opacities.BASE_4 + absMx * opacities.MULTIPLIER_HIGH) * tensionGlow ], configBorderOpacity = borderOpacity * opacityMultiplier, gradient1 = `linear-gradient(${angleB}deg, rgba(${WHITE}, 0) 0%, rgba(${WHITE}, ${(borderOpacities[0] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${WHITE}, ${(borderOpacities[1] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${WHITE}, 0) 100%)`, gradient2 = `linear-gradient(${angleR}deg, rgba(${WHITE}, 0) 0%, rgba(${WHITE}, ${(borderOpacities[2] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${WHITE}, ${(borderOpacities[3] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${WHITE}, 0) 100%)`;
3285
+ return {
3286
+ [BORDER.GRADIENT_CSS_VARS.GRADIENT_1]: gradient1,
3287
+ [BORDER.GRADIENT_CSS_VARS.GRADIENT_2]: gradient2
3288
+ };
3289
+ }({
3290
+ mouseOffset: mouseOffset,
3291
+ mouseVelocity: mouseVelocity,
3292
+ elasticVelocity: elasticVelocity,
3293
+ borderOpacity: overLightConfig.borderOpacity,
3294
+ opacityMultiplier: borderOpacityMultiplier,
3295
+ tensionFactor: tensionFactor
3296
+ });
3297
+ style.setProperty(borderVars.GRADIENT_1, borderCssVars[borderVars.GRADIENT_1] ?? ""),
3298
+ style.setProperty(borderVars.GRADIENT_2, borderCssVars[borderVars.GRADIENT_2] ?? "");
3299
+ } else style.removeProperty(borderVars.GRADIENT_1), style.removeProperty(borderVars.GRADIENT_2);
3300
+ // Hover gradients — cursor-relative radial positions for realistic light tracking.
3301
+ // hover-1: white overlay highlight following cursor (works on both dark + light)
3302
+ style.setProperty("--atomix-glass-hover-1-gradient", `radial-gradient(65% 55% at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${whiteColor}, 0.24) 0%, rgba(${whiteColor}, 0.06) 45%, rgba(${whiteColor}, 0) 72%)`),
3303
+ // hover-2: press depth — darkens at cursor with multiply blend, isOverLight uses stronger black
3304
+ style.setProperty("--atomix-glass-hover-2-gradient", isOverLight ? `radial-gradient(60% 50% at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${blackColor}, 0.22) 0%, rgba(${blackColor}, 0.06) 50%, rgba(${blackColor}, 0) 72%)` : `radial-gradient(60% 50% at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${blackColor}, 0.18) 0%, rgba(${blackColor}, 0.04) 50%, rgba(${blackColor}, 0) 72%)`),
3305
+ // hover-3: full-surface soft-light tint; linear gradient angled with cursor X
3306
+ style.setProperty("--atomix-glass-hover-3-gradient", `linear-gradient(${150 + .3 * mx}deg, rgba(${whiteColor}, ${isOverLight ? .08 : .12}) 0%, rgba(${whiteColor}, 0.04) 55%, rgba(${whiteColor}, 0) 100%)`),
3307
+ style.setProperty("--atomix-glass-base-gradient", isOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + mx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + my * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + absMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `linear-gradient(180deg, rgba(${blackColor}, 0.42) 0%, rgba(${blackColor}, 0.22) 55%, rgba(${blackColor}, 0.12) 100%)`),
3308
+ style.setProperty("--atomix-glass-overlay-gradient", isOverLight ? `radial-gradient(circle at ${basePosition.x}% ${basePosition.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + absMx * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + absMy * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `radial-gradient(120% 80% at 50% 0%, rgba(${whiteColor}, 0.14) 0%, rgba(${whiteColor}, 0) 55%)`),
2751
3309
  // Opacities
2752
3310
  style.setProperty("--atomix-glass-hover-1-opacity", opacityValues.hover1.toString()),
2753
3311
  style.setProperty("--atomix-glass-hover-2-opacity", opacityValues.hover2.toString()),
@@ -2784,151 +3342,16 @@ class {
2784
3342
  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})`;
2785
3343
  // Container variables
2786
3344
  const style = containerElement.style;
2787
- style.setProperty("--atomix-glass-container-padding", padding), style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
3345
+ style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
2788
3346
  style.setProperty("--atomix-glass-container-backdrop", backdropFilterString),
2789
3347
  // Shadows
2790
- style.setProperty("--atomix-glass-container-shadow", isOverLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${(.4 + .002 * mx) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 -1px 0 rgba(0, 0, 0, ${(.2 + .001 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 0 20px rgba(0, 0, 0, ${(.08 + .001 * Math.abs(mx + my)) * (overLightConfig.shadowIntensity || 1)})`, `0 2px 12px rgba(0, 0, 0, ${(.12 + .002 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})` ].join(", ") : "0 0 20px rgba(0, 0, 0, 0.15) inset, 0 4px 8px rgba(0, 0, 0, 0.08) inset"),
3348
+ style.setProperty("--atomix-glass-container-shadow", isOverLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${(.35 + .002 * mx) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 -1px 0 rgba(0, 0, 0, ${(.15 + .001 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 0 20px rgba(0, 0, 0, ${(.06 + .001 * Math.abs(mx + my)) * (overLightConfig.shadowIntensity || 1)})`, `0 2px 12px rgba(0, 0, 0, ${(.08 + .002 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})` ].join(", ") : ATOMIX_GLASS.CONSTANTS.CONTAINER_SHADOW.LIGHT),
2791
3349
  style.setProperty("--atomix-glass-container-shadow-opacity", effectiveWithoutEffects ? "0" : "1"),
2792
3350
  style.setProperty("--atomix-glass-container-bg", isOverLight ? `linear-gradient(${180 + .5 * mx}deg, rgba(255, 255, 255, 0.1) 0%, transparent 20%, transparent 80%, rgba(0, 0, 0, 0.05) 100%)` : "none"),
2793
3351
  style.setProperty("--atomix-glass-container-text-shadow", isOverLight ? "0px 1px 2px rgba(255, 255, 255, 0.15)" : "0px 2px 12px rgba(0, 0, 0, 0.4)"),
2794
- style.setProperty("--atomix-glass-container-box-shadow", isOverLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)");
3352
+ style.setProperty("--atomix-glass-container-box-shadow", isOverLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0 4px 16px rgba(0, 0, 0, 0.14), 0 1px 4px rgba(0, 0, 0, 0.10)");
2795
3353
  }
2796
- };
2797
-
2798
- /**
2799
- * Updates the styles of the AtomixGlass wrapper and container elements imperatively
2800
- * to avoid React re-renders on mouse movement.
2801
- */
2802
- /**
2803
- * Animation System for AtomixGlass Component
2804
- *
2805
- * Implements Phase 1 features from the AtomixGlass Feature Implementation Roadmap:
2806
- * - Feature 1.1: Time-Based Animation System
2807
- * - Feature 1.2: Multi-Layer Distortion System (FBM)
2808
- *
2809
- * @packageDocumentation
2810
- */
2811
- // ============================================================================
2812
- // Noise Functions for FBM (Feature 1.2)
2813
- // ============================================================================
2814
- /**
2815
- * Perlin noise implementation for smooth gradient noise
2816
- *
2817
- * @param x - X coordinate
2818
- * @param y - Y coordinate
2819
- * @returns Noise value in range [0, 1]
2820
- */
2821
- function perlinNoise(x, y) {
2822
- // Simplified Perlin noise using pseudo-random gradients
2823
- const X = 255 & Math.floor(x), Y = 255 & Math.floor(y), xf = x - Math.floor(x), yf = y - Math.floor(y), u = fade(xf), v = fade(yf), A = p[X] + Y & 255, B = p[X + 1] + Y & 255, ga = grad(p[A], xf, yf), gb = grad(p[B], xf - 1, yf), gc = grad(p[A + 1 & 255], xf, yf - 1), gd = grad(p[B + 1 & 255], xf - 1, yf - 1), lerpX1 = lerp(ga, gb, u), lerpX2 = lerp(gc, gd, u);
2824
- // Scale to [0, 1] range
2825
- return (lerp(lerpX1, lerpX2, v) + 1) / 2;
2826
- }
2827
-
2828
- // ============================================================================
2829
- // Fractal Brownian Motion (FBM) Engine (Feature 1.2)
2830
- // ============================================================================
2831
- /**
2832
- * Creates an FBM engine with configurable parameters
2833
- *
2834
- * @param config - FBM configuration (octaves, lacunarity, gain)
2835
- * @returns Object with fbm function
2836
- *
2837
- * @example
2838
- * ```typescript
2839
- * const fbmEngine = createFBMEngine({ octaves: 5, lacunarity: 2, gain: 0.5 });
2840
- *
2841
- * // Generate noise at position (0.5, 0.5) with time animation
2842
- * const noiseValue = fbmEngine.fbm(0.5, 0.5, Date.now());
2843
- * ```
2844
- */ function createFBMEngine(config) {
2845
- /**
2846
- * Fractal Brownian Motion function
2847
- * Combines multiple octaves of noise for complex, natural patterns
2848
- *
2849
- * @param x - X coordinate
2850
- * @param y - Y coordinate
2851
- * @param time - Optional time value for animation
2852
- * @returns FBM noise value in range [0, 1]
2853
- */
2854
- const fbm = (x, y, time = 0) => {
2855
- let value = 0, amplitude = .5, frequency = 1, phase = .001 * time;
2856
- // Convert to seconds for reasonable animation speed
2857
- for (let i = 0; i < config.octaves; i++)
2858
- // Apply time-based phase shift to all octaves
2859
- value += perlinNoise(x * frequency + phase, y * frequency + phase) * amplitude,
2860
- frequency *= config.lacunarity, // Increase frequency
2861
- amplitude *= config.gain;
2862
- return value;
2863
- };
2864
- /**
2865
- * Get FBM with simple time factor
2866
- */ return {
2867
- fbm: fbm,
2868
- fbmWithTime: (x, y, time) => fbm(x, y, time)
2869
- };
2870
- }
2871
-
2872
- /**
2873
- * Gets optimal FBM config based on quality preset
2874
- *
2875
- * @param quality - Quality preset level
2876
- * @returns FBM configuration for the quality level
2877
- */ const fbmEngineCache = new Map;
2878
-
2879
- // ============================================================================
2880
- // Shader Utility Functions for Time-Based Effects
2881
- // ============================================================================
2882
- /**
2883
- * Liquid glass distortion with time-based animation
2884
- * Uses FBM to create organic, flowing liquid effects
2885
- *
2886
- * @param uv - UV coordinates (normalized 0-1)
2887
- * @param time - Elapsed time in milliseconds
2888
- * @param config - FBM configuration
2889
- * @returns Distorted UV coordinates
2890
- */ function liquidGlassWithTime(uv, time, config) {
2891
- const configKey = `${config.octaves}-${config.lacunarity}-${config.gain}`;
2892
- let fbmEngine = fbmEngineCache.get(configKey);
2893
- fbmEngine || (fbmEngine = createFBMEngine(config), fbmEngineCache.set(configKey, fbmEngine));
2894
- // Animate noise with time
2895
- const animatedNoise = fbmEngine.fbmWithTime(2 * uv.x + 1e-4 * time, 2 * uv.y + 15e-5 * time, time);
2896
- return {
2897
- x: uv.x + .04 * (animatedNoise - .5),
2898
- y: uv.y + .04 * (animatedNoise - .5)
2899
- };
2900
- }
2901
-
2902
- // ============================================================================
2903
- // Helper Functions
2904
- // ============================================================================
2905
- /**
2906
- * Fade curve for smooth interpolation (Perlin's fade function)
2907
- */ function fade(t) {
2908
- return t * t * t * (t * (6 * t - 15) + 10);
2909
- }
2910
-
2911
- /**
2912
- * Linear interpolation
2913
- */ function lerp(a, b, t) {
2914
- return a + t * (b - a);
2915
- }
2916
-
2917
- /**
2918
- * Gradient calculation for Perlin noise
2919
- */ function grad(hash, x, y) {
2920
- const h = 15 & hash, u = h < 8 ? x : y, v = h < 4 ? y : 12 === h || 14 === h ? x : 0;
2921
- return (1 & h ? -u : u) + (2 & h ? -v : v);
2922
- }
2923
-
2924
- /**
2925
- * Permutation table for Perlin noise
2926
- */ const p = (() => {
2927
- const permutation = [];
2928
- for (let i = 0; i < 256; i++) permutation[i] = Math.floor(256 * Math.random());
2929
- // Duplicate for overflow handling
2930
- return [ ...permutation, ...permutation ];
2931
- })(), {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
3354
+ }, {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
2932
3355
 
2933
3356
  const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new WeakMap, setCachedBackgroundDetection = (parentElement, overLightConfig, result, threshold) => {
2934
3357
  parentElement && backgroundDetectionCache.set(parentElement, {
@@ -2943,12 +3366,35 @@ const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new Weak
2943
3366
  * Composable hook for AtomixGlass component logic
2944
3367
  * Manages all state, calculations, and event handlers
2945
3368
  */
2946
- 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:
2947
- // Default priority
2948
- // Phase 1: Animation System Props
2949
- 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}) {
3369
+ 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, border: border, withBorder: withBorder = !0, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, children: children, blurAmount: blurAmount, saturation: saturation, withLiquidBlur: withLiquidBlur, isFixedOrSticky: isFixedOrSticky = !1, priority: priority = 1}) {
2950
3370
  // State
2951
- const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1), cachedRectRef = useRef(null), internalGlobalMousePositionRef = useRef({
3371
+ const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1), resolvedBorder = useMemo((() =>
3372
+ /**
3373
+ * Resolves `border` and legacy `withBorder` into a single configuration object.
3374
+ */
3375
+ function(border, withBorder) {
3376
+ const legacyDefault = withBorder ?? !0;
3377
+ return void 0 === border ? {
3378
+ enabled: legacyDefault,
3379
+ width: BORDER.DEFAULT_WIDTH,
3380
+ opacityMultiplier: 1,
3381
+ animated: !0
3382
+ } : "boolean" == typeof border ? {
3383
+ enabled: border,
3384
+ width: BORDER.DEFAULT_WIDTH,
3385
+ opacityMultiplier: 1,
3386
+ animated: !0
3387
+ } : {
3388
+ enabled: border.enabled ?? legacyDefault,
3389
+ width: (value = border.width, void 0 === value ? BORDER.DEFAULT_WIDTH : "number" == typeof value ? `${value}px` : value),
3390
+ opacityMultiplier: border.opacity ?? 1,
3391
+ animated: !1 !== border.animated
3392
+ };
3393
+ /**
3394
+ * Formats border width for CSS custom properties.
3395
+ */
3396
+ var value;
3397
+ }(border, withBorder)), [ border, withBorder ]), cachedRectRef = useRef(null), internalGlobalMousePositionRef = useRef({
2952
3398
  x: 0,
2953
3399
  y: 0
2954
3400
  }), internalMouseOffsetRef = useRef({
@@ -2972,52 +3418,10 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2972
3418
  }), scaleVelocityRef = useRef({
2973
3419
  x: 0,
2974
3420
  y: 0
2975
- });
2976
- useRef(0);
2977
- const mouseVelocityRef = useRef({
3421
+ }), mouseVelocityRef = useRef({
2978
3422
  x: 0,
2979
3423
  y: 0
2980
- }), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1), animationFrameIdRef = useRef(null), animationStartTimeRef = useRef(0), elapsedTimeRef = useRef(0), shaderTimeRef = useRef(0), fbmConfig = useMemo((() => {
2981
- // If quality preset is provided, use it as base
2982
- const preset = (quality = distortionQuality, ATOMIX_GLASS.CONSTANTS.DISTORTION_QUALITY_PRESETS[quality]);
2983
- // Override with custom values if provided
2984
- var quality;
2985
- return {
2986
- octaves: distortionOctaves ?? preset.octaves,
2987
- lacunarity: distortionLacunarity ?? preset.lacunarity,
2988
- gain: distortionGain ?? preset.gain
2989
- };
2990
- }), [ distortionQuality, distortionOctaves, distortionLacunarity, distortionGain ]), fbmEngine = useMemo((() => withMultiLayerDistortion ? createFBMEngine(fbmConfig) : null), [ withMultiLayerDistortion, fbmConfig ]), effectiveReducedMotion = useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveWithTimeAnimation = useMemo((() => withTimeAnimation && !effectiveReducedMotion), [ withTimeAnimation, effectiveReducedMotion ]);
2991
- /**
2992
- * Animation loop for time-based effects
2993
- */
2994
- useEffect((() => {
2995
- if (!effectiveWithTimeAnimation || "undefined" == typeof window) return;
2996
- let lastFrameTime = performance.now();
2997
- /**
2998
- * Animation frame handler
2999
- */ const animate = currentTime => {
3000
- // Calculate delta time
3001
- const deltaTime = currentTime - lastFrameTime;
3002
- lastFrameTime = currentTime;
3003
- // Apply animation speed multiplier
3004
- const scaledDelta = deltaTime * animationSpeed;
3005
- elapsedTimeRef.current += scaledDelta, shaderTimeRef.current = elapsedTimeRef.current,
3006
- // Continue animation loop
3007
- animationFrameIdRef.current = requestAnimationFrame(animate);
3008
- };
3009
- // Start animation
3010
- // Cleanup
3011
- return animationStartTimeRef.current = performance.now(), animationFrameIdRef.current = requestAnimationFrame(animate),
3012
- () => {
3013
- null !== animationFrameIdRef.current && (cancelAnimationFrame(animationFrameIdRef.current),
3014
- animationFrameIdRef.current = null);
3015
- };
3016
- }), [ effectiveWithTimeAnimation, animationSpeed ]);
3017
- /**
3018
- * Get current shader time for animations
3019
- */
3020
- const getShaderTime = useCallback((() => shaderTimeRef.current), []), applyTimeBasedDistortion = useCallback((uv => effectiveWithTimeAnimation && fbmEngine ? liquidGlassWithTime(uv, shaderTimeRef.current, fbmConfig) : uv), [ effectiveWithTimeAnimation, fbmEngine, fbmConfig ]), effectiveBorderRadius = useMemo((() => void 0 !== borderRadius ? Math.max(0, borderRadius) : Math.max(0, dynamicBorderRadius)), [ borderRadius, dynamicBorderRadius ]), {glassSize: glassSize} = function({glassRef: glassRef, effectiveBorderRadius: effectiveBorderRadius, cachedRectRef: cachedRectRef}) {
3424
+ }), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1), effectiveReducedMotion = useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveBorderRadius = useMemo((() => void 0 !== borderRadius ? Math.max(0, borderRadius) : Math.max(0, dynamicBorderRadius)), [ borderRadius, dynamicBorderRadius ]), {glassSize: glassSize} = function({glassRef: glassRef, effectiveBorderRadius: effectiveBorderRadius, cachedRectRef: cachedRectRef}) {
3021
3425
  const [glassSize, setGlassSize] = useState({
3022
3426
  width: 270,
3023
3427
  height: 69
@@ -3077,9 +3481,6 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
3077
3481
  effectiveBorderRadius: effectiveBorderRadius,
3078
3482
  cachedRectRef: cachedRectRef
3079
3483
  }), effectiveHighContrast = useMemo((() => highContrast || userPrefersHighContrast), [ highContrast, userPrefersHighContrast ]), effectiveWithoutEffects = useMemo((() => withoutEffects || effectiveReducedMotion), [ withoutEffects, effectiveReducedMotion ]), globalMousePosition = externalGlobalMousePosition || internalGlobalMousePositionRef.current, mouseOffset = externalMouseOffset || internalMouseOffsetRef.current;
3080
- /**
3081
- * Apply time-based distortion to UV coordinates
3082
- */
3083
3484
  // Extract border-radius from children
3084
3485
  useEffect((() => {
3085
3486
  const extractRadius = () => {
@@ -3239,25 +3640,26 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
3239
3640
  * Get effective overLight value based on configuration
3240
3641
  */
3241
3642
  const getEffectiveOverLight = useCallback((() => "boolean" == typeof overLight ? overLight : ("auto" === overLight || "object" == typeof overLight && null !== overLight) && detectedOverLight), [ overLight, detectedOverLight ]), validateConfigValue = useCallback(((value, min, max, defaultValue) => "number" != typeof value || isNaN(value) || !isFinite(value) ? defaultValue : Math.min(max, Math.max(min, value))), []), overLightConfig = useMemo((() => {
3242
- const isOverLight = getEffectiveOverLight(), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1, baseConfig = {
3643
+ const isOverLight = getEffectiveOverLight(), {hoverIntensity: hoverIntensity, activeIntensity: activeIntensity} = getInteractionIntensity(isHovered, isActive), baseConfig = {
3243
3644
  isOverLight: isOverLight,
3244
3645
  threshold: .7,
3245
3646
  opacity: isOverLight ? Math.min(.6, Math.max(.2, .5 * hoverIntensity * activeIntensity)) : 0,
3246
- contrast: 1.4,
3247
- brightness: .9,
3248
- saturationBoost: 1.3,
3249
- // Fixed value dynamic saturation amplifies perceived displacement
3250
- shadowIntensity: .9,
3251
- borderOpacity: .7
3647
+ // Dark UI (Apple Music): neutral contrast + slight brightness lift
3648
+ contrast: isOverLight ? 1.4 : 1.02,
3649
+ brightness: isOverLight ? .9 : 1.02,
3650
+ saturationBoost: isOverLight ? 1.3 : 1,
3651
+ shadowIntensity: isOverLight ? .9 : 1,
3652
+ borderOpacity: isOverLight ? ATOMIX_GLASS.BORDER.OVER_LIGHT.opacity : ATOMIX_GLASS.BORDER.DARK.opacity
3252
3653
  };
3253
3654
  if ("object" == typeof overLight && null !== overLight) {
3254
- const objConfig = overLight, validatedThreshold = validateConfigValue(objConfig.threshold, .1, 1, baseConfig.threshold), validatedOpacity = validateConfigValue(objConfig.opacity, .1, 1, baseConfig.opacity), validatedContrast = validateConfigValue(objConfig.contrast, .5, 2.5, baseConfig.contrast), validatedBrightness = validateConfigValue(objConfig.brightness, .5, 2, baseConfig.brightness), validatedSaturationBoost = validateConfigValue(objConfig.saturationBoost, .5, 3, baseConfig.saturationBoost), finalConfig = {
3655
+ const objConfig = overLight, validatedThreshold = validateConfigValue(objConfig.threshold, .1, 1, baseConfig.threshold), validatedOpacity = validateConfigValue(objConfig.opacity, .1, 1, baseConfig.opacity), validatedContrast = validateConfigValue(objConfig.contrast, .5, 2.5, baseConfig.contrast), validatedBrightness = validateConfigValue(objConfig.brightness, .5, 2, baseConfig.brightness), validatedSaturationBoost = validateConfigValue(objConfig.saturationBoost, .5, 3, baseConfig.saturationBoost), validatedBorderOpacity = validateConfigValue(objConfig.borderOpacity, .1, 1, baseConfig.borderOpacity), finalConfig = {
3255
3656
  ...baseConfig,
3256
3657
  threshold: validatedThreshold,
3257
3658
  opacity: validatedOpacity * hoverIntensity * activeIntensity,
3258
3659
  contrast: validatedContrast,
3259
3660
  brightness: validatedBrightness,
3260
- saturationBoost: validatedSaturationBoost
3661
+ saturationBoost: validatedSaturationBoost,
3662
+ borderOpacity: validatedBorderOpacity
3261
3663
  };
3262
3664
  return "undefined" == typeof process || process.env, finalConfig;
3263
3665
  }
@@ -3282,8 +3684,8 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
3282
3684
  };
3283
3685
  const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
3284
3686
  internalGlobalMousePositionRef.current = {
3285
- x: lerp$1(curG.x, tgtG.x, CONSTANTS.LERP_FACTOR),
3286
- y: lerp$1(curG.y, tgtG.y, CONSTANTS.LERP_FACTOR)
3687
+ x: lerp(curG.x, tgtG.x, CONSTANTS.LERP_FACTOR),
3688
+ y: lerp(curG.y, tgtG.y, CONSTANTS.LERP_FACTOR)
3287
3689
  };
3288
3690
  // ── Calculate Elastic Physics ─────────────────────────────────────
3289
3691
  let targetElasticTranslation = {
@@ -3355,12 +3757,13 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
3355
3757
  withLiquidBlur: withLiquidBlur,
3356
3758
  blurAmount: blurAmount,
3357
3759
  saturation: saturation,
3358
- padding: padding,
3359
- isFixedOrSticky: isFixedOrSticky
3760
+ isFixedOrSticky: isFixedOrSticky,
3761
+ borderAnimated: resolvedBorder.animated,
3762
+ borderOpacityMultiplier: resolvedBorder.opacityMultiplier
3360
3763
  }), 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);
3361
3764
  };
3362
3765
  lerpRafRef.current = requestAnimationFrame(tick);
3363
- }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding, isFixedOrSticky, stopLerpLoop ]), handleGlobalMousePosition = useCallback((globalPos => {
3766
+ }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, isFixedOrSticky, resolvedBorder.animated, resolvedBorder.opacityMultiplier, stopLerpLoop ]), handleGlobalMousePosition = useCallback((globalPos => {
3364
3767
  if (externalGlobalMousePosition && externalMouseOffset) return;
3365
3768
  if (effectiveWithoutEffects) return;
3366
3769
  const container = mouseContainer?.current || glassRef.current;
@@ -3424,9 +3827,10 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
3424
3827
  withLiquidBlur: withLiquidBlur,
3425
3828
  blurAmount: blurAmount,
3426
3829
  saturation: saturation,
3427
- padding: padding
3830
+ borderAnimated: resolvedBorder.animated,
3831
+ borderOpacityMultiplier: resolvedBorder.opacityMultiplier
3428
3832
  });
3429
- }), [ isHovered, isActive, glassSize, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation, padding, onClick ]);
3833
+ }), [ isHovered, isActive, glassSize, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation, resolvedBorder.animated, resolvedBorder.opacityMultiplier, onClick ]);
3430
3834
  // Event handlers
3431
3835
  const handleMouseEnter = useCallback((() => setIsHovered(!0)), []), handleMouseLeave = useCallback((() => setIsHovered(!1)), []), handleMouseDown = useCallback((() => setIsActive(!0)), []), handleMouseUp = useCallback((() => setIsActive(!1)), []), handleKeyDown = useCallback((e => {
3432
3836
  !onClick || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), onClick());
@@ -3446,9 +3850,8 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
3446
3850
  mouseOffset: mouseOffset,
3447
3851
  // This is now static (refs or props) unless prop changes
3448
3852
  overLightConfig: overLightConfig,
3853
+ resolvedBorder: resolvedBorder,
3449
3854
  transformStyle: transformStyle,
3450
- getShaderTime: getShaderTime,
3451
- applyTimeBasedDistortion: applyTimeBasedDistortion,
3452
3855
  handleMouseEnter: handleMouseEnter,
3453
3856
  handleMouseLeave: handleMouseLeave,
3454
3857
  handleMouseDown: handleMouseDown,
@@ -3726,7 +4129,13 @@ function usePerformanceMonitor$1(config = {}) {
3726
4129
  timestamp: 0,
3727
4130
  isAutoScaling: !0,
3728
4131
  lowFpsCount: 0
3729
- }), [manualOverride, setManualOverride] = useState(!1), [isEnabled, setIsEnabled] = useState(enabled), frameCountRef = useRef(0), lastFpsUpdateRef = useRef(0), lastFrameTimeRef = useRef(0), animationFrameRef = useRef(null), lowFpsCountRef = useRef(0), highFpsCountRef = useRef(0), qualityLevelRef = useRef("medium"), updateMetrics = useCallback((newMetrics => {
4132
+ }), [manualOverride, setManualOverride] = useState(!1), [isEnabled, setIsEnabled] = useState(enabled);
4133
+ // Sync external `enabled` prop changes into internal state
4134
+ useEffect((() => {
4135
+ setIsEnabled(enabled ?? !0);
4136
+ }), [ enabled ]);
4137
+ // Refs for frame tracking
4138
+ const frameCountRef = useRef(0), lastFpsUpdateRef = useRef(0), lastFrameTimeRef = useRef(0), animationFrameRef = useRef(null), lowFpsCountRef = useRef(0), highFpsCountRef = useRef(0), qualityLevelRef = useRef("medium"), updateMetrics = useCallback((newMetrics => {
3730
4139
  setMetrics((prev => ({
3731
4140
  ...prev,
3732
4141
  ...newMetrics,
@@ -3853,157 +4262,9 @@ function usePerformanceMonitor$1(config = {}) {
3853
4262
  setQualityLevel: setQualityLevel,
3854
4263
  resetAutoScaling: resetAutoScaling,
3855
4264
  toggleMonitoring: toggleMonitoring
3856
- };
3857
- }
3858
-
3859
- /**
3860
- * Debug Overlay Component (Optional)
3861
- *
3862
- * Shows real-time performance metrics on screen.
3863
- * Only rendered when showOverlay is enabled.
3864
- */
3865
- /** Map an FPS value to a semantic color token string. */
3866
- const getQualityColor = quality => {
3867
- switch (quality) {
3868
- case "high":
3869
- return "var(--atomix-color-success, #4ade80)";
3870
-
3871
- case "medium":
3872
- return "var(--atomix-color-warning, #fbbf24)";
3873
-
3874
- case "low":
3875
- return "var(--atomix-color-danger, #ef4444)";
3876
-
3877
- default:
3878
- return "#9ca3af";
3879
- }
3880
- }, getFpsLabel = fps => fps >= 58 ? "Optimal" : fps >= 45 ? "Warning" : "Critical";
3881
-
3882
- /** Map a quality level string to a semantic color token string. */
3883
- // Inject keyframes once
3884
- if ("undefined" != typeof document) {
3885
- const styleId = "perf-dashboard-keyframes";
3886
- if (!document.getElementById(styleId)) {
3887
- const styleEl = document.createElement("style");
3888
- styleEl.id = styleId, styleEl.textContent = "\n@keyframes perf-dashboard-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n",
3889
- document.head.appendChild(styleEl);
3890
- }
4265
+ };
3891
4266
  }
3892
4267
 
3893
- /**
3894
- * PerformanceDashboard - Real-time performance monitoring overlay.
3895
- *
3896
- * Displays FPS, frame time, quality level, GPU memory, and auto-scaling status.
3897
- * Rendered only when `debugPerformance={true}` on the parent `AtomixGlass`.
3898
- */ const PerformanceDashboard = memo((({metrics: metrics, isVisible: isVisible = !0, onClose: onClose}) => {
3899
- if (!isVisible) return null;
3900
- const fpsColor = (fps = metrics.fps) >= 58 ? "var(--atomix-color-success, #4ade80)" : fps >= 45 ? "var(--atomix-color-warning, #fbbf24)" : "var(--atomix-color-danger, #ef4444)";
3901
- var fps;
3902
- const isCritical = metrics.fps < 45;
3903
- return jsxs("div", {
3904
- 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",
3905
- style: {
3906
- zIndex: 9999,
3907
- minWidth: "12.5rem",
3908
- // 200px
3909
- backgroundColor: "rgba(17, 24, 39, 0.95)",
3910
- backdropFilter: "blur(8px)",
3911
- transition: "opacity 0.3s ease"
3912
- },
3913
- children: [ jsxs("div", {
3914
- className: "u-flex u-items-center u-justify-between u-mb-2 u-pb-2 u-border-b u-border-white-alpha-10",
3915
- children: [ jsx("span", {
3916
- className: "u-text-sm u-font-bold u-text-white",
3917
- children: "Performance Monitor"
3918
- }), onClose && jsx("button", {
3919
- 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",
3920
- onClick: onClose,
3921
- "aria-label": "Close performance dashboard",
3922
- style: {
3923
- transition: "color 0.2s ease"
3924
- },
3925
- children: "×"
3926
- }) ]
3927
- }), jsxs("div", {
3928
- className: "u-flex u-items-center u-justify-between u-mb-1-5",
3929
- children: [ jsx("span", {
3930
- className: "u-text-gray-400 u-me-3",
3931
- children: "FPS"
3932
- }), jsx("span", {
3933
- className: "u-font-bold",
3934
- style: {
3935
- color: fpsColor
3936
- },
3937
- children: Math.round(metrics.fps)
3938
- }) ]
3939
- }), jsxs("div", {
3940
- className: "u-flex u-items-center u-justify-between u-mb-1-5",
3941
- children: [ jsx("span", {
3942
- className: "u-text-gray-400 u-me-3",
3943
- children: "Frame Time"
3944
- }), jsxs("span", {
3945
- className: "u-font-bold",
3946
- children: [ metrics.frameTime.toFixed(2), "ms" ]
3947
- }) ]
3948
- }), jsxs("div", {
3949
- className: "u-flex u-items-center u-justify-between u-mb-1-5",
3950
- children: [ jsx("span", {
3951
- className: "u-text-gray-400 u-me-3",
3952
- children: "Quality"
3953
- }), jsx("span", {
3954
- className: "u-font-bold u-text-uppercase",
3955
- style: {
3956
- fontSize: "0.6875rem",
3957
- // 11px
3958
- color: getQualityColor(metrics.qualityLevel)
3959
- },
3960
- children: metrics.qualityLevel
3961
- }) ]
3962
- }), metrics.gpuMemory && jsxs("div", {
3963
- className: "u-flex u-items-center u-justify-between u-mb-1-5",
3964
- children: [ jsx("span", {
3965
- className: "u-text-gray-400 u-me-3",
3966
- children: "GPU Memory"
3967
- }), jsxs("span", {
3968
- className: "u-font-bold",
3969
- children: [ "~", Math.round(metrics.gpuMemory / 1024), "MB" ]
3970
- }) ]
3971
- }), metrics.isAutoScaling && jsx("div", {
3972
- className: "u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10 u-text-center",
3973
- style: {
3974
- fontSize: "0.625rem",
3975
- // 10px
3976
- color: "#6b7280"
3977
- },
3978
- children: "Auto-scaling active"
3979
- }), jsxs("div", {
3980
- className: "u-flex u-items-center u-gap-2 u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10",
3981
- children: [ jsx("div", {
3982
- className: "u-rounded-full",
3983
- style: {
3984
- width: "0.5rem",
3985
- height: "0.5rem",
3986
- flexShrink: 0,
3987
- backgroundColor: fpsColor,
3988
- ...isCritical && {
3989
- animation: "perf-dashboard-pulse 1s infinite"
3990
- }
3991
- }
3992
- }), jsx("span", {
3993
- className: "u-text-xs",
3994
- style: {
3995
- fontSize: "0.625rem",
3996
- // 10px
3997
- color: fpsColor
3998
- },
3999
- children: getFpsLabel(metrics.fps)
4000
- }) ]
4001
- }) ]
4002
- });
4003
- }));
4004
-
4005
- PerformanceDashboard.displayName = "PerformanceDashboard";
4006
-
4007
4268
  /**
4008
4269
  * Mobile optimization presets
4009
4270
  *
@@ -4013,8 +4274,7 @@ PerformanceDashboard.displayName = "PerformanceDashboard";
4013
4274
  /**
4014
4275
  * Performance preset - Maximum FPS, reduced quality
4015
4276
  * Best for low-end devices or when battery saving is priority
4016
- */
4017
- const PERFORMANCE_PRESET = {
4277
+ */ const PERFORMANCE_PRESET = {
4018
4278
  distortionOctaves: 2,
4019
4279
  // Minimal FBM layers
4020
4280
  displacementScale: 50,
@@ -4177,18 +4437,13 @@ function getDevicePreset(presetName) {
4177
4437
  getPixelRatio: () => "undefined" == typeof window ? 1 : window.devicePixelRatio || 1,
4178
4438
  /** Check if device has touch support */
4179
4439
  hasTouchSupport: () => "undefined" != typeof window && ("ontouchstart" in window || navigator.maxTouchPoints > 0)
4180
- }, 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) {
4181
- const glassRef = useRef(null), contentRef = useRef(null), internalWrapperRef = useRef(null), mergedRef = useMemo((() =>
4182
- // Helper to merge refs
4183
- function(...refs) {
4184
- return node => {
4185
- refs.forEach((ref => {
4186
- "function" == typeof ref ? ref(node) : null != ref && (ref.current = node);
4187
- }));
4188
- };
4189
- }
4190
- // Internal implementation with forwardRef
4191
- (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({
4440
+ }, 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 = "", 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, border: border, withBorder: withBorder = !0, debugBorderRadius: debugBorderRadius = !1, 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) {
4441
+ const glassRef = useRef(null), contentRef = useRef(null), internalWrapperRef = useRef(null), mergedRef = useForkRef(ref, internalWrapperRef), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = (explicit = propsIsFixedOrSticky,
4442
+ position = restStyle.position, Boolean(explicit || "fixed" === position || "sticky" === position));
4443
+ var explicit, position;
4444
+ /**
4445
+ * Extracts layout-related properties from a React `CSSProperties` object.
4446
+ */ const {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveBorderRadius: effectiveBorderRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveWithoutEffects: effectiveWithoutEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown, resolvedBorder: resolvedBorder} = useAtomixGlass({
4192
4447
  glassRef: glassRef,
4193
4448
  contentRef: contentRef,
4194
4449
  wrapperRef: internalWrapperRef,
@@ -4208,19 +4463,12 @@ function getDevicePreset(presetName) {
4208
4463
  blurAmount: blurAmount,
4209
4464
  saturation: saturation,
4210
4465
  withLiquidBlur: withLiquidBlur,
4211
- padding: padding,
4466
+ border: border,
4467
+ withBorder: withBorder,
4468
+ debugBorderRadius: debugBorderRadius,
4212
4469
  style: style,
4213
- isFixedOrSticky: isFixedOrSticky,
4214
- // Phase 1: Animation System props
4215
- withTimeAnimation: withTimeAnimation,
4216
- animationSpeed: animationSpeed,
4217
- withMultiLayerDistortion: withMultiLayerDistortion,
4218
- distortionOctaves: distortionOctaves,
4219
- distortionLacunarity: distortionLacunarity,
4220
- distortionGain: distortionGain,
4221
- distortionQuality: distortionQuality
4470
+ isFixedOrSticky: isFixedOrSticky
4222
4471
  });
4223
- // Responsive breakpoint system - automatically adjusts parameters based on viewport
4224
4472
  useResponsiveGlass({
4225
4473
  baseParams: {
4226
4474
  ...useMemo((() => getDevicePreset(devicePreset)), [ devicePreset ]),
@@ -4235,185 +4483,213 @@ function getDevicePreset(presetName) {
4235
4483
  breakpoints: MOBILE_OPTIMIZED_BREAKPOINTS,
4236
4484
  enabled: !disableResponsiveBreakpoints && "undefined" != typeof window,
4237
4485
  debug: !1
4238
- });
4239
- // Performance monitoring - tracks FPS, frame time, memory usage
4240
- const {metrics: performanceMetrics, toggleMonitoring: toggleMonitoring} = usePerformanceMonitor$1({
4486
+ }), usePerformanceMonitor$1({
4241
4487
  enabled: debugPerformance,
4242
- // Enable when debugPerformance is true
4243
4488
  debug: !1,
4244
4489
  showOverlay: !1
4245
4490
  });
4246
- // Auto-start performance monitoring when debugPerformance is enabled
4247
- React.useEffect((() => {
4248
- debugPerformance && toggleMonitoring();
4249
- // eslint-disable-next-line react-hooks/exhaustive-deps
4250
- }), [ debugPerformance ]);
4251
- // Re-run when debugPerformance changes
4252
- const isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, rootLayoutStyle = useMemo((() => {
4253
- if (!isFixedOrSticky) return {};
4254
- const {position: p, top: t, left: l, right: r, bottom: b} = restStyle;
4255
- return {
4256
- ...p && {
4257
- position: p
4258
- },
4259
- ...void 0 !== t && {
4260
- top: t
4261
- },
4262
- ...void 0 !== l && {
4263
- left: l
4264
- },
4265
- ...void 0 !== r && {
4266
- right: r
4267
- },
4268
- ...void 0 !== b && {
4269
- bottom: b
4270
- }
4271
- };
4272
- }), [ isFixedOrSticky, restStyle ]);
4273
- // Calculate base style with transforms
4274
- // When layout is hoisted to the root, strip those props from the container
4275
- useMemo((() => {
4276
- if (isFixedOrSticky) {
4277
- const {position: _p, top: _t, left: _l, right: _r, bottom: _b, ...visualStyle} = restStyle;
4278
- return {
4279
- ...visualStyle
4280
- };
4491
+ const isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, containerStyle = useMemo((() => ({
4492
+ ...restStyle,
4493
+ ...void 0 !== customZIndex && {
4494
+ zIndex: customZIndex
4281
4495
  }
4496
+ })), [ restStyle, customZIndex ]), componentClassName = mergeClassNames(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), positionStyles = useMemo((() =>
4497
+ /**
4498
+ * Returns the internal positioning context for effect layers relative to the root.
4499
+ */
4500
+ function(isFixedOrSticky, restStyle) {
4282
4501
  return {
4283
- ...restStyle
4502
+ position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
4503
+ top: 0,
4504
+ left: 0,
4505
+ right: "auto",
4506
+ bottom: "auto"
4284
4507
  };
4285
- }), [ isFixedOrSticky, restStyle ]);
4286
- // Build className with state modifiers
4287
- 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((() => ({
4288
- position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
4289
- top: isFixedOrSticky ? restStyle.top ?? 0 : 0,
4290
- left: isFixedOrSticky ? restStyle.left ?? 0 : 0,
4291
- right: isFixedOrSticky ? restStyle.right ?? "auto" : "auto",
4292
- bottom: isFixedOrSticky ? restStyle.bottom ?? "auto" : "auto"
4293
- })), [ isFixedOrSticky, restStyle.position, restStyle.top, restStyle.left, restStyle.right, restStyle.bottom ]), adjustedSize = useMemo((() => {
4294
- // Keep a reference to positionStyles to avoid unused-variable lint,
4295
- // but sizing is driven by explicit width/height or measured size.
4296
- positionStyles.position;
4297
- 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;
4508
+ }
4509
+ /**
4510
+ * Computes `--atomix-glass-width` and `--atomix-glass-height` values.
4511
+ *
4512
+ * Fixed/sticky elements prefer explicit dimensions or measured size; in-flow
4513
+ * elements default to `100%`.
4514
+ */ (isFixedOrSticky, restStyle)), [ isFixedOrSticky, restStyle ]), adjustedSize = useMemo((() => function(options) {
4515
+ const {width: width, height: height, restStyle: restStyle, glassSize: glassSize, isFixedOrSticky: isFixedOrSticky} = options, 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;
4298
4516
  return {
4299
4517
  width: resolveLength(effectiveWidth, glassSize.width),
4300
4518
  height: resolveLength(effectiveHeight, glassSize.height)
4301
4519
  };
4302
- }), [ width, height, restStyle.width, restStyle.height, positionStyles.position, glassSize.width, glassSize.height, isFixedOrSticky ]), gradientValues = useMemo((() => {
4303
- const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT;
4304
- return {
4305
- borderGradientAngle: GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER,
4306
- borderStop1: Math.max(GRADIENT.BORDER_STOP_1.MIN, GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER),
4307
- borderStop2: Math.min(GRADIENT.BORDER_STOP_2.MAX, GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER),
4308
- 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 ],
4309
- hoverPositions: {
4310
- hover1: {
4311
- x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
4312
- y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1
4313
- },
4314
- hover2: {
4315
- x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_2,
4316
- y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_2
4317
- },
4318
- hover3: {
4319
- x: GRADIENT.CENTER_POSITION + mx * GRADIENT.HOVER_POSITION.MULTIPLIER_3,
4320
- y: GRADIENT.CENTER_POSITION + my * GRADIENT.HOVER_POSITION.MULTIPLIER_3
4321
- }
4322
- },
4323
- basePosition: {
4324
- x: GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER,
4325
- y: GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER
4326
- },
4327
- mx: mx,
4328
- my: my,
4329
- absMx: absMx,
4330
- absMy: absMy
4331
- };
4332
- }), [ 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((() => ({
4333
- hover1: isHovered || isActive ? .5 : 0,
4334
- hover2: isActive ? .5 : 0,
4335
- hover3: isHovered ? .4 : isActive ? .8 : 0,
4336
- base: isOverLight ? clampedOverLightOpacity || .4 : 0,
4337
- over: isOverLight ? 1.1 * (clampedOverLightOpacity || .4) : 0
4338
- })), [ isHovered, isActive, isOverLight, clampedOverLightOpacity ]), glassVars = useMemo((() => {
4339
- 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;
4520
+ }
4521
+ /**
4522
+ * Builds the CSS custom properties applied to the root `.c-atomix-glass` element.
4523
+ *
4524
+ * These variables drive layer geometry, transforms, and stacking offsets. They
4525
+ * must not include layout properties that would interfere with backdrop-filter.
4526
+ */ ({
4527
+ width: width,
4528
+ height: height,
4529
+ restStyle: restStyle,
4530
+ glassSize: glassSize,
4531
+ isFixedOrSticky: isFixedOrSticky
4532
+ })), [ width, height, restStyle, glassSize, isFixedOrSticky ]), glassVars = useMemo((() => function(input) {
4533
+ const {effectiveBorderRadius: effectiveBorderRadius, transformStyle: transformStyle, adjustedSize: adjustedSize, isOverLight: isOverLight, customZIndex: customZIndex, isFixedOrSticky: isFixedOrSticky, positionStyles: positionStyles, restStyle: restStyle, borderWidth: borderWidth = ATOMIX_GLASS.BORDER.DEFAULT_WIDTH} = input, layerPosition =
4534
+ /**
4535
+ * Resolves the `--atomix-glass-position` value for decorative layers.
4536
+ *
4537
+ * Fixed/sticky layers use the same positioning mode as the container; in-flow
4538
+ * layers default to the internal absolute positioning context.
4539
+ */
4540
+ function(isFixedOrSticky, positionStyles, restStyle) {
4541
+ return isFixedOrSticky ? `${function(style) {
4542
+ const {position: position, top: top, left: left, right: right, bottom: bottom, inset: inset} = style;
4543
+ return {
4544
+ ...null != position && {
4545
+ position: position
4546
+ },
4547
+ ...void 0 !== top && {
4548
+ top: top
4549
+ },
4550
+ ...void 0 !== left && {
4551
+ left: left
4552
+ },
4553
+ ...void 0 !== right && {
4554
+ right: right
4555
+ },
4556
+ ...void 0 !== bottom && {
4557
+ bottom: bottom
4558
+ },
4559
+ ...void 0 !== inset && {
4560
+ inset: inset
4561
+ }
4562
+ };
4563
+ }
4564
+ /**
4565
+ * Resolves inset custom properties for decorative layers (hover, borders, backgrounds).
4566
+ *
4567
+ * For fixed and sticky modes, insets mirror the container so sibling layers remain
4568
+ * aligned. In-flow modes, insets follow the consumer `style` when a non-default
4569
+ * `position` is provided.
4570
+ */ (restStyle).position ?? restStyle.position ?? "fixed"}` : `${positionStyles.position}`;
4571
+ }(isFixedOrSticky, positionStyles, restStyle), layerInsets = function(isFixedOrSticky, restStyle) {
4572
+ if (isFixedOrSticky) return {
4573
+ top: formatGlassInsetValue(restStyle.top, 0),
4574
+ left: formatGlassInsetValue(restStyle.left, 0),
4575
+ right: formatGlassInsetValue(restStyle.right, "auto"),
4576
+ bottom: formatGlassInsetValue(restStyle.bottom, "auto")
4577
+ };
4578
+ const position = restStyle.position;
4579
+ return null != position && "static" !== position && "relative" !== position ? {
4580
+ top: formatGlassInsetValue(restStyle.top, 0),
4581
+ left: formatGlassInsetValue(restStyle.left, 0),
4582
+ right: formatGlassInsetValue(restStyle.right, "auto"),
4583
+ bottom: formatGlassInsetValue(restStyle.bottom, "auto")
4584
+ } : {
4585
+ top: "0px",
4586
+ left: "0px",
4587
+ right: "auto",
4588
+ bottom: "auto"
4589
+ };
4590
+ }(isFixedOrSticky, restStyle);
4340
4591
  return {
4341
4592
  ...void 0 !== customZIndex && {
4342
4593
  "--atomix-glass-base-z-index": customZIndex
4343
4594
  },
4344
4595
  "--atomix-glass-radius": `${effectiveBorderRadius}px`,
4345
4596
  "--atomix-glass-transform": transformStyle || "none",
4346
- "--atomix-glass-container-position": `${isFixedOrSticky ? rootLayoutStyle.position : positionStyles.position}`,
4347
- "--atomix-glass-position": `${isFixedOrSticky ? rootLayoutStyle.position : positionStyles.position}`,
4348
- "--atomix-glass-top": `${isFixedOrSticky ? restStyle.top ?? 0 : 0}px`,
4349
- "--atomix-glass-left": `${isFixedOrSticky ? restStyle.left ?? 0 : 0}px`,
4350
- "--atomix-glass-right": isFixedOrSticky ? restStyle.right ?? "auto" : "auto",
4351
- "--atomix-glass-bottom": isFixedOrSticky ? restStyle.bottom ?? "auto" : "auto",
4597
+ "--atomix-glass-container-position": layerPosition,
4598
+ "--atomix-glass-position": layerPosition,
4599
+ "--atomix-glass-top": layerInsets.top,
4600
+ "--atomix-glass-left": layerInsets.left,
4601
+ "--atomix-glass-right": layerInsets.right,
4602
+ "--atomix-glass-bottom": layerInsets.bottom,
4352
4603
  "--atomix-glass-width": adjustedSize.width,
4353
4604
  "--atomix-glass-height": adjustedSize.height,
4354
- "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.125rem)",
4355
- "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay",
4356
- "--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%)`,
4357
- "--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%)`,
4358
- "--atomix-glass-hover-1-opacity": opacityValues.hover1,
4359
- "--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}%)`,
4360
- "--atomix-glass-hover-2-opacity": opacityValues.hover2,
4361
- "--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}%)`,
4362
- "--atomix-glass-hover-3-opacity": opacityValues.hover3,
4363
- "--atomix-glass-hover-3-gradient": isOverLight ? `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_STOP}%)`,
4364
- "--atomix-glass-base-opacity": opacityValues.base,
4365
- "--atomix-glass-base-gradient": isOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + mx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + my * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + absMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`,
4366
- "--atomix-glass-overlay-opacity": opacityValues.over,
4367
- "--atomix-glass-overlay-gradient": isOverLight ? `radial-gradient(circle at ${basePosition.x}% ${basePosition.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + absMx * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + absMy * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`,
4368
- "--atomix-glass-overlay-highlight-opacity": opacityValues.over * ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER,
4369
- "--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}%)`
4605
+ // Aliases maintained for backward compatibility and consumer overrides.
4606
+ "--atomix-glass-container-width": adjustedSize.width,
4607
+ "--atomix-glass-container-height": adjustedSize.height,
4608
+ [ATOMIX_GLASS.BORDER.WIDTH_CSS_VAR]: borderWidth,
4609
+ "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay"
4610
+ };
4611
+ }
4612
+ /**
4613
+ * Applies mode-specific multipliers and accessibility overrides to container effects.
4614
+ */ ({
4615
+ effectiveBorderRadius: effectiveBorderRadius,
4616
+ transformStyle: transformStyle,
4617
+ adjustedSize: adjustedSize,
4618
+ isOverLight: isOverLight,
4619
+ customZIndex: customZIndex,
4620
+ isFixedOrSticky: isFixedOrSticky,
4621
+ positionStyles: positionStyles,
4622
+ restStyle: restStyle,
4623
+ borderWidth: resolvedBorder.width
4624
+ })), [ effectiveBorderRadius, transformStyle, adjustedSize, isOverLight, customZIndex, isFixedOrSticky, positionStyles, restStyle, resolvedBorder.width ]), containerEffects = useMemo((() => function(options) {
4625
+ const {MULTIPLIERS: MULTIPLIERS, SATURATION: SATURATION} = ATOMIX_GLASS.CONSTANTS, zeroMouse = {
4626
+ x: 0,
4627
+ y: 0
4628
+ }, resolveSaturation = () => options.effectiveHighContrast ? SATURATION.HIGH_CONTRAST : options.isOverLight ? options.saturation * options.saturationBoost : options.saturation;
4629
+ if (options.effectiveWithoutEffects) return {
4630
+ displacementScale: 0,
4631
+ blurAmount: 0,
4632
+ saturation: resolveSaturation(),
4633
+ aberrationIntensity: 0,
4634
+ mouseOffset: zeroMouse,
4635
+ globalMousePosition: zeroMouse
4636
+ };
4637
+ let resolvedDisplacement = options.displacementScale;
4638
+ "shader" === options.mode ? resolvedDisplacement *= MULTIPLIERS.SHADER_DISPLACEMENT : options.isOverLight && (resolvedDisplacement *= MULTIPLIERS.OVER_LIGHT_DISPLACEMENT);
4639
+ let resolvedAberration = options.aberrationIntensity;
4640
+ return "shader" === options.mode && (resolvedAberration *= MULTIPLIERS.SHADER_ABERRATION),
4641
+ {
4642
+ displacementScale: resolvedDisplacement,
4643
+ blurAmount: options.blurAmount,
4644
+ saturation: resolveSaturation(),
4645
+ aberrationIntensity: resolvedAberration,
4646
+ mouseOffset: options.mouseOffset,
4647
+ globalMousePosition: options.globalMousePosition
4370
4648
  };
4371
- }), [ 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", {
4372
- 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(" ")
4649
+ }({
4650
+ displacementScale: displacementScale,
4651
+ blurAmount: blurAmount,
4652
+ saturation: saturation,
4653
+ aberrationIntensity: aberrationIntensity,
4654
+ mode: mode,
4655
+ effectiveWithoutEffects: effectiveWithoutEffects,
4656
+ effectiveHighContrast: effectiveHighContrast,
4657
+ isOverLight: isOverLight,
4658
+ saturationBoost: overLightConfig.saturationBoost,
4659
+ mouseOffset: mouseOffset,
4660
+ globalMousePosition: globalMousePosition
4661
+ })), [ displacementScale, blurAmount, saturation, aberrationIntensity, mode, effectiveWithoutEffects, effectiveHighContrast, isOverLight, overLightConfig.saturationBoost, mouseOffset, globalMousePosition ]), renderBackgroundLayer = layerType => jsx("div", {
4662
+ "aria-hidden": "true",
4663
+ className: mergeClassNames(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)
4373
4664
  });
4374
- // Calculate position and size styles for internal layers
4375
- // When root is fixed/sticky, internal layers use absolute (relative to root)
4376
- return jsxs("div", {
4665
+ return jsxs("div", {
4377
4666
  ...rest,
4378
4667
  ref: mergedRef,
4379
4668
  className: componentClassName,
4380
- style: {
4381
- ...glassVars
4382
- },
4669
+ style: glassVars,
4383
4670
  role: role || (onClick ? "button" : void 0),
4384
4671
  tabIndex: onClick ? tabIndex ?? 0 : tabIndex,
4385
4672
  "aria-label": ariaLabel,
4386
4673
  "aria-describedby": ariaDescribedBy,
4387
4674
  "aria-disabled": !(!onClick || !effectiveWithoutEffects) || !onClick && void 0,
4388
- "aria-pressed": onClick ? isActive : void 0,
4389
4675
  onKeyDown: onClick ? handleKeyDown : void 0,
4390
4676
  children: [ jsx(AtomixGlassContainer, {
4391
4677
  ref: glassRef,
4392
4678
  contentRef: contentRef,
4393
4679
  className: className,
4394
- style: {
4395
- ...restStyle
4396
- },
4680
+ style: containerStyle,
4397
4681
  borderRadius: effectiveBorderRadius,
4398
- displacementScale: effectiveWithoutEffects ? 0 : "shader" === mode ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_DISPLACEMENT : isOverLight ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.OVER_LIGHT_DISPLACEMENT : displacementScale,
4399
- blurAmount: effectiveWithoutEffects ? 0 : blurAmount,
4400
- saturation: effectiveHighContrast ? ATOMIX_GLASS.CONSTANTS.SATURATION.HIGH_CONTRAST : isOverLight ? saturation * overLightConfig.saturationBoost : saturation,
4401
- aberrationIntensity: effectiveWithoutEffects ? 0 : "shader" === mode ? aberrationIntensity * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_ABERRATION : aberrationIntensity,
4682
+ displacementScale: containerEffects.displacementScale,
4683
+ blurAmount: containerEffects.blurAmount,
4684
+ saturation: containerEffects.saturation,
4685
+ aberrationIntensity: containerEffects.aberrationIntensity,
4402
4686
  glassSize: glassSize,
4403
- padding: padding,
4404
- mouseOffset: effectiveWithoutEffects ? {
4405
- x: 0,
4406
- y: 0
4407
- } : mouseOffset,
4408
- globalMousePosition: effectiveWithoutEffects ? {
4409
- x: 0,
4410
- y: 0
4411
- } : globalMousePosition,
4687
+ mouseOffset: containerEffects.mouseOffset,
4688
+ globalMousePosition: containerEffects.globalMousePosition,
4412
4689
  onMouseEnter: handleMouseEnter,
4413
4690
  onMouseLeave: handleMouseLeave,
4414
4691
  onMouseDown: handleMouseDown,
4415
4692
  onMouseUp: handleMouseUp,
4416
- isHovered: isHovered,
4417
4693
  isActive: isActive,
4418
4694
  overLight: isOverLight,
4419
4695
  overLightConfig: {
@@ -4429,8 +4705,6 @@ function getDevicePreset(presetName) {
4429
4705
  shaderVariant: shaderVariant,
4430
4706
  withLiquidBlur: withLiquidBlur,
4431
4707
  isFixedOrSticky: isFixedOrSticky,
4432
- // Phase 1: Animation System props
4433
- shaderTime: getShaderTime(),
4434
4708
  withTimeAnimation: withTimeAnimation,
4435
4709
  animationSpeed: animationSpeed,
4436
4710
  withMultiLayerDistortion: withMultiLayerDistortion,
@@ -4441,42 +4715,129 @@ function getDevicePreset(presetName) {
4441
4715
  children: children
4442
4716
  }), Boolean(onClick) && jsxs(Fragment, {
4443
4717
  children: [ jsx("div", {
4718
+ "aria-hidden": "true",
4444
4719
  className: ATOMIX_GLASS.HOVER_1_CLASS
4445
4720
  }), jsx("div", {
4721
+ "aria-hidden": "true",
4446
4722
  className: ATOMIX_GLASS.HOVER_2_CLASS
4447
4723
  }), jsx("div", {
4724
+ "aria-hidden": "true",
4448
4725
  className: ATOMIX_GLASS.HOVER_3_CLASS
4449
4726
  }) ]
4450
- }), renderBackgroundLayer("dark"), renderBackgroundLayer("black"), shouldRenderOverLightLayers && jsxs(Fragment, {
4727
+ }), [ "dark", "black" ].map((layerType => jsx(React.Fragment, {
4728
+ children: renderBackgroundLayer(layerType)
4729
+ }, layerType))), shouldRenderOverLightLayers && jsxs(Fragment, {
4451
4730
  children: [ jsx("div", {
4731
+ "aria-hidden": "true",
4452
4732
  className: ATOMIX_GLASS.BASE_LAYER_CLASS
4453
4733
  }), jsx("div", {
4734
+ "aria-hidden": "true",
4454
4735
  className: ATOMIX_GLASS.OVERLAY_LAYER_CLASS
4455
4736
  }), jsx("div", {
4737
+ "aria-hidden": "true",
4456
4738
  className: ATOMIX_GLASS.OVERLAY_HIGHLIGHT_CLASS
4457
4739
  }) ]
4458
- }), withBorder && jsxs(Fragment, {
4740
+ }), resolvedBorder.enabled && jsxs(Fragment, {
4459
4741
  children: [ jsx("span", {
4742
+ "aria-hidden": "true",
4460
4743
  className: ATOMIX_GLASS.BORDER_BACKDROP_CLASS
4461
4744
  }), jsx("span", {
4745
+ "aria-hidden": "true",
4462
4746
  className: ATOMIX_GLASS.BORDER_1_CLASS
4463
4747
  }), jsx("span", {
4748
+ "aria-hidden": "true",
4464
4749
  className: ATOMIX_GLASS.BORDER_2_CLASS
4465
4750
  }) ]
4466
- }), debugPerformance && performanceMetrics && jsx(PerformanceDashboard, {
4467
- metrics: performanceMetrics,
4468
- isVisible: !0,
4469
- onClose: () => {}
4470
4751
  }) ]
4471
4752
  });
4472
4753
  }));
4473
4754
 
4474
- AtomixGlassInner.displayName = "AtomixGlass";
4475
-
4476
4755
  /**
4477
- * AtomixGlass - wrapped with React.memo to prevent unnecessary re-renders.
4478
- * Ref is forwarded to the root `<div>` element.
4756
+ * AtomixGlass - A high-performance glass morphism component with liquid distortion effects
4757
+ *
4758
+ * Features:
4759
+ * - Hardware-accelerated glass effects with SVG filters
4760
+ * - Mouse-responsive liquid distortion
4761
+ * - Dynamic border-radius extraction from children CSS properties
4762
+ * - Automatic light/dark theme detection via overLight prop
4763
+ * - Accessibility and performance optimizations
4764
+ * - Multiple displacement modes (standard, polar, prominent, shader)
4765
+ * - Design token integration for consistent theming
4766
+ * - Focus ring support for keyboard navigation
4767
+ * - Responsive breakpoints for mobile optimization
4768
+ * - Enhanced ARIA attributes for screen readers
4769
+ * - Time-based animation system with FBM distortion
4770
+ * - Device preset optimization for performance/quality balance
4771
+ *
4772
+ * Design System Compliance:
4773
+ * - Uses design tokens for opacity, spacing, and colors
4774
+ * - Follows BEM methodology for class naming
4775
+ * - Implements focus-ring mixin for accessibility
4776
+ * - Supports reduced motion and high contrast preferences
4777
+ *
4778
+ * Style architecture:
4779
+ * - Root (`.c-atomix-glass`): CSS custom properties for layer geometry and motion.
4780
+ * - Container (`.c-atomix-glass__container`): layout, z-index, and backdrop-filter.
4781
+ *
4782
+ * @example
4783
+ * // Basic usage with dynamic border-radius extraction
4784
+ * <AtomixGlass>
4785
+ * <div style={{ borderRadius: '12px' }}>Content with 12px radius</div>
4786
+ * </AtomixGlass>
4787
+ *
4788
+ * @example
4789
+ * // Manual border-radius override
4790
+ * <AtomixGlass borderRadius={20}>
4791
+ * <div>Content with 20px glass radius</div>
4792
+ * </AtomixGlass>
4793
+ *
4794
+ * @example
4795
+ * // Interactive glass with click handler
4796
+ * <AtomixGlass onClick={() => console.log('Clicked')} aria-label="Glass card">
4797
+ * <div>Clickable content</div>
4798
+ * </AtomixGlass>
4799
+ *
4800
+ * @example
4801
+ * // OverLight - Boolean mode (explicit control)
4802
+ * <AtomixGlass overLight={true}>
4803
+ * <div>Content on light background</div>
4804
+ * </AtomixGlass>
4805
+ *
4806
+ * @example
4807
+ * // OverLight - Auto-detection mode
4808
+ * <AtomixGlass overLight="auto">
4809
+ * <div>Content with auto-detected background</div>
4810
+ * </AtomixGlass>
4811
+ *
4812
+ * @example
4813
+ * // OverLight - Object config with custom settings
4814
+ * <AtomixGlass
4815
+ * overLight={{
4816
+ * threshold: 0.8,
4817
+ * opacity: 0.6,
4818
+ * contrast: 1.8,
4819
+ * brightness: 1.0,
4820
+ * saturationBoost: 1.5
4821
+ * }}
4822
+ * >
4823
+ * <div>Content with custom overLight config</div>
4824
+ * </AtomixGlass>
4825
+ *
4826
+ * @example
4827
+ * // Debug mode for overLight detection
4828
+ * <AtomixGlass overLight="auto" debugOverLight={true}>
4829
+ * <div>Content with debug logging enabled</div>
4830
+ * </AtomixGlass>
4831
+ *
4832
+ * @example
4833
+ * // Performance-optimized for mobile devices
4834
+ * <AtomixGlass devicePreset="performance" disableResponsiveBreakpoints={false}>
4835
+ * <div>Mobile-optimized glass effect</div>
4836
+ * </AtomixGlass>
4479
4837
  */
4838
+ /** Internal implementation; ref is forwarded to the root wrapper element. */ AtomixGlassInner.displayName = "AtomixGlass";
4839
+
4840
+ /** Memoized public export. Ref targets the root `.c-atomix-glass` wrapper. */
4480
4841
  const AtomixGlass = memo(AtomixGlassInner), DefaultIcon = () => jsx("i", {
4481
4842
  className: "c-accordion__icon",
4482
4843
  "aria-hidden": "true",
@@ -4604,10 +4965,7 @@ const AccordionImpl = memo((({title: title, children: children, defaultOpen: de
4604
4965
  });
4605
4966
  if (glass) {
4606
4967
  // Default glass settings for accordions
4607
- const defaultGlassProps = {
4608
- displacementScale: 20,
4609
- elasticity: 0
4610
- }, glassProps = !0 === glass ? defaultGlassProps : {
4968
+ const defaultGlassProps = GLASS_DEFAULTS.ACCORDION, glassProps = !0 === glass ? defaultGlassProps : {
4611
4969
  ...defaultGlassProps,
4612
4970
  ...glass
4613
4971
  };
@@ -4640,40 +4998,15 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
4640
4998
  d: "M12 6c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6zm0 10c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4z",
4641
4999
  fill: color
4642
5000
  }) ]
4643
- }), smoothStep = (a, b, t) => {
4644
- // Add input validation
4645
- if ("number" != typeof a || "number" != typeof b || "number" != typeof t) return 0;
4646
- const clamped = Math.max(0, Math.min(1, (t - a) / (b - a)));
4647
- return clamped * clamped * (3 - 2 * clamped);
4648
- }, calculateLength = (x, y) => {
4649
- // Add input validation and error handling
4650
- if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
4651
- // Prevent potential overflow
4652
- const maxX = Math.max(Math.abs(x), Math.abs(y));
4653
- if (0 === maxX) return 0;
4654
- const scaledX = x / maxX, scaledY = y / maxX;
4655
- return maxX * Math.sqrt(scaledX * scaledX + scaledY * scaledY);
4656
- }, roundedRectSDF = (x, y, width, height, radius) => {
5001
+ }), roundedRectSDF = (x, y, width, height, radius) => {
4657
5002
  // Add input validation
4658
5003
  if ("number" != typeof x || "number" != typeof y || "number" != typeof width || "number" != typeof height || "number" != typeof radius) return 0;
4659
5004
  const qx = Math.abs(x) - width + radius, qy = Math.abs(y) - height + radius;
4660
- return Math.min(Math.max(qx, qy), 0) + calculateLength(Math.max(qx, 0), Math.max(qy, 0)) - radius;
5005
+ return Math.min(Math.max(qx, qy), 0) + vec2Length(Math.max(qx, 0), Math.max(qy, 0)) - radius;
4661
5006
  }, createTexture = (x, y) => ({
4662
5007
  x: "number" != typeof x || isNaN(x) ? .5 : Math.max(0, Math.min(1, x)),
4663
5008
  y: "number" != typeof y || isNaN(y) ? .5 : Math.max(0, Math.min(1, y))
4664
- }), validateVec2 = vec => vec && "number" == typeof vec.x && "number" == typeof vec.y && !isNaN(vec.x) && !isNaN(vec.y), clampValue = (value, min, max) =>
4665
- // Add input validation
4666
- "number" != typeof value || "number" != typeof min || "number" != typeof max || isNaN(value) ? min : isNaN(min) ? 0 : isNaN(max) ? 1 : Math.max(min, Math.min(max, value)), easeInOutCubic = t => {
4667
- // Add input validation
4668
- if ("number" != typeof t || isNaN(t)) return 0;
4669
- const clampedT = Math.max(0, Math.min(1, t));
4670
- return clampedT < .5 ? 4 * clampedT * clampedT * clampedT : 1 - Math.pow(-2 * clampedT + 2, 3) / 2;
4671
- }, easeOutQuart = t => {
4672
- // Add input validation
4673
- if ("number" != typeof t || isNaN(t)) return 0;
4674
- const clampedT = Math.max(0, Math.min(1, t));
4675
- return 1 - Math.pow(1 - clampedT, 4);
4676
- }, noise2D = (x, y) => {
5009
+ }), validateVec2 = vec => vec && "number" == typeof vec.x && "number" == typeof vec.y && !isNaN(vec.x) && !isNaN(vec.y), noise2D = (x, y) => {
4677
5010
  // Add input validation
4678
5011
  if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
4679
5012
  const X = 255 & Math.floor(x), Y = 255 & Math.floor(y), xf = x - Math.floor(x), yf = y - Math.floor(y), u = easeInOutCubic(xf), v = easeInOutCubic(yf), hash = (i, j) => {
@@ -4712,13 +5045,13 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
4712
5045
  x: .5,
4713
5046
  y: .5
4714
5047
  };
4715
- const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now(), mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = calculateLength(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(2 * mouseDistance, 1)), organicFlow = fbm(12 * (ix + .5 * mouseX) + time, 12 * (iy + .5 * mouseY) + .7 * time, 3) - .5, distanceToEdge = roundedRectSDF(ix, iy, .4, .3, .35), baseDisplacement = smoothStep(.8, 0, distanceToEdge - .05), radialDist = ((x, y, strength) => {
5048
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now(), mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = vec2Length(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(2 * mouseDistance, 1)), organicFlow = fbm(12 * (ix + .5 * mouseX) + time, 12 * (iy + .5 * mouseY) + .7 * time, 3) - .5, distanceToEdge = roundedRectSDF(ix, iy, .4, .3, .35), baseDisplacement = smoothstepEdge(.8, 0, distanceToEdge - .05), radialDist = ((x, y, strength) => {
4716
5049
  // Add input validation
4717
5050
  if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y) || isNaN(strength)) return {
4718
5051
  x: 0,
4719
5052
  y: 0
4720
5053
  };
4721
- const distance = calculateLength(x, y), distortion = Math.pow(Math.min(distance, 10), 2) * strength;
5054
+ const distance = vec2Length(x, y), distortion = Math.pow(Math.min(distance, 10), 2) * strength;
4722
5055
  // Limit distance to prevent extreme values
4723
5056
  return {
4724
5057
  x: x * (1 + distortion),
@@ -4730,7 +5063,7 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
4730
5063
  x: 0,
4731
5064
  y: 0
4732
5065
  };
4733
- const distance = calculateLength(x, y);
5066
+ const distance = vec2Length(x, y);
4734
5067
  // Prevent division by zero and extreme values
4735
5068
  if (0 === distance) return {
4736
5069
  x: 0,
@@ -4741,8 +5074,8 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
4741
5074
  x: Math.cos(angle) * distance * intensity,
4742
5075
  y: Math.sin(angle) * distance * intensity
4743
5076
  };
4744
- })(ix, iy, .015 * baseDisplacement), scaled = smoothStep(0, 1, 1.15 * baseDisplacement), finalX = ix + totalDistortionX + .5 * chromaticOffset.x, finalY = iy + totalDistortionY + .5 * chromaticOffset.y;
4745
- return createTexture(clampValue(finalX * scaled + .5, 0, 1), clampValue(finalY * scaled + .5, 0, 1));
5077
+ })(ix, iy, .015 * baseDisplacement), scaled = smoothstepEdge(0, 1, 1.15 * baseDisplacement), finalX = ix + totalDistortionX + .5 * chromaticOffset.x, finalY = iy + totalDistortionY + .5 * chromaticOffset.y;
5078
+ return createTexture(clamp(finalX * scaled + .5, 0, 1), clamp(finalY * scaled + .5, 0, 1));
4746
5079
  },
4747
5080
  // Premium Apple-style fluid glass with enhanced organic flow
4748
5081
  appleFluid: (uv, mousePosition) => {
@@ -4750,8 +5083,8 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
4750
5083
  x: .5,
4751
5084
  y: .5
4752
5085
  };
4753
- const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .6, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = calculateLength(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(1.5 * mouseDistance, 1)), organicX = fbm(10 * (ix + .3 * mouseX) + time, 10 * (iy + .3 * mouseY), 5) - .5, organicY = fbm(10 * (ix - .3 * mouseX), 10 * (iy - .3 * mouseY) + .8 * time, 5) - .5, distanceToEdge = roundedRectSDF(ix, iy, .42, .32, .38), mask = smoothStep(.85, -.1, distanceToEdge), fluidVelocityX = Math.sin(6 * ix + 2 * time) * Math.cos(4 * iy - time) * .025, fluidVelocityY = Math.cos(4 * ix - time) * Math.sin(6 * iy + 2 * time) * .025, vortexAngle = Math.atan2(iy - mouseY, ix - mouseX), vortexStrength = mouseFalloff * mouseDistance * .08, vortexX = Math.cos(vortexAngle + time) * vortexStrength, totalY = iy + (.035 * organicY + fluidVelocityY + Math.sin(vortexAngle + time) * vortexStrength) * mask;
4754
- return createTexture(clampValue(ix + (.035 * organicX + fluidVelocityX + vortexX) * mask + .5, 0, 1), clampValue(totalY + .5, 0, 1));
5086
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .6, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = vec2Length(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(1.5 * mouseDistance, 1)), organicX = fbm(10 * (ix + .3 * mouseX) + time, 10 * (iy + .3 * mouseY), 5) - .5, organicY = fbm(10 * (ix - .3 * mouseX), 10 * (iy - .3 * mouseY) + .8 * time, 5) - .5, distanceToEdge = roundedRectSDF(ix, iy, .42, .32, .38), mask = smoothstepEdge(.85, -.1, distanceToEdge), fluidVelocityX = Math.sin(6 * ix + 2 * time) * Math.cos(4 * iy - time) * .025, fluidVelocityY = Math.cos(4 * ix - time) * Math.sin(6 * iy + 2 * time) * .025, vortexAngle = Math.atan2(iy - mouseY, ix - mouseX), vortexStrength = mouseFalloff * mouseDistance * .08, vortexX = Math.cos(vortexAngle + time) * vortexStrength, totalY = iy + (.035 * organicY + fluidVelocityY + Math.sin(vortexAngle + time) * vortexStrength) * mask;
5087
+ return createTexture(clamp(ix + (.035 * organicX + fluidVelocityX + vortexX) * mask + .5, 0, 1), clamp(totalY + .5, 0, 1));
4755
5088
  },
4756
5089
  // High-end glass with advanced refraction and depth
4757
5090
  premiumGlass: (uv, mousePosition) => {
@@ -4759,7 +5092,7 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
4759
5092
  x: .5,
4760
5093
  y: .5
4761
5094
  };
4762
- const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .4, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = calculateLength(mouseX, mouseY), centerDistance = calculateLength(ix, iy), refractionStrength = .3 * Math.pow(Math.min(centerDistance, 1), 1.5), refractionAngle = Math.atan2(iy, ix);
5095
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .4, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = vec2Length(mouseX, mouseY), centerDistance = vec2Length(ix, iy), refractionStrength = .3 * Math.pow(Math.min(centerDistance, 1), 1.5), refractionAngle = Math.atan2(iy, ix);
4763
5096
  // Multi-layer depth effect
4764
5097
  let depthX = 0, depthY = 0;
4765
5098
  for (let layer = 0; layer < 3; layer++) {
@@ -4767,8 +5100,8 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
4767
5100
  depthX += Math.sin(ix * layerScale + layerTime) * layerStrength, depthY += Math.cos(iy * layerScale - layerTime) * layerStrength;
4768
5101
  }
4769
5102
  // Glass refraction with mouse influence
4770
- const refractionX = Math.cos(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), refractionY = Math.sin(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), organicNoise = fbm(8 * ix + time, 8 * iy - time, 2) - .5, distanceToEdge = roundedRectSDF(ix, iy, .43, .33, .36), edgeMask = smoothStep(.9, -.05, distanceToEdge), finalY = iy + (refractionY + depthY + .015 * organicNoise) * edgeMask;
4771
- return createTexture(clampValue(ix + (refractionX + depthX + .015 * organicNoise) * edgeMask + .5, 0, 1), clampValue(finalY + .5, 0, 1));
5103
+ const refractionX = Math.cos(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), refractionY = Math.sin(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), organicNoise = fbm(8 * ix + time, 8 * iy - time, 2) - .5, distanceToEdge = roundedRectSDF(ix, iy, .43, .33, .36), edgeMask = smoothstepEdge(.9, -.05, distanceToEdge), finalY = iy + (refractionY + depthY + .015 * organicNoise) * edgeMask;
5104
+ return createTexture(clamp(ix + (refractionX + depthX + .015 * organicNoise) * edgeMask + .5, 0, 1), clamp(finalY + .5, 0, 1));
4772
5105
  },
4773
5106
  // Metallic liquid effect with shimmer
4774
5107
  liquidMetal: (uv, mousePosition) => {
@@ -4776,8 +5109,8 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
4776
5109
  x: .5,
4777
5110
  y: .5
4778
5111
  };
4779
- const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * 1.2, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, wave1 = Math.sin(20 * ix + 4 * time) * Math.cos(15 * iy - 3 * time) * .02, wave2 = Math.cos(15 * ix - 2 * time) * Math.sin(20 * iy + 5 * time) * .015, shimmer = .025 * fbm(25 * ix + 2 * time, 25 * iy - 2 * time, 4), flowAngle = Math.atan2(iy - mouseY, ix - mouseX), flowDistance = calculateLength(ix - mouseX, iy - mouseY), flowEffect = .02 * Math.sin(15 * flowDistance - 6 * time) * easeOutQuart(1 - Math.min(2 * flowDistance, 1)), distanceToEdge = roundedRectSDF(ix, iy, .41, .31, .37), mask = smoothStep(.88, -.08, distanceToEdge), totalX = ix + (wave1 + shimmer + Math.cos(flowAngle) * flowEffect) * mask, totalY = iy + (wave2 + .8 * shimmer + Math.sin(flowAngle) * flowEffect) * mask;
4780
- return createTexture(clampValue(totalX + .5, 0, 1), clampValue(totalY + .5, 0, 1));
5112
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * 1.2, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, wave1 = Math.sin(20 * ix + 4 * time) * Math.cos(15 * iy - 3 * time) * .02, wave2 = Math.cos(15 * ix - 2 * time) * Math.sin(20 * iy + 5 * time) * .015, shimmer = .025 * fbm(25 * ix + 2 * time, 25 * iy - 2 * time, 4), flowAngle = Math.atan2(iy - mouseY, ix - mouseX), flowDistance = vec2Length(ix - mouseX, iy - mouseY), flowEffect = .02 * Math.sin(15 * flowDistance - 6 * time) * easeOutQuart(1 - Math.min(2 * flowDistance, 1)), distanceToEdge = roundedRectSDF(ix, iy, .41, .31, .37), mask = smoothstepEdge(.88, -.08, distanceToEdge), totalX = ix + (wave1 + shimmer + Math.cos(flowAngle) * flowEffect) * mask, totalY = iy + (wave2 + .8 * shimmer + Math.sin(flowAngle) * flowEffect) * mask;
5113
+ return createTexture(clamp(totalX + .5, 0, 1), clamp(totalY + .5, 0, 1));
4781
5114
  },
4782
5115
  // basiBasi - Expert Premium Glass Shader
4783
5116
  // The most advanced shader with caustics, spectral dispersion, parallax depth, and volumetric effects
@@ -4786,7 +5119,7 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
4786
5119
  x: .5,
4787
5120
  y: .5
4788
5121
  };
4789
- const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .5, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = calculateLength(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(1.2 * mouseDistance, 1)), causticIntensity = ((x, y, time, intensity = 1) =>
5122
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .5, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = vec2Length(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(1.2 * mouseDistance, 1)), causticIntensity = ((x, y, time, intensity = 1) =>
4790
5123
  // Add input validation
4791
5124
  "number" != typeof x || "number" != typeof y || "number" != typeof time || "number" != typeof intensity || isNaN(x) || isNaN(y) || isNaN(time) || isNaN(intensity) ? .5 : .5 * (Math.sin(8 * x + 2 * time) * Math.cos(8 * y - 2 * time) * .5 + Math.sin(8 * (x + .5) * 1.3 - 2 * time * .8) * Math.cos(8 * (y - .3) * 1.3 + 2 * time * .8) * .3 + Math.sin(8 * (x - .3) * .7 + 2 * time * 1.2) * Math.cos(8 * (y + .4) * .7 - 2 * time * 1.2) * .2 + 1) * intensity)(ix, iy, time, .8), causticDistortion = .02 * (causticIntensity - .5), refractionAngle = Math.atan2(iy, ix), spectralDispersion = ((x, y, angle) => {
4792
5125
  // Add input validation
@@ -4804,7 +5137,7 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
4804
5137
  y: 0
4805
5138
  }
4806
5139
  };
4807
- const distance = calculateLength(x, y), dispersionStrength = Math.min(.025 * distance, 1), redOffset = .8 * dispersionStrength, greenOffset = 1 * dispersionStrength, blueOffset = 1.2 * dispersionStrength;
5140
+ const distance = vec2Length(x, y), dispersionStrength = Math.min(.025 * distance, 1), redOffset = .8 * dispersionStrength, greenOffset = 1 * dispersionStrength, blueOffset = 1.2 * dispersionStrength;
4808
5141
  return {
4809
5142
  r: {
4810
5143
  x: Math.cos(angle) * redOffset,
@@ -4844,8 +5177,8 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
4844
5177
  return turbulence;
4845
5178
  })(6 * ix, 6 * iy, time, 6), turbulenceX = .012 * Math.cos(turbulence * Math.PI * 2), turbulenceY = .012 * Math.sin(turbulence * Math.PI * 2), microSurface = ((x, y, time) =>
4846
5179
  // Add input validation
4847
- "number" != typeof x || "number" != typeof y || "number" != typeof time || isNaN(x) || isNaN(y) || isNaN(time) ? .5 : .5 * (.7 * fbm(40 * x + .3 * time, 40 * y - .3 * time, 6) + .3 * fbm(80 * x, 80 * y, 4)))(ix, iy, time), microDetailX = .008 * (microSurface - .5), microDetailY = .008 * (microSurface - .5), centerDistance = calculateLength(ix, iy), dynamicRefraction = .35 * Math.pow(Math.min(centerDistance, 1), 1.8) * (1 + mouseFalloff * mouseDistance * .8), refractionX = Math.cos(refractionAngle) * dynamicRefraction, refractionY = Math.sin(refractionAngle) * dynamicRefraction, vortexAngle = Math.atan2(iy - mouseY, ix - mouseX), vortexDistance = calculateLength(ix - mouseX, iy - mouseY), vortexStrength = mouseFalloff * Math.sin(10 * vortexDistance - 3 * time) * .025, vortexX = Math.cos(vortexAngle + 2 * time) * vortexStrength, vortexY = Math.sin(vortexAngle + 2 * time) * vortexStrength, fluidX = Math.sin(10 * ix + 5 * mouseX + 2.5 * time) * Math.cos(8 * iy - 2 * time) * .018, fluidY = Math.cos(8 * ix - 2 * time) * Math.sin(10 * iy + 5 * mouseY + 2.5 * time) * .018, rippleEffect = (.012 * Math.sin(15 * Math.min(centerDistance, 10) - 4 * time) + .008 * Math.cos(20 * Math.min(centerDistance, 10) + 3 * time)) * mouseFalloff, rippleX = Math.cos(refractionAngle) * rippleEffect, rippleY = Math.sin(refractionAngle) * rippleEffect, distanceToEdge = roundedRectSDF(ix, iy, .44, .34, .39), edgeMask = smoothStep(.92, -.12, distanceToEdge), edgeSoftness = smoothStep(.85, .1, distanceToEdge), finalY = iy + (1.2 * refractionY + .8 * spectralY + 1.5 * parallaxY + .9 * scatteringY + 1 * turbulenceY + .6 * microDetailY + 1.3 * vortexY + 1.1 * fluidY + .7 * rippleY + .8 * causticDistortion) * edgeMask * edgeSoftness * .85;
4848
- return createTexture(clampValue(ix + (1.2 * refractionX + .8 * spectralX + 1.5 * parallaxX + .9 * scatteringX + 1 * turbulenceX + .6 * microDetailX + 1.3 * vortexX + 1.1 * fluidX + .7 * rippleX + causticDistortion) * edgeMask * edgeSoftness * .85 + .5, 0, 1), clampValue(finalY + .5, 0, 1));
5180
+ "number" != typeof x || "number" != typeof y || "number" != typeof time || isNaN(x) || isNaN(y) || isNaN(time) ? .5 : .5 * (.7 * fbm(40 * x + .3 * time, 40 * y - .3 * time, 6) + .3 * fbm(80 * x, 80 * y, 4)))(ix, iy, time), microDetailX = .008 * (microSurface - .5), microDetailY = .008 * (microSurface - .5), centerDistance = vec2Length(ix, iy), dynamicRefraction = .35 * Math.pow(Math.min(centerDistance, 1), 1.8) * (1 + mouseFalloff * mouseDistance * .8), refractionX = Math.cos(refractionAngle) * dynamicRefraction, refractionY = Math.sin(refractionAngle) * dynamicRefraction, vortexAngle = Math.atan2(iy - mouseY, ix - mouseX), vortexDistance = vec2Length(ix - mouseX, iy - mouseY), vortexStrength = mouseFalloff * Math.sin(10 * vortexDistance - 3 * time) * .025, vortexX = Math.cos(vortexAngle + 2 * time) * vortexStrength, vortexY = Math.sin(vortexAngle + 2 * time) * vortexStrength, fluidX = Math.sin(10 * ix + 5 * mouseX + 2.5 * time) * Math.cos(8 * iy - 2 * time) * .018, fluidY = Math.cos(8 * ix - 2 * time) * Math.sin(10 * iy + 5 * mouseY + 2.5 * time) * .018, rippleEffect = (.012 * Math.sin(15 * Math.min(centerDistance, 10) - 4 * time) + .008 * Math.cos(20 * Math.min(centerDistance, 10) + 3 * time)) * mouseFalloff, rippleX = Math.cos(refractionAngle) * rippleEffect, rippleY = Math.sin(refractionAngle) * rippleEffect, distanceToEdge = roundedRectSDF(ix, iy, .44, .34, .39), edgeMask = smoothstepEdge(.92, -.12, distanceToEdge), edgeSoftness = smoothstepEdge(.85, .1, distanceToEdge), finalY = iy + (1.2 * refractionY + .8 * spectralY + 1.5 * parallaxY + .9 * scatteringY + 1 * turbulenceY + .6 * microDetailY + 1.3 * vortexY + 1.1 * fluidY + .7 * rippleY + .8 * causticDistortion) * edgeMask * edgeSoftness * .85;
5181
+ return createTexture(clamp(ix + (1.2 * refractionX + .8 * spectralX + 1.5 * parallaxX + .9 * scatteringX + 1 * turbulenceX + .6 * microDetailX + 1.3 * vortexX + 1.1 * fluidX + .7 * rippleX + causticDistortion) * edgeMask * edgeSoftness * .85 + .5, 0, 1), clamp(finalY + .5, 0, 1));
4849
5182
  },
4850
5183
  // Aliases for compatibility
4851
5184
  plasma: (uv, mousePosition) => fragmentShaders.premiumGlass(uv, mousePosition),
@@ -4887,8 +5220,8 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
4887
5220
  let dx = pos.x * w - x, dy = pos.y * h - y;
4888
5221
  // Apply edge smoothing for Apple-like effect
4889
5222
  const edgeX = 2 * Math.min(x / w, (w - x) / w), edgeY = 2 * Math.min(y / h, (h - y) / h), edgeFactor = Math.min(edgeX, edgeY);
4890
- dx *= smoothStep(0, .2, edgeFactor), dy *= smoothStep(0, .2, edgeFactor), maxScale = Math.max(maxScale, Math.abs(dx), Math.abs(dy)),
4891
- rawValues.push(dx, dy);
5223
+ dx *= smoothstepEdge(0, .2, edgeFactor), dy *= smoothstepEdge(0, .2, edgeFactor),
5224
+ maxScale = Math.max(maxScale, Math.abs(dx), Math.abs(dy)), rawValues.push(dx, dy);
4892
5225
  }
4893
5226
  // Improved normalization to prevent artifacts while maintaining intensity
4894
5227
  maxScale = Math.max(maxScale, 1);
@@ -4898,9 +5231,9 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
4898
5231
  let rawIndex = 0;
4899
5232
  for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) {
4900
5233
  const dx = rawValues[rawIndex++] || 0, dy = rawValues[rawIndex++] || 0, edgeDistance = Math.min(x, y, w - x - 1, h - y - 1), edgeFactor = Math.min(1, edgeDistance / 2), r = dx * edgeFactor / maxScale + .5, g = dy * edgeFactor / maxScale + .5, pixelIndex = 4 * (y * w + x);
4901
- data[pixelIndex] = clampValue(255 * r, 0, 255), // Red channel (X displacement)
4902
- data[pixelIndex + 1] = clampValue(255 * g, 0, 255), // Green channel (Y displacement)
4903
- data[pixelIndex + 2] = clampValue(255 * g, 0, 255), // Blue channel (Y displacement for SVG filter compatibility)
5234
+ data[pixelIndex] = clamp(255 * r, 0, 255), // Red channel (X displacement)
5235
+ data[pixelIndex + 1] = clamp(255 * g, 0, 255), // Green channel (Y displacement)
5236
+ data[pixelIndex + 2] = clamp(255 * g, 0, 255), // Blue channel (Y displacement for SVG filter compatibility)
4904
5237
  data[pixelIndex + 3] = 255;
4905
5238
  }
4906
5239
  return this.context.putImageData(imageData, 0, 0), this.canvas.toDataURL();
@@ -4928,9 +5261,7 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
4928
5261
  return this.canvasDPI;
4929
5262
  }
4930
5263
  },
4931
- createFBMEngine: createFBMEngine,
4932
- fragmentShaders: fragmentShaders,
4933
- liquidGlassWithTime: liquidGlassWithTime
5264
+ fragmentShaders: fragmentShaders
4934
5265
  }, Symbol.toStringTag, {
4935
5266
  value: "Module"
4936
5267
  })), sizeMap = {
@@ -5073,10 +5404,10 @@ const Badge = memo((({label: label, variant: variant = "primary", size: size =
5073
5404
  if (glass) {
5074
5405
  // Default glass settings for badges
5075
5406
  const defaultGlassProps = {
5076
- displacementScale: 20,
5077
- borderRadius: ref.current?.getBoundingClientRect().width ? ref.current?.getBoundingClientRect().width / 2 : 16,
5078
- className: "c-badge--glass",
5079
- elasticity: 0
5407
+ ...GLASS_DEFAULTS.BADGE,
5408
+ // Override borderRadius dynamically if the ref is available
5409
+ borderRadius: ref.current?.getBoundingClientRect().width ? ref.current?.getBoundingClientRect().width / 2 : GLASS_DEFAULTS.BADGE.borderRadius,
5410
+ className: "c-badge--glass"
5080
5411
  }, glassProps = !0 === glass ? defaultGlassProps : {
5081
5412
  ...defaultGlassProps,
5082
5413
  ...glass
@@ -5327,12 +5658,7 @@ const Spinner = memo( forwardRef((({size: size = "md", variant: variant = "prim
5327
5658
  })
5328
5659
  });
5329
5660
  if (glass) {
5330
- const defaultGlassProps = {
5331
- displacementScale: 20,
5332
- blurAmount: 1,
5333
- borderRadius: 999,
5334
- mode: "shader"
5335
- }, glassProps = !0 === glass ? defaultGlassProps : {
5661
+ const defaultGlassProps = GLASS_DEFAULTS.SPINNER, glassProps = !0 === glass ? defaultGlassProps : {
5336
5662
  ...defaultGlassProps,
5337
5663
  ...glass
5338
5664
  };
@@ -5434,62 +5760,6 @@ class ThemeNaming {
5434
5760
  }
5435
5761
  }
5436
5762
 
5437
- ThemeNaming.prefix = "atomix";
5438
-
5439
- var aCallable = aCallable$3, toObject = toObject$2, IndexedObject = indexedObject, lengthOfArrayLike = lengthOfArrayLike$2, $TypeError = TypeError, REDUCE_EMPTY = "Reduce of empty array with no initial value", createMethod = function(IS_RIGHT) {
5440
- return function(that, callbackfn, argumentsLength, memo) {
5441
- var O = toObject(that), self = IndexedObject(O), length = lengthOfArrayLike(O);
5442
- if (aCallable(callbackfn), 0 === length && argumentsLength < 2) throw new $TypeError(REDUCE_EMPTY);
5443
- var index = IS_RIGHT ? length - 1 : 0, i = IS_RIGHT ? -1 : 1;
5444
- if (argumentsLength < 2) for (;;) {
5445
- if (index in self) {
5446
- memo = self[index], index += i;
5447
- break;
5448
- }
5449
- if (index += i, IS_RIGHT ? index < 0 : length <= index) throw new $TypeError(REDUCE_EMPTY);
5450
- }
5451
- for (;IS_RIGHT ? index >= 0 : length > index; index += i) index in self && (memo = callbackfn(memo, self[index], index, O));
5452
- return memo;
5453
- };
5454
- }, arrayReduce = {
5455
- // `Array.prototype.reduce` method
5456
- // https://tc39.es/ecma262/#sec-array.prototype.reduce
5457
- left: createMethod(!1),
5458
- // `Array.prototype.reduceRight` method
5459
- // https://tc39.es/ecma262/#sec-array.prototype.reduceright
5460
- right: createMethod(!0)
5461
- }, fails = fails$9, globalThis$1 = globalThis_1, userAgent = environmentUserAgent, classof = classofRaw$2, userAgentStartsWith = function(string) {
5462
- return userAgent.slice(0, string.length) === string;
5463
- }, environment = userAgentStartsWith("Bun/") ? "BUN" : userAgentStartsWith("Cloudflare-Workers") ? "CLOUDFLARE" : userAgentStartsWith("Deno/") ? "DENO" : userAgentStartsWith("Node.js/") ? "NODE" : globalThis$1.Bun && "string" == typeof Bun.version ? "BUN" : globalThis$1.Deno && "object" == typeof Deno.version ? "DENO" : "process" === classof(globalThis$1.process) ? "NODE" : globalThis$1.window && globalThis$1.document ? "BROWSER" : "REST", $reduce = arrayReduce.left;
5464
-
5465
- // `Array.prototype.reduce` method
5466
- // https://tc39.es/ecma262/#sec-array.prototype.reduce
5467
- _export({
5468
- target: "Array",
5469
- proto: !0,
5470
- forced: !("NODE" === environment) && environmentV8Version > 79 && environmentV8Version < 83 || !function(METHOD_NAME, argument) {
5471
- var method = [][METHOD_NAME];
5472
- return !!method && fails((function() {
5473
- // eslint-disable-next-line no-useless-call -- required for testing
5474
- method.call(null, argument || function() {
5475
- return 1;
5476
- }, 1);
5477
- }));
5478
- }("reduce")
5479
- }, {
5480
- reduce: function(callbackfn /* , initialValue */) {
5481
- var length = arguments.length;
5482
- return $reduce(this, callbackfn, length, length > 1 ? arguments[1] : void 0);
5483
- }
5484
- });
5485
-
5486
- var reduce$3 = getBuiltInPrototypeMethod$3("Array", "reduce"), isPrototypeOf = objectIsPrototypeOf, method = reduce$3, ArrayPrototype = Array.prototype;
5487
-
5488
- const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
5489
- var own = it.reduce;
5490
- return it === ArrayPrototype || isPrototypeOf(ArrayPrototype, it) && own === ArrayPrototype.reduce ? method : own;
5491
- }));
5492
-
5493
5763
  /**
5494
5764
  * Render a slot with the given props
5495
5765
  *
@@ -5504,7 +5774,8 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
5504
5774
  * { render: (props) => <CustomButton {...props} /> },
5505
5775
  * { onClick: handleClick, children: 'Click me' }
5506
5776
  * )
5507
- */ function renderSlot(slot, props, fallback) {
5777
+ */
5778
+ function renderSlot(slot, props, fallback) {
5508
5779
  // No slot provided, use fallback
5509
5780
  if (!slot) return fallback;
5510
5781
  // Slot is a plain React node
@@ -5581,6 +5852,8 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
5581
5852
  return React.useMemo((() => renderSlot(slot, props, fallback)), [ slot, props, fallback ]);
5582
5853
  }
5583
5854
 
5855
+ ThemeNaming.prefix = "atomix";
5856
+
5584
5857
  const Button = React.memo( forwardRef((({label: label, children: children, onClick: onClick, variant: variant = "primary", size: size = "md", disabled: disabled = !1, loading: loading = !1, loadingText: loadingText, icon: icon, iconName: iconName, iconSize: iconSize = "sm", iconPosition: iconPosition = "start", iconOnly: iconOnly = !1, rounded: rounded = !1, fullWidth: fullWidth = !1, block: block = !1, active: active = !1, selected: selected = !1, type: type = "button", className: className = "", as: Component = "button", href: href, target: target, glass: glass, onHover: onHover, onFocus: onFocus, onBlur: onBlur, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, "aria-expanded": ariaExpanded, "aria-controls": ariaControls, tabIndex: tabIndex, style: style, linkComponent: linkComponent, slots: slots, ...props}, ref) => {
5585
5858
  const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href), iconElement = iconName ? jsx(Icon, {
5586
5859
  name: iconName,
@@ -5689,11 +5962,7 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
5689
5962
  // This is a safe fallback for disabled links.
5690
5963
  if (glass) {
5691
5964
  // Default glass props
5692
- const defaultGlassProps = {
5693
- displacementScale: 20,
5694
- blurAmount: 0,
5695
- saturation: 200
5696
- }, glassProps = !0 === glass ? defaultGlassProps : {
5965
+ const defaultGlassProps = GLASS_DEFAULTS.BUTTON, glassProps = !0 === glass ? defaultGlassProps : {
5697
5966
  ...defaultGlassProps,
5698
5967
  ...glass
5699
5968
  };
@@ -5892,11 +6161,7 @@ const Callout = memo((({title: title, children: children, icon: icon, variant:
5892
6161
  // Determine appropriate ARIA attributes based on variant
5893
6162
  if (glass) {
5894
6163
  // Default glass settings for callouts
5895
- const defaultGlassProps = {
5896
- displacementScale: 30,
5897
- borderRadius: 8,
5898
- elasticity: 0
5899
- }, glassProps = !0 === glass ? defaultGlassProps : {
6164
+ const defaultGlassProps = GLASS_DEFAULTS.CALLOUT, glassProps = !0 === glass ? defaultGlassProps : {
5900
6165
  ...defaultGlassProps,
5901
6166
  ...glass
5902
6167
  };
@@ -10698,15 +10963,7 @@ const range = (start, end) => {
10698
10963
  }) ]
10699
10964
  });
10700
10965
  if (glass) {
10701
- // Default glass settings for pagination
10702
- const defaultGlassProps = {
10703
- displacementScale: 60,
10704
- blurAmount: 1,
10705
- saturation: 160,
10706
- aberrationIntensity: .5,
10707
- borderRadius: 8,
10708
- mode: "shader"
10709
- }, glassProps = !0 === glass ? defaultGlassProps : {
10966
+ const defaultGlassProps = GLASS_DEFAULTS.PAGINATION, glassProps = !0 === glass ? defaultGlassProps : {
10710
10967
  ...defaultGlassProps,
10711
10968
  ...glass
10712
10969
  };
@@ -10770,14 +11027,7 @@ const Checkbox = React.memo( forwardRef((({label: label, checked: checked, onCh
10770
11027
  style: style,
10771
11028
  children: inputElement
10772
11029
  }), glass) {
10773
- const defaultGlassProps = {
10774
- displacementScale: 40,
10775
- blurAmount: 1,
10776
- saturation: 160,
10777
- aberrationIntensity: .3,
10778
- borderRadius: 6,
10779
- mode: "shader"
10780
- }, glassProps = !0 === glass ? defaultGlassProps : {
11030
+ const defaultGlassProps = GLASS_DEFAULTS.CHECKBOX, glassProps = !0 === glass ? defaultGlassProps : {
10781
11031
  ...defaultGlassProps,
10782
11032
  ...glass
10783
11033
  };
@@ -11038,13 +11288,8 @@ const DropdownStyleContext = createContext({}), Dropdown = memo((function({chi
11038
11288
  "aria-orientation": "vertical",
11039
11289
  "aria-hidden": !isOpen,
11040
11290
  onKeyDown: handleKeyDown,
11041
- children: glass ?
11042
- // Default glass settings for dropdowns
11043
- (() => {
11044
- const defaultGlassProps = {
11045
- displacementScale: 20,
11046
- elasticity: 0
11047
- }, glassProps = !0 === glass ? defaultGlassProps : {
11291
+ children: glass ? (() => {
11292
+ const defaultGlassProps = GLASS_DEFAULTS.DROPDOWN, glassProps = !0 === glass ? defaultGlassProps : {
11048
11293
  ...defaultGlassProps,
11049
11294
  ...glass
11050
11295
  };
@@ -12607,17 +12852,9 @@ const Input = memo( forwardRef((({type: type = "text", value: value, defaultVal
12607
12852
  style: glass ? {
12608
12853
  ...style
12609
12854
  } : style
12610
- });
12611
- if (glass) {
12612
- // Default glass settings for inputs
12613
- const defaultGlassProps = {
12614
- displacementScale: 60,
12615
- blurAmount: 1,
12616
- saturation: 180,
12617
- aberrationIntensity: .2,
12618
- borderRadius: 12,
12619
- mode: "shader"
12620
- }, glassProps = !0 === glass ? defaultGlassProps : {
12855
+ });
12856
+ if (glass) {
12857
+ const defaultGlassProps = GLASS_DEFAULTS.INPUT, glassProps = !0 === glass ? defaultGlassProps : {
12621
12858
  ...defaultGlassProps,
12622
12859
  ...glass
12623
12860
  };
@@ -12802,497 +13039,291 @@ function useHero(initialProps) {
12802
13039
  },
12803
13040
  generateContentColClass: (size = defaultProps.contentColSize || 5, customClass) => {
12804
13041
  const classes = [ `o-grid__col o-grid__col--md-${size}` ];
12805
- // Handle mobile stacking order
12806
- return defaultProps.reverseOnMobile && ("right" === defaultProps.alignment || "center" === defaultProps.alignment ? classes.push("u-order-last u-order-md-first") : classes.push("u-order-first u-order-md-last")),
12807
- customClass && classes.push(customClass), classes.join(" ");
12808
- },
12809
- hasBackgroundImage: hasBackgroundImage,
12810
- hasForegroundImage: hasForegroundImage,
12811
- useGridLayout: useGridLayout,
12812
- heroRef: heroRef,
12813
- videoRef: videoRef,
12814
- applyParallaxEffect: applyParallaxEffect,
12815
- removeParallaxEffect: removeParallaxEffect,
12816
- backgroundSlider: backgroundSlider,
12817
- hasBackgroundSlider: hasBackgroundSlider
12818
- };
12819
- }
12820
-
12821
- /**
12822
- * Hook for River component functionality
12823
- * @param initialProps - Initial river props
12824
- * @returns River methods and state
12825
- */ function useRiver(initialProps) {
12826
- const defaultProps = {
12827
- center: !1,
12828
- breakout: !1,
12829
- reverse: !1,
12830
- imageAlt: "Image",
12831
- showOverlay: !0,
12832
- ...initialProps
12833
- };
12834
- /**
12835
- * Check if the river has a background image
12836
- */ return {
12837
- generateRiverClassNames: (baseClassName = "") => {
12838
- const classes = [ RIVER.SELECTORS.RIVER.replace(".", "") ];
12839
- // Add layout classes
12840
- return defaultProps.center && classes.push(RIVER.CLASSES.CENTER), defaultProps.breakout && classes.push(RIVER.CLASSES.BREAKOUT),
12841
- defaultProps.reverse && classes.push(RIVER.CLASSES.REVERSE), baseClassName && classes.push(baseClassName),
12842
- classes.join(" ");
12843
- },
12844
- generateContentClass: () => RIVER.SELECTORS.CONTENT.replace(".", ""),
12845
- generateVisualClass: () => RIVER.SELECTORS.VISUAL.replace(".", ""),
12846
- hasBackgroundImage: !!defaultProps.backgroundImageSrc,
12847
- hasForegroundImage: !!defaultProps.imageSrc,
12848
- textContent: "string" == typeof defaultProps.text ? [ defaultProps.text ] : defaultProps.text || []
12849
- };
12850
- }
12851
-
12852
- /**
12853
- * Navbar state and functionality
12854
- * @param initialProps - Initial navbar properties
12855
- * @returns Navbar state and methods
12856
- */ function useNavbar(initialProps) {
12857
- // Default navbar properties
12858
- const defaultProps = {
12859
- position: "static",
12860
- collapsible: !0,
12861
- backdrop: !1,
12862
- closeOnOutsideClick: !0,
12863
- closeOnEscape: !0,
12864
- "aria-label": "Main navigation",
12865
- ...initialProps
12866
- }, [isExpanded, setIsExpanded] = useState(defaultProps.expanded || !1);
12867
- // Local expanded state for when not controlled externally
12868
- return {
12869
- defaultProps: defaultProps,
12870
- isExpanded: isExpanded,
12871
- setIsExpanded: setIsExpanded,
12872
- generateNavbarClass: props => {
12873
- const {position: position = defaultProps.position, variant: variant, collapsible: collapsible = defaultProps.collapsible, className: className = ""} = props;
12874
- return `c-navbar ${"static" !== position ? `c-navbar--${position}` : ""} ${variant ? `c-navbar--${variant}` : ""} ${collapsible ? "c-navbar--collapsible" : ""} ${className}`.trim();
12875
- },
12876
- generateContainerStyle: width => width ? {
12877
- maxWidth: width
12878
- } : {},
12879
- generateCollapseClass: expanded => ("c-navbar__collapse " + (expanded ? "is-expanded" : "")).trim(),
12880
- toggleExpanded: () => {
12881
- const newState = !isExpanded;
12882
- setIsExpanded(newState), defaultProps.onToggle && defaultProps.onToggle(newState);
12883
- },
12884
- getExpandedState: controlled => void 0 !== controlled ? controlled : isExpanded
12885
- };
12886
- }
12887
-
12888
- /**
12889
- * Nav state and functionality
12890
- * @param initialProps - Initial nav properties
12891
- * @returns Nav state and methods
12892
- */ function useNav(initialProps) {
12893
- // Default nav properties
12894
- const defaultProps = {
12895
- alignment: "start",
12896
- variant: "default",
12897
- ...initialProps
12898
- };
12899
- /**
12900
- * Generate nav class based on properties
12901
- * @param props - Nav properties
12902
- * @returns Class string
12903
- */ return {
12904
- defaultProps: defaultProps,
12905
- generateNavClass: props => {
12906
- const {alignment: alignment = defaultProps.alignment, variant: variant = defaultProps.variant, className: className = ""} = props;
12907
- return `c-nav ${"start" !== alignment ? `c-nav--${alignment}` : ""} ${"default" !== variant ? `c-nav--${variant}` : ""} ${className}`.trim();
12908
- }
12909
- };
12910
- }
12911
-
12912
- /**
12913
- * Nav item state and functionality
12914
- * @param initialProps - Initial nav item properties
12915
- * @returns Nav item state and methods
12916
- */ function useNavItem(initialProps) {
12917
- // Default nav item properties
12918
- const defaultProps = {
12919
- dropdown: !1,
12920
- megaMenu: !1,
12921
- active: !1,
12922
- ...initialProps
12923
- };
12924
- /**
12925
- * Generate nav item class based on properties
12926
- * @param props - Nav item properties
12927
- * @returns Class string
12928
- */ return {
12929
- defaultProps: defaultProps,
12930
- generateNavItemClass: props => {
12931
- const {dropdown: dropdown = defaultProps.dropdown, megaMenu: megaMenu = defaultProps.megaMenu, active: active = defaultProps.active, disabled: disabled = defaultProps.disabled, className: className = ""} = props;
12932
- // Apply dropdown class only for regular dropdowns, not mega menus
12933
- return `c-nav__item ${dropdown && !megaMenu ? NAV.SELECTORS.DROPDOWN.replace(".", "") : ""} ${megaMenu ? "c-nav__item--mega-menu" : ""} ${active ? NAV.CLASSES.ACTIVE : ""} ${disabled ? NAV.CLASSES.DISABLED : ""} ${className}`.trim();
12934
- },
12935
- generateNavLinkClass: (active = !1, disabled = !1, className = "") => `c-nav__link ${active ? NAV.CLASSES.ACTIVE : ""} ${disabled ? "c-nav__link--disabled" : ""} ${className}`.trim(),
12936
- handleClick: handler => e => {
12937
- !defaultProps.disabled && handler ? handler() : e.preventDefault();
12938
- }
12939
- };
12940
- }
12941
-
12942
- /**
12943
- * Nav dropdown state and functionality
12944
- * @param initialProps - Initial dropdown properties
12945
- * @returns Dropdown state and methods
12946
- */ function useNavDropdown(initialProps) {
12947
- // Default dropdown properties
12948
- const defaultProps = {
12949
- alignment: "start",
12950
- megaMenu: !1,
12951
- ...initialProps
12952
- }, isInFixedBottomNavbar = () => null !== document.querySelector(".c-navbar--fixed-bottom");
12953
- /**
12954
- * Generate dropdown menu class based on properties
12955
- * @param props - Dropdown properties
12956
- * @returns Class string
12957
- */ return {
12958
- defaultProps: defaultProps,
12959
- generateDropdownMenuClass: props => {
12960
- const {alignment: alignment = defaultProps.alignment, megaMenu: megaMenu = defaultProps.megaMenu, className: className = ""} = props, baseClass = megaMenu ? NAV.SELECTORS.MEGA_MENU.replace(".", "") : NAV.SELECTORS.DROPDOWN_MENU.replace(".", "");
12961
- // Select the base class based on mega menu or regular dropdown
12962
- // Add alignment class if not default 'start'
12963
- let alignmentClass = "";
12964
- return "center" === alignment ? alignmentClass = `${baseClass}--center` : "end" === alignment && (alignmentClass = `${baseClass}--end`),
12965
- `${baseClass} ${alignmentClass} ${className}`.trim();
12966
- },
12967
- isInFixedBottomNavbar: isInFixedBottomNavbar,
12968
- getIconName: (isMegaMenu = !1) => isInFixedBottomNavbar() ? "CaretUp" : "CaretDown"
12969
- };
12970
- }
12971
-
12972
- /**
12973
- * SideMenu state and functionality
12974
- * @param initialProps - Initial side menu properties
12975
- * @returns SideMenu state and methods
12976
- */ function useSideMenu(initialProps) {
12977
- const {collapsible: collapsible = !0, collapsibleDesktop: collapsibleDesktop = !1, defaultCollapsedDesktop: defaultCollapsedDesktop = !1, isOpen: isOpen, onToggle: onToggle, disabled: disabled = !1} = initialProps || {}, [isOpenState, setIsOpenState] = useState(void 0 !== defaultCollapsedDesktop ? !defaultCollapsedDesktop : isOpen || !1), wrapperRef = useRef(null), innerRef = useRef(null), sideMenuRef = useRef(null);
12978
- // Local open state for when not controlled externally
12979
- // Update local state when external state changes
12980
- useEffect((() => {
12981
- void 0 !== isOpen ? setIsOpenState(isOpen) : void 0 !== defaultCollapsedDesktop && setIsOpenState(!defaultCollapsedDesktop);
12982
- }), [ isOpen, defaultCollapsedDesktop ]),
12983
- // Set initial height on mount
12984
- useEffect((() => {
12985
- const shouldCollapse = window.innerWidth < 768 ? collapsible : collapsibleDesktop, currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
12986
- if (shouldCollapse && wrapperRef.current && innerRef.current) {
12987
- // Use setTimeout to ensure DOM is fully rendered
12988
- const timeoutId = setTimeout((() => {
12989
- wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
12990
- }), 0);
12991
- return () => clearTimeout(timeoutId);
12992
- }
12993
- !shouldCollapse && wrapperRef.current && (wrapperRef.current.style.height = "auto");
12994
- }), [ collapsible, collapsibleDesktop, isOpen, isOpenState ]),
12995
- // Handle responsive behavior - vertical collapse for both mobile and desktop
12996
- useEffect((() => {
12997
- const handleResize = () => {
12998
- if (window.innerWidth < 768 ? collapsible : collapsibleDesktop) {
12999
- if (wrapperRef.current && innerRef.current) {
13000
- // Set proper height for vertical animation (both mobile and desktop)
13001
- const currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
13002
- // Use requestAnimationFrame to ensure DOM is ready
13003
- requestAnimationFrame((() => {
13004
- wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
13005
- }));
13006
- }
13007
- } else
13008
- // Not collapsible - always show content
13009
- wrapperRef.current && (wrapperRef.current.style.height = "auto");
13010
- }, timeoutId = setTimeout(handleResize, 0);
13011
- // Initial call with a small delay to ensure DOM is ready
13012
- return window.addEventListener("resize", handleResize), () => {
13013
- clearTimeout(timeoutId), window.removeEventListener("resize", handleResize);
13014
- };
13015
- }), [ collapsible, collapsibleDesktop, isOpen, onToggle, isOpenState ]),
13016
- // Update wrapper height when open state changes (both mobile and desktop)
13017
- useEffect((() => {
13018
- const shouldCollapse = window.innerWidth < 768 ? collapsible : collapsibleDesktop;
13019
- if (shouldCollapse && wrapperRef.current && innerRef.current) {
13020
- const currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
13021
- // Use requestAnimationFrame to ensure DOM is ready
13022
- requestAnimationFrame((() => {
13023
- wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
13024
- }));
13025
- } else !shouldCollapse && wrapperRef.current && (
13026
- // Not collapsible - always show content
13027
- wrapperRef.current.style.height = "auto");
13028
- }), [ isOpen, isOpenState, collapsible, collapsibleDesktop ]);
13029
- /**
13030
- * Generate side menu class based on properties
13031
- * @param props - Side menu properties
13032
- * @returns Class string
13033
- */
13034
- const handleToggle = () => {
13035
- if (disabled) return;
13036
- const newState = void 0 !== isOpen ? !isOpen : !isOpenState;
13037
- "function" == typeof onToggle ?
13038
- // Controlled component
13039
- onToggle(newState) :
13040
- // Uncontrolled component
13041
- setIsOpenState(newState);
13042
- }, getCurrentOpenState = () => void 0 !== isOpen ? isOpen : isOpenState;
13043
- /**
13044
- * Generate wrapper class
13045
- * @returns Class string
13046
- */ return {
13047
- isOpenState: getCurrentOpenState(),
13048
- wrapperRef: wrapperRef,
13049
- innerRef: innerRef,
13050
- sideMenuRef: sideMenuRef,
13051
- generateSideMenuClass: props => {
13052
- const {className: className = "", isOpen: isOpen = !1} = props, openClass = isOpen ? SIDE_MENU.CLASSES.IS_OPEN : "";
13053
- return `${SIDE_MENU.CLASSES.BASE} ${openClass} ${className}`.trim();
13054
- },
13055
- generateWrapperClass: () => SIDE_MENU.CLASSES.WRAPPER,
13056
- handleToggle: handleToggle,
13057
- handleDesktopCollapse: () => {
13058
- handleToggle();
13042
+ // Handle mobile stacking order
13043
+ return defaultProps.reverseOnMobile && ("right" === defaultProps.alignment || "center" === defaultProps.alignment ? classes.push("u-order-last u-order-md-first") : classes.push("u-order-first u-order-md-last")),
13044
+ customClass && classes.push(customClass), classes.join(" ");
13059
13045
  },
13060
- getCurrentOpenState: getCurrentOpenState
13046
+ hasBackgroundImage: hasBackgroundImage,
13047
+ hasForegroundImage: hasForegroundImage,
13048
+ useGridLayout: useGridLayout,
13049
+ heroRef: heroRef,
13050
+ videoRef: videoRef,
13051
+ applyParallaxEffect: applyParallaxEffect,
13052
+ removeParallaxEffect: removeParallaxEffect,
13053
+ backgroundSlider: backgroundSlider,
13054
+ hasBackgroundSlider: hasBackgroundSlider
13061
13055
  };
13062
13056
  }
13063
13057
 
13064
13058
  /**
13065
- * SideMenuItem state and functionality
13066
- * @param initialProps - Initial side menu item properties
13067
- * @returns SideMenuItem state and methods
13068
- */ function useSideMenuItem(initialProps) {
13069
- // Default side menu item properties
13059
+ * Hook for River component functionality
13060
+ * @param initialProps - Initial river props
13061
+ * @returns River methods and state
13062
+ */ function useRiver(initialProps) {
13070
13063
  const defaultProps = {
13071
- active: !1,
13072
- disabled: !1,
13064
+ center: !1,
13065
+ breakout: !1,
13066
+ reverse: !1,
13067
+ imageAlt: "Image",
13068
+ showOverlay: !0,
13073
13069
  ...initialProps
13074
13070
  };
13075
13071
  /**
13076
- * Generate side menu item class based on properties
13077
- * @returns Class string
13072
+ * Check if the river has a background image
13078
13073
  */ return {
13079
- defaultProps: defaultProps,
13080
- generateSideMenuItemClass: () => {
13081
- const {active: active = defaultProps.active, disabled: disabled = defaultProps.disabled, className: className = ""} = defaultProps, activeClass = active ? SIDE_MENU.CLASSES.ACTIVE : "", disabledClass = disabled ? SIDE_MENU.CLASSES.DISABLED : "";
13082
- return `${SIDE_MENU.CLASSES.LINK} ${activeClass} ${disabledClass} ${className}`.trim();
13074
+ generateRiverClassNames: (baseClassName = "") => {
13075
+ const classes = [ RIVER.SELECTORS.RIVER.replace(".", "") ];
13076
+ // Add layout classes
13077
+ return defaultProps.center && classes.push(RIVER.CLASSES.CENTER), defaultProps.breakout && classes.push(RIVER.CLASSES.BREAKOUT),
13078
+ defaultProps.reverse && classes.push(RIVER.CLASSES.REVERSE), baseClassName && classes.push(baseClassName),
13079
+ classes.join(" ");
13083
13080
  },
13084
- handleClick: handler => e => {
13085
- defaultProps.disabled ? e.preventDefault() : handler && handler(e);
13086
- }
13081
+ generateContentClass: () => RIVER.SELECTORS.CONTENT.replace(".", ""),
13082
+ generateVisualClass: () => RIVER.SELECTORS.VISUAL.replace(".", ""),
13083
+ hasBackgroundImage: !!defaultProps.backgroundImageSrc,
13084
+ hasForegroundImage: !!defaultProps.imageSrc,
13085
+ textContent: "string" == typeof defaultProps.text ? [ defaultProps.text ] : defaultProps.text || []
13087
13086
  };
13088
13087
  }
13089
13088
 
13090
13089
  /**
13091
- * Map SCSS tokens to CSS custom properties
13092
- *
13093
- * @example
13094
- * const tokens = { '$primary-color': '#7AFFD7', '$spacing-md': '16px' }
13095
- * const vars = mapSCSSTokensToCSSVars(tokens)
13096
- * // Returns: { '--primary-color': '#7AFFD7', '--spacing-md': '16px' }
13097
- */ function mapSCSSTokensToCSSVars(tokens, options = {}) {
13098
- const vars = {}, {prefix: prefix = "atomix", separator: separator = "-"} = options;
13099
- return Object.entries(tokens).forEach((([key, value]) => {
13100
- // Remove $ prefix from SCSS variables
13101
- const normalizedKey = (key.startsWith("$") ? key.slice(1) : key).replace(/_/g, separator);
13102
- // Convert underscores to separators
13103
- vars[`--${prefix}${separator}${normalizedKey}`] = String(value);
13104
- })), vars;
13105
- }
13106
-
13107
- /**
13108
- * Apply CSS variables to an element
13109
- *
13110
- * @param vars - CSS variables to apply
13111
- * @param element - Target element (defaults to document.documentElement)
13112
- */ function applyCSSVariables(vars, element) {
13113
- if ("undefined" == typeof window) return;
13114
- // SSR safety
13115
- const target = element || document.documentElement;
13116
- Object.entries(vars).forEach((([key, value]) => {
13117
- target.style.setProperty(key, String(value));
13118
- }));
13119
- }
13120
-
13121
- /**
13122
- * Remove CSS variables from an element
13123
- *
13124
- * @param varNames - Variable names to remove
13125
- * @param element - Target element (defaults to document.documentElement)
13126
- */ function removeCSSVariables(varNames, element) {
13127
- if ("undefined" == typeof window) return;
13128
- // SSR safety
13129
- const target = element || document.documentElement;
13130
- varNames.forEach((varName => {
13131
- target.style.removeProperty(varName);
13132
- }));
13133
- }
13134
-
13135
- /**
13136
- * Get CSS variable value from an element
13137
- *
13138
- * @param varName - Variable name to get
13139
- * @param element - Target element (defaults to document.documentElement)
13140
- * @returns Variable value or null if not found
13141
- */ function getCSSVariable(varName, element) {
13142
- if ("undefined" == typeof window) return null;
13143
- // SSR safety
13144
- const target = element || document.documentElement;
13145
- return getComputedStyle(target).getPropertyValue(varName).trim() || null;
13146
- }
13147
-
13148
- /**
13149
- * Convert CSS variable object to inline style object
13150
- *
13151
- * @example
13152
- * const vars = { '--atomix-button-bg': '#000' }
13153
- * const style = cssVarsToStyle(vars)
13154
- * // Returns: { '--atomix-button-bg': '#000' } as React.CSSProperties
13155
- */ function cssVarsToStyle(vars) {
13156
- var _context;
13157
- return _reduceInstanceProperty(_context = Object.entries(vars)).call(_context, ((acc, [key, value]) => (acc[key] = "number" == typeof value ? `${value}px` : value,
13158
- acc)), {});
13159
- }
13160
-
13161
- /**
13162
- * Merge multiple CSS variable objects
13163
- * Later objects override earlier ones
13164
- */ function mergeCSSVars(...varObjects) {
13165
- return _reduceInstanceProperty(varObjects).call(varObjects, ((acc, vars) => (vars && Object.assign(acc, vars),
13166
- acc)), {});
13167
- }
13168
-
13169
- /**
13170
- * Validate CSS variable name format
13171
- */ function isValidCSSVariableName(name) {
13172
- return /^--[a-z0-9-]+$/.test(name);
13173
- }
13174
-
13175
- /**
13176
- * Extract component name from CSS variable name
13177
- *
13178
- * @example
13179
- * extractComponentName('--atomix-button-bg')
13180
- * // Returns: 'button'
13181
- */ function extractComponentName(varName, prefix = "atomix") {
13182
- const regex = new RegExp(`^--${prefix}-([a-z0-9]+)-`), match = varName.match(regex);
13183
- return match ? match[1] ?? null : null;
13184
- }
13185
-
13186
- /**
13187
- * Component Utilities
13188
- *
13189
- * Helper functions for component development with the new customization system
13190
- */
13191
- /**
13192
- * Merge multiple class names
13193
- */ function mergeClassNames(...classes) {
13194
- return classes.filter(Boolean).join(" ");
13090
+ * Navbar state and functionality
13091
+ * @param initialProps - Initial navbar properties
13092
+ * @returns Navbar state and methods
13093
+ */ function useNavbar(initialProps) {
13094
+ // Default navbar properties
13095
+ const defaultProps = {
13096
+ position: "static",
13097
+ collapsible: !0,
13098
+ backdrop: !1,
13099
+ closeOnOutsideClick: !0,
13100
+ closeOnEscape: !0,
13101
+ "aria-label": "Main navigation",
13102
+ ...initialProps
13103
+ }, [isExpanded, setIsExpanded] = useState(defaultProps.expanded || !1);
13104
+ // Local expanded state for when not controlled externally
13105
+ return {
13106
+ defaultProps: defaultProps,
13107
+ isExpanded: isExpanded,
13108
+ setIsExpanded: setIsExpanded,
13109
+ generateNavbarClass: props => {
13110
+ const {position: position = defaultProps.position, variant: variant, collapsible: collapsible = defaultProps.collapsible, className: className = ""} = props;
13111
+ return `c-navbar ${"static" !== position ? `c-navbar--${position}` : ""} ${variant ? `c-navbar--${variant}` : ""} ${collapsible ? "c-navbar--collapsible" : ""} ${className}`.trim();
13112
+ },
13113
+ generateContainerStyle: width => width ? {
13114
+ maxWidth: width
13115
+ } : {},
13116
+ generateCollapseClass: expanded => ("c-navbar__collapse " + (expanded ? "is-expanded" : "")).trim(),
13117
+ toggleExpanded: () => {
13118
+ const newState = !isExpanded;
13119
+ setIsExpanded(newState), defaultProps.onToggle && defaultProps.onToggle(newState);
13120
+ },
13121
+ getExpandedState: controlled => void 0 !== controlled ? controlled : isExpanded
13122
+ };
13195
13123
  }
13196
13124
 
13197
13125
  /**
13198
- * Apply part styles to element props
13199
- */ function applyPartStyles(baseProps, partStyles) {
13200
- return partStyles ? {
13201
- ...baseProps,
13202
- className: mergeClassNames(baseProps.className, partStyles.className),
13203
- style: {
13204
- ...baseProps.style,
13205
- ...partStyles.style
13126
+ * Nav state and functionality
13127
+ * @param initialProps - Initial nav properties
13128
+ * @returns Nav state and methods
13129
+ */ function useNav(initialProps) {
13130
+ // Default nav properties
13131
+ const defaultProps = {
13132
+ alignment: "start",
13133
+ variant: "default",
13134
+ ...initialProps
13135
+ };
13136
+ /**
13137
+ * Generate nav class based on properties
13138
+ * @param props - Nav properties
13139
+ * @returns Class string
13140
+ */ return {
13141
+ defaultProps: defaultProps,
13142
+ generateNavClass: props => {
13143
+ const {alignment: alignment = defaultProps.alignment, variant: variant = defaultProps.variant, className: className = ""} = props;
13144
+ return `c-nav ${"start" !== alignment ? `c-nav--${alignment}` : ""} ${"default" !== variant ? `c-nav--${variant}` : ""} ${className}`.trim();
13206
13145
  }
13207
- } : baseProps;
13146
+ };
13208
13147
  }
13209
13148
 
13210
13149
  /**
13211
- * Create style object from CSS variables
13212
- */ function createCSSVarStyle(cssVars, baseStyle) {
13213
- return cssVars ? {
13214
- ...cssVarsToStyle(cssVars),
13215
- ...baseStyle
13216
- } : baseStyle || {};
13217
- }
13218
-
13219
- function mergeComponentProps(baseProps, customization) {
13220
- const {className: className, style: style, cssVars: cssVars, parts: parts} = customization, cssVarStyle = cssVars ? cssVarsToStyle(cssVars) : {};
13221
- // Merge CSS variables into style
13222
- return {
13223
- ...baseProps,
13224
- className: mergeClassNames(baseProps.className, className),
13225
- style: {
13226
- ...cssVarStyle,
13227
- ...baseProps.style,
13228
- ...style
13150
+ * Nav item state and functionality
13151
+ * @param initialProps - Initial nav item properties
13152
+ * @returns Nav item state and methods
13153
+ */ function useNavItem(initialProps) {
13154
+ // Default nav item properties
13155
+ const defaultProps = {
13156
+ dropdown: !1,
13157
+ megaMenu: !1,
13158
+ active: !1,
13159
+ ...initialProps
13160
+ };
13161
+ /**
13162
+ * Generate nav item class based on properties
13163
+ * @param props - Nav item properties
13164
+ * @returns Class string
13165
+ */ return {
13166
+ defaultProps: defaultProps,
13167
+ generateNavItemClass: props => {
13168
+ const {dropdown: dropdown = defaultProps.dropdown, megaMenu: megaMenu = defaultProps.megaMenu, active: active = defaultProps.active, disabled: disabled = defaultProps.disabled, className: className = ""} = props;
13169
+ // Apply dropdown class only for regular dropdowns, not mega menus
13170
+ return `c-nav__item ${dropdown && !megaMenu ? NAV.SELECTORS.DROPDOWN.replace(".", "") : ""} ${megaMenu ? "c-nav__item--mega-menu" : ""} ${active ? NAV.CLASSES.ACTIVE : ""} ${disabled ? NAV.CLASSES.DISABLED : ""} ${className}`.trim();
13171
+ },
13172
+ generateNavLinkClass: (active = !1, disabled = !1, className = "") => `c-nav__link ${active ? NAV.CLASSES.ACTIVE : ""} ${disabled ? "c-nav__link--disabled" : ""} ${className}`.trim(),
13173
+ handleClick: handler => e => {
13174
+ !defaultProps.disabled && handler ? handler() : e.preventDefault();
13229
13175
  }
13230
13176
  };
13231
13177
  }
13232
13178
 
13233
13179
  /**
13234
- * Get part styles from parts object
13235
- */ function getPartStyles(parts, partName) {
13236
- return parts?.[partName];
13180
+ * Nav dropdown state and functionality
13181
+ * @param initialProps - Initial dropdown properties
13182
+ * @returns Dropdown state and methods
13183
+ */ function useNavDropdown(initialProps) {
13184
+ // Default dropdown properties
13185
+ const defaultProps = {
13186
+ alignment: "start",
13187
+ megaMenu: !1,
13188
+ ...initialProps
13189
+ }, isInFixedBottomNavbar = () => null !== document.querySelector(".c-navbar--fixed-bottom");
13190
+ /**
13191
+ * Generate dropdown menu class based on properties
13192
+ * @param props - Dropdown properties
13193
+ * @returns Class string
13194
+ */ return {
13195
+ defaultProps: defaultProps,
13196
+ generateDropdownMenuClass: props => {
13197
+ const {alignment: alignment = defaultProps.alignment, megaMenu: megaMenu = defaultProps.megaMenu, className: className = ""} = props, baseClass = megaMenu ? NAV.SELECTORS.MEGA_MENU.replace(".", "") : NAV.SELECTORS.DROPDOWN_MENU.replace(".", "");
13198
+ // Select the base class based on mega menu or regular dropdown
13199
+ // Add alignment class if not default 'start'
13200
+ let alignmentClass = "";
13201
+ return "center" === alignment ? alignmentClass = `${baseClass}--center` : "end" === alignment && (alignmentClass = `${baseClass}--end`),
13202
+ `${baseClass} ${alignmentClass} ${className}`.trim();
13203
+ },
13204
+ isInFixedBottomNavbar: isInFixedBottomNavbar,
13205
+ getIconName: (isMegaMenu = !1) => isInFixedBottomNavbar() ? "CaretUp" : "CaretDown"
13206
+ };
13237
13207
  }
13238
13208
 
13239
13209
  /**
13240
- * Create element props with part styles
13241
- */ function createPartProps(baseClassName, partStyles, additionalProps) {
13242
- return {
13243
- ...additionalProps,
13244
- className: mergeClassNames(baseClassName, partStyles?.className),
13245
- style: {
13246
- ...partStyles?.style,
13247
- ...additionalProps?.style
13210
+ * SideMenu state and functionality
13211
+ * @param initialProps - Initial side menu properties
13212
+ * @returns SideMenu state and methods
13213
+ */ function useSideMenu(initialProps) {
13214
+ const {collapsible: collapsible = !0, collapsibleDesktop: collapsibleDesktop = !1, defaultCollapsedDesktop: defaultCollapsedDesktop = !1, isOpen: isOpen, onToggle: onToggle, disabled: disabled = !1} = initialProps || {}, [isOpenState, setIsOpenState] = useState(void 0 !== defaultCollapsedDesktop ? !defaultCollapsedDesktop : isOpen || !1), wrapperRef = useRef(null), innerRef = useRef(null), sideMenuRef = useRef(null);
13215
+ // Local open state for when not controlled externally
13216
+ // Update local state when external state changes
13217
+ useEffect((() => {
13218
+ void 0 !== isOpen ? setIsOpenState(isOpen) : void 0 !== defaultCollapsedDesktop && setIsOpenState(!defaultCollapsedDesktop);
13219
+ }), [ isOpen, defaultCollapsedDesktop ]),
13220
+ // Set initial height on mount
13221
+ useEffect((() => {
13222
+ const shouldCollapse = window.innerWidth < 768 ? collapsible : collapsibleDesktop, currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
13223
+ if (shouldCollapse && wrapperRef.current && innerRef.current) {
13224
+ // Use setTimeout to ensure DOM is fully rendered
13225
+ const timeoutId = setTimeout((() => {
13226
+ wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
13227
+ }), 0);
13228
+ return () => clearTimeout(timeoutId);
13248
13229
  }
13230
+ !shouldCollapse && wrapperRef.current && (wrapperRef.current.style.height = "auto");
13231
+ }), [ collapsible, collapsibleDesktop, isOpen, isOpenState ]),
13232
+ // Handle responsive behavior - vertical collapse for both mobile and desktop
13233
+ useEffect((() => {
13234
+ const handleResize = () => {
13235
+ if (window.innerWidth < 768 ? collapsible : collapsibleDesktop) {
13236
+ if (wrapperRef.current && innerRef.current) {
13237
+ // Set proper height for vertical animation (both mobile and desktop)
13238
+ const currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
13239
+ // Use requestAnimationFrame to ensure DOM is ready
13240
+ requestAnimationFrame((() => {
13241
+ wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
13242
+ }));
13243
+ }
13244
+ } else
13245
+ // Not collapsible - always show content
13246
+ wrapperRef.current && (wrapperRef.current.style.height = "auto");
13247
+ }, timeoutId = setTimeout(handleResize, 0);
13248
+ // Initial call with a small delay to ensure DOM is ready
13249
+ return window.addEventListener("resize", handleResize), () => {
13250
+ clearTimeout(timeoutId), window.removeEventListener("resize", handleResize);
13251
+ };
13252
+ }), [ collapsible, collapsibleDesktop, isOpen, onToggle, isOpenState ]),
13253
+ // Update wrapper height when open state changes (both mobile and desktop)
13254
+ useEffect((() => {
13255
+ const shouldCollapse = window.innerWidth < 768 ? collapsible : collapsibleDesktop;
13256
+ if (shouldCollapse && wrapperRef.current && innerRef.current) {
13257
+ const currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
13258
+ // Use requestAnimationFrame to ensure DOM is ready
13259
+ requestAnimationFrame((() => {
13260
+ wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
13261
+ }));
13262
+ } else !shouldCollapse && wrapperRef.current && (
13263
+ // Not collapsible - always show content
13264
+ wrapperRef.current.style.height = "auto");
13265
+ }), [ isOpen, isOpenState, collapsible, collapsibleDesktop ]);
13266
+ /**
13267
+ * Generate side menu class based on properties
13268
+ * @param props - Side menu properties
13269
+ * @returns Class string
13270
+ */
13271
+ const handleToggle = () => {
13272
+ if (disabled) return;
13273
+ const newState = void 0 !== isOpen ? !isOpen : !isOpenState;
13274
+ "function" == typeof onToggle ?
13275
+ // Controlled component
13276
+ onToggle(newState) :
13277
+ // Uncontrolled component
13278
+ setIsOpenState(newState);
13279
+ }, getCurrentOpenState = () => void 0 !== isOpen ? isOpen : isOpenState;
13280
+ /**
13281
+ * Generate wrapper class
13282
+ * @returns Class string
13283
+ */ return {
13284
+ isOpenState: getCurrentOpenState(),
13285
+ wrapperRef: wrapperRef,
13286
+ innerRef: innerRef,
13287
+ sideMenuRef: sideMenuRef,
13288
+ generateSideMenuClass: props => {
13289
+ const {className: className = "", isOpen: isOpen = !1} = props, openClass = isOpen ? SIDE_MENU.CLASSES.IS_OPEN : "";
13290
+ return `${SIDE_MENU.CLASSES.BASE} ${openClass} ${className}`.trim();
13291
+ },
13292
+ generateWrapperClass: () => SIDE_MENU.CLASSES.WRAPPER,
13293
+ handleToggle: handleToggle,
13294
+ handleDesktopCollapse: () => {
13295
+ handleToggle();
13296
+ },
13297
+ getCurrentOpenState: getCurrentOpenState
13249
13298
  };
13250
13299
  }
13251
13300
 
13252
13301
  /**
13253
- * Check if component has customization
13254
- */ function hasCustomization(props) {
13255
- return Boolean(props.parts || props.cssVars || props.slots);
13256
- }
13257
-
13258
- /**
13259
- * Create data attributes for debugging
13260
- */ function createDebugAttrs(componentName, variant) {
13261
- return "undefined" == typeof process || "development" !== process.env?.NODE_ENV ? {} : {
13262
- "data-component": componentName,
13263
- ...variant && {
13264
- "data-variant": variant
13302
+ * SideMenuItem state and functionality
13303
+ * @param initialProps - Initial side menu item properties
13304
+ * @returns SideMenuItem state and methods
13305
+ */ function useSideMenuItem(initialProps) {
13306
+ // Default side menu item properties
13307
+ const defaultProps = {
13308
+ active: !1,
13309
+ disabled: !1,
13310
+ ...initialProps
13311
+ };
13312
+ /**
13313
+ * Generate side menu item class based on properties
13314
+ * @returns Class string
13315
+ */ return {
13316
+ defaultProps: defaultProps,
13317
+ generateSideMenuItemClass: () => {
13318
+ const {active: active = defaultProps.active, disabled: disabled = defaultProps.disabled, className: className = ""} = defaultProps, activeClass = active ? SIDE_MENU.CLASSES.ACTIVE : "", disabledClass = disabled ? SIDE_MENU.CLASSES.DISABLED : "";
13319
+ return `${SIDE_MENU.CLASSES.LINK} ${activeClass} ${disabledClass} ${className}`.trim();
13320
+ },
13321
+ handleClick: handler => e => {
13322
+ defaultProps.disabled ? e.preventDefault() : handler && handler(e);
13265
13323
  }
13266
13324
  };
13267
13325
  }
13268
13326
 
13269
- /**
13270
- * Generate a UUID v4
13271
- */ function generateUUID() {
13272
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c => {
13273
- const r = 16 * Math.random() | 0;
13274
- return ("x" === c ? r : 3 & r | 8).toString(16);
13275
- }));
13276
- }
13277
-
13278
- /**
13279
- * Check if a URL is a YouTube URL
13280
- */ function isYouTubeUrl(url) {
13281
- return /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+/.test(url);
13282
- }
13283
-
13284
- /**
13285
- * Extract YouTube video ID from URL
13286
- */ function extractYouTubeId(url) {
13287
- if (!isYouTubeUrl(url)) return null;
13288
- const patterns = [ /(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([^&\n?#]+)/, /youtube\.com\/.*[?&]v=([^&\n?#]+)/ ];
13289
- for (const pattern of patterns) {
13290
- const match = url.match(pattern);
13291
- if (match && match[1]) return match[1];
13292
- }
13293
- return null;
13294
- }
13295
-
13296
13327
  /**
13297
13328
  * Font Preloading Utilities
13298
13329
  *
@@ -13660,48 +13691,11 @@ const composablesImport = Object.freeze( Object.defineProperty({
13660
13691
  DeviceDetector: DeviceDetector,
13661
13692
  MOBILE_OPTIMIZED_BREAKPOINTS: MOBILE_OPTIMIZED_BREAKPOINTS,
13662
13693
  PERFORMANCE_PRESET: PERFORMANCE_PRESET,
13663
- PerformanceOverlay: function({metrics: metrics}) {
13664
- return null;
13665
- // Performance overlay removed - will be implemented as separate component
13666
- }
13667
- /**
13668
- * Utility to get quality multipliers for glass parameters
13669
- */ ,
13670
13694
  QUALITY_PRESET: QUALITY_PRESET,
13671
13695
  createBreakpoints: createBreakpoints$1,
13672
13696
  getDefaultBreakpoints: getDefaultBreakpoints,
13673
13697
  getDevicePreset: getDevicePreset,
13674
13698
  getMobileOptimizedParams: getMobileOptimizedParams,
13675
- getQualityMultipliers: function(quality) {
13676
- switch (quality) {
13677
- case "low":
13678
- return {
13679
- distortionOctaves: 2,
13680
- displacementScale: .6,
13681
- blurAmount: .7,
13682
- animationSpeed: .8,
13683
- chromaticIntensity: .5
13684
- };
13685
-
13686
- case "medium":
13687
- return {
13688
- distortionOctaves: 4,
13689
- displacementScale: .85,
13690
- blurAmount: .9,
13691
- animationSpeed: .95,
13692
- chromaticIntensity: .75
13693
- };
13694
-
13695
- case "high":
13696
- return {
13697
- distortionOctaves: 5,
13698
- displacementScale: 1,
13699
- blurAmount: 1,
13700
- animationSpeed: 1,
13701
- chromaticIntensity: 1
13702
- };
13703
- }
13704
- },
13705
13699
  useAccordion: useAccordion,
13706
13700
  useAtomixGlass: useAtomixGlass,
13707
13701
  useBadge: useBadge,
@@ -14004,12 +13998,7 @@ const SelectComponentBase = ({options: options, value: value, onChange: onChange
14004
13998
  });
14005
13999
  // Handle item selection
14006
14000
  if (glass) {
14007
- // Default glass settings for select components
14008
- const defaultGlassProps = {
14009
- displacementScale: 60,
14010
- blurAmount: 10,
14011
- mode: "shader"
14012
- }, glassProps = !0 === glass ? defaultGlassProps : {
14001
+ const defaultGlassProps = GLASS_DEFAULTS.SELECT, glassProps = !0 === glass ? defaultGlassProps : {
14013
14002
  ...defaultGlassProps,
14014
14003
  ...glass
14015
14004
  };
@@ -14059,15 +14048,7 @@ const Radio = memo((({label: label, checked: checked = !1, onChange: onChange,
14059
14048
  }) ]
14060
14049
  });
14061
14050
  if (glass) {
14062
- // Default glass settings for radio buttons
14063
- const defaultGlassProps = {
14064
- displacementScale: 40,
14065
- blurAmount: 1,
14066
- saturation: 160,
14067
- aberrationIntensity: .3,
14068
- borderRadius: 6,
14069
- mode: "shader"
14070
- }, glassProps = !0 === glass ? defaultGlassProps : {
14051
+ const defaultGlassProps = GLASS_DEFAULTS.RADIO, glassProps = !0 === glass ? defaultGlassProps : {
14071
14052
  ...defaultGlassProps,
14072
14053
  ...glass
14073
14054
  };
@@ -14125,15 +14106,7 @@ const Textarea = memo( forwardRef((({value: value, defaultValue: defaultValue,
14125
14106
  } : style
14126
14107
  });
14127
14108
  if (glass) {
14128
- // Default glass settings for textareas
14129
- const defaultGlassProps = {
14130
- displacementScale: 60,
14131
- blurAmount: 1,
14132
- saturation: 180,
14133
- aberrationIntensity: 1,
14134
- borderRadius: 8,
14135
- mode: "shader"
14136
- }, glassProps = !0 === glass ? defaultGlassProps : {
14109
+ const defaultGlassProps = GLASS_DEFAULTS.TEXTAREA, glassProps = !0 === glass ? defaultGlassProps : {
14137
14110
  ...defaultGlassProps,
14138
14111
  ...glass
14139
14112
  };
@@ -15249,12 +15222,7 @@ const Messages = ({messages: messages = [], otherAvatar: otherAvatar, selfAvatar
15249
15222
  };
15250
15223
  })({
15251
15224
  onSendMessage: onSendMessage
15252
- }), messagesId = id || `messages-${Math.random().toString(36).substr(2, 9)}`, inputId = `${messagesId}-input`, defaultGlassProps = {
15253
- displacementScale: 150,
15254
- borderRadius: 12,
15255
- elasticity: 0,
15256
- aberrationIntensity: 2
15257
- }, messagesClasses = `${MESSAGES.CLASSES.BASE} ${glass ? "c-messages--glass" : ""} ${disabled ? "is-disabled" : ""} ${className}`, messagesContent = jsxs(Fragment, {
15225
+ }), messagesId = id || `messages-${Math.random().toString(36).substr(2, 9)}`, inputId = `${messagesId}-input`, defaultGlassProps = GLASS_DEFAULTS.MESSAGES, messagesClasses = `${MESSAGES.CLASSES.BASE} ${glass ? "c-messages--glass" : ""} ${disabled ? "is-disabled" : ""} ${className}`, messagesContent = jsxs(Fragment, {
15258
15226
  children: [ jsx("div", {
15259
15227
  className: MESSAGES.CLASSES.BODY,
15260
15228
  style: bodyHeight ? {
@@ -15614,12 +15582,11 @@ const ModalImpl = memo((({children: children, isOpen: isOpen = !1, onOpenChange
15614
15582
  children: glass ?
15615
15583
  // Default glass settings for modals
15616
15584
  (() => {
15585
+ // Default glass settings for modals
15617
15586
  const defaultGlassProps = {
15618
- displacementScale: document.querySelector(".c-modal---glass .c-modal__content")?.clientHeight,
15619
- blurAmount: 2.2,
15620
- elasticity: 0,
15621
- mode: "shader",
15622
- shaderMode: "premiumGlass"
15587
+ ...GLASS_DEFAULTS.MODAL,
15588
+ // displacementScale driven by modal content height at runtime
15589
+ displacementScale: document.querySelector(".c-modal---glass .c-modal__content")?.clientHeight
15623
15590
  }, glassProps = !0 === glass ? defaultGlassProps : {
15624
15591
  ...defaultGlassProps,
15625
15592
  ...glass
@@ -15667,12 +15634,7 @@ const Modal = ModalWithSubcomponents, Nav = forwardRef((({children: children, a
15667
15634
  }))
15668
15635
  });
15669
15636
  if (glass) {
15670
- const defaultGlassProps = {
15671
- displacementScale: 60,
15672
- blurAmount: 1.5,
15673
- borderRadius: 8,
15674
- mode: "shader"
15675
- }, glassProps = !0 === glass ? defaultGlassProps : {
15637
+ const defaultGlassProps = GLASS_DEFAULTS.NAV, glassProps = !0 === glass ? defaultGlassProps : {
15676
15638
  ...defaultGlassProps,
15677
15639
  ...glass
15678
15640
  };
@@ -15698,24 +15660,7 @@ const Modal = ModalWithSubcomponents, Nav = forwardRef((({children: children, a
15698
15660
  * </NavDropdown>
15699
15661
  * </Nav>
15700
15662
  * ```
15701
- */
15702
- /**
15703
- * Utility to merge multiple React refs into one
15704
- */
15705
- function setRef(ref, value) {
15706
- "function" == typeof ref ? ref(value) : ref && (
15707
- // This is safe because we're checking that ref exists first
15708
- ref.current = value);
15709
- }
15710
-
15711
- /**
15712
- * Combines two React refs into a single ref function
15713
- * This is used when you need to use and forward a ref at the same time
15714
- */ function useForkRef(refA, refB) {
15715
- return React.useMemo((() => null == refA && null == refB ? null : refValue => {
15716
- setRef(refA, refValue), setRef(refB, refValue);
15717
- }), [ refA, refB ]);
15718
- }
15663
+ */ Nav.displayName = "Nav";
15719
15664
 
15720
15665
  /**
15721
15666
  * NavItem component represents a single navigation item that can be a link, dropdown trigger, or mega menu trigger.
@@ -15744,8 +15689,7 @@ function setRef(ref, value) {
15744
15689
  * </MegaMenu>
15745
15690
  * </NavItem>
15746
15691
  * ```
15747
- */ Nav.displayName = "Nav";
15748
-
15692
+ */
15749
15693
  const NavItem = forwardRef((({children: children, dropdown: dropdown = !1, megaMenu: megaMenu = !1, active: active = !1, href: href, target: target, onClick: onClick, className: className = "", disabled: disabled = !1, "aria-expanded": ariaExpanded, linkComponent: linkComponent}, ref) => {
15750
15694
  const {generateNavItemClass: generateNavItemClass, generateNavLinkClass: generateNavLinkClass, handleClick: handleClick} = useNavItem({
15751
15695
  dropdown: dropdown,
@@ -15912,14 +15856,7 @@ const Navbar = forwardRef((({brand: brand, children: children, variant: variant
15912
15856
  });
15913
15857
  // Generate the container style
15914
15858
  if (glass) {
15915
- const defaultGlassProps = {
15916
- displacementScale: 30,
15917
- blurAmount: 2,
15918
- borderRadius: 0,
15919
- elasticity: 0,
15920
- mode: "shader",
15921
- shaderVariant: "premiumGlass"
15922
- }, glassProps = !0 === glass ? defaultGlassProps : {
15859
+ const defaultGlassProps = GLASS_DEFAULTS.NAVBAR, glassProps = !0 === glass ? defaultGlassProps : {
15923
15860
  ...defaultGlassProps,
15924
15861
  ...glass
15925
15862
  };
@@ -16277,12 +16214,7 @@ const SideMenu = forwardRef((({title: title, children: children, menuItems: men
16277
16214
  }) ]
16278
16215
  });
16279
16216
  if (glass) {
16280
- const defaultGlassProps = {
16281
- displacementScale: 70,
16282
- blurAmount: 2,
16283
- borderRadius: 12,
16284
- mode: "shader"
16285
- }, glassProps = !0 === glass ? defaultGlassProps : {
16217
+ const defaultGlassProps = GLASS_DEFAULTS.SIDE_MENU, glassProps = !0 === glass ? defaultGlassProps : {
16286
16218
  ...defaultGlassProps,
16287
16219
  ...glass
16288
16220
  };
@@ -17863,14 +17795,7 @@ const PopoverContext = createContext({
17863
17795
  children: [ glass ?
17864
17796
  // Default glass settings for popovers
17865
17797
  (() => {
17866
- const defaultGlassProps = {
17867
- displacementScale: 50,
17868
- blurAmount: 1,
17869
- saturation: 160,
17870
- aberrationIntensity: .5,
17871
- borderRadius: 8,
17872
- mode: "shader"
17873
- }, glassProps = !0 === glass ? defaultGlassProps : {
17798
+ const defaultGlassProps = GLASS_DEFAULTS.POPOVER, glassProps = !0 === glass ? defaultGlassProps : {
17874
17799
  ...defaultGlassProps,
17875
17800
  ...glass
17876
17801
  };
@@ -18095,15 +18020,7 @@ const calculateStarValue = (e, starValue, allowHalf) => {
18095
18020
  });
18096
18021
  // Generate stars
18097
18022
  if (glass) {
18098
- // Default glass settings for ratings
18099
- const defaultGlassProps = {
18100
- displacementScale: 60,
18101
- blurAmount: 1,
18102
- saturation: 160,
18103
- aberrationIntensity: .5,
18104
- borderRadius: 8,
18105
- mode: "shader"
18106
- }, glassProps = !0 === glass ? defaultGlassProps : {
18023
+ const defaultGlassProps = GLASS_DEFAULTS.RATING, glassProps = !0 === glass ? defaultGlassProps : {
18107
18024
  ...defaultGlassProps,
18108
18025
  ...glass
18109
18026
  };
@@ -18259,12 +18176,7 @@ const Progress = memo( forwardRef((({value: value, variant: variant = "primary"
18259
18176
  })
18260
18177
  });
18261
18178
  if (glass) {
18262
- const defaultGlassProps = {
18263
- displacementScale: 30,
18264
- blurAmount: .5,
18265
- borderRadius: 8,
18266
- mode: "shader"
18267
- }, glassProps = !0 === glass ? defaultGlassProps : {
18179
+ const defaultGlassProps = GLASS_DEFAULTS.PROGRESS, glassProps = !0 === glass ? defaultGlassProps : {
18268
18180
  ...defaultGlassProps,
18269
18181
  ...glass
18270
18182
  };
@@ -18913,15 +18825,7 @@ const Steps = ({items: items, activeIndex: activeIndex = 0, vertical: vertical =
18913
18825
  children: content
18914
18826
  });
18915
18827
  if (glass) {
18916
- // Default glass settings for steps
18917
- const defaultGlassProps = {
18918
- displacementScale: 60,
18919
- blurAmount: 1,
18920
- saturation: 160,
18921
- aberrationIntensity: .5,
18922
- borderRadius: 8,
18923
- mode: "shader"
18924
- }, glassProps = !0 === glass ? defaultGlassProps : {
18828
+ const defaultGlassProps = GLASS_DEFAULTS.STEPS, glassProps = !0 === glass ? defaultGlassProps : {
18925
18829
  ...defaultGlassProps,
18926
18830
  ...glass
18927
18831
  };
@@ -19125,14 +19029,7 @@ const TabsComponentBase = ({items: items, activeIndex: activeIndex = TAB.DEFAULT
19125
19029
  });
19126
19030
  if (glass) {
19127
19031
  // Default glass settings for tabs
19128
- const defaultGlassProps = {
19129
- displacementScale: 60,
19130
- blurAmount: 1,
19131
- saturation: 160,
19132
- aberrationIntensity: .5,
19133
- borderRadius: 8,
19134
- mode: "shader"
19135
- }, glassProps = !0 === glass ? defaultGlassProps : {
19032
+ const defaultGlassProps = GLASS_DEFAULTS.TABS, glassProps = !0 === glass ? defaultGlassProps : {
19136
19033
  ...defaultGlassProps,
19137
19034
  ...glass
19138
19035
  };
@@ -19368,15 +19265,7 @@ const Toggle = ({checked: controlledChecked, defaultChecked: defaultChecked = !1
19368
19265
  })
19369
19266
  });
19370
19267
  if (glass) {
19371
- // Default glass settings for toggles
19372
- const defaultGlassProps = {
19373
- displacementScale: 60,
19374
- blurAmount: 1,
19375
- saturation: 160,
19376
- aberrationIntensity: .5,
19377
- borderRadius: 8,
19378
- mode: "shader"
19379
- }, glassProps = !0 === glass ? defaultGlassProps : {
19268
+ const defaultGlassProps = GLASS_DEFAULTS.TOGGLE, glassProps = !0 === glass ? defaultGlassProps : {
19380
19269
  ...defaultGlassProps,
19381
19270
  ...glass
19382
19271
  };
@@ -19564,10 +19453,7 @@ const Tooltip = memo((({content: content, children: children, position: positio
19564
19453
  }), content ]
19565
19454
  });
19566
19455
  if (glass) {
19567
- const defaultGlassProps = {
19568
- displacementScale: 100,
19569
- blurAmount: 3
19570
- }, glassProps = !0 === glass ? defaultGlassProps : {
19456
+ const defaultGlassProps = GLASS_DEFAULTS.TOOLTIP, glassProps = !0 === glass ? defaultGlassProps : {
19571
19457
  ...defaultGlassProps,
19572
19458
  ...glass
19573
19459
  };
@@ -20741,6 +20627,8 @@ const components = Object.freeze( Object.defineProperty({
20741
20627
  FOOTER: FOOTER,
20742
20628
  FORM: FORM,
20743
20629
  FORM_GROUP: FORM_GROUP,
20630
+ GLASS_BORDER_GRADIENT: GLASS_BORDER_GRADIENT,
20631
+ GLASS_DEFAULTS: GLASS_DEFAULTS,
20744
20632
  HERO: HERO,
20745
20633
  INPUT: INPUT,
20746
20634
  LIST: LIST,
@@ -28527,5 +28415,5 @@ const atomix = {
28527
28415
  types: types
28528
28416
  };
28529
28417
 
28530
- export { ACCORDION, ATOMIX_GLASS, AVATAR, AVATAR_GROUP, Accordion, AreaChart, AtomixGlass, AtomixLogo, Avatar, AvatarGroup, BADGE, BADGE_CSS_VARS, BALANCED_PRESET, BLOCK, BREADCRUMB, BUTTON, BUTTON_CSS_VARS, BUTTON_GROUP, Badge, BarChart, Block, Breadcrumb, BubbleChart, Button, ButtonGroup, CALLOUT, CARD, CARD_CSS_VARS, CHART, CHECKBOX_CSS_VARS, CLASS_PREFIX, CODE_SNIPPET, COMPONENT_CSS_VARS, COUNTDOWN, Callout, CandlestickChart, Card, Chart, ChartRenderer, Checkbox, ColorModeToggle, Container, Countdown, DATA_TABLE_CLASSES, DATA_TABLE_SELECTORS, DATEPICKER, DEFAULT_ATOMIX_FONTS, DEFAULT_BREAKPOINTS, DROPDOWN, DROPDOWN_CSS_VARS, DataTable, DatePicker, DesignTokensCustomizer, DeviceDetector, DonutChart, Dropdown, EDGE_PANEL, EdgePanel, ElevationCard, FOOTER, FORM, FORM_GROUP, Footer, FooterLink, FooterSection, FooterSocialLink, Form, FormGroup, FunnelChart, GaugeChart, Grid, GridCol, HERO, HeatmapChart, Hero, INPUT, INPUT_CSS_VARS, Icon, Input, LIST, LIST_GROUP, LineChart, List, ListGroup, MESSAGES, MOBILE_OPTIMIZED_BREAKPOINTS, MODAL, MODAL_CSS_VARS, MasonryGrid, MasonryGridItem, MegaMenu, MegaMenuColumn, MegaMenuLink, Menu, MenuDivider, MenuItem, Messages, Modal, MultiAxisChart, NAV, NAVBAR, Nav, NavDropdown, NavItem, Navbar, PAGINATION_DEFAULTS, PERFORMANCE_PRESET, PHOTOVIEWER, POPOVER, PROGRESS, PROGRESS_CSS_VARS, Pagination, PhotoViewer, PieChart, Popover, ProductReview, Progress, QUALITY_PRESET, RADIO, RADIO_CSS_VARS, RATING, RIVER, RTLManager, RadarChart, Radio, Rating, River, Row, SECTION_INTRO, SELECT, SIDE_MENU, SIZES, SLIDER, SPINNER, STEPS, ScatterChart, SectionIntro, Select, SideMenu, SideMenuItem, SideMenuList, Slider, Spinner, Steps, TAB, TABS_CSS_VARS, TESTIMONIAL, TEXTAREA, THEME_COLORS, THEME_NAMING, TODO, TOGGLE, TOOLTIP, TOOLTIP_CSS_VARS, TYPEDBUTTON, Tabs, Testimonial, Textarea, ThemeApplicator, ThemeComparator, ThemeContext, ThemeErrorBoundary, ThemeInspector, ThemeLiveEditor, ThemePreview, ThemeProvider, ThemeToggle, ThemeValidator, Todo, Toggle, Tooltip, TreemapChart, UPLOAD, Upload, VIDEO_PLAYER, VideoPlayer, WaterfallChart, alpha, applyCSSVariables, applyCSSVarsToStyle, applyComponentTheme, applyPartStyles, applyTheme, camelToKebab, clearThemePreference, clearThemes, composables, configToTokens, constants, createBreakpoints$1 as createBreakpoints, createCSSVarStyle, createDarkVariant, createDebugAttrs, createFontPreloadLink, createPartProps, createPerformanceMonitor, createRTLManager, createResponsiveUtil, createSlotComponent, createSlotProps, createSpacing, createTheme, createThemeRegistry, createTokens, cssVarsToStyle, darken, deepMerge, atomix as default, defaultTokens, defineConfig, designTokensToCSSVars, emphasize, exportTheme, extendTheme, extractComponentName, extractYouTubeId, generateCSSVariableName, generateCSSVariables$1 as generateCSSVariables, generateCSSVariablesForSelector, generateClassName, generateComponentCSSVars, generateFontPreloadTags, generateUUID, getAllThemes, getCSSVariable, getComponentCSSVars, getComponentThemeValue, getContrastRatio, getContrastText, getCurrentTheme, getDefaultBreakpoints, getDevicePreset, getDirectionFromLocale, getLuminance, getMobileOptimizedParams, getPartStyles, getSystemTheme, getTheme, getThemeApplicator, getThemeCount, getThemeIds, getThemeMetadata, hasCustomization, hasTheme, hexToRgb$1 as hexToRgb, importTheme, initializeTheme, injectCSS$1 as injectCSS, injectTheme, isAccessible, isCSSInjected, isDesignTokens, isRTLLocale, isSlot, isValidCSSVariableName, isYouTubeUrl, lighten, listenToSystemTheme, loadAtomixConfig, loadConfig, mapSCSSTokensToCSSVars, mergeCSSVars, mergeClassNames, mergeComponentProps, mergePartStyles, mergeSlots, mergeTheme, mergeTokens, normalizeThemeTokens, omitTokens, overrideTokens, persistTheme, pickTokens, preloadFonts, printConfigReport, quickTheme, registerTheme, removeCSS, removeCSSVariables, removeTheme, renderSlot, resolveConfigPath, rgbToHex, rtlCSS, sliderConstants, supportsDarkMode, switchTheme, theme, themePropertyToCSSVar, themeToCSS, toggleTheme, types, unregisterTheme, useAccordion, useAtomixGlass, useBadge, useBarChart, useBlock, useChartData, useChartInteraction, useChartScale, useComponentCustomization, useComponentDefaultProps, useComponentTheme, useEdgePanel, useForm, useFormGroup, useHero, useHistory, useInput, useLineChart, useMergedProps, useNav, useNavDropdown, useNavItem, useNavbar, usePerformanceMonitor, usePieChart, useRadio, useResponsive, useResponsiveGlass, useRiver, useSelect, useSideMenu, useSideMenuItem, useSlot, useSpinner, useTextarea, useTheme, useThemeSwitcher, useThemeTokens, useTodo, utils, validateConfig, validateConfiguration, validateTheme };
28418
+ export { ACCORDION, ATOMIX_GLASS, AVATAR, AVATAR_GROUP, Accordion, AreaChart, AtomixGlass, AtomixLogo, Avatar, AvatarGroup, BADGE, BADGE_CSS_VARS, BALANCED_PRESET, BLOCK, BREADCRUMB, BUTTON, BUTTON_CSS_VARS, BUTTON_GROUP, Badge, BarChart, Block, Breadcrumb, BubbleChart, Button, ButtonGroup, CALLOUT, CARD, CARD_CSS_VARS, CHART, CHECKBOX_CSS_VARS, CLASS_PREFIX, CODE_SNIPPET, COMPONENT_CSS_VARS, COUNTDOWN, Callout, CandlestickChart, Card, Chart, ChartRenderer, Checkbox, ColorModeToggle, Container, Countdown, DATA_TABLE_CLASSES, DATA_TABLE_SELECTORS, DATEPICKER, DEFAULT_ATOMIX_FONTS, DEFAULT_BREAKPOINTS, DROPDOWN, DROPDOWN_CSS_VARS, DataTable, DatePicker, DesignTokensCustomizer, DeviceDetector, DonutChart, Dropdown, EDGE_PANEL, EdgePanel, ElevationCard, FOOTER, FORM, FORM_GROUP, Footer, FooterLink, FooterSection, FooterSocialLink, Form, FormGroup, FunnelChart, GLASS_BORDER_GRADIENT, GLASS_DEFAULTS, GaugeChart, Grid, GridCol, HERO, HeatmapChart, Hero, INPUT, INPUT_CSS_VARS, Icon, Input, LIST, LIST_GROUP, LineChart, List, ListGroup, MESSAGES, MOBILE_OPTIMIZED_BREAKPOINTS, MODAL, MODAL_CSS_VARS, MasonryGrid, MasonryGridItem, MegaMenu, MegaMenuColumn, MegaMenuLink, Menu, MenuDivider, MenuItem, Messages, Modal, MultiAxisChart, NAV, NAVBAR, Nav, NavDropdown, NavItem, Navbar, PAGINATION_DEFAULTS, PERFORMANCE_PRESET, PHOTOVIEWER, POPOVER, PROGRESS, PROGRESS_CSS_VARS, Pagination, PhotoViewer, PieChart, Popover, ProductReview, Progress, QUALITY_PRESET, RADIO, RADIO_CSS_VARS, RATING, RIVER, RTLManager, RadarChart, Radio, Rating, River, Row, SECTION_INTRO, SELECT, SIDE_MENU, SIZES, SLIDER, SPINNER, STEPS, ScatterChart, SectionIntro, Select, SideMenu, SideMenuItem, SideMenuList, Slider, Spinner, Steps, TAB, TABS_CSS_VARS, TESTIMONIAL, TEXTAREA, THEME_COLORS, THEME_NAMING, TODO, TOGGLE, TOOLTIP, TOOLTIP_CSS_VARS, TYPEDBUTTON, Tabs, Testimonial, Textarea, ThemeApplicator, ThemeComparator, ThemeContext, ThemeErrorBoundary, ThemeInspector, ThemeLiveEditor, ThemePreview, ThemeProvider, ThemeToggle, ThemeValidator, Todo, Toggle, Tooltip, TreemapChart, UPLOAD, Upload, VIDEO_PLAYER, VideoPlayer, WaterfallChart, alpha, applyCSSVariables, applyCSSVarsToStyle, applyComponentTheme, applyPartStyles, applyTheme, camelToKebab, clearThemePreference, clearThemes, composables, configToTokens, constants, createBreakpoints$1 as createBreakpoints, createCSSVarStyle, createDarkVariant, createDebugAttrs, createFontPreloadLink, createPartProps, createPerformanceMonitor, createRTLManager, createResponsiveUtil, createSlotComponent, createSlotProps, createSpacing, createTheme, createThemeRegistry, createTokens, cssVarsToStyle, darken, deepMerge, atomix as default, defaultTokens, defineConfig, designTokensToCSSVars, emphasize, exportTheme, extendTheme, extractComponentName, extractYouTubeId, generateCSSVariableName, generateCSSVariables$1 as generateCSSVariables, generateCSSVariablesForSelector, generateClassName, generateComponentCSSVars, generateFontPreloadTags, generateUUID, getAllThemes, getCSSVariable, getComponentCSSVars, getComponentThemeValue, getContrastRatio, getContrastText, getCurrentTheme, getDefaultBreakpoints, getDevicePreset, getDirectionFromLocale, getLuminance, getMobileOptimizedParams, getPartStyles, getSystemTheme, getTheme, getThemeApplicator, getThemeCount, getThemeIds, getThemeMetadata, hasCustomization, hasTheme, hexToRgb$1 as hexToRgb, importTheme, initializeTheme, injectCSS$1 as injectCSS, injectTheme, isAccessible, isCSSInjected, isDesignTokens, isRTLLocale, isSlot, isValidCSSVariableName, isYouTubeUrl, lighten, listenToSystemTheme, loadAtomixConfig, loadConfig, mapSCSSTokensToCSSVars, mergeCSSVars, mergeClassNames, mergeComponentProps, mergePartStyles, mergeSlots, mergeTheme, mergeTokens, normalizeThemeTokens, omitTokens, overrideTokens, persistTheme, pickTokens, preloadFonts, printConfigReport, quickTheme, registerTheme, removeCSS, removeCSSVariables, removeTheme, renderSlot, resolveConfigPath, rgbToHex, rtlCSS, sliderConstants, supportsDarkMode, switchTheme, theme, themePropertyToCSSVar, themeToCSS, toggleTheme, types, unregisterTheme, useAccordion, useAtomixGlass, useBadge, useBarChart, useBlock, useChartData, useChartInteraction, useChartScale, useComponentCustomization, useComponentDefaultProps, useComponentTheme, useEdgePanel, useForm, useFormGroup, useHero, useHistory, useInput, useLineChart, useMergedProps, useNav, useNavDropdown, useNavItem, useNavbar, usePerformanceMonitor, usePieChart, useRadio, useResponsive, useResponsiveGlass, useRiver, useSelect, useSideMenu, useSideMenuItem, useSlot, useSpinner, useTextarea, useTheme, useThemeSwitcher, useThemeTokens, useTodo, utils, validateConfig, validateConfiguration, validateTheme };
28531
28419
  //# sourceMappingURL=index.esm.js.map