@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.
- package/dist/atomix.css +117 -38
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +1 -1
- package/dist/atomix.min.css.map +1 -1
- package/dist/atomix.umd.js +1 -1
- package/dist/atomix.umd.js.map +1 -1
- package/dist/atomix.umd.min.js +1 -1
- package/dist/charts.d.ts +30 -1
- package/dist/charts.js +625 -846
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +30 -1
- package/dist/core.js +659 -873
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +30 -1
- package/dist/forms.js +1171 -1402
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +31 -89
- package/dist/heavy.js +975 -1195
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +383 -140
- package/dist/index.esm.js +1567 -1679
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1556 -1667
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Accordion/Accordion.tsx +2 -5
- package/src/components/AtomixGlass/AtomixGlass.test.tsx +14 -16
- package/src/components/AtomixGlass/AtomixGlass.tsx +137 -364
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +32 -251
- package/src/components/AtomixGlass/GlassFilter.tsx +62 -68
- package/src/components/AtomixGlass/README.md +2 -1
- package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +19 -18
- package/src/components/AtomixGlass/glass-border-styles.test.ts +58 -0
- package/src/components/AtomixGlass/glass-border-styles.ts +136 -0
- package/src/components/AtomixGlass/glass-utils.ts +456 -22
- package/src/components/AtomixGlass/shader-utils.ts +19 -77
- package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +158 -537
- package/src/components/AtomixGlass/stories/Border.stories.tsx +149 -0
- package/src/components/AtomixGlass/stories/Examples.stories.tsx +229 -89
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +29 -340
- package/src/components/AtomixGlass/stories/argTypes.ts +30 -13
- package/src/components/AtomixGlass/stories/premium-presets.ts +206 -0
- package/src/components/AtomixGlass/stories/shared-components.tsx +52 -8
- package/src/components/Badge/Badge.tsx +4 -4
- package/src/components/Button/Button.tsx +2 -6
- package/src/components/Callout/Callout.test.tsx +4 -3
- package/src/components/Callout/Callout.tsx +2 -5
- package/src/components/Dropdown/Dropdown.tsx +3 -7
- package/src/components/Form/Checkbox.tsx +2 -8
- package/src/components/Form/Input.tsx +2 -9
- package/src/components/Form/Radio.tsx +2 -9
- package/src/components/Form/Select.test.tsx +6 -6
- package/src/components/Form/Select.tsx +2 -7
- package/src/components/Form/Textarea.stories.tsx +5 -5
- package/src/components/Form/Textarea.tsx +2 -9
- package/src/components/Messages/Messages.tsx +2 -8
- package/src/components/Modal/Modal.tsx +4 -5
- package/src/components/Navigation/Nav/Nav.tsx +2 -6
- package/src/components/Navigation/Navbar/Navbar.tsx +2 -9
- package/src/components/Navigation/SideMenu/SideMenu.tsx +2 -6
- package/src/components/Pagination/Pagination.tsx +2 -10
- package/src/components/Popover/Popover.tsx +2 -9
- package/src/components/Progress/Progress.tsx +2 -7
- package/src/components/Rating/Rating.tsx +2 -10
- package/src/components/Spinner/Spinner.tsx +2 -7
- package/src/components/Steps/Steps.tsx +2 -10
- package/src/components/Tabs/Tabs.tsx +2 -9
- package/src/components/Toggle/Toggle.tsx +2 -10
- package/src/components/Tooltip/Tooltip.tsx +2 -5
- package/src/lib/composables/useAtomixGlass.ts +42 -143
- package/src/lib/composables/useAtomixGlassStyles.ts +61 -77
- package/src/lib/composables/usePerformanceMonitor.ts +5 -66
- package/src/lib/constants/components.ts +363 -46
- package/src/lib/types/components.ts +33 -1
- package/src/styles/01-settings/_settings.atomix-glass.scss +66 -28
- package/src/styles/02-tools/_tools.button.scss +51 -42
- package/src/styles/02-tools/_tools.glass.scss +45 -3
- package/src/styles/06-components/_components.atomix-glass.scss +116 -79
- package/src/components/AtomixGlass/PerformanceDashboard.tsx +0 -171
- package/src/components/AtomixGlass/animation-system.ts +0 -578
- package/src/components/AtomixGlass/deprecated/AtomixGlass.deprecated.tsx +0 -390
package/dist/index.js
CHANGED
|
@@ -1710,6 +1710,268 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
|
|
|
1710
1710
|
NEWSLETTER_BUTTON_TEXT: "Subscribe",
|
|
1711
1711
|
BACK_TO_TOP_TEXT: "Back to Top"
|
|
1712
1712
|
}
|
|
1713
|
+
}, GLASS_DEFAULTS = {
|
|
1714
|
+
/**
|
|
1715
|
+
* Button — compact interactive element.
|
|
1716
|
+
* Low displacement + no blur override so the backdrop token handles frosting.
|
|
1717
|
+
* Zero elasticity: the button itself handles press/hover feedback.
|
|
1718
|
+
*/
|
|
1719
|
+
BUTTON: {
|
|
1720
|
+
displacementScale: 16,
|
|
1721
|
+
saturation: 180,
|
|
1722
|
+
elasticity: 0
|
|
1723
|
+
},
|
|
1724
|
+
/**
|
|
1725
|
+
* Badge — pill-shaped tag. Tiny surface, minimal distortion.
|
|
1726
|
+
* borderRadius is set dynamically at runtime; this serves as a safe fallback.
|
|
1727
|
+
*/
|
|
1728
|
+
BADGE: {
|
|
1729
|
+
displacementScale: 14,
|
|
1730
|
+
borderRadius: 16,
|
|
1731
|
+
elasticity: 0
|
|
1732
|
+
},
|
|
1733
|
+
/**
|
|
1734
|
+
* Accordion — block-level content container.
|
|
1735
|
+
* Gentle displacement; zero elasticity so open/close animation isn't jittery.
|
|
1736
|
+
*/
|
|
1737
|
+
ACCORDION: {
|
|
1738
|
+
displacementScale: 18,
|
|
1739
|
+
elasticity: 0
|
|
1740
|
+
},
|
|
1741
|
+
/**
|
|
1742
|
+
* Callout — notification / alert banner.
|
|
1743
|
+
* Slightly more frosted than Accordion to give it visual priority.
|
|
1744
|
+
*/
|
|
1745
|
+
CALLOUT: {
|
|
1746
|
+
displacementScale: 22,
|
|
1747
|
+
borderRadius: 8,
|
|
1748
|
+
elasticity: 0
|
|
1749
|
+
},
|
|
1750
|
+
/**
|
|
1751
|
+
* Dropdown — floating menu. Small surface, should feel light and airy.
|
|
1752
|
+
* No blur override — rely on the backdrop token.
|
|
1753
|
+
*/
|
|
1754
|
+
DROPDOWN: {
|
|
1755
|
+
displacementScale: 16,
|
|
1756
|
+
elasticity: 0
|
|
1757
|
+
},
|
|
1758
|
+
/**
|
|
1759
|
+
* EdgePanel — full-height side drawer.
|
|
1760
|
+
* Empty config: the panel inherits all ATOMIX_GLASS.DEFAULTS.
|
|
1761
|
+
* borderRadius and size are managed by the panel's own SCSS.
|
|
1762
|
+
*/
|
|
1763
|
+
EDGE_PANEL: {},
|
|
1764
|
+
/**
|
|
1765
|
+
* Modal — full-screen overlay dialog. Shader mode for premium refraction.
|
|
1766
|
+
* displacementScale omitted — set dynamically from modal content height at runtime.
|
|
1767
|
+
* elasticity: 0 — modals should not wobble when the user interacts with them.
|
|
1768
|
+
*/
|
|
1769
|
+
MODAL: {
|
|
1770
|
+
blurAmount: 28,
|
|
1771
|
+
elasticity: 0,
|
|
1772
|
+
mode: "shader",
|
|
1773
|
+
shaderMode: "premiumGlass"
|
|
1774
|
+
},
|
|
1775
|
+
/**
|
|
1776
|
+
* Navbar — sticky / fixed navigation bar spanning full width.
|
|
1777
|
+
* Shader gives the top edge a polished lens look.
|
|
1778
|
+
* borderRadius: 0 — navbars run edge-to-edge.
|
|
1779
|
+
* elasticity: 0 — no wobble on a fixed chrome element.
|
|
1780
|
+
*/
|
|
1781
|
+
NAVBAR: {
|
|
1782
|
+
displacementScale: 24,
|
|
1783
|
+
blurAmount: 24,
|
|
1784
|
+
borderRadius: 0,
|
|
1785
|
+
elasticity: 0,
|
|
1786
|
+
mode: "shader",
|
|
1787
|
+
shaderVariant: "premiumGlass"
|
|
1788
|
+
},
|
|
1789
|
+
/**
|
|
1790
|
+
* Nav (inline nav list) — narrower than a full Navbar, standard mode is
|
|
1791
|
+
* enough. Rounded corners to match typical pill / tab nav designs.
|
|
1792
|
+
*/
|
|
1793
|
+
NAV: {
|
|
1794
|
+
displacementScale: 24,
|
|
1795
|
+
blurAmount: 20,
|
|
1796
|
+
borderRadius: 8,
|
|
1797
|
+
elasticity: 0,
|
|
1798
|
+
mode: "shader"
|
|
1799
|
+
},
|
|
1800
|
+
/**
|
|
1801
|
+
* SideMenu — persistent sidebar navigation.
|
|
1802
|
+
* Moderate displacement; shader for depth. Zero elasticity.
|
|
1803
|
+
*/
|
|
1804
|
+
SIDE_MENU: {
|
|
1805
|
+
displacementScale: 24,
|
|
1806
|
+
blurAmount: 24,
|
|
1807
|
+
borderRadius: 0,
|
|
1808
|
+
elasticity: 0,
|
|
1809
|
+
mode: "shader"
|
|
1810
|
+
},
|
|
1811
|
+
/**
|
|
1812
|
+
* Popover — small floating card above content.
|
|
1813
|
+
* Shader mode + aberration for the characteristic lens fringe.
|
|
1814
|
+
* Low displacement so the content remains readable.
|
|
1815
|
+
*/
|
|
1816
|
+
POPOVER: {
|
|
1817
|
+
displacementScale: 22,
|
|
1818
|
+
blurAmount: 20,
|
|
1819
|
+
saturation: 180,
|
|
1820
|
+
aberrationIntensity: .35,
|
|
1821
|
+
borderRadius: 12,
|
|
1822
|
+
elasticity: 0,
|
|
1823
|
+
mode: "shader"
|
|
1824
|
+
},
|
|
1825
|
+
/**
|
|
1826
|
+
* Tooltip — tiny single-line label.
|
|
1827
|
+
* Higher displacement than other small elements because tooltips float
|
|
1828
|
+
* freely and the distortion reads as depth. No shader (too small to matter).
|
|
1829
|
+
*/
|
|
1830
|
+
TOOLTIP: {
|
|
1831
|
+
displacementScale: 18,
|
|
1832
|
+
blurAmount: 16,
|
|
1833
|
+
elasticity: 0
|
|
1834
|
+
},
|
|
1835
|
+
/**
|
|
1836
|
+
* Tabs — tabbed content panel. Shader for the nav strip refraction.
|
|
1837
|
+
*/
|
|
1838
|
+
TABS: {
|
|
1839
|
+
displacementScale: 24,
|
|
1840
|
+
blurAmount: 20,
|
|
1841
|
+
saturation: 180,
|
|
1842
|
+
aberrationIntensity: .35,
|
|
1843
|
+
borderRadius: 12,
|
|
1844
|
+
elasticity: 0,
|
|
1845
|
+
mode: "shader"
|
|
1846
|
+
},
|
|
1847
|
+
/**
|
|
1848
|
+
* Toggle — switch control. Compact, pill shape.
|
|
1849
|
+
* Relies on borderRadius from the component's own SCSS.
|
|
1850
|
+
*/
|
|
1851
|
+
TOGGLE: {
|
|
1852
|
+
displacementScale: 16,
|
|
1853
|
+
elasticity: 0
|
|
1854
|
+
},
|
|
1855
|
+
/**
|
|
1856
|
+
* Form inputs (Input, Textarea, Select, Checkbox, Radio).
|
|
1857
|
+
* Unified glass feel for all form controls — subtle displacement,
|
|
1858
|
+
* rounded corners matching the $input-border-radius token (≈ 6px).
|
|
1859
|
+
*/
|
|
1860
|
+
INPUT: {
|
|
1861
|
+
displacementScale: 18,
|
|
1862
|
+
borderRadius: 6,
|
|
1863
|
+
elasticity: 0
|
|
1864
|
+
},
|
|
1865
|
+
TEXTAREA: {
|
|
1866
|
+
displacementScale: 18,
|
|
1867
|
+
borderRadius: 6,
|
|
1868
|
+
elasticity: 0
|
|
1869
|
+
},
|
|
1870
|
+
SELECT: {
|
|
1871
|
+
displacementScale: 18,
|
|
1872
|
+
borderRadius: 6,
|
|
1873
|
+
elasticity: 0
|
|
1874
|
+
},
|
|
1875
|
+
CHECKBOX: {
|
|
1876
|
+
displacementScale: 14,
|
|
1877
|
+
borderRadius: 4,
|
|
1878
|
+
elasticity: 0
|
|
1879
|
+
},
|
|
1880
|
+
RADIO: {
|
|
1881
|
+
displacementScale: 14,
|
|
1882
|
+
borderRadius: 99,
|
|
1883
|
+
elasticity: 0
|
|
1884
|
+
},
|
|
1885
|
+
/**
|
|
1886
|
+
* Pagination — row of page buttons.
|
|
1887
|
+
* Thin, horizontal strip; low displacement so numbers stay legible.
|
|
1888
|
+
*/
|
|
1889
|
+
PAGINATION: {
|
|
1890
|
+
displacementScale: 18,
|
|
1891
|
+
borderRadius: 8,
|
|
1892
|
+
elasticity: 0
|
|
1893
|
+
},
|
|
1894
|
+
/**
|
|
1895
|
+
* Progress — horizontal bar track.
|
|
1896
|
+
* Very low displacement — the bar should not distort.
|
|
1897
|
+
*/
|
|
1898
|
+
PROGRESS: {
|
|
1899
|
+
displacementScale: 10,
|
|
1900
|
+
borderRadius: 99,
|
|
1901
|
+
elasticity: 0
|
|
1902
|
+
},
|
|
1903
|
+
/**
|
|
1904
|
+
* Rating — star picker.
|
|
1905
|
+
* Compact inline element; minimal glass, no shader needed.
|
|
1906
|
+
*/
|
|
1907
|
+
RATING: {
|
|
1908
|
+
displacementScale: 16,
|
|
1909
|
+
elasticity: 0
|
|
1910
|
+
},
|
|
1911
|
+
/**
|
|
1912
|
+
* Spinner — loading indicator.
|
|
1913
|
+
* Barely-there glass; the spinner itself provides visual interest.
|
|
1914
|
+
*/
|
|
1915
|
+
SPINNER: {
|
|
1916
|
+
displacementScale: 12,
|
|
1917
|
+
elasticity: 0
|
|
1918
|
+
},
|
|
1919
|
+
/**
|
|
1920
|
+
* Steps — horizontal / vertical stepper.
|
|
1921
|
+
* Moderate displacement so the connector lines remain crisp.
|
|
1922
|
+
*/
|
|
1923
|
+
STEPS: {
|
|
1924
|
+
displacementScale: 22,
|
|
1925
|
+
borderRadius: 8,
|
|
1926
|
+
elasticity: 0
|
|
1927
|
+
},
|
|
1928
|
+
/**
|
|
1929
|
+
* Messages / chat bubbles.
|
|
1930
|
+
* Rounded pill-like bubbles; gentle glass to aid readability.
|
|
1931
|
+
*/
|
|
1932
|
+
MESSAGES: {
|
|
1933
|
+
displacementScale: 20,
|
|
1934
|
+
borderRadius: 16,
|
|
1935
|
+
elasticity: 0
|
|
1936
|
+
}
|
|
1937
|
+
}, GLASS_BORDER_GRADIENT = {
|
|
1938
|
+
BASE_ANGLE: 135,
|
|
1939
|
+
ANGLE_MULTIPLIER: .5,
|
|
1940
|
+
VELOCITY_ANGLE_MULTIPLIER: .5,
|
|
1941
|
+
CHROMATIC_OFFSET: 1.5,
|
|
1942
|
+
STOP_1: {
|
|
1943
|
+
MIN: 10,
|
|
1944
|
+
BASE: 33,
|
|
1945
|
+
get MULTIPLIER() {
|
|
1946
|
+
return .009 * this.BASE;
|
|
1947
|
+
}
|
|
1948
|
+
},
|
|
1949
|
+
STOP_2: {
|
|
1950
|
+
MAX: 90,
|
|
1951
|
+
BASE: 66,
|
|
1952
|
+
get MULTIPLIER() {
|
|
1953
|
+
return .006 * this.BASE;
|
|
1954
|
+
}
|
|
1955
|
+
},
|
|
1956
|
+
OPACITY: {
|
|
1957
|
+
/** Matches $glass-border-1-opacity (0.08) */
|
|
1958
|
+
BASE_1: .08,
|
|
1959
|
+
get BASE_2() {
|
|
1960
|
+
return 3.33 * this.BASE_1;
|
|
1961
|
+
},
|
|
1962
|
+
get BASE_3() {
|
|
1963
|
+
return 2.66 * this.BASE_1;
|
|
1964
|
+
},
|
|
1965
|
+
get BASE_4() {
|
|
1966
|
+
return 5 * this.BASE_1;
|
|
1967
|
+
},
|
|
1968
|
+
get MULTIPLIER_LOW() {
|
|
1969
|
+
return .066 * this.BASE_1;
|
|
1970
|
+
},
|
|
1971
|
+
get MULTIPLIER_HIGH() {
|
|
1972
|
+
return .1 * this.BASE_1;
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1713
1975
|
}, ATOMIX_GLASS = {
|
|
1714
1976
|
BASE_CLASS: "c-atomix-glass",
|
|
1715
1977
|
CONTAINER_CLASS: "c-atomix-glass__container",
|
|
@@ -1721,6 +1983,22 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
|
|
|
1721
1983
|
BORDER_BACKDROP_CLASS: "c-atomix-glass__border-backdrop",
|
|
1722
1984
|
BORDER_1_CLASS: "c-atomix-glass__border-1",
|
|
1723
1985
|
BORDER_2_CLASS: "c-atomix-glass__border-2",
|
|
1986
|
+
/** Centralized liquid glass rim configuration */
|
|
1987
|
+
BORDER: {
|
|
1988
|
+
WIDTH_CSS_VAR: "--atomix-glass-border-width",
|
|
1989
|
+
DEFAULT_WIDTH: "0.5px",
|
|
1990
|
+
GRADIENT_CSS_VARS: {
|
|
1991
|
+
GRADIENT_1: "--atomix-glass-border-gradient-1",
|
|
1992
|
+
GRADIENT_2: "--atomix-glass-border-gradient-2"
|
|
1993
|
+
},
|
|
1994
|
+
GRADIENT: GLASS_BORDER_GRADIENT,
|
|
1995
|
+
OVER_LIGHT: {
|
|
1996
|
+
opacity: .7
|
|
1997
|
+
},
|
|
1998
|
+
DARK: {
|
|
1999
|
+
opacity: .35
|
|
2000
|
+
}
|
|
2001
|
+
},
|
|
1724
2002
|
HOVER_1_CLASS: "c-atomix-glass__hover-1",
|
|
1725
2003
|
HOVER_2_CLASS: "c-atomix-glass__hover-2",
|
|
1726
2004
|
HOVER_3_CLASS: "c-atomix-glass__hover-3",
|
|
@@ -1749,25 +2027,22 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
|
|
|
1749
2027
|
SHADER: "c-atomix-glass--shader"
|
|
1750
2028
|
},
|
|
1751
2029
|
DEFAULTS: {
|
|
1752
|
-
|
|
2030
|
+
/** Subtle refraction — Apple UI chrome avoids heavy liquid distortion */
|
|
2031
|
+
DISPLACEMENT_SCALE: 28,
|
|
1753
2032
|
get BLUR_AMOUNT() {
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
// Saturate relative to intensity
|
|
1760
|
-
},
|
|
2033
|
+
// Apple Music sidebar / player bar: ~20–40px frost (see $glass-backdrop-filter)
|
|
2034
|
+
return Math.max(20, .72 * this.DISPLACEMENT_SCALE);
|
|
2035
|
+
},
|
|
2036
|
+
/** Fixed 180% matches Apple's saturate(180%) backdrop recipe */
|
|
2037
|
+
SATURATION: 180,
|
|
1761
2038
|
get ABERRATION_INTENSITY() {
|
|
1762
|
-
return .
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
ELASTICITY: .15,
|
|
2039
|
+
return .02 * this.DISPLACEMENT_SCALE;
|
|
2040
|
+
},
|
|
2041
|
+
ELASTICITY: .05,
|
|
1766
2042
|
get CORNER_RADIUS() {
|
|
1767
2043
|
return 16;
|
|
1768
2044
|
// Use 16 to match SCSS design system (was 20)
|
|
1769
2045
|
},
|
|
1770
|
-
PADDING: "0",
|
|
1771
2046
|
MODE: "standard",
|
|
1772
2047
|
OVER_LIGHT: !1,
|
|
1773
2048
|
ENABLE_OVER_LIGHT_LAYERS: !0,
|
|
@@ -1783,19 +2058,29 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
|
|
|
1783
2058
|
},
|
|
1784
2059
|
CONSTANTS: {
|
|
1785
2060
|
ACTIVATION_ZONE: 200,
|
|
1786
|
-
LERP_FACTOR: .
|
|
2061
|
+
LERP_FACTOR: .05,
|
|
2062
|
+
// Lower = more viscous, liquid-smooth tracking (Apple feel)
|
|
1787
2063
|
SMOOTHSTEP_POWER: 2.5,
|
|
1788
2064
|
MIN_BLUR: .1,
|
|
1789
2065
|
MOUSE_INFLUENCE_DIVISOR: 100,
|
|
1790
2066
|
EDGE_FADE_PIXELS: 2,
|
|
1791
|
-
//
|
|
1792
|
-
|
|
2067
|
+
// Interaction intensity multipliers shared by the hook and the imperative style updater
|
|
2068
|
+
INTERACTION: {
|
|
2069
|
+
HOVER_INTENSITY: 1.4,
|
|
2070
|
+
ACTIVE_INTENSITY: 1.6
|
|
2071
|
+
},
|
|
2072
|
+
// Elasticity physics constants — Apple-tuned: soft springs, fast settling, minimal stretch
|
|
2073
|
+
ELASTICITY_TRANSLATION_FACTOR: .06,
|
|
2074
|
+
// Subtler elastic shift (was 0.1)
|
|
1793
2075
|
ELASTICITY_DISTANCE_THRESHOLD: 200,
|
|
1794
2076
|
ELASTICITY_COMPRESSION_FACTOR: .3,
|
|
1795
|
-
ELASTICITY_STIFFNESS: .
|
|
1796
|
-
|
|
2077
|
+
ELASTICITY_STIFFNESS: .06,
|
|
2078
|
+
// Softer springs = gentler motion (was 0.1)
|
|
2079
|
+
ELASTICITY_DAMPING: .88,
|
|
2080
|
+
// Fast settling, no wobble (was 0.76)
|
|
1797
2081
|
ELASTICITY_VELOCITY_FACTOR: .65,
|
|
1798
|
-
ELASTICITY_STRETCH_RATIO: .
|
|
2082
|
+
ELASTICITY_STRETCH_RATIO: .25,
|
|
2083
|
+
// Less visible surface tension stretch (was 0.45)
|
|
1799
2084
|
ELASTICITY_MAGNIFICATION_BASE: 1.02,
|
|
1800
2085
|
// Note: This default must match the SCSS variable --atomix-radius-md
|
|
1801
2086
|
// @see src/styles/01-settings/_settings.global.scss
|
|
@@ -1809,55 +2094,16 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
|
|
|
1809
2094
|
},
|
|
1810
2095
|
// Gradient calculation constants
|
|
1811
2096
|
GRADIENT: {
|
|
1812
|
-
BASE_ANGLE:
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
// Minimum percentage for border stop 1
|
|
1823
|
-
BASE: 33,
|
|
1824
|
-
// Base percentage for border stop 1
|
|
1825
|
-
get MULTIPLIER() {
|
|
1826
|
-
return .009 * this.BASE;
|
|
1827
|
-
}
|
|
1828
|
-
},
|
|
1829
|
-
BORDER_STOP_2: {
|
|
1830
|
-
MAX: 90,
|
|
1831
|
-
// Maximum percentage for border stop 2
|
|
1832
|
-
BASE: 66,
|
|
1833
|
-
// Base percentage for border stop 2
|
|
1834
|
-
get MULTIPLIER() {
|
|
1835
|
-
return .006 * this.BASE;
|
|
1836
|
-
}
|
|
1837
|
-
},
|
|
1838
|
-
BORDER_OPACITY: {
|
|
1839
|
-
BASE_1: .12,
|
|
1840
|
-
// Base opacity for border gradient 1
|
|
1841
|
-
get BASE_2() {
|
|
1842
|
-
return 3.33 * this.BASE_1;
|
|
1843
|
-
},
|
|
1844
|
-
// Base opacity for border gradient 2
|
|
1845
|
-
get BASE_3() {
|
|
1846
|
-
return 2.66 * this.BASE_1;
|
|
1847
|
-
},
|
|
1848
|
-
// Base opacity for border gradient 3
|
|
1849
|
-
get BASE_4() {
|
|
1850
|
-
return 5 * this.BASE_1;
|
|
1851
|
-
},
|
|
1852
|
-
// Base opacity for border gradient 4
|
|
1853
|
-
get MULTIPLIER_LOW() {
|
|
1854
|
-
return .066 * this.BASE_1;
|
|
1855
|
-
},
|
|
1856
|
-
// Low multiplier for mouse influence on opacity
|
|
1857
|
-
get MULTIPLIER_HIGH() {
|
|
1858
|
-
return .1 * this.BASE_1;
|
|
1859
|
-
}
|
|
1860
|
-
},
|
|
2097
|
+
BASE_ANGLE: GLASS_BORDER_GRADIENT.BASE_ANGLE,
|
|
2098
|
+
ANGLE_MULTIPLIER: GLASS_BORDER_GRADIENT.ANGLE_MULTIPLIER,
|
|
2099
|
+
VELOCITY_ANGLE_MULTIPLIER: GLASS_BORDER_GRADIENT.VELOCITY_ANGLE_MULTIPLIER,
|
|
2100
|
+
CHROMATIC_OFFSET: GLASS_BORDER_GRADIENT.CHROMATIC_OFFSET,
|
|
2101
|
+
/** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.STOP_1 */
|
|
2102
|
+
BORDER_STOP_1: GLASS_BORDER_GRADIENT.STOP_1,
|
|
2103
|
+
/** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.STOP_2 */
|
|
2104
|
+
BORDER_STOP_2: GLASS_BORDER_GRADIENT.STOP_2,
|
|
2105
|
+
/** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.OPACITY */
|
|
2106
|
+
BORDER_OPACITY: GLASS_BORDER_GRADIENT.OPACITY,
|
|
1861
2107
|
CENTER_POSITION: 50,
|
|
1862
2108
|
// Center position percentage (50%)
|
|
1863
2109
|
HOVER_POSITION: {
|
|
@@ -1890,8 +2136,8 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
|
|
|
1890
2136
|
return 2 * this.BLACK_STOP;
|
|
1891
2137
|
},
|
|
1892
2138
|
// End percentage for black hover 1
|
|
1893
|
-
WHITE_START: .
|
|
1894
|
-
//
|
|
2139
|
+
WHITE_START: .35,
|
|
2140
|
+
// Gentler hover flash — Apple hover is barely visible
|
|
1895
2141
|
get WHITE_STOP() {
|
|
1896
2142
|
return this.BLACK_END - 10;
|
|
1897
2143
|
}
|
|
@@ -1909,8 +2155,8 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
|
|
|
1909
2155
|
return 2 * this.BLACK_STOP;
|
|
1910
2156
|
},
|
|
1911
2157
|
// End percentage for black hover 2
|
|
1912
|
-
WHITE_START:
|
|
1913
|
-
//
|
|
2158
|
+
WHITE_START: .7,
|
|
2159
|
+
// Gentler hover flash
|
|
1914
2160
|
get WHITE_STOP() {
|
|
1915
2161
|
return this.BLACK_END;
|
|
1916
2162
|
}
|
|
@@ -1928,8 +2174,8 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
|
|
|
1928
2174
|
return 2 * this.BLACK_STOP;
|
|
1929
2175
|
},
|
|
1930
2176
|
// End percentage for black hover 3
|
|
1931
|
-
WHITE_START:
|
|
1932
|
-
//
|
|
2177
|
+
WHITE_START: .7,
|
|
2178
|
+
// Gentler hover flash
|
|
1933
2179
|
get WHITE_STOP() {
|
|
1934
2180
|
return this.BLACK_END;
|
|
1935
2181
|
}
|
|
@@ -1939,13 +2185,13 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
|
|
|
1939
2185
|
BASE_GRADIENT: {
|
|
1940
2186
|
ANGLE: 135,
|
|
1941
2187
|
// Gradient angle in degrees
|
|
1942
|
-
BLACK_START_BASE: .
|
|
2188
|
+
BLACK_START_BASE: .1,
|
|
1943
2189
|
// Base start opacity for black
|
|
1944
2190
|
get BLACK_START_MULTIPLIER() {
|
|
1945
2191
|
return .02 * this.BLACK_START_BASE;
|
|
1946
2192
|
},
|
|
1947
2193
|
// Multiplier for mouse X influence on start
|
|
1948
|
-
BLACK_MID_BASE: .
|
|
2194
|
+
BLACK_MID_BASE: .07,
|
|
1949
2195
|
// Base mid opacity for black
|
|
1950
2196
|
get BLACK_MID_MULTIPLIER() {
|
|
1951
2197
|
return .02 * this.BLACK_MID_BASE;
|
|
@@ -1966,7 +2212,7 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
|
|
|
1966
2212
|
}
|
|
1967
2213
|
},
|
|
1968
2214
|
OVERLAY_GRADIENT: {
|
|
1969
|
-
BLACK_START_BASE: .
|
|
2215
|
+
BLACK_START_BASE: .08,
|
|
1970
2216
|
// Base start opacity for black overlay
|
|
1971
2217
|
get BLACK_START_MULTIPLIER() {
|
|
1972
2218
|
return .025 * this.BLACK_START_BASE;
|
|
@@ -1990,14 +2236,14 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
|
|
|
1990
2236
|
return .416 * this.BLACK_START_BASE;
|
|
1991
2237
|
}
|
|
1992
2238
|
},
|
|
1993
|
-
// Overlay highlight constants
|
|
2239
|
+
// Overlay highlight constants — Apple places specular at the top-center
|
|
1994
2240
|
OVERLAY_HIGHLIGHT: {
|
|
1995
|
-
POSITION_X:
|
|
1996
|
-
//
|
|
1997
|
-
POSITION_Y:
|
|
1998
|
-
//
|
|
1999
|
-
WHITE_OPACITY: .
|
|
2000
|
-
//
|
|
2241
|
+
POSITION_X: 50,
|
|
2242
|
+
// Centered horizontal — Apple's top-center specular
|
|
2243
|
+
POSITION_Y: 5,
|
|
2244
|
+
// Very top — catches light like a curved glass surface
|
|
2245
|
+
WHITE_OPACITY: .28,
|
|
2246
|
+
// Softer specular — visible but not glaring
|
|
2001
2247
|
get STOP() {
|
|
2002
2248
|
return 150 * this.WHITE_OPACITY;
|
|
2003
2249
|
},
|
|
@@ -2018,6 +2264,10 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
|
|
|
2018
2264
|
SATURATION: {
|
|
2019
2265
|
HIGH_CONTRAST: 200
|
|
2020
2266
|
},
|
|
2267
|
+
// Container shadows — hairline inner catch + soft floating lift (Apple player bar)
|
|
2268
|
+
CONTAINER_SHADOW: {
|
|
2269
|
+
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)"
|
|
2270
|
+
},
|
|
2021
2271
|
// Phase 1: Animation System Constants
|
|
2022
2272
|
ANIMATION: {
|
|
2023
2273
|
// Breathing effect timing (in milliseconds)
|
|
@@ -2114,120 +2364,472 @@ function useAccordion(initialProps) {
|
|
|
2114
2364
|
};
|
|
2115
2365
|
}
|
|
2116
2366
|
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$2.MOUSE_INFLUENCE_DIVISOR;
|
|
2127
|
-
return Math.min(.8, influence);
|
|
2128
|
-
// Tighter cap to prevent blur/filter blow-out
|
|
2129
|
-
}, 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 => {
|
|
2130
|
-
if ("number" == typeof value) return Math.max(0, value);
|
|
2131
|
-
if ("string" != typeof value || !value.trim()) return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
|
|
2132
|
-
const trimmedValue = value.trim();
|
|
2133
|
-
// Handle px values
|
|
2134
|
-
if (trimmedValue.endsWith("px")) {
|
|
2135
|
-
const parsed = parseFloat(trimmedValue);
|
|
2136
|
-
return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, parsed);
|
|
2137
|
-
}
|
|
2138
|
-
// Handle rem values (assume 16px = 1rem)
|
|
2139
|
-
if (trimmedValue.endsWith("rem")) {
|
|
2140
|
-
const parsed = parseFloat(trimmedValue);
|
|
2141
|
-
return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
|
|
2142
|
-
}
|
|
2143
|
-
// Handle em values (assume 16px = 1em for simplicity)
|
|
2144
|
-
if (trimmedValue.endsWith("em")) {
|
|
2145
|
-
const parsed = parseFloat(trimmedValue);
|
|
2146
|
-
return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
|
|
2147
|
-
}
|
|
2148
|
-
// Handle percentage (convert to approximate px value, assuming 200px container)
|
|
2149
|
-
if (trimmedValue.endsWith("%")) {
|
|
2150
|
-
const parsed = parseFloat(trimmedValue);
|
|
2151
|
-
return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, parsed / 100 * 200);
|
|
2152
|
-
}
|
|
2153
|
-
// Handle unitless numbers
|
|
2154
|
-
const numValue = parseFloat(trimmedValue);
|
|
2155
|
-
return isNaN(numValue) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, numValue);
|
|
2156
|
-
}, extractBorderRadiusFromElement = element => {
|
|
2157
|
-
if (!element || !element.props) return null;
|
|
2158
|
-
// Check inline styles first (highest priority)
|
|
2159
|
-
if (element.props.style) {
|
|
2160
|
-
const radiusFromStyle = (style => {
|
|
2161
|
-
if (!style) return null;
|
|
2162
|
-
// Check various border-radius properties
|
|
2163
|
-
const borderRadius = style.borderRadius || style.borderTopLeftRadius || style.borderTopRightRadius || style.borderBottomLeftRadius || style.borderBottomRightRadius;
|
|
2164
|
-
return void 0 !== borderRadius ? parseBorderRadiusValue(borderRadius) : null;
|
|
2165
|
-
})(element.props.style);
|
|
2166
|
-
if (null !== radiusFromStyle && radiusFromStyle > 0) return radiusFromStyle;
|
|
2167
|
-
}
|
|
2168
|
-
// If element has children, recursively check them
|
|
2169
|
-
if (element.props.children) {
|
|
2170
|
-
const childRadius = extractBorderRadiusFromChildren(element.props.children);
|
|
2171
|
-
if (childRadius > 0 && childRadius !== CONSTANTS$2.DEFAULT_CORNER_RADIUS) return childRadius;
|
|
2172
|
-
}
|
|
2173
|
-
return null;
|
|
2174
|
-
}, extractBorderRadiusFromChildren = children => {
|
|
2175
|
-
if (!children) return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
|
|
2176
|
-
try {
|
|
2177
|
-
const childArray = React__default.default.Children.toArray(children);
|
|
2178
|
-
for (let i = 0; i < childArray.length; i++) {
|
|
2179
|
-
const child = childArray[i];
|
|
2180
|
-
if ( React__default.default.isValidElement(child)) {
|
|
2181
|
-
const radius = extractBorderRadiusFromElement(child);
|
|
2182
|
-
if (null !== radius) return radius;
|
|
2367
|
+
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) {
|
|
2368
|
+
return function(that, callbackfn, argumentsLength, memo) {
|
|
2369
|
+
var O = toObject(that), self = IndexedObject(O), length = lengthOfArrayLike(O);
|
|
2370
|
+
if (aCallable(callbackfn), 0 === length && argumentsLength < 2) throw new $TypeError(REDUCE_EMPTY);
|
|
2371
|
+
var index = IS_RIGHT ? length - 1 : 0, i = IS_RIGHT ? -1 : 1;
|
|
2372
|
+
if (argumentsLength < 2) for (;;) {
|
|
2373
|
+
if (index in self) {
|
|
2374
|
+
memo = self[index], index += i;
|
|
2375
|
+
break;
|
|
2183
2376
|
}
|
|
2377
|
+
if (index += i, IS_RIGHT ? index < 0 : length <= index) throw new $TypeError(REDUCE_EMPTY);
|
|
2184
2378
|
}
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
}
|
|
2188
|
-
return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
|
|
2189
|
-
}, smoothstep = t => {
|
|
2190
|
-
const clamped = Math.max(0, Math.min(1, t));
|
|
2191
|
-
return clamped * clamped * (3 - 2 * clamped);
|
|
2192
|
-
}, lerp$1 = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), calculateSpring = (current, target, velocity, stiffness = .1, damping = .8) => {
|
|
2193
|
-
const newVelocity = (velocity + (target - current) * stiffness) * damping;
|
|
2194
|
-
return {
|
|
2195
|
-
value: current + newVelocity,
|
|
2196
|
-
velocity: newVelocity
|
|
2379
|
+
for (;IS_RIGHT ? index >= 0 : length > index; index += i) index in self && (memo = callbackfn(memo, self[index], index, O));
|
|
2380
|
+
return memo;
|
|
2197
2381
|
};
|
|
2198
|
-
},
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2382
|
+
}, arrayReduce = {
|
|
2383
|
+
// `Array.prototype.reduce` method
|
|
2384
|
+
// https://tc39.es/ecma262/#sec-array.prototype.reduce
|
|
2385
|
+
left: createMethod(!1),
|
|
2386
|
+
// `Array.prototype.reduceRight` method
|
|
2387
|
+
// https://tc39.es/ecma262/#sec-array.prototype.reduceright
|
|
2388
|
+
right: createMethod(!0)
|
|
2389
|
+
}, fails = fails$9, globalThis$1 = globalThis_1, userAgent = environmentUserAgent, classof = classofRaw$2, userAgentStartsWith = function(string) {
|
|
2390
|
+
return userAgent.slice(0, string.length) === string;
|
|
2391
|
+
}, 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;
|
|
2202
2392
|
|
|
2203
|
-
|
|
2204
|
-
|
|
2393
|
+
// `Array.prototype.reduce` method
|
|
2394
|
+
// https://tc39.es/ecma262/#sec-array.prototype.reduce
|
|
2395
|
+
_export({
|
|
2396
|
+
target: "Array",
|
|
2397
|
+
proto: !0,
|
|
2398
|
+
forced: !("NODE" === environment) && environmentV8Version > 79 && environmentV8Version < 83 || !function(METHOD_NAME, argument) {
|
|
2399
|
+
var method = [][METHOD_NAME];
|
|
2400
|
+
return !!method && fails((function() {
|
|
2401
|
+
// eslint-disable-next-line no-useless-call -- required for testing
|
|
2402
|
+
method.call(null, argument || function() {
|
|
2403
|
+
return 1;
|
|
2404
|
+
}, 1);
|
|
2405
|
+
}));
|
|
2406
|
+
}("reduce")
|
|
2407
|
+
}, {
|
|
2408
|
+
reduce: function(callbackfn /* , initialValue */) {
|
|
2409
|
+
var length = arguments.length;
|
|
2410
|
+
return $reduce(this, callbackfn, length, length > 1 ? arguments[1] : void 0);
|
|
2411
|
+
}
|
|
2412
|
+
});
|
|
2205
2413
|
|
|
2206
|
-
|
|
2207
|
-
|
|
2414
|
+
var reduce$3 = getBuiltInPrototypeMethod$3("Array", "reduce"), isPrototypeOf = objectIsPrototypeOf, method = reduce$3, ArrayPrototype = Array.prototype, _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
2415
|
+
var own = it.reduce;
|
|
2416
|
+
return it === ArrayPrototype || isPrototypeOf(ArrayPrototype, it) && own === ArrayPrototype.reduce ? method : own;
|
|
2417
|
+
}));
|
|
2208
2418
|
|
|
2209
|
-
|
|
2210
|
-
|
|
2419
|
+
/**
|
|
2420
|
+
* Map SCSS tokens to CSS custom properties
|
|
2421
|
+
*
|
|
2422
|
+
* @example
|
|
2423
|
+
* const tokens = { '$primary-color': '#7AFFD7', '$spacing-md': '16px' }
|
|
2424
|
+
* const vars = mapSCSSTokensToCSSVars(tokens)
|
|
2425
|
+
* // Returns: { '--primary-color': '#7AFFD7', '--spacing-md': '16px' }
|
|
2426
|
+
*/
|
|
2427
|
+
function mapSCSSTokensToCSSVars(tokens, options = {}) {
|
|
2428
|
+
const vars = {}, {prefix: prefix = "atomix", separator: separator = "-"} = options;
|
|
2429
|
+
return Object.entries(tokens).forEach((([key, value]) => {
|
|
2430
|
+
// Remove $ prefix from SCSS variables
|
|
2431
|
+
const normalizedKey = (key.startsWith("$") ? key.slice(1) : key).replace(/_/g, separator);
|
|
2432
|
+
// Convert underscores to separators
|
|
2433
|
+
vars[`--${prefix}${separator}${normalizedKey}`] = String(value);
|
|
2434
|
+
})), vars;
|
|
2435
|
+
}
|
|
2211
2436
|
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2437
|
+
/**
|
|
2438
|
+
* Apply CSS variables to an element
|
|
2439
|
+
*
|
|
2440
|
+
* @param vars - CSS variables to apply
|
|
2441
|
+
* @param element - Target element (defaults to document.documentElement)
|
|
2442
|
+
*/ function applyCSSVariables(vars, element) {
|
|
2443
|
+
if ("undefined" == typeof window) return;
|
|
2444
|
+
// SSR safety
|
|
2445
|
+
const target = element || document.documentElement;
|
|
2446
|
+
Object.entries(vars).forEach((([key, value]) => {
|
|
2447
|
+
target.style.setProperty(key, String(value));
|
|
2448
|
+
}));
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2451
|
+
/**
|
|
2452
|
+
* Remove CSS variables from an element
|
|
2453
|
+
*
|
|
2454
|
+
* @param varNames - Variable names to remove
|
|
2455
|
+
* @param element - Target element (defaults to document.documentElement)
|
|
2456
|
+
*/ function removeCSSVariables(varNames, element) {
|
|
2457
|
+
if ("undefined" == typeof window) return;
|
|
2458
|
+
// SSR safety
|
|
2459
|
+
const target = element || document.documentElement;
|
|
2460
|
+
varNames.forEach((varName => {
|
|
2461
|
+
target.style.removeProperty(varName);
|
|
2462
|
+
}));
|
|
2463
|
+
}
|
|
2464
|
+
|
|
2465
|
+
/**
|
|
2466
|
+
* Get CSS variable value from an element
|
|
2467
|
+
*
|
|
2468
|
+
* @param varName - Variable name to get
|
|
2469
|
+
* @param element - Target element (defaults to document.documentElement)
|
|
2470
|
+
* @returns Variable value or null if not found
|
|
2471
|
+
*/ function getCSSVariable(varName, element) {
|
|
2472
|
+
if ("undefined" == typeof window) return null;
|
|
2473
|
+
// SSR safety
|
|
2474
|
+
const target = element || document.documentElement;
|
|
2475
|
+
return getComputedStyle(target).getPropertyValue(varName).trim() || null;
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2478
|
+
/**
|
|
2479
|
+
* Convert CSS variable object to inline style object
|
|
2480
|
+
*
|
|
2481
|
+
* @example
|
|
2482
|
+
* const vars = { '--atomix-button-bg': '#000' }
|
|
2483
|
+
* const style = cssVarsToStyle(vars)
|
|
2484
|
+
* // Returns: { '--atomix-button-bg': '#000' } as React.CSSProperties
|
|
2485
|
+
*/ function cssVarsToStyle(vars) {
|
|
2486
|
+
var _context;
|
|
2487
|
+
return _reduceInstanceProperty(_context = Object.entries(vars)).call(_context, ((acc, [key, value]) => (acc[key] = "number" == typeof value ? `${value}px` : value,
|
|
2488
|
+
acc)), {});
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
/**
|
|
2492
|
+
* Merge multiple CSS variable objects
|
|
2493
|
+
* Later objects override earlier ones
|
|
2494
|
+
*/ function mergeCSSVars(...varObjects) {
|
|
2495
|
+
return _reduceInstanceProperty(varObjects).call(varObjects, ((acc, vars) => (vars && Object.assign(acc, vars),
|
|
2496
|
+
acc)), {});
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
/**
|
|
2500
|
+
* Validate CSS variable name format
|
|
2501
|
+
*/ function isValidCSSVariableName(name) {
|
|
2502
|
+
return /^--[a-z0-9-]+$/.test(name);
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2505
|
+
/**
|
|
2506
|
+
* Extract component name from CSS variable name
|
|
2507
|
+
*
|
|
2508
|
+
* @example
|
|
2509
|
+
* extractComponentName('--atomix-button-bg')
|
|
2510
|
+
* // Returns: 'button'
|
|
2511
|
+
*/ function extractComponentName(varName, prefix = "atomix") {
|
|
2512
|
+
const regex = new RegExp(`^--${prefix}-([a-z0-9]+)-`), match = varName.match(regex);
|
|
2513
|
+
return match ? match[1] ?? null : null;
|
|
2514
|
+
}
|
|
2515
|
+
|
|
2516
|
+
/**
|
|
2517
|
+
* Component Utilities
|
|
2518
|
+
*
|
|
2519
|
+
* Helper functions for component development with the new customization system
|
|
2520
|
+
*/
|
|
2521
|
+
/**
|
|
2522
|
+
* Merge multiple class names
|
|
2523
|
+
*/ function mergeClassNames(...classes) {
|
|
2524
|
+
return classes.filter(Boolean).join(" ");
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
/**
|
|
2528
|
+
* Apply part styles to element props
|
|
2529
|
+
*/ function applyPartStyles(baseProps, partStyles) {
|
|
2530
|
+
return partStyles ? {
|
|
2531
|
+
...baseProps,
|
|
2532
|
+
className: mergeClassNames(baseProps.className, partStyles.className),
|
|
2533
|
+
style: {
|
|
2534
|
+
...baseProps.style,
|
|
2535
|
+
...partStyles.style
|
|
2536
|
+
}
|
|
2537
|
+
} : baseProps;
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
/**
|
|
2541
|
+
* Create style object from CSS variables
|
|
2542
|
+
*/ function createCSSVarStyle(cssVars, baseStyle) {
|
|
2543
|
+
return cssVars ? {
|
|
2544
|
+
...cssVarsToStyle(cssVars),
|
|
2545
|
+
...baseStyle
|
|
2546
|
+
} : baseStyle || {};
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
function mergeComponentProps(baseProps, customization) {
|
|
2550
|
+
const {className: className, style: style, cssVars: cssVars, parts: parts} = customization, cssVarStyle = cssVars ? cssVarsToStyle(cssVars) : {};
|
|
2551
|
+
// Merge CSS variables into style
|
|
2552
|
+
return {
|
|
2553
|
+
...baseProps,
|
|
2554
|
+
className: mergeClassNames(baseProps.className, className),
|
|
2555
|
+
style: {
|
|
2556
|
+
...cssVarStyle,
|
|
2557
|
+
...baseProps.style,
|
|
2558
|
+
...style
|
|
2559
|
+
}
|
|
2560
|
+
};
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
/**
|
|
2564
|
+
* Get part styles from parts object
|
|
2565
|
+
*/ function getPartStyles(parts, partName) {
|
|
2566
|
+
return parts?.[partName];
|
|
2567
|
+
}
|
|
2568
|
+
|
|
2569
|
+
/**
|
|
2570
|
+
* Create element props with part styles
|
|
2571
|
+
*/ function createPartProps(baseClassName, partStyles, additionalProps) {
|
|
2572
|
+
return {
|
|
2573
|
+
...additionalProps,
|
|
2574
|
+
className: mergeClassNames(baseClassName, partStyles?.className),
|
|
2575
|
+
style: {
|
|
2576
|
+
...partStyles?.style,
|
|
2577
|
+
...additionalProps?.style
|
|
2578
|
+
}
|
|
2579
|
+
};
|
|
2580
|
+
}
|
|
2581
|
+
|
|
2582
|
+
/**
|
|
2583
|
+
* Check if component has customization
|
|
2584
|
+
*/ function hasCustomization(props) {
|
|
2585
|
+
return Boolean(props.parts || props.cssVars || props.slots);
|
|
2586
|
+
}
|
|
2587
|
+
|
|
2588
|
+
/**
|
|
2589
|
+
* Create data attributes for debugging
|
|
2590
|
+
*/ function createDebugAttrs(componentName, variant) {
|
|
2591
|
+
return "undefined" == typeof process || "development" !== process.env?.NODE_ENV ? {} : {
|
|
2592
|
+
"data-component": componentName,
|
|
2593
|
+
...variant && {
|
|
2594
|
+
"data-variant": variant
|
|
2595
|
+
}
|
|
2596
|
+
};
|
|
2597
|
+
}
|
|
2598
|
+
|
|
2599
|
+
/**
|
|
2600
|
+
* Generate a UUID v4
|
|
2601
|
+
*/ function generateUUID() {
|
|
2602
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c => {
|
|
2603
|
+
const r = 16 * Math.random() | 0;
|
|
2604
|
+
return ("x" === c ? r : 3 & r | 8).toString(16);
|
|
2605
|
+
}));
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
/**
|
|
2609
|
+
* Check if a URL is a YouTube URL
|
|
2610
|
+
*/ function isYouTubeUrl(url) {
|
|
2611
|
+
return /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+/.test(url);
|
|
2612
|
+
}
|
|
2613
|
+
|
|
2614
|
+
/**
|
|
2615
|
+
* Extract YouTube video ID from URL
|
|
2616
|
+
*/ function extractYouTubeId(url) {
|
|
2617
|
+
if (!isYouTubeUrl(url)) return null;
|
|
2618
|
+
const patterns = [ /(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([^&\n?#]+)/, /youtube\.com\/.*[?&]v=([^&\n?#]+)/ ];
|
|
2619
|
+
for (const pattern of patterns) {
|
|
2620
|
+
const match = url.match(pattern);
|
|
2621
|
+
if (match && match[1]) return match[1];
|
|
2622
|
+
}
|
|
2623
|
+
return null;
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2626
|
+
/**
|
|
2627
|
+
* Utility to merge multiple React refs into one
|
|
2628
|
+
*/ function setRef(ref, value) {
|
|
2629
|
+
"function" == typeof ref ? ref(value) : ref && (
|
|
2630
|
+
// This is safe because we're checking that ref exists first
|
|
2631
|
+
ref.current = value);
|
|
2632
|
+
}
|
|
2633
|
+
|
|
2634
|
+
/**
|
|
2635
|
+
* Combines two React refs into a single ref function
|
|
2636
|
+
* This is used when you need to use and forward a ref at the same time
|
|
2637
|
+
*/ function useForkRef(refA, refB) {
|
|
2638
|
+
return React__default.default.useMemo((() => null == refA && null == refB ? null : refValue => {
|
|
2639
|
+
setRef(refA, refValue), setRef(refB, refValue);
|
|
2640
|
+
}), [ refA, refB ]);
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
const {CONSTANTS: CONSTANTS$3} = ATOMIX_GLASS, calculateElementCenter = rect => rect ? {
|
|
2644
|
+
x: rect.left + rect.width / 2,
|
|
2645
|
+
y: rect.top + rect.height / 2
|
|
2646
|
+
} : {
|
|
2647
|
+
x: 0,
|
|
2648
|
+
y: 0
|
|
2649
|
+
}, calculateMouseInfluence = mouseOffset => {
|
|
2650
|
+
if (!mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y) return 0;
|
|
2651
|
+
// Clamp influence to keep mouse response subtle and stable.
|
|
2652
|
+
const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$3.MOUSE_INFLUENCE_DIVISOR;
|
|
2653
|
+
return Math.min(.8, influence);
|
|
2654
|
+
// Tighter cap to prevent blur/filter blow-out
|
|
2655
|
+
}, 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 => {
|
|
2656
|
+
if ("number" == typeof value) return Math.max(0, value);
|
|
2657
|
+
if ("string" != typeof value || !value.trim()) return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
|
|
2658
|
+
const trimmedValue = value.trim();
|
|
2659
|
+
// Handle px values
|
|
2660
|
+
if (trimmedValue.endsWith("px")) {
|
|
2661
|
+
const parsed = parseFloat(trimmedValue);
|
|
2662
|
+
return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, parsed);
|
|
2663
|
+
}
|
|
2664
|
+
// Handle rem values (assume 16px = 1rem)
|
|
2665
|
+
if (trimmedValue.endsWith("rem")) {
|
|
2666
|
+
const parsed = parseFloat(trimmedValue);
|
|
2667
|
+
return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
|
|
2668
|
+
}
|
|
2669
|
+
// Handle em values (assume 16px = 1em for simplicity)
|
|
2670
|
+
if (trimmedValue.endsWith("em")) {
|
|
2671
|
+
const parsed = parseFloat(trimmedValue);
|
|
2672
|
+
return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
|
|
2673
|
+
}
|
|
2674
|
+
// Handle percentage (convert to approximate px value, assuming 200px container)
|
|
2675
|
+
if (trimmedValue.endsWith("%")) {
|
|
2676
|
+
const parsed = parseFloat(trimmedValue);
|
|
2677
|
+
return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, parsed / 100 * 200);
|
|
2678
|
+
}
|
|
2679
|
+
// Handle unitless numbers
|
|
2680
|
+
const numValue = parseFloat(trimmedValue);
|
|
2681
|
+
return isNaN(numValue) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, numValue);
|
|
2682
|
+
}, extractBorderRadiusFromElement = element => {
|
|
2683
|
+
if (!element || !element.props) return null;
|
|
2684
|
+
// Check inline styles first (highest priority)
|
|
2685
|
+
if (element.props.style) {
|
|
2686
|
+
const radiusFromStyle = (style => {
|
|
2687
|
+
if (!style) return null;
|
|
2688
|
+
// Check various border-radius properties
|
|
2689
|
+
const borderRadius = style.borderRadius || style.borderTopLeftRadius || style.borderTopRightRadius || style.borderBottomLeftRadius || style.borderBottomRightRadius;
|
|
2690
|
+
return void 0 !== borderRadius ? parseBorderRadiusValue(borderRadius) : null;
|
|
2691
|
+
})(element.props.style);
|
|
2692
|
+
if (null !== radiusFromStyle && radiusFromStyle > 0) return radiusFromStyle;
|
|
2693
|
+
}
|
|
2694
|
+
// If element has children, recursively check them
|
|
2695
|
+
if (element.props.children) {
|
|
2696
|
+
const childRadius = extractBorderRadiusFromChildren(element.props.children);
|
|
2697
|
+
if (childRadius > 0 && childRadius !== CONSTANTS$3.DEFAULT_CORNER_RADIUS) return childRadius;
|
|
2698
|
+
}
|
|
2699
|
+
return null;
|
|
2700
|
+
}, extractBorderRadiusFromChildren = children => {
|
|
2701
|
+
if (!children) return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
|
|
2702
|
+
try {
|
|
2703
|
+
const childArray = React__default.default.Children.toArray(children);
|
|
2704
|
+
for (let i = 0; i < childArray.length; i++) {
|
|
2705
|
+
const child = childArray[i];
|
|
2706
|
+
if ( React__default.default.isValidElement(child)) {
|
|
2707
|
+
const radius = extractBorderRadiusFromElement(child);
|
|
2708
|
+
if (null !== radius) return radius;
|
|
2709
|
+
}
|
|
2710
|
+
}
|
|
2711
|
+
} catch (error) {
|
|
2712
|
+
// Silently handle errors
|
|
2713
|
+
}
|
|
2714
|
+
return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
|
|
2715
|
+
}, smoothstep = t => {
|
|
2716
|
+
const clamped = Math.max(0, Math.min(1, t));
|
|
2717
|
+
return clamped * clamped * (3 - 2 * clamped);
|
|
2718
|
+
}, 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 => {
|
|
2719
|
+
if ("number" != typeof t || isNaN(t)) return 0;
|
|
2720
|
+
const clamped = Math.max(0, Math.min(1, t));
|
|
2721
|
+
return clamped < .5 ? 4 * clamped * clamped * clamped : 1 - Math.pow(-2 * clamped + 2, 3) / 2;
|
|
2722
|
+
}, easeOutQuart = t => {
|
|
2723
|
+
if ("number" != typeof t || isNaN(t)) return 0;
|
|
2724
|
+
const clamped = Math.max(0, Math.min(1, t));
|
|
2725
|
+
return 1 - Math.pow(1 - clamped, 4);
|
|
2726
|
+
}, vec2Length = (x, y) => {
|
|
2727
|
+
if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
|
|
2728
|
+
const maxComponent = Math.max(Math.abs(x), Math.abs(y));
|
|
2729
|
+
if (0 === maxComponent) return 0;
|
|
2730
|
+
const scaledX = x / maxComponent, scaledY = y / maxComponent;
|
|
2731
|
+
return maxComponent * Math.sqrt(scaledX * scaledX + scaledY * scaledY);
|
|
2732
|
+
}, getInteractionIntensity = (isHovered, isActive) => ({
|
|
2733
|
+
hoverIntensity: isHovered ? CONSTANTS$3.INTERACTION.HOVER_INTENSITY : 1,
|
|
2734
|
+
activeIntensity: isActive ? CONSTANTS$3.INTERACTION.ACTIVE_INTENSITY : 1
|
|
2735
|
+
})
|
|
2736
|
+
/**
|
|
2737
|
+
* Spring-damper integration helper
|
|
2738
|
+
* Calculates the next value based on velocity, stiffness, and damping.
|
|
2739
|
+
*/ , calculateSpring = (current, target, velocity, stiffness = .1, damping = .8) => {
|
|
2740
|
+
const newVelocity = (velocity + (target - current) * stiffness) * damping;
|
|
2741
|
+
return {
|
|
2742
|
+
value: current + newVelocity,
|
|
2743
|
+
velocity: newVelocity
|
|
2744
|
+
};
|
|
2745
|
+
};
|
|
2746
|
+
|
|
2747
|
+
/**
|
|
2748
|
+
* Calculate element center from bounding rect
|
|
2749
|
+
*/
|
|
2750
|
+
/**
|
|
2751
|
+
* Normalizes a layout inset for use in CSS custom properties.
|
|
2752
|
+
*
|
|
2753
|
+
* @param value - Raw inset from `style` (number, px string, or `auto`).
|
|
2754
|
+
* @param fallback - Value used when `value` is undefined.
|
|
2755
|
+
*/
|
|
2756
|
+
function formatGlassInsetValue(value, fallback = "auto") {
|
|
2757
|
+
return void 0 === value ? "number" == typeof fallback ? `${fallback}px` : String(fallback) : "auto" === value ? "auto" : "number" == typeof value ? `${value}px` : value;
|
|
2758
|
+
}
|
|
2759
|
+
|
|
2760
|
+
/**
|
|
2761
|
+
* Determines whether the glass should use fixed/sticky layout semantics.
|
|
2762
|
+
*
|
|
2763
|
+
* @param explicit - Value of the `isFixedOrSticky` prop.
|
|
2764
|
+
* @param position - `position` from the consumer `style` object.
|
|
2765
|
+
*/
|
|
2766
|
+
/** Coerces a value to a finite number, returning `fallback` when invalid. */
|
|
2767
|
+
function toSafeNumber(value, fallback = 0) {
|
|
2768
|
+
return "number" != typeof value || isNaN(value) ? fallback : value;
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
/**
|
|
2772
|
+
* Calculates the target frame rate for shader time-animation loops.
|
|
2773
|
+
*
|
|
2774
|
+
* Balances visual quality against distortion complexity and `animationSpeed`.
|
|
2775
|
+
*/
|
|
2776
|
+
/**
|
|
2777
|
+
* Computes per-channel displacement scale for the SVG chromatic-aberration filter.
|
|
2778
|
+
*/
|
|
2779
|
+
function getChromaticDisplacementScale(mode, displacementScale, aberrationIntensity, channelFactor) {
|
|
2780
|
+
return displacementScale * (("shader" === mode ? 1 : -1) - aberrationIntensity * channelFactor);
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
/**
|
|
2784
|
+
* Get displacement map URL based on mode
|
|
2785
|
+
*/ const getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
|
|
2786
|
+
switch (mode) {
|
|
2787
|
+
case "standard":
|
|
2788
|
+
return displacementMap;
|
|
2789
|
+
|
|
2790
|
+
case "polar":
|
|
2791
|
+
return polarDisplacementMap;
|
|
2792
|
+
|
|
2793
|
+
case "prominent":
|
|
2794
|
+
return prominentDisplacementMap;
|
|
2795
|
+
|
|
2796
|
+
case "shader":
|
|
2797
|
+
return shaderMapUrl || displacementMap;
|
|
2798
|
+
|
|
2799
|
+
default:
|
|
2800
|
+
return console.warn("AtomixGlass: Invalid displacement mode"), displacementMap;
|
|
2801
|
+
}
|
|
2802
|
+
}, sharedShaderCache = new Map, CHROMATIC_CHANNELS = [ {
|
|
2803
|
+
result: "RED_DISPLACED",
|
|
2804
|
+
channelResult: "RED_CHANNEL",
|
|
2805
|
+
aberrationFactor: 0,
|
|
2806
|
+
colorMatrix: "1 0 0 0 0\n0 0 0 0 0\n0 0 0 0 0\n0 0 0 1 0"
|
|
2807
|
+
}, {
|
|
2808
|
+
result: "GREEN_DISPLACED",
|
|
2809
|
+
channelResult: "GREEN_CHANNEL",
|
|
2810
|
+
aberrationFactor: .02,
|
|
2811
|
+
colorMatrix: "0 0 0 0 0\n0 1 0 0 0\n0 0 0 0 0\n0 0 0 1 0"
|
|
2812
|
+
}, {
|
|
2813
|
+
result: "BLUE_DISPLACED",
|
|
2814
|
+
channelResult: "BLUE_CHANNEL",
|
|
2815
|
+
aberrationFactor: .03,
|
|
2816
|
+
colorMatrix: "0 0 0 0 0\n0 0 0 0 0\n0 0 1 0 0\n0 0 0 1 0"
|
|
2817
|
+
} ], FILTER_SVG_STYLE = {
|
|
2818
|
+
position: "absolute",
|
|
2819
|
+
width: "100%",
|
|
2820
|
+
height: "100%",
|
|
2821
|
+
inset: 0
|
|
2822
|
+
}, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsxRuntime.jsx("svg", {
|
|
2823
|
+
style: FILTER_SVG_STYLE,
|
|
2824
|
+
"aria-hidden": "true",
|
|
2825
|
+
children: jsxRuntime.jsxs("defs", {
|
|
2826
|
+
children: [ jsxRuntime.jsxs("radialGradient", {
|
|
2827
|
+
id: `${id}-edge-mask`,
|
|
2828
|
+
cx: "50%",
|
|
2829
|
+
cy: "50%",
|
|
2830
|
+
r: "50%",
|
|
2831
|
+
children: [ jsxRuntime.jsx("stop", {
|
|
2832
|
+
offset: "0%",
|
|
2231
2833
|
stopColor: "black",
|
|
2232
2834
|
stopOpacity: "0"
|
|
2233
2835
|
}), jsxRuntime.jsx("stop", {
|
|
@@ -2272,43 +2874,21 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect =>
|
|
|
2272
2874
|
dx: "0",
|
|
2273
2875
|
dy: "0",
|
|
2274
2876
|
result: "CENTER_ORIGINAL"
|
|
2275
|
-
}), jsxRuntime.
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
scale: displacementScale * (("shader" === mode ? 1 : -1) - .02 * aberrationIntensity),
|
|
2291
|
-
xChannelSelector: "R",
|
|
2292
|
-
yChannelSelector: "B",
|
|
2293
|
-
result: "GREEN_DISPLACED"
|
|
2294
|
-
}), jsxRuntime.jsx("feColorMatrix", {
|
|
2295
|
-
in: "GREEN_DISPLACED",
|
|
2296
|
-
type: "matrix",
|
|
2297
|
-
values: "0 0 0 0 0\n 0 1 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0",
|
|
2298
|
-
result: "GREEN_CHANNEL"
|
|
2299
|
-
}), jsxRuntime.jsx("feDisplacementMap", {
|
|
2300
|
-
in: "SourceGraphic",
|
|
2301
|
-
in2: "DISPLACEMENT_MAP",
|
|
2302
|
-
scale: displacementScale * (("shader" === mode ? 1 : -1) - .03 * aberrationIntensity),
|
|
2303
|
-
xChannelSelector: "R",
|
|
2304
|
-
yChannelSelector: "B",
|
|
2305
|
-
result: "BLUE_DISPLACED"
|
|
2306
|
-
}), jsxRuntime.jsx("feColorMatrix", {
|
|
2307
|
-
in: "BLUE_DISPLACED",
|
|
2308
|
-
type: "matrix",
|
|
2309
|
-
values: "0 0 0 0 0\n 0 0 0 0 0\n 0 0 1 0 0\n 0 0 0 1 0",
|
|
2310
|
-
result: "BLUE_CHANNEL"
|
|
2311
|
-
}), jsxRuntime.jsx("feBlend", {
|
|
2877
|
+
}), CHROMATIC_CHANNELS.map((channel => jsxRuntime.jsxs(React__default.default.Fragment, {
|
|
2878
|
+
children: [ jsxRuntime.jsx("feDisplacementMap", {
|
|
2879
|
+
in: "SourceGraphic",
|
|
2880
|
+
in2: "DISPLACEMENT_MAP",
|
|
2881
|
+
scale: getChromaticDisplacementScale(mode, displacementScale, aberrationIntensity, channel.aberrationFactor),
|
|
2882
|
+
xChannelSelector: "R",
|
|
2883
|
+
yChannelSelector: "B",
|
|
2884
|
+
result: channel.result
|
|
2885
|
+
}), jsxRuntime.jsx("feColorMatrix", {
|
|
2886
|
+
in: channel.result,
|
|
2887
|
+
type: "matrix",
|
|
2888
|
+
values: channel.colorMatrix,
|
|
2889
|
+
result: channel.channelResult
|
|
2890
|
+
}) ]
|
|
2891
|
+
}, channel.channelResult))), jsxRuntime.jsx("feBlend", {
|
|
2312
2892
|
in: "GREEN_CHANNEL",
|
|
2313
2893
|
in2: "BLUE_CHANNEL",
|
|
2314
2894
|
mode: "screen",
|
|
@@ -2349,21 +2929,22 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect =>
|
|
|
2349
2929
|
});
|
|
2350
2930
|
|
|
2351
2931
|
/**
|
|
2352
|
-
*
|
|
2932
|
+
* Module-level LRU cache for shader displacement maps.
|
|
2933
|
+
*
|
|
2934
|
+
* Shared across all `AtomixGlassContainer` instances so identical size and
|
|
2935
|
+
* variant combinations are generated once.
|
|
2353
2936
|
*/ GlassFilterComponent.displayName = "GlassFilter";
|
|
2354
2937
|
|
|
2355
|
-
|
|
2938
|
+
/** Shallow prop comparison to avoid redundant SVG filter regeneration. */
|
|
2356
2939
|
const GlassFilter = React.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 = React.forwardRef((({children: children, className: className = "", style: style, displacementScale: displacementScale = 25, blurAmount: blurAmount = .0625, saturation: saturation = 180, aberrationIntensity: aberrationIntensity = 2, mouseOffset: mouseOffset = {
|
|
2357
2940
|
x: 0,
|
|
2358
2941
|
y: 0
|
|
2359
|
-
}, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0,
|
|
2942
|
+
}, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0, glassSize: glassSize = {
|
|
2360
2943
|
width: 0,
|
|
2361
2944
|
height: 0
|
|
2362
|
-
}, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, isFixedOrSticky: isFixedOrSticky = !1,
|
|
2363
|
-
// Phase 1: Animation System props
|
|
2364
|
-
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) => {
|
|
2945
|
+
}, 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) => {
|
|
2365
2946
|
// React 18 useId — stable, unique, and SSR-safe (no module-level counter)
|
|
2366
|
-
const rawId = React.useId(), filterId = React.useMemo((() => `atomix-glass-filter-${rawId.replace(/:/g, "")}`), [ rawId ]), [shaderMapUrl, setShaderMapUrl] = React.useState(""), shaderGeneratorRef = React.useRef(null), shaderUtilsRef = React.useRef(null), shaderDebounceTimeoutRef = React.useRef(null), shaderUpdateTimeoutRef = React.useRef(null), animationFrameRef = React.useRef(null);
|
|
2947
|
+
const rawId = React.useId(), filterId = React.useMemo((() => `atomix-glass-filter-${rawId.replace(/:/g, "")}`), [ rawId ]), containerRef = useForkRef(ref, null), [shaderMapUrl, setShaderMapUrl] = React.useState(""), shaderGeneratorRef = React.useRef(null), shaderUtilsRef = React.useRef(null), shaderDebounceTimeoutRef = React.useRef(null), shaderUpdateTimeoutRef = React.useRef(null), animationFrameRef = React.useRef(null);
|
|
2367
2948
|
// Lazy load shader utilities only when shader mode is needed
|
|
2368
2949
|
React.useEffect((() => {
|
|
2369
2950
|
"shader" === mode ?
|
|
@@ -2443,15 +3024,23 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
|
|
|
2443
3024
|
shaderGeneratorRef.current = null;
|
|
2444
3025
|
}
|
|
2445
3026
|
};
|
|
2446
|
-
}), [ mode, glassSize, shaderVariant ]),
|
|
2447
|
-
// Phase 1: Time-Based Animation Loop - Continuous shader regeneration
|
|
2448
|
-
React.useEffect((() => {
|
|
3027
|
+
}), [ mode, glassSize, shaderVariant ]), React.useEffect((() => {
|
|
2449
3028
|
// Only run animations in shader mode with time animation enabled
|
|
2450
3029
|
if ("shader" !== mode || !withTimeAnimation || effectiveReducedMotion || effectiveWithoutEffects)
|
|
2451
3030
|
// Cancel any existing animation frame
|
|
2452
3031
|
return void (null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
|
|
2453
3032
|
animationFrameRef.current = null));
|
|
2454
|
-
const
|
|
3033
|
+
const targetFps = function(options) {
|
|
3034
|
+
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;
|
|
3035
|
+
return Math.max(12, Math.min(60, Math.round(baseFps * effectiveSpeed / complexity)));
|
|
3036
|
+
}({
|
|
3037
|
+
distortionQuality: distortionQuality,
|
|
3038
|
+
animationSpeed: animationSpeed,
|
|
3039
|
+
withMultiLayerDistortion: withMultiLayerDistortion,
|
|
3040
|
+
distortionOctaves: distortionOctaves,
|
|
3041
|
+
distortionLacunarity: distortionLacunarity,
|
|
3042
|
+
distortionGain: distortionGain
|
|
3043
|
+
}), frameInterval = 1e3 / targetFps;
|
|
2455
3044
|
let lastUpdate = 0, isCancelled = !1;
|
|
2456
3045
|
const animate = currentTime => {
|
|
2457
3046
|
if (!isCancelled) {
|
|
@@ -2475,88 +3064,21 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
|
|
|
2475
3064
|
};
|
|
2476
3065
|
}), [ mode, withTimeAnimation, animationSpeed, displacementScale, withMultiLayerDistortion, distortionOctaves, distortionLacunarity, distortionGain, distortionQuality, effectiveReducedMotion, effectiveWithoutEffects, glassSize ]);
|
|
2477
3066
|
// Removed forced reflow to avoid layout thrash and potential feedback sizing loops
|
|
2478
|
-
const
|
|
2479
|
-
React.useEffect((() => {
|
|
2480
|
-
if (!ref || "function" == typeof ref) return;
|
|
2481
|
-
const element = ref.current;
|
|
2482
|
-
if (element) try {
|
|
2483
|
-
setRectCache(element.getBoundingClientRect());
|
|
2484
|
-
} catch (error) {
|
|
2485
|
-
console.warn("AtomixGlassContainer: Error getting element bounds", error), setRectCache(null);
|
|
2486
|
-
}
|
|
2487
|
-
}), [ ref, glassSize ]);
|
|
2488
|
-
const liquidBlur = React.useMemo((() => {
|
|
2489
|
-
const defaultBlur = {
|
|
2490
|
-
baseBlur: blurAmount,
|
|
2491
|
-
edgeBlur: 1.25 * blurAmount,
|
|
2492
|
-
centerBlur: 1.1 * blurAmount,
|
|
2493
|
-
flowBlur: 1.2 * blurAmount
|
|
2494
|
-
};
|
|
2495
|
-
// Enhanced validation for liquid blur
|
|
2496
|
-
if (!withLiquidBlur || !rectCache || !mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y || isNaN(mouseOffset.x) || isNaN(mouseOffset.y)) return defaultBlur;
|
|
3067
|
+
const containerVars = React.useMemo((() => {
|
|
2497
3068
|
try {
|
|
2498
|
-
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);
|
|
2499
|
-
// NOTE: hover/active multipliers intentionally omitted here —
|
|
2500
|
-
// they belong on opacity layers, not the blur filter itself.
|
|
2501
3069
|
return {
|
|
2502
|
-
|
|
2503
|
-
edgeBlur: clampBlur(edgeBlur),
|
|
2504
|
-
centerBlur: clampBlur(centerBlur),
|
|
2505
|
-
flowBlur: clampBlur(flowBlur)
|
|
2506
|
-
};
|
|
2507
|
-
} catch (error) {
|
|
2508
|
-
return console.warn("AtomixGlassContainer: Error calculating liquid blur", error),
|
|
2509
|
-
defaultBlur;
|
|
2510
|
-
}
|
|
2511
|
-
}), [ withLiquidBlur, blurAmount, mouseOffset, rectCache ]), backdropStyle = React.useMemo((() => {
|
|
2512
|
-
try {
|
|
2513
|
-
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;
|
|
2514
|
-
// Validate blur values before using them
|
|
2515
|
-
return !withLiquidBlur || effectiveReducedMotion || effectiveWithoutEffects || area > 18e4 ? {
|
|
2516
|
-
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})`
|
|
2517
|
-
} : {
|
|
2518
|
-
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})`
|
|
2519
|
-
};
|
|
2520
|
-
// Single-pass fallback: stronger radius to match perceived blur of multi-pass
|
|
2521
|
-
} catch (error) {
|
|
2522
|
-
return console.warn("AtomixGlassContainer: Error calculating backdrop style", error),
|
|
2523
|
-
{
|
|
2524
|
-
backdropFilter: `blur(${blurAmount}px) saturate(${saturation}%) contrast(1.05) brightness(1.05)`
|
|
2525
|
-
};
|
|
2526
|
-
}
|
|
2527
|
-
}), [ liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion, effectiveWithoutEffects, withLiquidBlur, overLightConfig ]), containerVars = React.useMemo((() => {
|
|
2528
|
-
try {
|
|
2529
|
-
// Safe extraction of mouse offset values
|
|
2530
|
-
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;
|
|
2531
|
-
return {
|
|
2532
|
-
"--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px`,
|
|
2533
|
-
"--atomix-glass-container-backdrop": backdropStyle?.backdropFilter || "none",
|
|
2534
|
-
"--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",
|
|
2535
|
-
"--atomix-glass-container-shadow-opacity": effectiveWithoutEffects ? 0 : 1,
|
|
2536
|
-
// Background and shadow values use design token-aligned RGB values
|
|
2537
|
-
"--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",
|
|
2538
|
-
"--atomix-glass-container-text-shadow": overLight ? "0px 1px 2px rgba(255, 255, 255, 0.15)" : "0px 2px 12px rgba(0, 0, 0, 0.4)",
|
|
2539
|
-
"--atomix-glass-container-box-shadow": overLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)"
|
|
3070
|
+
"--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px`
|
|
2540
3071
|
};
|
|
2541
3072
|
} catch (error) {
|
|
2542
3073
|
return console.warn("AtomixGlassContainer: Error generating container variables", error),
|
|
2543
3074
|
{
|
|
2544
|
-
"--atomix-glass-container-
|
|
2545
|
-
"--atomix-glass-container-radius": "0px",
|
|
2546
|
-
"--atomix-glass-container-backdrop": "none",
|
|
2547
|
-
"--atomix-glass-container-shadow": "none",
|
|
2548
|
-
"--atomix-glass-container-shadow-opacity": 1,
|
|
2549
|
-
"--atomix-glass-container-bg": "none",
|
|
2550
|
-
"--atomix-glass-container-text-shadow": "none"
|
|
3075
|
+
"--atomix-glass-container-radius": "0px"
|
|
2551
3076
|
};
|
|
2552
3077
|
}
|
|
2553
|
-
}), [ borderRadius
|
|
3078
|
+
}), [ borderRadius ]);
|
|
2554
3079
|
return jsxRuntime.jsx("div", {
|
|
2555
|
-
ref:
|
|
2556
|
-
|
|
2557
|
-
"function" == typeof ref ? ref(el) : ref && (ref.current = el);
|
|
2558
|
-
},
|
|
2559
|
-
className: `${ATOMIX_GLASS.CONTAINER_CLASS} ${className} ${isActive ? ATOMIX_GLASS.CLASSES.ACTIVE : ""} ${overLight ? ATOMIX_GLASS.CLASSES.OVER_LIGHT : ""}`,
|
|
3080
|
+
ref: containerRef,
|
|
3081
|
+
className: mergeClassNames(ATOMIX_GLASS.CONTAINER_CLASS, className, isActive && ATOMIX_GLASS.CLASSES.ACTIVE, overLight && ATOMIX_GLASS.CLASSES.OVER_LIGHT),
|
|
2560
3082
|
style: {
|
|
2561
3083
|
...style,
|
|
2562
3084
|
...containerVars
|
|
@@ -2574,8 +3096,8 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
|
|
|
2574
3096
|
blurAmount: blurAmount,
|
|
2575
3097
|
mode: mode,
|
|
2576
3098
|
id: filterId,
|
|
2577
|
-
displacementScale:
|
|
2578
|
-
aberrationIntensity:
|
|
3099
|
+
displacementScale: toSafeNumber(displacementScale),
|
|
3100
|
+
aberrationIntensity: toSafeNumber(aberrationIntensity),
|
|
2579
3101
|
shaderMapUrl: shaderMapUrl
|
|
2580
3102
|
}), jsxRuntime.jsx("div", {
|
|
2581
3103
|
className: ATOMIX_GLASS.FILTER_OVERLAY_CLASS,
|
|
@@ -2597,8 +3119,12 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
|
|
|
2597
3119
|
});
|
|
2598
3120
|
}));
|
|
2599
3121
|
|
|
2600
|
-
|
|
2601
|
-
|
|
3122
|
+
/**
|
|
3123
|
+
* Internal glass surface that owns backdrop-filter, SVG distortion, and content.
|
|
3124
|
+
*
|
|
3125
|
+
* Layout and stacking styles are applied via the `style` prop from the parent.
|
|
3126
|
+
* The root wrapper supplies CSS custom properties only.
|
|
3127
|
+
*/ AtomixGlassContainer.displayName = "AtomixGlassContainer";
|
|
2602
3128
|
|
|
2603
3129
|
// Singleton instance
|
|
2604
3130
|
const globalMouseTracker = new
|
|
@@ -2713,28 +3239,32 @@ class {
|
|
|
2713
3239
|
*/ getSubscriberCount() {
|
|
2714
3240
|
return this.listeners.size;
|
|
2715
3241
|
}
|
|
2716
|
-
}, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
|
|
3242
|
+
}, {BORDER: BORDER, CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, BORDER_GRADIENT = BORDER.GRADIENT, WHITE = CONSTANTS$2.PALETTE.WHITE, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
|
|
2717
3243
|
if (!wrapperElement && !containerElement) return;
|
|
2718
3244
|
if (!validateGlassSize(params.glassSize)) return;
|
|
2719
|
-
const {mouseOffset: mouseOffset, globalMousePosition: globalMousePosition, glassSize: glassSize, isHovered: isHovered, isActive: isActive, isOverLight: isOverLight, baseOverLightConfig: baseOverLightConfig, effectiveBorderRadius: effectiveBorderRadius, effectiveWithoutEffects: effectiveWithoutEffects, effectiveReducedMotion: effectiveReducedMotion, elasticity: elasticity, elasticTranslation: elasticTranslation, elasticVelocity: elasticVelocity, mouseVelocity: mouseVelocity, directionalScale: directionalScale, scaleBase: scaleBase, onClick: onClick, withLiquidBlur: withLiquidBlur, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION,
|
|
3245
|
+
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 = {
|
|
2720
3246
|
opacity: baseOverLightConfig.opacity * hoverIntensity * activeIntensity,
|
|
2721
3247
|
contrast: Math.min(1.6, baseOverLightConfig.contrast + .1 * mouseInfluence),
|
|
2722
3248
|
brightness: Math.min(1.1, baseOverLightConfig.brightness + .05 * mouseInfluence),
|
|
2723
3249
|
shadowIntensity: Math.min(1.2, Math.max(.5, baseOverLightConfig.shadowIntensity + .2 * mouseInfluence)),
|
|
2724
3250
|
borderOpacity: Math.min(1, Math.max(.3, baseOverLightConfig.borderOpacity + .1 * mouseInfluence)),
|
|
2725
3251
|
saturationBoost: baseOverLightConfig.saturationBoost
|
|
2726
|
-
}, scaleX = directionalScale.x * scaleBase, scaleY = directionalScale.y * scaleBase, transformStyle = effectiveWithoutEffects ? `scale(${scaleBase})` : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) scaleX(${scaleX}) scaleY(${scaleY})`,
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
x
|
|
2732
|
-
|
|
2733
|
-
}
|
|
3252
|
+
}, scaleX = directionalScale.x * scaleBase, scaleY = directionalScale.y * scaleBase, transformStyle = effectiveWithoutEffects ? `scale(${scaleBase})` : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) scaleX(${scaleX}) scaleY(${scaleY})`, tensionFactor =
|
|
3253
|
+
/**
|
|
3254
|
+
* Computes tension factor from elastic translation magnitude (0–1).
|
|
3255
|
+
*/
|
|
3256
|
+
function(elasticTranslation) {
|
|
3257
|
+
const magnitude = Math.hypot(elasticTranslation.x, elasticTranslation.y);
|
|
3258
|
+
return smoothstep(magnitude / 80);
|
|
3259
|
+
}
|
|
3260
|
+
/**
|
|
3261
|
+
* Updates the styles of the AtomixGlass wrapper and container elements imperatively
|
|
3262
|
+
* to avoid React re-renders on mouse movement.
|
|
3263
|
+
*/ (elasticTranslation), lightingContrast = Math.min(1.8, overLightConfig.contrast + .2 * tensionFactor), lightingBrightness = Math.min(1.2, overLightConfig.brightness + .1 * tensionFactor);
|
|
2734
3264
|
// Calculate mouse influence
|
|
2735
3265
|
// Update Wrapper Styles (glassVars)
|
|
2736
3266
|
if (wrapperElement) {
|
|
2737
|
-
const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT,
|
|
3267
|
+
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 = {
|
|
2738
3268
|
hover1: {
|
|
2739
3269
|
x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
|
|
2740
3270
|
y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1
|
|
@@ -2751,28 +3281,55 @@ class {
|
|
|
2751
3281
|
x: GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER,
|
|
2752
3282
|
y: GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER
|
|
2753
3283
|
}, opacityValues = {
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
3284
|
+
// hover-1: ambient highlight glow — present on hover and during press
|
|
3285
|
+
hover1: isHovered || isActive ? 1 : 0,
|
|
3286
|
+
// hover-2: press depth shadow — only fires on active (mousedown)
|
|
3287
|
+
hover2: isActive ? 1 : 0,
|
|
3288
|
+
// hover-3: global soft-light surface shift — half-strength on hover, full on press
|
|
3289
|
+
hover3: isActive ? 1 : isHovered ? .55 : 0,
|
|
3290
|
+
// Dark chrome: faint smoky tint; over-light keeps stronger fill
|
|
3291
|
+
base: isOverLight ? overLightConfig.opacity : .14,
|
|
3292
|
+
over: isOverLight ? 1.1 * overLightConfig.opacity : .1
|
|
2759
3293
|
}, style = wrapperElement.style;
|
|
2760
3294
|
style.setProperty("--atomix-glass-transform", transformStyle || "none");
|
|
2761
3295
|
// Parallax for content (liquid refraction feel)
|
|
2762
3296
|
const parallaxFactor = .38 + .12 * tensionFactor;
|
|
2763
3297
|
style.setProperty("--atomix-glass-child-parallax", `translate(${elasticTranslation.x * -parallaxFactor}px, ${elasticTranslation.y * -parallaxFactor}px)`),
|
|
2764
|
-
style.setProperty("--atomix-glass-contrast", lightingContrast.toString()), style.setProperty("--atomix-glass-brightness", lightingBrightness.toString())
|
|
3298
|
+
style.setProperty("--atomix-glass-contrast", lightingContrast.toString()), style.setProperty("--atomix-glass-brightness", lightingBrightness.toString());
|
|
2765
3299
|
// ── Chromatic Rim Lighting ──────────────────────────────────────
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
3300
|
+
const borderVars = ATOMIX_GLASS.BORDER.GRADIENT_CSS_VARS;
|
|
3301
|
+
if (borderAnimated && !effectiveWithoutEffects) {
|
|
3302
|
+
const borderCssVars =
|
|
3303
|
+
/**
|
|
3304
|
+
* Builds animated chromatic rim CSS variables for border layers 1 and 2.
|
|
3305
|
+
* When empty, SCSS static conic/linear fallbacks apply.
|
|
3306
|
+
*/
|
|
3307
|
+
function(params) {
|
|
3308
|
+
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%)`;
|
|
3309
|
+
return {
|
|
3310
|
+
[BORDER.GRADIENT_CSS_VARS.GRADIENT_1]: gradient1,
|
|
3311
|
+
[BORDER.GRADIENT_CSS_VARS.GRADIENT_2]: gradient2
|
|
3312
|
+
};
|
|
3313
|
+
}({
|
|
3314
|
+
mouseOffset: mouseOffset,
|
|
3315
|
+
mouseVelocity: mouseVelocity,
|
|
3316
|
+
elasticVelocity: elasticVelocity,
|
|
3317
|
+
borderOpacity: overLightConfig.borderOpacity,
|
|
3318
|
+
opacityMultiplier: borderOpacityMultiplier,
|
|
3319
|
+
tensionFactor: tensionFactor
|
|
3320
|
+
});
|
|
3321
|
+
style.setProperty(borderVars.GRADIENT_1, borderCssVars[borderVars.GRADIENT_1] ?? ""),
|
|
3322
|
+
style.setProperty(borderVars.GRADIENT_2, borderCssVars[borderVars.GRADIENT_2] ?? "");
|
|
3323
|
+
} else style.removeProperty(borderVars.GRADIENT_1), style.removeProperty(borderVars.GRADIENT_2);
|
|
3324
|
+
// Hover gradients — cursor-relative radial positions for realistic light tracking.
|
|
3325
|
+
// hover-1: white overlay highlight following cursor (works on both dark + light)
|
|
3326
|
+
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%)`),
|
|
3327
|
+
// hover-2: press depth — darkens at cursor with multiply blend, isOverLight uses stronger black
|
|
3328
|
+
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%)`),
|
|
3329
|
+
// hover-3: full-surface soft-light tint; linear gradient angled with cursor X
|
|
3330
|
+
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%)`),
|
|
3331
|
+
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%)`),
|
|
3332
|
+
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%)`),
|
|
2776
3333
|
// Opacities
|
|
2777
3334
|
style.setProperty("--atomix-glass-hover-1-opacity", opacityValues.hover1.toString()),
|
|
2778
3335
|
style.setProperty("--atomix-glass-hover-2-opacity", opacityValues.hover2.toString()),
|
|
@@ -2809,151 +3366,16 @@ class {
|
|
|
2809
3366
|
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})`;
|
|
2810
3367
|
// Container variables
|
|
2811
3368
|
const style = containerElement.style;
|
|
2812
|
-
style.setProperty("--atomix-glass-container-
|
|
3369
|
+
style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
|
|
2813
3370
|
style.setProperty("--atomix-glass-container-backdrop", backdropFilterString),
|
|
2814
3371
|
// Shadows
|
|
2815
|
-
style.setProperty("--atomix-glass-container-shadow", isOverLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${(.
|
|
3372
|
+
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),
|
|
2816
3373
|
style.setProperty("--atomix-glass-container-shadow-opacity", effectiveWithoutEffects ? "0" : "1"),
|
|
2817
3374
|
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"),
|
|
2818
3375
|
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)"),
|
|
2819
|
-
style.setProperty("--atomix-glass-container-box-shadow", isOverLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "
|
|
3376
|
+
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)");
|
|
2820
3377
|
}
|
|
2821
|
-
};
|
|
2822
|
-
|
|
2823
|
-
/**
|
|
2824
|
-
* Updates the styles of the AtomixGlass wrapper and container elements imperatively
|
|
2825
|
-
* to avoid React re-renders on mouse movement.
|
|
2826
|
-
*/
|
|
2827
|
-
/**
|
|
2828
|
-
* Animation System for AtomixGlass Component
|
|
2829
|
-
*
|
|
2830
|
-
* Implements Phase 1 features from the AtomixGlass Feature Implementation Roadmap:
|
|
2831
|
-
* - Feature 1.1: Time-Based Animation System
|
|
2832
|
-
* - Feature 1.2: Multi-Layer Distortion System (FBM)
|
|
2833
|
-
*
|
|
2834
|
-
* @packageDocumentation
|
|
2835
|
-
*/
|
|
2836
|
-
// ============================================================================
|
|
2837
|
-
// Noise Functions for FBM (Feature 1.2)
|
|
2838
|
-
// ============================================================================
|
|
2839
|
-
/**
|
|
2840
|
-
* Perlin noise implementation for smooth gradient noise
|
|
2841
|
-
*
|
|
2842
|
-
* @param x - X coordinate
|
|
2843
|
-
* @param y - Y coordinate
|
|
2844
|
-
* @returns Noise value in range [0, 1]
|
|
2845
|
-
*/
|
|
2846
|
-
function perlinNoise(x, y) {
|
|
2847
|
-
// Simplified Perlin noise using pseudo-random gradients
|
|
2848
|
-
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);
|
|
2849
|
-
// Scale to [0, 1] range
|
|
2850
|
-
return (lerp(lerpX1, lerpX2, v) + 1) / 2;
|
|
2851
|
-
}
|
|
2852
|
-
|
|
2853
|
-
// ============================================================================
|
|
2854
|
-
// Fractal Brownian Motion (FBM) Engine (Feature 1.2)
|
|
2855
|
-
// ============================================================================
|
|
2856
|
-
/**
|
|
2857
|
-
* Creates an FBM engine with configurable parameters
|
|
2858
|
-
*
|
|
2859
|
-
* @param config - FBM configuration (octaves, lacunarity, gain)
|
|
2860
|
-
* @returns Object with fbm function
|
|
2861
|
-
*
|
|
2862
|
-
* @example
|
|
2863
|
-
* ```typescript
|
|
2864
|
-
* const fbmEngine = createFBMEngine({ octaves: 5, lacunarity: 2, gain: 0.5 });
|
|
2865
|
-
*
|
|
2866
|
-
* // Generate noise at position (0.5, 0.5) with time animation
|
|
2867
|
-
* const noiseValue = fbmEngine.fbm(0.5, 0.5, Date.now());
|
|
2868
|
-
* ```
|
|
2869
|
-
*/ function createFBMEngine(config) {
|
|
2870
|
-
/**
|
|
2871
|
-
* Fractal Brownian Motion function
|
|
2872
|
-
* Combines multiple octaves of noise for complex, natural patterns
|
|
2873
|
-
*
|
|
2874
|
-
* @param x - X coordinate
|
|
2875
|
-
* @param y - Y coordinate
|
|
2876
|
-
* @param time - Optional time value for animation
|
|
2877
|
-
* @returns FBM noise value in range [0, 1]
|
|
2878
|
-
*/
|
|
2879
|
-
const fbm = (x, y, time = 0) => {
|
|
2880
|
-
let value = 0, amplitude = .5, frequency = 1, phase = .001 * time;
|
|
2881
|
-
// Convert to seconds for reasonable animation speed
|
|
2882
|
-
for (let i = 0; i < config.octaves; i++)
|
|
2883
|
-
// Apply time-based phase shift to all octaves
|
|
2884
|
-
value += perlinNoise(x * frequency + phase, y * frequency + phase) * amplitude,
|
|
2885
|
-
frequency *= config.lacunarity, // Increase frequency
|
|
2886
|
-
amplitude *= config.gain;
|
|
2887
|
-
return value;
|
|
2888
|
-
};
|
|
2889
|
-
/**
|
|
2890
|
-
* Get FBM with simple time factor
|
|
2891
|
-
*/ return {
|
|
2892
|
-
fbm: fbm,
|
|
2893
|
-
fbmWithTime: (x, y, time) => fbm(x, y, time)
|
|
2894
|
-
};
|
|
2895
|
-
}
|
|
2896
|
-
|
|
2897
|
-
/**
|
|
2898
|
-
* Gets optimal FBM config based on quality preset
|
|
2899
|
-
*
|
|
2900
|
-
* @param quality - Quality preset level
|
|
2901
|
-
* @returns FBM configuration for the quality level
|
|
2902
|
-
*/ const fbmEngineCache = new Map;
|
|
2903
|
-
|
|
2904
|
-
// ============================================================================
|
|
2905
|
-
// Shader Utility Functions for Time-Based Effects
|
|
2906
|
-
// ============================================================================
|
|
2907
|
-
/**
|
|
2908
|
-
* Liquid glass distortion with time-based animation
|
|
2909
|
-
* Uses FBM to create organic, flowing liquid effects
|
|
2910
|
-
*
|
|
2911
|
-
* @param uv - UV coordinates (normalized 0-1)
|
|
2912
|
-
* @param time - Elapsed time in milliseconds
|
|
2913
|
-
* @param config - FBM configuration
|
|
2914
|
-
* @returns Distorted UV coordinates
|
|
2915
|
-
*/ function liquidGlassWithTime(uv, time, config) {
|
|
2916
|
-
const configKey = `${config.octaves}-${config.lacunarity}-${config.gain}`;
|
|
2917
|
-
let fbmEngine = fbmEngineCache.get(configKey);
|
|
2918
|
-
fbmEngine || (fbmEngine = createFBMEngine(config), fbmEngineCache.set(configKey, fbmEngine));
|
|
2919
|
-
// Animate noise with time
|
|
2920
|
-
const animatedNoise = fbmEngine.fbmWithTime(2 * uv.x + 1e-4 * time, 2 * uv.y + 15e-5 * time, time);
|
|
2921
|
-
return {
|
|
2922
|
-
x: uv.x + .04 * (animatedNoise - .5),
|
|
2923
|
-
y: uv.y + .04 * (animatedNoise - .5)
|
|
2924
|
-
};
|
|
2925
|
-
}
|
|
2926
|
-
|
|
2927
|
-
// ============================================================================
|
|
2928
|
-
// Helper Functions
|
|
2929
|
-
// ============================================================================
|
|
2930
|
-
/**
|
|
2931
|
-
* Fade curve for smooth interpolation (Perlin's fade function)
|
|
2932
|
-
*/ function fade(t) {
|
|
2933
|
-
return t * t * t * (t * (6 * t - 15) + 10);
|
|
2934
|
-
}
|
|
2935
|
-
|
|
2936
|
-
/**
|
|
2937
|
-
* Linear interpolation
|
|
2938
|
-
*/ function lerp(a, b, t) {
|
|
2939
|
-
return a + t * (b - a);
|
|
2940
|
-
}
|
|
2941
|
-
|
|
2942
|
-
/**
|
|
2943
|
-
* Gradient calculation for Perlin noise
|
|
2944
|
-
*/ function grad(hash, x, y) {
|
|
2945
|
-
const h = 15 & hash, u = h < 8 ? x : y, v = h < 4 ? y : 12 === h || 14 === h ? x : 0;
|
|
2946
|
-
return (1 & h ? -u : u) + (2 & h ? -v : v);
|
|
2947
|
-
}
|
|
2948
|
-
|
|
2949
|
-
/**
|
|
2950
|
-
* Permutation table for Perlin noise
|
|
2951
|
-
*/ const p = (() => {
|
|
2952
|
-
const permutation = [];
|
|
2953
|
-
for (let i = 0; i < 256; i++) permutation[i] = Math.floor(256 * Math.random());
|
|
2954
|
-
// Duplicate for overflow handling
|
|
2955
|
-
return [ ...permutation, ...permutation ];
|
|
2956
|
-
})(), {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
|
|
3378
|
+
}, {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
|
|
2957
3379
|
|
|
2958
3380
|
const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new WeakMap, setCachedBackgroundDetection = (parentElement, overLightConfig, result, threshold) => {
|
|
2959
3381
|
parentElement && backgroundDetectionCache.set(parentElement, {
|
|
@@ -2968,12 +3390,35 @@ const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new Weak
|
|
|
2968
3390
|
* Composable hook for AtomixGlass component logic
|
|
2969
3391
|
* Manages all state, calculations, and event handlers
|
|
2970
3392
|
*/
|
|
2971
|
-
function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef: wrapperRef, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, children: children, blurAmount: blurAmount, saturation: saturation,
|
|
2972
|
-
// Default priority
|
|
2973
|
-
// Phase 1: Animation System Props
|
|
2974
|
-
withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: animationSpeed = ATOMIX_GLASS.DEFAULTS.ANIMATION_SPEED, withMultiLayerDistortion: withMultiLayerDistortion = ATOMIX_GLASS.DEFAULTS.WITH_MULTI_LAYER_DISTORTION, distortionOctaves: distortionOctaves = ATOMIX_GLASS.DEFAULTS.DISTORTION_OCTAVES, distortionLacunarity: distortionLacunarity = ATOMIX_GLASS.DEFAULTS.DISTORTION_LACUNARITY, distortionGain: distortionGain = ATOMIX_GLASS.DEFAULTS.DISTORTION_GAIN, distortionQuality: distortionQuality = ATOMIX_GLASS.DEFAULTS.DISTORTION_QUALITY}) {
|
|
3393
|
+
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}) {
|
|
2975
3394
|
// State
|
|
2976
|
-
const [isHovered, setIsHovered] = React.useState(!1), [isActive, setIsActive] = React.useState(!1),
|
|
3395
|
+
const [isHovered, setIsHovered] = React.useState(!1), [isActive, setIsActive] = React.useState(!1), resolvedBorder = React.useMemo((() =>
|
|
3396
|
+
/**
|
|
3397
|
+
* Resolves `border` and legacy `withBorder` into a single configuration object.
|
|
3398
|
+
*/
|
|
3399
|
+
function(border, withBorder) {
|
|
3400
|
+
const legacyDefault = withBorder ?? !0;
|
|
3401
|
+
return void 0 === border ? {
|
|
3402
|
+
enabled: legacyDefault,
|
|
3403
|
+
width: BORDER.DEFAULT_WIDTH,
|
|
3404
|
+
opacityMultiplier: 1,
|
|
3405
|
+
animated: !0
|
|
3406
|
+
} : "boolean" == typeof border ? {
|
|
3407
|
+
enabled: border,
|
|
3408
|
+
width: BORDER.DEFAULT_WIDTH,
|
|
3409
|
+
opacityMultiplier: 1,
|
|
3410
|
+
animated: !0
|
|
3411
|
+
} : {
|
|
3412
|
+
enabled: border.enabled ?? legacyDefault,
|
|
3413
|
+
width: (value = border.width, void 0 === value ? BORDER.DEFAULT_WIDTH : "number" == typeof value ? `${value}px` : value),
|
|
3414
|
+
opacityMultiplier: border.opacity ?? 1,
|
|
3415
|
+
animated: !1 !== border.animated
|
|
3416
|
+
};
|
|
3417
|
+
/**
|
|
3418
|
+
* Formats border width for CSS custom properties.
|
|
3419
|
+
*/
|
|
3420
|
+
var value;
|
|
3421
|
+
}(border, withBorder)), [ border, withBorder ]), cachedRectRef = React.useRef(null), internalGlobalMousePositionRef = React.useRef({
|
|
2977
3422
|
x: 0,
|
|
2978
3423
|
y: 0
|
|
2979
3424
|
}), internalMouseOffsetRef = React.useRef({
|
|
@@ -2997,52 +3442,10 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
2997
3442
|
}), scaleVelocityRef = React.useRef({
|
|
2998
3443
|
x: 0,
|
|
2999
3444
|
y: 0
|
|
3000
|
-
})
|
|
3001
|
-
React.useRef(0);
|
|
3002
|
-
const mouseVelocityRef = React.useRef({
|
|
3445
|
+
}), mouseVelocityRef = React.useRef({
|
|
3003
3446
|
x: 0,
|
|
3004
3447
|
y: 0
|
|
3005
|
-
}), [userPrefersReducedMotion, setUserPrefersReducedMotion] = React.useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = React.useState(!1), [detectedOverLight, setDetectedOverLight] = React.useState(!1),
|
|
3006
|
-
// If quality preset is provided, use it as base
|
|
3007
|
-
const preset = (quality = distortionQuality, ATOMIX_GLASS.CONSTANTS.DISTORTION_QUALITY_PRESETS[quality]);
|
|
3008
|
-
// Override with custom values if provided
|
|
3009
|
-
var quality;
|
|
3010
|
-
return {
|
|
3011
|
-
octaves: distortionOctaves ?? preset.octaves,
|
|
3012
|
-
lacunarity: distortionLacunarity ?? preset.lacunarity,
|
|
3013
|
-
gain: distortionGain ?? preset.gain
|
|
3014
|
-
};
|
|
3015
|
-
}), [ distortionQuality, distortionOctaves, distortionLacunarity, distortionGain ]), fbmEngine = React.useMemo((() => withMultiLayerDistortion ? createFBMEngine(fbmConfig) : null), [ withMultiLayerDistortion, fbmConfig ]), effectiveReducedMotion = React.useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveWithTimeAnimation = React.useMemo((() => withTimeAnimation && !effectiveReducedMotion), [ withTimeAnimation, effectiveReducedMotion ]);
|
|
3016
|
-
/**
|
|
3017
|
-
* Animation loop for time-based effects
|
|
3018
|
-
*/
|
|
3019
|
-
React.useEffect((() => {
|
|
3020
|
-
if (!effectiveWithTimeAnimation || "undefined" == typeof window) return;
|
|
3021
|
-
let lastFrameTime = performance.now();
|
|
3022
|
-
/**
|
|
3023
|
-
* Animation frame handler
|
|
3024
|
-
*/ const animate = currentTime => {
|
|
3025
|
-
// Calculate delta time
|
|
3026
|
-
const deltaTime = currentTime - lastFrameTime;
|
|
3027
|
-
lastFrameTime = currentTime;
|
|
3028
|
-
// Apply animation speed multiplier
|
|
3029
|
-
const scaledDelta = deltaTime * animationSpeed;
|
|
3030
|
-
elapsedTimeRef.current += scaledDelta, shaderTimeRef.current = elapsedTimeRef.current,
|
|
3031
|
-
// Continue animation loop
|
|
3032
|
-
animationFrameIdRef.current = requestAnimationFrame(animate);
|
|
3033
|
-
};
|
|
3034
|
-
// Start animation
|
|
3035
|
-
// Cleanup
|
|
3036
|
-
return animationStartTimeRef.current = performance.now(), animationFrameIdRef.current = requestAnimationFrame(animate),
|
|
3037
|
-
() => {
|
|
3038
|
-
null !== animationFrameIdRef.current && (cancelAnimationFrame(animationFrameIdRef.current),
|
|
3039
|
-
animationFrameIdRef.current = null);
|
|
3040
|
-
};
|
|
3041
|
-
}), [ effectiveWithTimeAnimation, animationSpeed ]);
|
|
3042
|
-
/**
|
|
3043
|
-
* Get current shader time for animations
|
|
3044
|
-
*/
|
|
3045
|
-
const getShaderTime = React.useCallback((() => shaderTimeRef.current), []), applyTimeBasedDistortion = React.useCallback((uv => effectiveWithTimeAnimation && fbmEngine ? liquidGlassWithTime(uv, shaderTimeRef.current, fbmConfig) : uv), [ effectiveWithTimeAnimation, fbmEngine, fbmConfig ]), effectiveBorderRadius = React.useMemo((() => void 0 !== borderRadius ? Math.max(0, borderRadius) : Math.max(0, dynamicBorderRadius)), [ borderRadius, dynamicBorderRadius ]), {glassSize: glassSize} = function({glassRef: glassRef, effectiveBorderRadius: effectiveBorderRadius, cachedRectRef: cachedRectRef}) {
|
|
3448
|
+
}), [userPrefersReducedMotion, setUserPrefersReducedMotion] = React.useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = React.useState(!1), [detectedOverLight, setDetectedOverLight] = React.useState(!1), effectiveReducedMotion = React.useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveBorderRadius = React.useMemo((() => void 0 !== borderRadius ? Math.max(0, borderRadius) : Math.max(0, dynamicBorderRadius)), [ borderRadius, dynamicBorderRadius ]), {glassSize: glassSize} = function({glassRef: glassRef, effectiveBorderRadius: effectiveBorderRadius, cachedRectRef: cachedRectRef}) {
|
|
3046
3449
|
const [glassSize, setGlassSize] = React.useState({
|
|
3047
3450
|
width: 270,
|
|
3048
3451
|
height: 69
|
|
@@ -3102,9 +3505,6 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
3102
3505
|
effectiveBorderRadius: effectiveBorderRadius,
|
|
3103
3506
|
cachedRectRef: cachedRectRef
|
|
3104
3507
|
}), effectiveHighContrast = React.useMemo((() => highContrast || userPrefersHighContrast), [ highContrast, userPrefersHighContrast ]), effectiveWithoutEffects = React.useMemo((() => withoutEffects || effectiveReducedMotion), [ withoutEffects, effectiveReducedMotion ]), globalMousePosition = externalGlobalMousePosition || internalGlobalMousePositionRef.current, mouseOffset = externalMouseOffset || internalMouseOffsetRef.current;
|
|
3105
|
-
/**
|
|
3106
|
-
* Apply time-based distortion to UV coordinates
|
|
3107
|
-
*/
|
|
3108
3508
|
// Extract border-radius from children
|
|
3109
3509
|
React.useEffect((() => {
|
|
3110
3510
|
const extractRadius = () => {
|
|
@@ -3264,25 +3664,26 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
3264
3664
|
* Get effective overLight value based on configuration
|
|
3265
3665
|
*/
|
|
3266
3666
|
const getEffectiveOverLight = React.useCallback((() => "boolean" == typeof overLight ? overLight : ("auto" === overLight || "object" == typeof overLight && null !== overLight) && detectedOverLight), [ overLight, detectedOverLight ]), validateConfigValue = React.useCallback(((value, min, max, defaultValue) => "number" != typeof value || isNaN(value) || !isFinite(value) ? defaultValue : Math.min(max, Math.max(min, value))), []), overLightConfig = React.useMemo((() => {
|
|
3267
|
-
const isOverLight = getEffectiveOverLight(), hoverIntensity
|
|
3667
|
+
const isOverLight = getEffectiveOverLight(), {hoverIntensity: hoverIntensity, activeIntensity: activeIntensity} = getInteractionIntensity(isHovered, isActive), baseConfig = {
|
|
3268
3668
|
isOverLight: isOverLight,
|
|
3269
3669
|
threshold: .7,
|
|
3270
3670
|
opacity: isOverLight ? Math.min(.6, Math.max(.2, .5 * hoverIntensity * activeIntensity)) : 0,
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
shadowIntensity: .9,
|
|
3276
|
-
borderOpacity: .
|
|
3671
|
+
// Dark UI (Apple Music): neutral contrast + slight brightness lift
|
|
3672
|
+
contrast: isOverLight ? 1.4 : 1.02,
|
|
3673
|
+
brightness: isOverLight ? .9 : 1.02,
|
|
3674
|
+
saturationBoost: isOverLight ? 1.3 : 1,
|
|
3675
|
+
shadowIntensity: isOverLight ? .9 : 1,
|
|
3676
|
+
borderOpacity: isOverLight ? ATOMIX_GLASS.BORDER.OVER_LIGHT.opacity : ATOMIX_GLASS.BORDER.DARK.opacity
|
|
3277
3677
|
};
|
|
3278
3678
|
if ("object" == typeof overLight && null !== overLight) {
|
|
3279
|
-
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 = {
|
|
3679
|
+
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 = {
|
|
3280
3680
|
...baseConfig,
|
|
3281
3681
|
threshold: validatedThreshold,
|
|
3282
3682
|
opacity: validatedOpacity * hoverIntensity * activeIntensity,
|
|
3283
3683
|
contrast: validatedContrast,
|
|
3284
3684
|
brightness: validatedBrightness,
|
|
3285
|
-
saturationBoost: validatedSaturationBoost
|
|
3685
|
+
saturationBoost: validatedSaturationBoost,
|
|
3686
|
+
borderOpacity: validatedBorderOpacity
|
|
3286
3687
|
};
|
|
3287
3688
|
return "undefined" == typeof process || process.env, finalConfig;
|
|
3288
3689
|
}
|
|
@@ -3307,8 +3708,8 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
3307
3708
|
};
|
|
3308
3709
|
const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
|
|
3309
3710
|
internalGlobalMousePositionRef.current = {
|
|
3310
|
-
x: lerp
|
|
3311
|
-
y: lerp
|
|
3711
|
+
x: lerp(curG.x, tgtG.x, CONSTANTS.LERP_FACTOR),
|
|
3712
|
+
y: lerp(curG.y, tgtG.y, CONSTANTS.LERP_FACTOR)
|
|
3312
3713
|
};
|
|
3313
3714
|
// ── Calculate Elastic Physics ─────────────────────────────────────
|
|
3314
3715
|
let targetElasticTranslation = {
|
|
@@ -3380,12 +3781,13 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
3380
3781
|
withLiquidBlur: withLiquidBlur,
|
|
3381
3782
|
blurAmount: blurAmount,
|
|
3382
3783
|
saturation: saturation,
|
|
3383
|
-
|
|
3384
|
-
|
|
3784
|
+
isFixedOrSticky: isFixedOrSticky,
|
|
3785
|
+
borderAnimated: resolvedBorder.animated,
|
|
3786
|
+
borderOpacityMultiplier: resolvedBorder.opacityMultiplier
|
|
3385
3787
|
}), 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);
|
|
3386
3788
|
};
|
|
3387
3789
|
lerpRafRef.current = requestAnimationFrame(tick);
|
|
3388
|
-
}), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation,
|
|
3790
|
+
}), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, isFixedOrSticky, resolvedBorder.animated, resolvedBorder.opacityMultiplier, stopLerpLoop ]), handleGlobalMousePosition = React.useCallback((globalPos => {
|
|
3389
3791
|
if (externalGlobalMousePosition && externalMouseOffset) return;
|
|
3390
3792
|
if (effectiveWithoutEffects) return;
|
|
3391
3793
|
const container = mouseContainer?.current || glassRef.current;
|
|
@@ -3449,9 +3851,10 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
3449
3851
|
withLiquidBlur: withLiquidBlur,
|
|
3450
3852
|
blurAmount: blurAmount,
|
|
3451
3853
|
saturation: saturation,
|
|
3452
|
-
|
|
3854
|
+
borderAnimated: resolvedBorder.animated,
|
|
3855
|
+
borderOpacityMultiplier: resolvedBorder.opacityMultiplier
|
|
3453
3856
|
});
|
|
3454
|
-
}), [ isHovered, isActive, glassSize, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation,
|
|
3857
|
+
}), [ isHovered, isActive, glassSize, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation, resolvedBorder.animated, resolvedBorder.opacityMultiplier, onClick ]);
|
|
3455
3858
|
// Event handlers
|
|
3456
3859
|
const handleMouseEnter = React.useCallback((() => setIsHovered(!0)), []), handleMouseLeave = React.useCallback((() => setIsHovered(!1)), []), handleMouseDown = React.useCallback((() => setIsActive(!0)), []), handleMouseUp = React.useCallback((() => setIsActive(!1)), []), handleKeyDown = React.useCallback((e => {
|
|
3457
3860
|
!onClick || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), onClick());
|
|
@@ -3471,9 +3874,8 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
3471
3874
|
mouseOffset: mouseOffset,
|
|
3472
3875
|
// This is now static (refs or props) unless prop changes
|
|
3473
3876
|
overLightConfig: overLightConfig,
|
|
3877
|
+
resolvedBorder: resolvedBorder,
|
|
3474
3878
|
transformStyle: transformStyle,
|
|
3475
|
-
getShaderTime: getShaderTime,
|
|
3476
|
-
applyTimeBasedDistortion: applyTimeBasedDistortion,
|
|
3477
3879
|
handleMouseEnter: handleMouseEnter,
|
|
3478
3880
|
handleMouseLeave: handleMouseLeave,
|
|
3479
3881
|
handleMouseDown: handleMouseDown,
|
|
@@ -3751,7 +4153,13 @@ function usePerformanceMonitor$1(config = {}) {
|
|
|
3751
4153
|
timestamp: 0,
|
|
3752
4154
|
isAutoScaling: !0,
|
|
3753
4155
|
lowFpsCount: 0
|
|
3754
|
-
}), [manualOverride, setManualOverride] = React.useState(!1), [isEnabled, setIsEnabled] = React.useState(enabled)
|
|
4156
|
+
}), [manualOverride, setManualOverride] = React.useState(!1), [isEnabled, setIsEnabled] = React.useState(enabled);
|
|
4157
|
+
// Sync external `enabled` prop changes into internal state
|
|
4158
|
+
React.useEffect((() => {
|
|
4159
|
+
setIsEnabled(enabled ?? !0);
|
|
4160
|
+
}), [ enabled ]);
|
|
4161
|
+
// Refs for frame tracking
|
|
4162
|
+
const frameCountRef = React.useRef(0), lastFpsUpdateRef = React.useRef(0), lastFrameTimeRef = React.useRef(0), animationFrameRef = React.useRef(null), lowFpsCountRef = React.useRef(0), highFpsCountRef = React.useRef(0), qualityLevelRef = React.useRef("medium"), updateMetrics = React.useCallback((newMetrics => {
|
|
3755
4163
|
setMetrics((prev => ({
|
|
3756
4164
|
...prev,
|
|
3757
4165
|
...newMetrics,
|
|
@@ -3872,163 +4280,15 @@ function usePerformanceMonitor$1(config = {}) {
|
|
|
3872
4280
|
* Reset to auto-scaling mode
|
|
3873
4281
|
*/ var fps, currentQuality;
|
|
3874
4282
|
return {
|
|
3875
|
-
metrics: metrics,
|
|
3876
|
-
recommendedQuality: (fps = metrics.fps, currentQuality = metrics.qualityLevel, fps >= 58 ? "high" : fps >= 45 ? "high" === currentQuality ? "high" : "medium" : "low"),
|
|
3877
|
-
isUnderperforming: metrics.fps < minFps,
|
|
3878
|
-
setQualityLevel: setQualityLevel,
|
|
3879
|
-
resetAutoScaling: resetAutoScaling,
|
|
3880
|
-
toggleMonitoring: toggleMonitoring
|
|
3881
|
-
};
|
|
3882
|
-
}
|
|
3883
|
-
|
|
3884
|
-
/**
|
|
3885
|
-
* Debug Overlay Component (Optional)
|
|
3886
|
-
*
|
|
3887
|
-
* Shows real-time performance metrics on screen.
|
|
3888
|
-
* Only rendered when showOverlay is enabled.
|
|
3889
|
-
*/
|
|
3890
|
-
/** Map an FPS value to a semantic color token string. */
|
|
3891
|
-
const getQualityColor = quality => {
|
|
3892
|
-
switch (quality) {
|
|
3893
|
-
case "high":
|
|
3894
|
-
return "var(--atomix-color-success, #4ade80)";
|
|
3895
|
-
|
|
3896
|
-
case "medium":
|
|
3897
|
-
return "var(--atomix-color-warning, #fbbf24)";
|
|
3898
|
-
|
|
3899
|
-
case "low":
|
|
3900
|
-
return "var(--atomix-color-danger, #ef4444)";
|
|
3901
|
-
|
|
3902
|
-
default:
|
|
3903
|
-
return "#9ca3af";
|
|
3904
|
-
}
|
|
3905
|
-
}, getFpsLabel = fps => fps >= 58 ? "Optimal" : fps >= 45 ? "Warning" : "Critical";
|
|
3906
|
-
|
|
3907
|
-
/** Map a quality level string to a semantic color token string. */
|
|
3908
|
-
// Inject keyframes once
|
|
3909
|
-
if ("undefined" != typeof document) {
|
|
3910
|
-
const styleId = "perf-dashboard-keyframes";
|
|
3911
|
-
if (!document.getElementById(styleId)) {
|
|
3912
|
-
const styleEl = document.createElement("style");
|
|
3913
|
-
styleEl.id = styleId, styleEl.textContent = "\n@keyframes perf-dashboard-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n",
|
|
3914
|
-
document.head.appendChild(styleEl);
|
|
3915
|
-
}
|
|
4283
|
+
metrics: metrics,
|
|
4284
|
+
recommendedQuality: (fps = metrics.fps, currentQuality = metrics.qualityLevel, fps >= 58 ? "high" : fps >= 45 ? "high" === currentQuality ? "high" : "medium" : "low"),
|
|
4285
|
+
isUnderperforming: metrics.fps < minFps,
|
|
4286
|
+
setQualityLevel: setQualityLevel,
|
|
4287
|
+
resetAutoScaling: resetAutoScaling,
|
|
4288
|
+
toggleMonitoring: toggleMonitoring
|
|
4289
|
+
};
|
|
3916
4290
|
}
|
|
3917
4291
|
|
|
3918
|
-
/**
|
|
3919
|
-
* PerformanceDashboard - Real-time performance monitoring overlay.
|
|
3920
|
-
*
|
|
3921
|
-
* Displays FPS, frame time, quality level, GPU memory, and auto-scaling status.
|
|
3922
|
-
* Rendered only when `debugPerformance={true}` on the parent `AtomixGlass`.
|
|
3923
|
-
*/ const PerformanceDashboard = React.memo((({metrics: metrics, isVisible: isVisible = !0, onClose: onClose}) => {
|
|
3924
|
-
if (!isVisible) return null;
|
|
3925
|
-
const fpsColor = (fps = metrics.fps) >= 58 ? "var(--atomix-color-success, #4ade80)" : fps >= 45 ? "var(--atomix-color-warning, #fbbf24)" : "var(--atomix-color-danger, #ef4444)";
|
|
3926
|
-
var fps;
|
|
3927
|
-
const isCritical = metrics.fps < 45;
|
|
3928
|
-
return jsxRuntime.jsxs("div", {
|
|
3929
|
-
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",
|
|
3930
|
-
style: {
|
|
3931
|
-
zIndex: 9999,
|
|
3932
|
-
minWidth: "12.5rem",
|
|
3933
|
-
// 200px
|
|
3934
|
-
backgroundColor: "rgba(17, 24, 39, 0.95)",
|
|
3935
|
-
backdropFilter: "blur(8px)",
|
|
3936
|
-
transition: "opacity 0.3s ease"
|
|
3937
|
-
},
|
|
3938
|
-
children: [ jsxRuntime.jsxs("div", {
|
|
3939
|
-
className: "u-flex u-items-center u-justify-between u-mb-2 u-pb-2 u-border-b u-border-white-alpha-10",
|
|
3940
|
-
children: [ jsxRuntime.jsx("span", {
|
|
3941
|
-
className: "u-text-sm u-font-bold u-text-white",
|
|
3942
|
-
children: "Performance Monitor"
|
|
3943
|
-
}), onClose && jsxRuntime.jsx("button", {
|
|
3944
|
-
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",
|
|
3945
|
-
onClick: onClose,
|
|
3946
|
-
"aria-label": "Close performance dashboard",
|
|
3947
|
-
style: {
|
|
3948
|
-
transition: "color 0.2s ease"
|
|
3949
|
-
},
|
|
3950
|
-
children: "×"
|
|
3951
|
-
}) ]
|
|
3952
|
-
}), jsxRuntime.jsxs("div", {
|
|
3953
|
-
className: "u-flex u-items-center u-justify-between u-mb-1-5",
|
|
3954
|
-
children: [ jsxRuntime.jsx("span", {
|
|
3955
|
-
className: "u-text-gray-400 u-me-3",
|
|
3956
|
-
children: "FPS"
|
|
3957
|
-
}), jsxRuntime.jsx("span", {
|
|
3958
|
-
className: "u-font-bold",
|
|
3959
|
-
style: {
|
|
3960
|
-
color: fpsColor
|
|
3961
|
-
},
|
|
3962
|
-
children: Math.round(metrics.fps)
|
|
3963
|
-
}) ]
|
|
3964
|
-
}), jsxRuntime.jsxs("div", {
|
|
3965
|
-
className: "u-flex u-items-center u-justify-between u-mb-1-5",
|
|
3966
|
-
children: [ jsxRuntime.jsx("span", {
|
|
3967
|
-
className: "u-text-gray-400 u-me-3",
|
|
3968
|
-
children: "Frame Time"
|
|
3969
|
-
}), jsxRuntime.jsxs("span", {
|
|
3970
|
-
className: "u-font-bold",
|
|
3971
|
-
children: [ metrics.frameTime.toFixed(2), "ms" ]
|
|
3972
|
-
}) ]
|
|
3973
|
-
}), jsxRuntime.jsxs("div", {
|
|
3974
|
-
className: "u-flex u-items-center u-justify-between u-mb-1-5",
|
|
3975
|
-
children: [ jsxRuntime.jsx("span", {
|
|
3976
|
-
className: "u-text-gray-400 u-me-3",
|
|
3977
|
-
children: "Quality"
|
|
3978
|
-
}), jsxRuntime.jsx("span", {
|
|
3979
|
-
className: "u-font-bold u-text-uppercase",
|
|
3980
|
-
style: {
|
|
3981
|
-
fontSize: "0.6875rem",
|
|
3982
|
-
// 11px
|
|
3983
|
-
color: getQualityColor(metrics.qualityLevel)
|
|
3984
|
-
},
|
|
3985
|
-
children: metrics.qualityLevel
|
|
3986
|
-
}) ]
|
|
3987
|
-
}), metrics.gpuMemory && jsxRuntime.jsxs("div", {
|
|
3988
|
-
className: "u-flex u-items-center u-justify-between u-mb-1-5",
|
|
3989
|
-
children: [ jsxRuntime.jsx("span", {
|
|
3990
|
-
className: "u-text-gray-400 u-me-3",
|
|
3991
|
-
children: "GPU Memory"
|
|
3992
|
-
}), jsxRuntime.jsxs("span", {
|
|
3993
|
-
className: "u-font-bold",
|
|
3994
|
-
children: [ "~", Math.round(metrics.gpuMemory / 1024), "MB" ]
|
|
3995
|
-
}) ]
|
|
3996
|
-
}), metrics.isAutoScaling && jsxRuntime.jsx("div", {
|
|
3997
|
-
className: "u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10 u-text-center",
|
|
3998
|
-
style: {
|
|
3999
|
-
fontSize: "0.625rem",
|
|
4000
|
-
// 10px
|
|
4001
|
-
color: "#6b7280"
|
|
4002
|
-
},
|
|
4003
|
-
children: "Auto-scaling active"
|
|
4004
|
-
}), jsxRuntime.jsxs("div", {
|
|
4005
|
-
className: "u-flex u-items-center u-gap-2 u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10",
|
|
4006
|
-
children: [ jsxRuntime.jsx("div", {
|
|
4007
|
-
className: "u-rounded-full",
|
|
4008
|
-
style: {
|
|
4009
|
-
width: "0.5rem",
|
|
4010
|
-
height: "0.5rem",
|
|
4011
|
-
flexShrink: 0,
|
|
4012
|
-
backgroundColor: fpsColor,
|
|
4013
|
-
...isCritical && {
|
|
4014
|
-
animation: "perf-dashboard-pulse 1s infinite"
|
|
4015
|
-
}
|
|
4016
|
-
}
|
|
4017
|
-
}), jsxRuntime.jsx("span", {
|
|
4018
|
-
className: "u-text-xs",
|
|
4019
|
-
style: {
|
|
4020
|
-
fontSize: "0.625rem",
|
|
4021
|
-
// 10px
|
|
4022
|
-
color: fpsColor
|
|
4023
|
-
},
|
|
4024
|
-
children: getFpsLabel(metrics.fps)
|
|
4025
|
-
}) ]
|
|
4026
|
-
}) ]
|
|
4027
|
-
});
|
|
4028
|
-
}));
|
|
4029
|
-
|
|
4030
|
-
PerformanceDashboard.displayName = "PerformanceDashboard";
|
|
4031
|
-
|
|
4032
4292
|
/**
|
|
4033
4293
|
* Mobile optimization presets
|
|
4034
4294
|
*
|
|
@@ -4038,8 +4298,7 @@ PerformanceDashboard.displayName = "PerformanceDashboard";
|
|
|
4038
4298
|
/**
|
|
4039
4299
|
* Performance preset - Maximum FPS, reduced quality
|
|
4040
4300
|
* Best for low-end devices or when battery saving is priority
|
|
4041
|
-
*/
|
|
4042
|
-
const PERFORMANCE_PRESET = {
|
|
4301
|
+
*/ const PERFORMANCE_PRESET = {
|
|
4043
4302
|
distortionOctaves: 2,
|
|
4044
4303
|
// Minimal FBM layers
|
|
4045
4304
|
displacementScale: 50,
|
|
@@ -4202,18 +4461,13 @@ function getDevicePreset(presetName) {
|
|
|
4202
4461
|
getPixelRatio: () => "undefined" == typeof window ? 1 : window.devicePixelRatio || 1,
|
|
4203
4462
|
/** Check if device has touch support */
|
|
4204
4463
|
hasTouchSupport: () => "undefined" != typeof window && ("ontouchstart" in window || navigator.maxTouchPoints > 0)
|
|
4205
|
-
}, AtomixGlassInner = React.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 = "",
|
|
4206
|
-
const glassRef = React.useRef(null), contentRef = React.useRef(null), internalWrapperRef = React.useRef(null), mergedRef =
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
}));
|
|
4213
|
-
};
|
|
4214
|
-
}
|
|
4215
|
-
// Internal implementation with forwardRef
|
|
4216
|
-
(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({
|
|
4464
|
+
}, AtomixGlassInner = React.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) {
|
|
4465
|
+
const glassRef = React.useRef(null), contentRef = React.useRef(null), internalWrapperRef = React.useRef(null), mergedRef = useForkRef(ref, internalWrapperRef), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = (explicit = propsIsFixedOrSticky,
|
|
4466
|
+
position = restStyle.position, Boolean(explicit || "fixed" === position || "sticky" === position));
|
|
4467
|
+
var explicit, position;
|
|
4468
|
+
/**
|
|
4469
|
+
* Extracts layout-related properties from a React `CSSProperties` object.
|
|
4470
|
+
*/ 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({
|
|
4217
4471
|
glassRef: glassRef,
|
|
4218
4472
|
contentRef: contentRef,
|
|
4219
4473
|
wrapperRef: internalWrapperRef,
|
|
@@ -4233,19 +4487,12 @@ function getDevicePreset(presetName) {
|
|
|
4233
4487
|
blurAmount: blurAmount,
|
|
4234
4488
|
saturation: saturation,
|
|
4235
4489
|
withLiquidBlur: withLiquidBlur,
|
|
4236
|
-
|
|
4490
|
+
border: border,
|
|
4491
|
+
withBorder: withBorder,
|
|
4492
|
+
debugBorderRadius: debugBorderRadius,
|
|
4237
4493
|
style: style,
|
|
4238
|
-
isFixedOrSticky: isFixedOrSticky
|
|
4239
|
-
// Phase 1: Animation System props
|
|
4240
|
-
withTimeAnimation: withTimeAnimation,
|
|
4241
|
-
animationSpeed: animationSpeed,
|
|
4242
|
-
withMultiLayerDistortion: withMultiLayerDistortion,
|
|
4243
|
-
distortionOctaves: distortionOctaves,
|
|
4244
|
-
distortionLacunarity: distortionLacunarity,
|
|
4245
|
-
distortionGain: distortionGain,
|
|
4246
|
-
distortionQuality: distortionQuality
|
|
4494
|
+
isFixedOrSticky: isFixedOrSticky
|
|
4247
4495
|
});
|
|
4248
|
-
// Responsive breakpoint system - automatically adjusts parameters based on viewport
|
|
4249
4496
|
useResponsiveGlass({
|
|
4250
4497
|
baseParams: {
|
|
4251
4498
|
...React.useMemo((() => getDevicePreset(devicePreset)), [ devicePreset ]),
|
|
@@ -4260,185 +4507,213 @@ function getDevicePreset(presetName) {
|
|
|
4260
4507
|
breakpoints: MOBILE_OPTIMIZED_BREAKPOINTS,
|
|
4261
4508
|
enabled: !disableResponsiveBreakpoints && "undefined" != typeof window,
|
|
4262
4509
|
debug: !1
|
|
4263
|
-
})
|
|
4264
|
-
// Performance monitoring - tracks FPS, frame time, memory usage
|
|
4265
|
-
const {metrics: performanceMetrics, toggleMonitoring: toggleMonitoring} = usePerformanceMonitor$1({
|
|
4510
|
+
}), usePerformanceMonitor$1({
|
|
4266
4511
|
enabled: debugPerformance,
|
|
4267
|
-
// Enable when debugPerformance is true
|
|
4268
4512
|
debug: !1,
|
|
4269
4513
|
showOverlay: !1
|
|
4270
4514
|
});
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
}), [ debugPerformance ]);
|
|
4276
|
-
// Re-run when debugPerformance changes
|
|
4277
|
-
const isOverLight = React.useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, rootLayoutStyle = React.useMemo((() => {
|
|
4278
|
-
if (!isFixedOrSticky) return {};
|
|
4279
|
-
const {position: p, top: t, left: l, right: r, bottom: b} = restStyle;
|
|
4280
|
-
return {
|
|
4281
|
-
...p && {
|
|
4282
|
-
position: p
|
|
4283
|
-
},
|
|
4284
|
-
...void 0 !== t && {
|
|
4285
|
-
top: t
|
|
4286
|
-
},
|
|
4287
|
-
...void 0 !== l && {
|
|
4288
|
-
left: l
|
|
4289
|
-
},
|
|
4290
|
-
...void 0 !== r && {
|
|
4291
|
-
right: r
|
|
4292
|
-
},
|
|
4293
|
-
...void 0 !== b && {
|
|
4294
|
-
bottom: b
|
|
4295
|
-
}
|
|
4296
|
-
};
|
|
4297
|
-
}), [ isFixedOrSticky, restStyle ]);
|
|
4298
|
-
// Calculate base style with transforms
|
|
4299
|
-
// When layout is hoisted to the root, strip those props from the container
|
|
4300
|
-
React.useMemo((() => {
|
|
4301
|
-
if (isFixedOrSticky) {
|
|
4302
|
-
const {position: _p, top: _t, left: _l, right: _r, bottom: _b, ...visualStyle} = restStyle;
|
|
4303
|
-
return {
|
|
4304
|
-
...visualStyle
|
|
4305
|
-
};
|
|
4515
|
+
const isOverLight = React.useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, containerStyle = React.useMemo((() => ({
|
|
4516
|
+
...restStyle,
|
|
4517
|
+
...void 0 !== customZIndex && {
|
|
4518
|
+
zIndex: customZIndex
|
|
4306
4519
|
}
|
|
4520
|
+
})), [ 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 = React.useMemo((() =>
|
|
4521
|
+
/**
|
|
4522
|
+
* Returns the internal positioning context for effect layers relative to the root.
|
|
4523
|
+
*/
|
|
4524
|
+
function(isFixedOrSticky, restStyle) {
|
|
4307
4525
|
return {
|
|
4308
|
-
|
|
4526
|
+
position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
|
|
4527
|
+
top: 0,
|
|
4528
|
+
left: 0,
|
|
4529
|
+
right: "auto",
|
|
4530
|
+
bottom: "auto"
|
|
4309
4531
|
};
|
|
4310
|
-
}
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
})), [ isFixedOrSticky, restStyle.position, restStyle.top, restStyle.left, restStyle.right, restStyle.bottom ]), adjustedSize = React.useMemo((() => {
|
|
4319
|
-
// Keep a reference to positionStyles to avoid unused-variable lint,
|
|
4320
|
-
// but sizing is driven by explicit width/height or measured size.
|
|
4321
|
-
positionStyles.position;
|
|
4322
|
-
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;
|
|
4532
|
+
}
|
|
4533
|
+
/**
|
|
4534
|
+
* Computes `--atomix-glass-width` and `--atomix-glass-height` values.
|
|
4535
|
+
*
|
|
4536
|
+
* Fixed/sticky elements prefer explicit dimensions or measured size; in-flow
|
|
4537
|
+
* elements default to `100%`.
|
|
4538
|
+
*/ (isFixedOrSticky, restStyle)), [ isFixedOrSticky, restStyle ]), adjustedSize = React.useMemo((() => function(options) {
|
|
4539
|
+
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;
|
|
4323
4540
|
return {
|
|
4324
4541
|
width: resolveLength(effectiveWidth, glassSize.width),
|
|
4325
4542
|
height: resolveLength(effectiveHeight, glassSize.height)
|
|
4326
4543
|
};
|
|
4327
|
-
}
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4544
|
+
}
|
|
4545
|
+
/**
|
|
4546
|
+
* Builds the CSS custom properties applied to the root `.c-atomix-glass` element.
|
|
4547
|
+
*
|
|
4548
|
+
* These variables drive layer geometry, transforms, and stacking offsets. They
|
|
4549
|
+
* must not include layout properties that would interfere with backdrop-filter.
|
|
4550
|
+
*/ ({
|
|
4551
|
+
width: width,
|
|
4552
|
+
height: height,
|
|
4553
|
+
restStyle: restStyle,
|
|
4554
|
+
glassSize: glassSize,
|
|
4555
|
+
isFixedOrSticky: isFixedOrSticky
|
|
4556
|
+
})), [ width, height, restStyle, glassSize, isFixedOrSticky ]), glassVars = React.useMemo((() => function(input) {
|
|
4557
|
+
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 =
|
|
4558
|
+
/**
|
|
4559
|
+
* Resolves the `--atomix-glass-position` value for decorative layers.
|
|
4560
|
+
*
|
|
4561
|
+
* Fixed/sticky layers use the same positioning mode as the container; in-flow
|
|
4562
|
+
* layers default to the internal absolute positioning context.
|
|
4563
|
+
*/
|
|
4564
|
+
function(isFixedOrSticky, positionStyles, restStyle) {
|
|
4565
|
+
return isFixedOrSticky ? `${function(style) {
|
|
4566
|
+
const {position: position, top: top, left: left, right: right, bottom: bottom, inset: inset} = style;
|
|
4567
|
+
return {
|
|
4568
|
+
...null != position && {
|
|
4569
|
+
position: position
|
|
4570
|
+
},
|
|
4571
|
+
...void 0 !== top && {
|
|
4572
|
+
top: top
|
|
4573
|
+
},
|
|
4574
|
+
...void 0 !== left && {
|
|
4575
|
+
left: left
|
|
4576
|
+
},
|
|
4577
|
+
...void 0 !== right && {
|
|
4578
|
+
right: right
|
|
4579
|
+
},
|
|
4580
|
+
...void 0 !== bottom && {
|
|
4581
|
+
bottom: bottom
|
|
4582
|
+
},
|
|
4583
|
+
...void 0 !== inset && {
|
|
4584
|
+
inset: inset
|
|
4585
|
+
}
|
|
4586
|
+
};
|
|
4587
|
+
}
|
|
4588
|
+
/**
|
|
4589
|
+
* Resolves inset custom properties for decorative layers (hover, borders, backgrounds).
|
|
4590
|
+
*
|
|
4591
|
+
* For fixed and sticky modes, insets mirror the container so sibling layers remain
|
|
4592
|
+
* aligned. In-flow modes, insets follow the consumer `style` when a non-default
|
|
4593
|
+
* `position` is provided.
|
|
4594
|
+
*/ (restStyle).position ?? restStyle.position ?? "fixed"}` : `${positionStyles.position}`;
|
|
4595
|
+
}(isFixedOrSticky, positionStyles, restStyle), layerInsets = function(isFixedOrSticky, restStyle) {
|
|
4596
|
+
if (isFixedOrSticky) return {
|
|
4597
|
+
top: formatGlassInsetValue(restStyle.top, 0),
|
|
4598
|
+
left: formatGlassInsetValue(restStyle.left, 0),
|
|
4599
|
+
right: formatGlassInsetValue(restStyle.right, "auto"),
|
|
4600
|
+
bottom: formatGlassInsetValue(restStyle.bottom, "auto")
|
|
4601
|
+
};
|
|
4602
|
+
const position = restStyle.position;
|
|
4603
|
+
return null != position && "static" !== position && "relative" !== position ? {
|
|
4604
|
+
top: formatGlassInsetValue(restStyle.top, 0),
|
|
4605
|
+
left: formatGlassInsetValue(restStyle.left, 0),
|
|
4606
|
+
right: formatGlassInsetValue(restStyle.right, "auto"),
|
|
4607
|
+
bottom: formatGlassInsetValue(restStyle.bottom, "auto")
|
|
4608
|
+
} : {
|
|
4609
|
+
top: "0px",
|
|
4610
|
+
left: "0px",
|
|
4611
|
+
right: "auto",
|
|
4612
|
+
bottom: "auto"
|
|
4613
|
+
};
|
|
4614
|
+
}(isFixedOrSticky, restStyle);
|
|
4365
4615
|
return {
|
|
4366
4616
|
...void 0 !== customZIndex && {
|
|
4367
4617
|
"--atomix-glass-base-z-index": customZIndex
|
|
4368
4618
|
},
|
|
4369
4619
|
"--atomix-glass-radius": `${effectiveBorderRadius}px`,
|
|
4370
4620
|
"--atomix-glass-transform": transformStyle || "none",
|
|
4371
|
-
"--atomix-glass-container-position":
|
|
4372
|
-
"--atomix-glass-position":
|
|
4373
|
-
"--atomix-glass-top":
|
|
4374
|
-
"--atomix-glass-left":
|
|
4375
|
-
"--atomix-glass-right":
|
|
4376
|
-
"--atomix-glass-bottom":
|
|
4621
|
+
"--atomix-glass-container-position": layerPosition,
|
|
4622
|
+
"--atomix-glass-position": layerPosition,
|
|
4623
|
+
"--atomix-glass-top": layerInsets.top,
|
|
4624
|
+
"--atomix-glass-left": layerInsets.left,
|
|
4625
|
+
"--atomix-glass-right": layerInsets.right,
|
|
4626
|
+
"--atomix-glass-bottom": layerInsets.bottom,
|
|
4377
4627
|
"--atomix-glass-width": adjustedSize.width,
|
|
4378
4628
|
"--atomix-glass-height": adjustedSize.height,
|
|
4379
|
-
|
|
4380
|
-
"--atomix-glass-
|
|
4381
|
-
"--atomix-glass-
|
|
4382
|
-
|
|
4383
|
-
"--atomix-glass-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4629
|
+
// Aliases maintained for backward compatibility and consumer overrides.
|
|
4630
|
+
"--atomix-glass-container-width": adjustedSize.width,
|
|
4631
|
+
"--atomix-glass-container-height": adjustedSize.height,
|
|
4632
|
+
[ATOMIX_GLASS.BORDER.WIDTH_CSS_VAR]: borderWidth,
|
|
4633
|
+
"--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay"
|
|
4634
|
+
};
|
|
4635
|
+
}
|
|
4636
|
+
/**
|
|
4637
|
+
* Applies mode-specific multipliers and accessibility overrides to container effects.
|
|
4638
|
+
*/ ({
|
|
4639
|
+
effectiveBorderRadius: effectiveBorderRadius,
|
|
4640
|
+
transformStyle: transformStyle,
|
|
4641
|
+
adjustedSize: adjustedSize,
|
|
4642
|
+
isOverLight: isOverLight,
|
|
4643
|
+
customZIndex: customZIndex,
|
|
4644
|
+
isFixedOrSticky: isFixedOrSticky,
|
|
4645
|
+
positionStyles: positionStyles,
|
|
4646
|
+
restStyle: restStyle,
|
|
4647
|
+
borderWidth: resolvedBorder.width
|
|
4648
|
+
})), [ effectiveBorderRadius, transformStyle, adjustedSize, isOverLight, customZIndex, isFixedOrSticky, positionStyles, restStyle, resolvedBorder.width ]), containerEffects = React.useMemo((() => function(options) {
|
|
4649
|
+
const {MULTIPLIERS: MULTIPLIERS, SATURATION: SATURATION} = ATOMIX_GLASS.CONSTANTS, zeroMouse = {
|
|
4650
|
+
x: 0,
|
|
4651
|
+
y: 0
|
|
4652
|
+
}, resolveSaturation = () => options.effectiveHighContrast ? SATURATION.HIGH_CONTRAST : options.isOverLight ? options.saturation * options.saturationBoost : options.saturation;
|
|
4653
|
+
if (options.effectiveWithoutEffects) return {
|
|
4654
|
+
displacementScale: 0,
|
|
4655
|
+
blurAmount: 0,
|
|
4656
|
+
saturation: resolveSaturation(),
|
|
4657
|
+
aberrationIntensity: 0,
|
|
4658
|
+
mouseOffset: zeroMouse,
|
|
4659
|
+
globalMousePosition: zeroMouse
|
|
4660
|
+
};
|
|
4661
|
+
let resolvedDisplacement = options.displacementScale;
|
|
4662
|
+
"shader" === options.mode ? resolvedDisplacement *= MULTIPLIERS.SHADER_DISPLACEMENT : options.isOverLight && (resolvedDisplacement *= MULTIPLIERS.OVER_LIGHT_DISPLACEMENT);
|
|
4663
|
+
let resolvedAberration = options.aberrationIntensity;
|
|
4664
|
+
return "shader" === options.mode && (resolvedAberration *= MULTIPLIERS.SHADER_ABERRATION),
|
|
4665
|
+
{
|
|
4666
|
+
displacementScale: resolvedDisplacement,
|
|
4667
|
+
blurAmount: options.blurAmount,
|
|
4668
|
+
saturation: resolveSaturation(),
|
|
4669
|
+
aberrationIntensity: resolvedAberration,
|
|
4670
|
+
mouseOffset: options.mouseOffset,
|
|
4671
|
+
globalMousePosition: options.globalMousePosition
|
|
4395
4672
|
};
|
|
4396
|
-
}
|
|
4397
|
-
|
|
4673
|
+
}({
|
|
4674
|
+
displacementScale: displacementScale,
|
|
4675
|
+
blurAmount: blurAmount,
|
|
4676
|
+
saturation: saturation,
|
|
4677
|
+
aberrationIntensity: aberrationIntensity,
|
|
4678
|
+
mode: mode,
|
|
4679
|
+
effectiveWithoutEffects: effectiveWithoutEffects,
|
|
4680
|
+
effectiveHighContrast: effectiveHighContrast,
|
|
4681
|
+
isOverLight: isOverLight,
|
|
4682
|
+
saturationBoost: overLightConfig.saturationBoost,
|
|
4683
|
+
mouseOffset: mouseOffset,
|
|
4684
|
+
globalMousePosition: globalMousePosition
|
|
4685
|
+
})), [ displacementScale, blurAmount, saturation, aberrationIntensity, mode, effectiveWithoutEffects, effectiveHighContrast, isOverLight, overLightConfig.saturationBoost, mouseOffset, globalMousePosition ]), renderBackgroundLayer = layerType => jsxRuntime.jsx("div", {
|
|
4686
|
+
"aria-hidden": "true",
|
|
4687
|
+
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)
|
|
4398
4688
|
});
|
|
4399
|
-
|
|
4400
|
-
// When root is fixed/sticky, internal layers use absolute (relative to root)
|
|
4401
|
-
return jsxRuntime.jsxs("div", {
|
|
4689
|
+
return jsxRuntime.jsxs("div", {
|
|
4402
4690
|
...rest,
|
|
4403
4691
|
ref: mergedRef,
|
|
4404
4692
|
className: componentClassName,
|
|
4405
|
-
style:
|
|
4406
|
-
...glassVars
|
|
4407
|
-
},
|
|
4693
|
+
style: glassVars,
|
|
4408
4694
|
role: role || (onClick ? "button" : void 0),
|
|
4409
4695
|
tabIndex: onClick ? tabIndex ?? 0 : tabIndex,
|
|
4410
4696
|
"aria-label": ariaLabel,
|
|
4411
4697
|
"aria-describedby": ariaDescribedBy,
|
|
4412
4698
|
"aria-disabled": !(!onClick || !effectiveWithoutEffects) || !onClick && void 0,
|
|
4413
|
-
"aria-pressed": onClick ? isActive : void 0,
|
|
4414
4699
|
onKeyDown: onClick ? handleKeyDown : void 0,
|
|
4415
4700
|
children: [ jsxRuntime.jsx(AtomixGlassContainer, {
|
|
4416
4701
|
ref: glassRef,
|
|
4417
4702
|
contentRef: contentRef,
|
|
4418
4703
|
className: className,
|
|
4419
|
-
style:
|
|
4420
|
-
...restStyle
|
|
4421
|
-
},
|
|
4704
|
+
style: containerStyle,
|
|
4422
4705
|
borderRadius: effectiveBorderRadius,
|
|
4423
|
-
displacementScale:
|
|
4424
|
-
blurAmount:
|
|
4425
|
-
saturation:
|
|
4426
|
-
aberrationIntensity:
|
|
4706
|
+
displacementScale: containerEffects.displacementScale,
|
|
4707
|
+
blurAmount: containerEffects.blurAmount,
|
|
4708
|
+
saturation: containerEffects.saturation,
|
|
4709
|
+
aberrationIntensity: containerEffects.aberrationIntensity,
|
|
4427
4710
|
glassSize: glassSize,
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
x: 0,
|
|
4431
|
-
y: 0
|
|
4432
|
-
} : mouseOffset,
|
|
4433
|
-
globalMousePosition: effectiveWithoutEffects ? {
|
|
4434
|
-
x: 0,
|
|
4435
|
-
y: 0
|
|
4436
|
-
} : globalMousePosition,
|
|
4711
|
+
mouseOffset: containerEffects.mouseOffset,
|
|
4712
|
+
globalMousePosition: containerEffects.globalMousePosition,
|
|
4437
4713
|
onMouseEnter: handleMouseEnter,
|
|
4438
4714
|
onMouseLeave: handleMouseLeave,
|
|
4439
4715
|
onMouseDown: handleMouseDown,
|
|
4440
4716
|
onMouseUp: handleMouseUp,
|
|
4441
|
-
isHovered: isHovered,
|
|
4442
4717
|
isActive: isActive,
|
|
4443
4718
|
overLight: isOverLight,
|
|
4444
4719
|
overLightConfig: {
|
|
@@ -4454,8 +4729,6 @@ function getDevicePreset(presetName) {
|
|
|
4454
4729
|
shaderVariant: shaderVariant,
|
|
4455
4730
|
withLiquidBlur: withLiquidBlur,
|
|
4456
4731
|
isFixedOrSticky: isFixedOrSticky,
|
|
4457
|
-
// Phase 1: Animation System props
|
|
4458
|
-
shaderTime: getShaderTime(),
|
|
4459
4732
|
withTimeAnimation: withTimeAnimation,
|
|
4460
4733
|
animationSpeed: animationSpeed,
|
|
4461
4734
|
withMultiLayerDistortion: withMultiLayerDistortion,
|
|
@@ -4466,42 +4739,129 @@ function getDevicePreset(presetName) {
|
|
|
4466
4739
|
children: children
|
|
4467
4740
|
}), Boolean(onClick) && jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
4468
4741
|
children: [ jsxRuntime.jsx("div", {
|
|
4742
|
+
"aria-hidden": "true",
|
|
4469
4743
|
className: ATOMIX_GLASS.HOVER_1_CLASS
|
|
4470
4744
|
}), jsxRuntime.jsx("div", {
|
|
4745
|
+
"aria-hidden": "true",
|
|
4471
4746
|
className: ATOMIX_GLASS.HOVER_2_CLASS
|
|
4472
4747
|
}), jsxRuntime.jsx("div", {
|
|
4748
|
+
"aria-hidden": "true",
|
|
4473
4749
|
className: ATOMIX_GLASS.HOVER_3_CLASS
|
|
4474
4750
|
}) ]
|
|
4475
|
-
}),
|
|
4751
|
+
}), [ "dark", "black" ].map((layerType => jsxRuntime.jsx(React__default.default.Fragment, {
|
|
4752
|
+
children: renderBackgroundLayer(layerType)
|
|
4753
|
+
}, layerType))), shouldRenderOverLightLayers && jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
4476
4754
|
children: [ jsxRuntime.jsx("div", {
|
|
4755
|
+
"aria-hidden": "true",
|
|
4477
4756
|
className: ATOMIX_GLASS.BASE_LAYER_CLASS
|
|
4478
4757
|
}), jsxRuntime.jsx("div", {
|
|
4758
|
+
"aria-hidden": "true",
|
|
4479
4759
|
className: ATOMIX_GLASS.OVERLAY_LAYER_CLASS
|
|
4480
4760
|
}), jsxRuntime.jsx("div", {
|
|
4761
|
+
"aria-hidden": "true",
|
|
4481
4762
|
className: ATOMIX_GLASS.OVERLAY_HIGHLIGHT_CLASS
|
|
4482
4763
|
}) ]
|
|
4483
|
-
}),
|
|
4764
|
+
}), resolvedBorder.enabled && jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
4484
4765
|
children: [ jsxRuntime.jsx("span", {
|
|
4766
|
+
"aria-hidden": "true",
|
|
4485
4767
|
className: ATOMIX_GLASS.BORDER_BACKDROP_CLASS
|
|
4486
4768
|
}), jsxRuntime.jsx("span", {
|
|
4769
|
+
"aria-hidden": "true",
|
|
4487
4770
|
className: ATOMIX_GLASS.BORDER_1_CLASS
|
|
4488
4771
|
}), jsxRuntime.jsx("span", {
|
|
4772
|
+
"aria-hidden": "true",
|
|
4489
4773
|
className: ATOMIX_GLASS.BORDER_2_CLASS
|
|
4490
4774
|
}) ]
|
|
4491
|
-
}), debugPerformance && performanceMetrics && jsxRuntime.jsx(PerformanceDashboard, {
|
|
4492
|
-
metrics: performanceMetrics,
|
|
4493
|
-
isVisible: !0,
|
|
4494
|
-
onClose: () => {}
|
|
4495
4775
|
}) ]
|
|
4496
4776
|
});
|
|
4497
4777
|
}));
|
|
4498
4778
|
|
|
4499
|
-
AtomixGlassInner.displayName = "AtomixGlass";
|
|
4500
|
-
|
|
4501
4779
|
/**
|
|
4502
|
-
* AtomixGlass -
|
|
4503
|
-
*
|
|
4780
|
+
* AtomixGlass - A high-performance glass morphism component with liquid distortion effects
|
|
4781
|
+
*
|
|
4782
|
+
* Features:
|
|
4783
|
+
* - Hardware-accelerated glass effects with SVG filters
|
|
4784
|
+
* - Mouse-responsive liquid distortion
|
|
4785
|
+
* - Dynamic border-radius extraction from children CSS properties
|
|
4786
|
+
* - Automatic light/dark theme detection via overLight prop
|
|
4787
|
+
* - Accessibility and performance optimizations
|
|
4788
|
+
* - Multiple displacement modes (standard, polar, prominent, shader)
|
|
4789
|
+
* - Design token integration for consistent theming
|
|
4790
|
+
* - Focus ring support for keyboard navigation
|
|
4791
|
+
* - Responsive breakpoints for mobile optimization
|
|
4792
|
+
* - Enhanced ARIA attributes for screen readers
|
|
4793
|
+
* - Time-based animation system with FBM distortion
|
|
4794
|
+
* - Device preset optimization for performance/quality balance
|
|
4795
|
+
*
|
|
4796
|
+
* Design System Compliance:
|
|
4797
|
+
* - Uses design tokens for opacity, spacing, and colors
|
|
4798
|
+
* - Follows BEM methodology for class naming
|
|
4799
|
+
* - Implements focus-ring mixin for accessibility
|
|
4800
|
+
* - Supports reduced motion and high contrast preferences
|
|
4801
|
+
*
|
|
4802
|
+
* Style architecture:
|
|
4803
|
+
* - Root (`.c-atomix-glass`): CSS custom properties for layer geometry and motion.
|
|
4804
|
+
* - Container (`.c-atomix-glass__container`): layout, z-index, and backdrop-filter.
|
|
4805
|
+
*
|
|
4806
|
+
* @example
|
|
4807
|
+
* // Basic usage with dynamic border-radius extraction
|
|
4808
|
+
* <AtomixGlass>
|
|
4809
|
+
* <div style={{ borderRadius: '12px' }}>Content with 12px radius</div>
|
|
4810
|
+
* </AtomixGlass>
|
|
4811
|
+
*
|
|
4812
|
+
* @example
|
|
4813
|
+
* // Manual border-radius override
|
|
4814
|
+
* <AtomixGlass borderRadius={20}>
|
|
4815
|
+
* <div>Content with 20px glass radius</div>
|
|
4816
|
+
* </AtomixGlass>
|
|
4817
|
+
*
|
|
4818
|
+
* @example
|
|
4819
|
+
* // Interactive glass with click handler
|
|
4820
|
+
* <AtomixGlass onClick={() => console.log('Clicked')} aria-label="Glass card">
|
|
4821
|
+
* <div>Clickable content</div>
|
|
4822
|
+
* </AtomixGlass>
|
|
4823
|
+
*
|
|
4824
|
+
* @example
|
|
4825
|
+
* // OverLight - Boolean mode (explicit control)
|
|
4826
|
+
* <AtomixGlass overLight={true}>
|
|
4827
|
+
* <div>Content on light background</div>
|
|
4828
|
+
* </AtomixGlass>
|
|
4829
|
+
*
|
|
4830
|
+
* @example
|
|
4831
|
+
* // OverLight - Auto-detection mode
|
|
4832
|
+
* <AtomixGlass overLight="auto">
|
|
4833
|
+
* <div>Content with auto-detected background</div>
|
|
4834
|
+
* </AtomixGlass>
|
|
4835
|
+
*
|
|
4836
|
+
* @example
|
|
4837
|
+
* // OverLight - Object config with custom settings
|
|
4838
|
+
* <AtomixGlass
|
|
4839
|
+
* overLight={{
|
|
4840
|
+
* threshold: 0.8,
|
|
4841
|
+
* opacity: 0.6,
|
|
4842
|
+
* contrast: 1.8,
|
|
4843
|
+
* brightness: 1.0,
|
|
4844
|
+
* saturationBoost: 1.5
|
|
4845
|
+
* }}
|
|
4846
|
+
* >
|
|
4847
|
+
* <div>Content with custom overLight config</div>
|
|
4848
|
+
* </AtomixGlass>
|
|
4849
|
+
*
|
|
4850
|
+
* @example
|
|
4851
|
+
* // Debug mode for overLight detection
|
|
4852
|
+
* <AtomixGlass overLight="auto" debugOverLight={true}>
|
|
4853
|
+
* <div>Content with debug logging enabled</div>
|
|
4854
|
+
* </AtomixGlass>
|
|
4855
|
+
*
|
|
4856
|
+
* @example
|
|
4857
|
+
* // Performance-optimized for mobile devices
|
|
4858
|
+
* <AtomixGlass devicePreset="performance" disableResponsiveBreakpoints={false}>
|
|
4859
|
+
* <div>Mobile-optimized glass effect</div>
|
|
4860
|
+
* </AtomixGlass>
|
|
4504
4861
|
*/
|
|
4862
|
+
/** Internal implementation; ref is forwarded to the root wrapper element. */ AtomixGlassInner.displayName = "AtomixGlass";
|
|
4863
|
+
|
|
4864
|
+
/** Memoized public export. Ref targets the root `.c-atomix-glass` wrapper. */
|
|
4505
4865
|
const AtomixGlass = React.memo(AtomixGlassInner), DefaultIcon = () => jsxRuntime.jsx("i", {
|
|
4506
4866
|
className: "c-accordion__icon",
|
|
4507
4867
|
"aria-hidden": "true",
|
|
@@ -4629,10 +4989,7 @@ const AccordionImpl = React.memo((({title: title, children: children, defaultOp
|
|
|
4629
4989
|
});
|
|
4630
4990
|
if (glass) {
|
|
4631
4991
|
// Default glass settings for accordions
|
|
4632
|
-
const defaultGlassProps = {
|
|
4633
|
-
displacementScale: 20,
|
|
4634
|
-
elasticity: 0
|
|
4635
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
4992
|
+
const defaultGlassProps = GLASS_DEFAULTS.ACCORDION, glassProps = !0 === glass ? defaultGlassProps : {
|
|
4636
4993
|
...defaultGlassProps,
|
|
4637
4994
|
...glass
|
|
4638
4995
|
};
|
|
@@ -4665,40 +5022,15 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
|
|
|
4665
5022
|
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",
|
|
4666
5023
|
fill: color
|
|
4667
5024
|
}) ]
|
|
4668
|
-
}),
|
|
4669
|
-
// Add input validation
|
|
4670
|
-
if ("number" != typeof a || "number" != typeof b || "number" != typeof t) return 0;
|
|
4671
|
-
const clamped = Math.max(0, Math.min(1, (t - a) / (b - a)));
|
|
4672
|
-
return clamped * clamped * (3 - 2 * clamped);
|
|
4673
|
-
}, calculateLength = (x, y) => {
|
|
4674
|
-
// Add input validation and error handling
|
|
4675
|
-
if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
|
|
4676
|
-
// Prevent potential overflow
|
|
4677
|
-
const maxX = Math.max(Math.abs(x), Math.abs(y));
|
|
4678
|
-
if (0 === maxX) return 0;
|
|
4679
|
-
const scaledX = x / maxX, scaledY = y / maxX;
|
|
4680
|
-
return maxX * Math.sqrt(scaledX * scaledX + scaledY * scaledY);
|
|
4681
|
-
}, roundedRectSDF = (x, y, width, height, radius) => {
|
|
5025
|
+
}), roundedRectSDF = (x, y, width, height, radius) => {
|
|
4682
5026
|
// Add input validation
|
|
4683
5027
|
if ("number" != typeof x || "number" != typeof y || "number" != typeof width || "number" != typeof height || "number" != typeof radius) return 0;
|
|
4684
5028
|
const qx = Math.abs(x) - width + radius, qy = Math.abs(y) - height + radius;
|
|
4685
|
-
return Math.min(Math.max(qx, qy), 0) +
|
|
5029
|
+
return Math.min(Math.max(qx, qy), 0) + vec2Length(Math.max(qx, 0), Math.max(qy, 0)) - radius;
|
|
4686
5030
|
}, createTexture = (x, y) => ({
|
|
4687
5031
|
x: "number" != typeof x || isNaN(x) ? .5 : Math.max(0, Math.min(1, x)),
|
|
4688
5032
|
y: "number" != typeof y || isNaN(y) ? .5 : Math.max(0, Math.min(1, y))
|
|
4689
|
-
}), validateVec2 = vec => vec && "number" == typeof vec.x && "number" == typeof vec.y && !isNaN(vec.x) && !isNaN(vec.y),
|
|
4690
|
-
// Add input validation
|
|
4691
|
-
"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 => {
|
|
4692
|
-
// Add input validation
|
|
4693
|
-
if ("number" != typeof t || isNaN(t)) return 0;
|
|
4694
|
-
const clampedT = Math.max(0, Math.min(1, t));
|
|
4695
|
-
return clampedT < .5 ? 4 * clampedT * clampedT * clampedT : 1 - Math.pow(-2 * clampedT + 2, 3) / 2;
|
|
4696
|
-
}, easeOutQuart = t => {
|
|
4697
|
-
// Add input validation
|
|
4698
|
-
if ("number" != typeof t || isNaN(t)) return 0;
|
|
4699
|
-
const clampedT = Math.max(0, Math.min(1, t));
|
|
4700
|
-
return 1 - Math.pow(1 - clampedT, 4);
|
|
4701
|
-
}, noise2D = (x, y) => {
|
|
5033
|
+
}), validateVec2 = vec => vec && "number" == typeof vec.x && "number" == typeof vec.y && !isNaN(vec.x) && !isNaN(vec.y), noise2D = (x, y) => {
|
|
4702
5034
|
// Add input validation
|
|
4703
5035
|
if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
|
|
4704
5036
|
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) => {
|
|
@@ -4737,13 +5069,13 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
|
|
|
4737
5069
|
x: .5,
|
|
4738
5070
|
y: .5
|
|
4739
5071
|
};
|
|
4740
|
-
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 =
|
|
5072
|
+
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) => {
|
|
4741
5073
|
// Add input validation
|
|
4742
5074
|
if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y) || isNaN(strength)) return {
|
|
4743
5075
|
x: 0,
|
|
4744
5076
|
y: 0
|
|
4745
5077
|
};
|
|
4746
|
-
const distance =
|
|
5078
|
+
const distance = vec2Length(x, y), distortion = Math.pow(Math.min(distance, 10), 2) * strength;
|
|
4747
5079
|
// Limit distance to prevent extreme values
|
|
4748
5080
|
return {
|
|
4749
5081
|
x: x * (1 + distortion),
|
|
@@ -4755,7 +5087,7 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
|
|
|
4755
5087
|
x: 0,
|
|
4756
5088
|
y: 0
|
|
4757
5089
|
};
|
|
4758
|
-
const distance =
|
|
5090
|
+
const distance = vec2Length(x, y);
|
|
4759
5091
|
// Prevent division by zero and extreme values
|
|
4760
5092
|
if (0 === distance) return {
|
|
4761
5093
|
x: 0,
|
|
@@ -4766,8 +5098,8 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
|
|
|
4766
5098
|
x: Math.cos(angle) * distance * intensity,
|
|
4767
5099
|
y: Math.sin(angle) * distance * intensity
|
|
4768
5100
|
};
|
|
4769
|
-
})(ix, iy, .015 * baseDisplacement), scaled =
|
|
4770
|
-
return createTexture(
|
|
5101
|
+
})(ix, iy, .015 * baseDisplacement), scaled = smoothstepEdge(0, 1, 1.15 * baseDisplacement), finalX = ix + totalDistortionX + .5 * chromaticOffset.x, finalY = iy + totalDistortionY + .5 * chromaticOffset.y;
|
|
5102
|
+
return createTexture(clamp(finalX * scaled + .5, 0, 1), clamp(finalY * scaled + .5, 0, 1));
|
|
4771
5103
|
},
|
|
4772
5104
|
// Premium Apple-style fluid glass with enhanced organic flow
|
|
4773
5105
|
appleFluid: (uv, mousePosition) => {
|
|
@@ -4775,8 +5107,8 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
|
|
|
4775
5107
|
x: .5,
|
|
4776
5108
|
y: .5
|
|
4777
5109
|
};
|
|
4778
|
-
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 =
|
|
4779
|
-
return createTexture(
|
|
5110
|
+
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;
|
|
5111
|
+
return createTexture(clamp(ix + (.035 * organicX + fluidVelocityX + vortexX) * mask + .5, 0, 1), clamp(totalY + .5, 0, 1));
|
|
4780
5112
|
},
|
|
4781
5113
|
// High-end glass with advanced refraction and depth
|
|
4782
5114
|
premiumGlass: (uv, mousePosition) => {
|
|
@@ -4784,7 +5116,7 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
|
|
|
4784
5116
|
x: .5,
|
|
4785
5117
|
y: .5
|
|
4786
5118
|
};
|
|
4787
|
-
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 =
|
|
5119
|
+
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);
|
|
4788
5120
|
// Multi-layer depth effect
|
|
4789
5121
|
let depthX = 0, depthY = 0;
|
|
4790
5122
|
for (let layer = 0; layer < 3; layer++) {
|
|
@@ -4792,8 +5124,8 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
|
|
|
4792
5124
|
depthX += Math.sin(ix * layerScale + layerTime) * layerStrength, depthY += Math.cos(iy * layerScale - layerTime) * layerStrength;
|
|
4793
5125
|
}
|
|
4794
5126
|
// Glass refraction with mouse influence
|
|
4795
|
-
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 =
|
|
4796
|
-
return createTexture(
|
|
5127
|
+
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;
|
|
5128
|
+
return createTexture(clamp(ix + (refractionX + depthX + .015 * organicNoise) * edgeMask + .5, 0, 1), clamp(finalY + .5, 0, 1));
|
|
4797
5129
|
},
|
|
4798
5130
|
// Metallic liquid effect with shimmer
|
|
4799
5131
|
liquidMetal: (uv, mousePosition) => {
|
|
@@ -4801,8 +5133,8 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
|
|
|
4801
5133
|
x: .5,
|
|
4802
5134
|
y: .5
|
|
4803
5135
|
};
|
|
4804
|
-
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 =
|
|
4805
|
-
return createTexture(
|
|
5136
|
+
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;
|
|
5137
|
+
return createTexture(clamp(totalX + .5, 0, 1), clamp(totalY + .5, 0, 1));
|
|
4806
5138
|
},
|
|
4807
5139
|
// basiBasi - Expert Premium Glass Shader
|
|
4808
5140
|
// The most advanced shader with caustics, spectral dispersion, parallax depth, and volumetric effects
|
|
@@ -4811,7 +5143,7 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
|
|
|
4811
5143
|
x: .5,
|
|
4812
5144
|
y: .5
|
|
4813
5145
|
};
|
|
4814
|
-
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 =
|
|
5146
|
+
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) =>
|
|
4815
5147
|
// Add input validation
|
|
4816
5148
|
"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) => {
|
|
4817
5149
|
// Add input validation
|
|
@@ -4829,7 +5161,7 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
|
|
|
4829
5161
|
y: 0
|
|
4830
5162
|
}
|
|
4831
5163
|
};
|
|
4832
|
-
const distance =
|
|
5164
|
+
const distance = vec2Length(x, y), dispersionStrength = Math.min(.025 * distance, 1), redOffset = .8 * dispersionStrength, greenOffset = 1 * dispersionStrength, blueOffset = 1.2 * dispersionStrength;
|
|
4833
5165
|
return {
|
|
4834
5166
|
r: {
|
|
4835
5167
|
x: Math.cos(angle) * redOffset,
|
|
@@ -4869,8 +5201,8 @@ const Accordion = AccordionWithSubcomponents, AtomixLogo = ({height: height = 24
|
|
|
4869
5201
|
return turbulence;
|
|
4870
5202
|
})(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) =>
|
|
4871
5203
|
// Add input validation
|
|
4872
|
-
"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 =
|
|
4873
|
-
return createTexture(
|
|
5204
|
+
"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;
|
|
5205
|
+
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));
|
|
4874
5206
|
},
|
|
4875
5207
|
// Aliases for compatibility
|
|
4876
5208
|
plasma: (uv, mousePosition) => fragmentShaders.premiumGlass(uv, mousePosition),
|
|
@@ -4914,8 +5246,8 @@ var shaderUtils = Object.freeze({
|
|
|
4914
5246
|
let dx = pos.x * w - x, dy = pos.y * h - y;
|
|
4915
5247
|
// Apply edge smoothing for Apple-like effect
|
|
4916
5248
|
const edgeX = 2 * Math.min(x / w, (w - x) / w), edgeY = 2 * Math.min(y / h, (h - y) / h), edgeFactor = Math.min(edgeX, edgeY);
|
|
4917
|
-
dx *=
|
|
4918
|
-
rawValues.push(dx, dy);
|
|
5249
|
+
dx *= smoothstepEdge(0, .2, edgeFactor), dy *= smoothstepEdge(0, .2, edgeFactor),
|
|
5250
|
+
maxScale = Math.max(maxScale, Math.abs(dx), Math.abs(dy)), rawValues.push(dx, dy);
|
|
4919
5251
|
}
|
|
4920
5252
|
// Improved normalization to prevent artifacts while maintaining intensity
|
|
4921
5253
|
maxScale = Math.max(maxScale, 1);
|
|
@@ -4925,9 +5257,9 @@ var shaderUtils = Object.freeze({
|
|
|
4925
5257
|
let rawIndex = 0;
|
|
4926
5258
|
for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) {
|
|
4927
5259
|
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);
|
|
4928
|
-
data[pixelIndex] =
|
|
4929
|
-
data[pixelIndex + 1] =
|
|
4930
|
-
data[pixelIndex + 2] =
|
|
5260
|
+
data[pixelIndex] = clamp(255 * r, 0, 255), // Red channel (X displacement)
|
|
5261
|
+
data[pixelIndex + 1] = clamp(255 * g, 0, 255), // Green channel (Y displacement)
|
|
5262
|
+
data[pixelIndex + 2] = clamp(255 * g, 0, 255), // Blue channel (Y displacement for SVG filter compatibility)
|
|
4931
5263
|
data[pixelIndex + 3] = 255;
|
|
4932
5264
|
}
|
|
4933
5265
|
return this.context.putImageData(imageData, 0, 0), this.canvas.toDataURL();
|
|
@@ -4955,9 +5287,7 @@ var shaderUtils = Object.freeze({
|
|
|
4955
5287
|
return this.canvasDPI;
|
|
4956
5288
|
}
|
|
4957
5289
|
},
|
|
4958
|
-
|
|
4959
|
-
fragmentShaders: fragmentShaders,
|
|
4960
|
-
liquidGlassWithTime: liquidGlassWithTime
|
|
5290
|
+
fragmentShaders: fragmentShaders
|
|
4961
5291
|
});
|
|
4962
5292
|
|
|
4963
5293
|
// Map string sizes to pixel values
|
|
@@ -5106,10 +5436,10 @@ const Badge = React.memo((({label: label, variant: variant = "primary", size: s
|
|
|
5106
5436
|
if (glass) {
|
|
5107
5437
|
// Default glass settings for badges
|
|
5108
5438
|
const defaultGlassProps = {
|
|
5109
|
-
|
|
5110
|
-
borderRadius
|
|
5111
|
-
|
|
5112
|
-
|
|
5439
|
+
...GLASS_DEFAULTS.BADGE,
|
|
5440
|
+
// Override borderRadius dynamically if the ref is available
|
|
5441
|
+
borderRadius: ref.current?.getBoundingClientRect().width ? ref.current?.getBoundingClientRect().width / 2 : GLASS_DEFAULTS.BADGE.borderRadius,
|
|
5442
|
+
className: "c-badge--glass"
|
|
5113
5443
|
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
5114
5444
|
...defaultGlassProps,
|
|
5115
5445
|
...glass
|
|
@@ -5360,12 +5690,7 @@ const Spinner = React.memo( React.forwardRef((({size: size = "md", variant: var
|
|
|
5360
5690
|
})
|
|
5361
5691
|
});
|
|
5362
5692
|
if (glass) {
|
|
5363
|
-
const defaultGlassProps = {
|
|
5364
|
-
displacementScale: 20,
|
|
5365
|
-
blurAmount: 1,
|
|
5366
|
-
borderRadius: 999,
|
|
5367
|
-
mode: "shader"
|
|
5368
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
5693
|
+
const defaultGlassProps = GLASS_DEFAULTS.SPINNER, glassProps = !0 === glass ? defaultGlassProps : {
|
|
5369
5694
|
...defaultGlassProps,
|
|
5370
5695
|
...glass
|
|
5371
5696
|
};
|
|
@@ -5467,60 +5792,6 @@ class ThemeNaming {
|
|
|
5467
5792
|
}
|
|
5468
5793
|
}
|
|
5469
5794
|
|
|
5470
|
-
ThemeNaming.prefix = "atomix";
|
|
5471
|
-
|
|
5472
|
-
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) {
|
|
5473
|
-
return function(that, callbackfn, argumentsLength, memo) {
|
|
5474
|
-
var O = toObject(that), self = IndexedObject(O), length = lengthOfArrayLike(O);
|
|
5475
|
-
if (aCallable(callbackfn), 0 === length && argumentsLength < 2) throw new $TypeError(REDUCE_EMPTY);
|
|
5476
|
-
var index = IS_RIGHT ? length - 1 : 0, i = IS_RIGHT ? -1 : 1;
|
|
5477
|
-
if (argumentsLength < 2) for (;;) {
|
|
5478
|
-
if (index in self) {
|
|
5479
|
-
memo = self[index], index += i;
|
|
5480
|
-
break;
|
|
5481
|
-
}
|
|
5482
|
-
if (index += i, IS_RIGHT ? index < 0 : length <= index) throw new $TypeError(REDUCE_EMPTY);
|
|
5483
|
-
}
|
|
5484
|
-
for (;IS_RIGHT ? index >= 0 : length > index; index += i) index in self && (memo = callbackfn(memo, self[index], index, O));
|
|
5485
|
-
return memo;
|
|
5486
|
-
};
|
|
5487
|
-
}, arrayReduce = {
|
|
5488
|
-
// `Array.prototype.reduce` method
|
|
5489
|
-
// https://tc39.es/ecma262/#sec-array.prototype.reduce
|
|
5490
|
-
left: createMethod(!1),
|
|
5491
|
-
// `Array.prototype.reduceRight` method
|
|
5492
|
-
// https://tc39.es/ecma262/#sec-array.prototype.reduceright
|
|
5493
|
-
right: createMethod(!0)
|
|
5494
|
-
}, fails = fails$9, globalThis$1 = globalThis_1, userAgent = environmentUserAgent, classof = classofRaw$2, userAgentStartsWith = function(string) {
|
|
5495
|
-
return userAgent.slice(0, string.length) === string;
|
|
5496
|
-
}, 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;
|
|
5497
|
-
|
|
5498
|
-
// `Array.prototype.reduce` method
|
|
5499
|
-
// https://tc39.es/ecma262/#sec-array.prototype.reduce
|
|
5500
|
-
_export({
|
|
5501
|
-
target: "Array",
|
|
5502
|
-
proto: !0,
|
|
5503
|
-
forced: !("NODE" === environment) && environmentV8Version > 79 && environmentV8Version < 83 || !function(METHOD_NAME, argument) {
|
|
5504
|
-
var method = [][METHOD_NAME];
|
|
5505
|
-
return !!method && fails((function() {
|
|
5506
|
-
// eslint-disable-next-line no-useless-call -- required for testing
|
|
5507
|
-
method.call(null, argument || function() {
|
|
5508
|
-
return 1;
|
|
5509
|
-
}, 1);
|
|
5510
|
-
}));
|
|
5511
|
-
}("reduce")
|
|
5512
|
-
}, {
|
|
5513
|
-
reduce: function(callbackfn /* , initialValue */) {
|
|
5514
|
-
var length = arguments.length;
|
|
5515
|
-
return $reduce(this, callbackfn, length, length > 1 ? arguments[1] : void 0);
|
|
5516
|
-
}
|
|
5517
|
-
});
|
|
5518
|
-
|
|
5519
|
-
var reduce$3 = getBuiltInPrototypeMethod$3("Array", "reduce"), isPrototypeOf = objectIsPrototypeOf, method = reduce$3, ArrayPrototype = Array.prototype, _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
5520
|
-
var own = it.reduce;
|
|
5521
|
-
return it === ArrayPrototype || isPrototypeOf(ArrayPrototype, it) && own === ArrayPrototype.reduce ? method : own;
|
|
5522
|
-
}));
|
|
5523
|
-
|
|
5524
5795
|
/**
|
|
5525
5796
|
* Render a slot with the given props
|
|
5526
5797
|
*
|
|
@@ -5562,7 +5833,9 @@ function renderSlot(slot, props, fallback) {
|
|
|
5562
5833
|
|
|
5563
5834
|
/**
|
|
5564
5835
|
* Check if a value is a slot configuration
|
|
5565
|
-
*/
|
|
5836
|
+
*/ ThemeNaming.prefix = "atomix";
|
|
5837
|
+
|
|
5838
|
+
const Button = React__default.default.memo( React.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) => {
|
|
5566
5839
|
const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href), iconElement = iconName ? jsxRuntime.jsx(Icon, {
|
|
5567
5840
|
name: iconName,
|
|
5568
5841
|
size: iconSize
|
|
@@ -5670,11 +5943,7 @@ function renderSlot(slot, props, fallback) {
|
|
|
5670
5943
|
// This is a safe fallback for disabled links.
|
|
5671
5944
|
if (glass) {
|
|
5672
5945
|
// Default glass props
|
|
5673
|
-
const defaultGlassProps = {
|
|
5674
|
-
displacementScale: 20,
|
|
5675
|
-
blurAmount: 0,
|
|
5676
|
-
saturation: 200
|
|
5677
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
5946
|
+
const defaultGlassProps = GLASS_DEFAULTS.BUTTON, glassProps = !0 === glass ? defaultGlassProps : {
|
|
5678
5947
|
...defaultGlassProps,
|
|
5679
5948
|
...glass
|
|
5680
5949
|
};
|
|
@@ -5873,11 +6142,7 @@ const CalloutComponentBase = ({title: title, children: children, icon: icon, var
|
|
|
5873
6142
|
// Determine appropriate ARIA attributes based on variant
|
|
5874
6143
|
if (glass) {
|
|
5875
6144
|
// Default glass settings for callouts
|
|
5876
|
-
const defaultGlassProps = {
|
|
5877
|
-
displacementScale: 30,
|
|
5878
|
-
borderRadius: 8,
|
|
5879
|
-
elasticity: 0
|
|
5880
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
6145
|
+
const defaultGlassProps = GLASS_DEFAULTS.CALLOUT, glassProps = !0 === glass ? defaultGlassProps : {
|
|
5881
6146
|
...defaultGlassProps,
|
|
5882
6147
|
...glass
|
|
5883
6148
|
};
|
|
@@ -10695,15 +10960,7 @@ const range = (start, end) => {
|
|
|
10695
10960
|
}) ]
|
|
10696
10961
|
});
|
|
10697
10962
|
if (glass) {
|
|
10698
|
-
|
|
10699
|
-
const defaultGlassProps = {
|
|
10700
|
-
displacementScale: 60,
|
|
10701
|
-
blurAmount: 1,
|
|
10702
|
-
saturation: 160,
|
|
10703
|
-
aberrationIntensity: .5,
|
|
10704
|
-
borderRadius: 8,
|
|
10705
|
-
mode: "shader"
|
|
10706
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
10963
|
+
const defaultGlassProps = GLASS_DEFAULTS.PAGINATION, glassProps = !0 === glass ? defaultGlassProps : {
|
|
10707
10964
|
...defaultGlassProps,
|
|
10708
10965
|
...glass
|
|
10709
10966
|
};
|
|
@@ -10767,14 +11024,7 @@ const Checkbox = React__default.default.memo( React.forwardRef((({label: label,
|
|
|
10767
11024
|
style: style,
|
|
10768
11025
|
children: inputElement
|
|
10769
11026
|
}), glass) {
|
|
10770
|
-
const defaultGlassProps = {
|
|
10771
|
-
displacementScale: 40,
|
|
10772
|
-
blurAmount: 1,
|
|
10773
|
-
saturation: 160,
|
|
10774
|
-
aberrationIntensity: .3,
|
|
10775
|
-
borderRadius: 6,
|
|
10776
|
-
mode: "shader"
|
|
10777
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
11027
|
+
const defaultGlassProps = GLASS_DEFAULTS.CHECKBOX, glassProps = !0 === glass ? defaultGlassProps : {
|
|
10778
11028
|
...defaultGlassProps,
|
|
10779
11029
|
...glass
|
|
10780
11030
|
};
|
|
@@ -11044,13 +11294,8 @@ const DropdownStyleContext = React.createContext({}), Dropdown = React.memo((f
|
|
|
11044
11294
|
"aria-orientation": "vertical",
|
|
11045
11295
|
"aria-hidden": !isOpen,
|
|
11046
11296
|
onKeyDown: handleKeyDown,
|
|
11047
|
-
children: glass ?
|
|
11048
|
-
|
|
11049
|
-
(() => {
|
|
11050
|
-
const defaultGlassProps = {
|
|
11051
|
-
displacementScale: 20,
|
|
11052
|
-
elasticity: 0
|
|
11053
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
11297
|
+
children: glass ? (() => {
|
|
11298
|
+
const defaultGlassProps = GLASS_DEFAULTS.DROPDOWN, glassProps = !0 === glass ? defaultGlassProps : {
|
|
11054
11299
|
...defaultGlassProps,
|
|
11055
11300
|
...glass
|
|
11056
11301
|
};
|
|
@@ -12614,16 +12859,8 @@ const Input = React.memo( React.forwardRef((({type: type = "text", value: value
|
|
|
12614
12859
|
...style
|
|
12615
12860
|
} : style
|
|
12616
12861
|
});
|
|
12617
|
-
if (glass) {
|
|
12618
|
-
|
|
12619
|
-
const defaultGlassProps = {
|
|
12620
|
-
displacementScale: 60,
|
|
12621
|
-
blurAmount: 1,
|
|
12622
|
-
saturation: 180,
|
|
12623
|
-
aberrationIntensity: .2,
|
|
12624
|
-
borderRadius: 12,
|
|
12625
|
-
mode: "shader"
|
|
12626
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
12862
|
+
if (glass) {
|
|
12863
|
+
const defaultGlassProps = GLASS_DEFAULTS.INPUT, glassProps = !0 === glass ? defaultGlassProps : {
|
|
12627
12864
|
...defaultGlassProps,
|
|
12628
12865
|
...glass
|
|
12629
12866
|
};
|
|
@@ -12807,498 +13044,292 @@ function useHero(initialProps) {
|
|
|
12807
13044
|
customClass && classes.push(customClass), classes.join(" ");
|
|
12808
13045
|
},
|
|
12809
13046
|
generateContentColClass: (size = defaultProps.contentColSize || 5, customClass) => {
|
|
12810
|
-
const classes = [ `o-grid__col o-grid__col--md-${size}` ];
|
|
12811
|
-
// Handle mobile stacking order
|
|
12812
|
-
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")),
|
|
12813
|
-
customClass && classes.push(customClass), classes.join(" ");
|
|
12814
|
-
},
|
|
12815
|
-
hasBackgroundImage: hasBackgroundImage,
|
|
12816
|
-
hasForegroundImage: hasForegroundImage,
|
|
12817
|
-
useGridLayout: useGridLayout,
|
|
12818
|
-
heroRef: heroRef,
|
|
12819
|
-
videoRef: videoRef,
|
|
12820
|
-
applyParallaxEffect: applyParallaxEffect,
|
|
12821
|
-
removeParallaxEffect: removeParallaxEffect,
|
|
12822
|
-
backgroundSlider: backgroundSlider,
|
|
12823
|
-
hasBackgroundSlider: hasBackgroundSlider
|
|
12824
|
-
};
|
|
12825
|
-
}
|
|
12826
|
-
|
|
12827
|
-
/**
|
|
12828
|
-
* Hook for River component functionality
|
|
12829
|
-
* @param initialProps - Initial river props
|
|
12830
|
-
* @returns River methods and state
|
|
12831
|
-
*/ function useRiver(initialProps) {
|
|
12832
|
-
const defaultProps = {
|
|
12833
|
-
center: !1,
|
|
12834
|
-
breakout: !1,
|
|
12835
|
-
reverse: !1,
|
|
12836
|
-
imageAlt: "Image",
|
|
12837
|
-
showOverlay: !0,
|
|
12838
|
-
...initialProps
|
|
12839
|
-
};
|
|
12840
|
-
/**
|
|
12841
|
-
* Check if the river has a background image
|
|
12842
|
-
*/ return {
|
|
12843
|
-
generateRiverClassNames: (baseClassName = "") => {
|
|
12844
|
-
const classes = [ RIVER.SELECTORS.RIVER.replace(".", "") ];
|
|
12845
|
-
// Add layout classes
|
|
12846
|
-
return defaultProps.center && classes.push(RIVER.CLASSES.CENTER), defaultProps.breakout && classes.push(RIVER.CLASSES.BREAKOUT),
|
|
12847
|
-
defaultProps.reverse && classes.push(RIVER.CLASSES.REVERSE), baseClassName && classes.push(baseClassName),
|
|
12848
|
-
classes.join(" ");
|
|
12849
|
-
},
|
|
12850
|
-
generateContentClass: () => RIVER.SELECTORS.CONTENT.replace(".", ""),
|
|
12851
|
-
generateVisualClass: () => RIVER.SELECTORS.VISUAL.replace(".", ""),
|
|
12852
|
-
hasBackgroundImage: !!defaultProps.backgroundImageSrc,
|
|
12853
|
-
hasForegroundImage: !!defaultProps.imageSrc,
|
|
12854
|
-
textContent: "string" == typeof defaultProps.text ? [ defaultProps.text ] : defaultProps.text || []
|
|
12855
|
-
};
|
|
12856
|
-
}
|
|
12857
|
-
|
|
12858
|
-
/**
|
|
12859
|
-
* Navbar state and functionality
|
|
12860
|
-
* @param initialProps - Initial navbar properties
|
|
12861
|
-
* @returns Navbar state and methods
|
|
12862
|
-
*/ function useNavbar(initialProps) {
|
|
12863
|
-
// Default navbar properties
|
|
12864
|
-
const defaultProps = {
|
|
12865
|
-
position: "static",
|
|
12866
|
-
collapsible: !0,
|
|
12867
|
-
backdrop: !1,
|
|
12868
|
-
closeOnOutsideClick: !0,
|
|
12869
|
-
closeOnEscape: !0,
|
|
12870
|
-
"aria-label": "Main navigation",
|
|
12871
|
-
...initialProps
|
|
12872
|
-
}, [isExpanded, setIsExpanded] = React.useState(defaultProps.expanded || !1);
|
|
12873
|
-
// Local expanded state for when not controlled externally
|
|
12874
|
-
return {
|
|
12875
|
-
defaultProps: defaultProps,
|
|
12876
|
-
isExpanded: isExpanded,
|
|
12877
|
-
setIsExpanded: setIsExpanded,
|
|
12878
|
-
generateNavbarClass: props => {
|
|
12879
|
-
const {position: position = defaultProps.position, variant: variant, collapsible: collapsible = defaultProps.collapsible, className: className = ""} = props;
|
|
12880
|
-
return `c-navbar ${"static" !== position ? `c-navbar--${position}` : ""} ${variant ? `c-navbar--${variant}` : ""} ${collapsible ? "c-navbar--collapsible" : ""} ${className}`.trim();
|
|
12881
|
-
},
|
|
12882
|
-
generateContainerStyle: width => width ? {
|
|
12883
|
-
maxWidth: width
|
|
12884
|
-
} : {},
|
|
12885
|
-
generateCollapseClass: expanded => ("c-navbar__collapse " + (expanded ? "is-expanded" : "")).trim(),
|
|
12886
|
-
toggleExpanded: () => {
|
|
12887
|
-
const newState = !isExpanded;
|
|
12888
|
-
setIsExpanded(newState), defaultProps.onToggle && defaultProps.onToggle(newState);
|
|
12889
|
-
},
|
|
12890
|
-
getExpandedState: controlled => void 0 !== controlled ? controlled : isExpanded
|
|
12891
|
-
};
|
|
12892
|
-
}
|
|
12893
|
-
|
|
12894
|
-
/**
|
|
12895
|
-
* Nav state and functionality
|
|
12896
|
-
* @param initialProps - Initial nav properties
|
|
12897
|
-
* @returns Nav state and methods
|
|
12898
|
-
*/ function useNav(initialProps) {
|
|
12899
|
-
// Default nav properties
|
|
12900
|
-
const defaultProps = {
|
|
12901
|
-
alignment: "start",
|
|
12902
|
-
variant: "default",
|
|
12903
|
-
...initialProps
|
|
12904
|
-
};
|
|
12905
|
-
/**
|
|
12906
|
-
* Generate nav class based on properties
|
|
12907
|
-
* @param props - Nav properties
|
|
12908
|
-
* @returns Class string
|
|
12909
|
-
*/ return {
|
|
12910
|
-
defaultProps: defaultProps,
|
|
12911
|
-
generateNavClass: props => {
|
|
12912
|
-
const {alignment: alignment = defaultProps.alignment, variant: variant = defaultProps.variant, className: className = ""} = props;
|
|
12913
|
-
return `c-nav ${"start" !== alignment ? `c-nav--${alignment}` : ""} ${"default" !== variant ? `c-nav--${variant}` : ""} ${className}`.trim();
|
|
12914
|
-
}
|
|
12915
|
-
};
|
|
12916
|
-
}
|
|
12917
|
-
|
|
12918
|
-
/**
|
|
12919
|
-
* Nav item state and functionality
|
|
12920
|
-
* @param initialProps - Initial nav item properties
|
|
12921
|
-
* @returns Nav item state and methods
|
|
12922
|
-
*/ function useNavItem(initialProps) {
|
|
12923
|
-
// Default nav item properties
|
|
12924
|
-
const defaultProps = {
|
|
12925
|
-
dropdown: !1,
|
|
12926
|
-
megaMenu: !1,
|
|
12927
|
-
active: !1,
|
|
12928
|
-
...initialProps
|
|
12929
|
-
};
|
|
12930
|
-
/**
|
|
12931
|
-
* Generate nav item class based on properties
|
|
12932
|
-
* @param props - Nav item properties
|
|
12933
|
-
* @returns Class string
|
|
12934
|
-
*/ return {
|
|
12935
|
-
defaultProps: defaultProps,
|
|
12936
|
-
generateNavItemClass: props => {
|
|
12937
|
-
const {dropdown: dropdown = defaultProps.dropdown, megaMenu: megaMenu = defaultProps.megaMenu, active: active = defaultProps.active, disabled: disabled = defaultProps.disabled, className: className = ""} = props;
|
|
12938
|
-
// Apply dropdown class only for regular dropdowns, not mega menus
|
|
12939
|
-
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();
|
|
12940
|
-
},
|
|
12941
|
-
generateNavLinkClass: (active = !1, disabled = !1, className = "") => `c-nav__link ${active ? NAV.CLASSES.ACTIVE : ""} ${disabled ? "c-nav__link--disabled" : ""} ${className}`.trim(),
|
|
12942
|
-
handleClick: handler => e => {
|
|
12943
|
-
!defaultProps.disabled && handler ? handler() : e.preventDefault();
|
|
12944
|
-
}
|
|
12945
|
-
};
|
|
12946
|
-
}
|
|
12947
|
-
|
|
12948
|
-
/**
|
|
12949
|
-
* Nav dropdown state and functionality
|
|
12950
|
-
* @param initialProps - Initial dropdown properties
|
|
12951
|
-
* @returns Dropdown state and methods
|
|
12952
|
-
*/ function useNavDropdown(initialProps) {
|
|
12953
|
-
// Default dropdown properties
|
|
12954
|
-
const defaultProps = {
|
|
12955
|
-
alignment: "start",
|
|
12956
|
-
megaMenu: !1,
|
|
12957
|
-
...initialProps
|
|
12958
|
-
}, isInFixedBottomNavbar = () => null !== document.querySelector(".c-navbar--fixed-bottom");
|
|
12959
|
-
/**
|
|
12960
|
-
* Generate dropdown menu class based on properties
|
|
12961
|
-
* @param props - Dropdown properties
|
|
12962
|
-
* @returns Class string
|
|
12963
|
-
*/ return {
|
|
12964
|
-
defaultProps: defaultProps,
|
|
12965
|
-
generateDropdownMenuClass: props => {
|
|
12966
|
-
const {alignment: alignment = defaultProps.alignment, megaMenu: megaMenu = defaultProps.megaMenu, className: className = ""} = props, baseClass = megaMenu ? NAV.SELECTORS.MEGA_MENU.replace(".", "") : NAV.SELECTORS.DROPDOWN_MENU.replace(".", "");
|
|
12967
|
-
// Select the base class based on mega menu or regular dropdown
|
|
12968
|
-
// Add alignment class if not default 'start'
|
|
12969
|
-
let alignmentClass = "";
|
|
12970
|
-
return "center" === alignment ? alignmentClass = `${baseClass}--center` : "end" === alignment && (alignmentClass = `${baseClass}--end`),
|
|
12971
|
-
`${baseClass} ${alignmentClass} ${className}`.trim();
|
|
12972
|
-
},
|
|
12973
|
-
isInFixedBottomNavbar: isInFixedBottomNavbar,
|
|
12974
|
-
getIconName: (isMegaMenu = !1) => isInFixedBottomNavbar() ? "CaretUp" : "CaretDown"
|
|
12975
|
-
};
|
|
12976
|
-
}
|
|
12977
|
-
|
|
12978
|
-
/**
|
|
12979
|
-
* SideMenu state and functionality
|
|
12980
|
-
* @param initialProps - Initial side menu properties
|
|
12981
|
-
* @returns SideMenu state and methods
|
|
12982
|
-
*/ function useSideMenu(initialProps) {
|
|
12983
|
-
const {collapsible: collapsible = !0, collapsibleDesktop: collapsibleDesktop = !1, defaultCollapsedDesktop: defaultCollapsedDesktop = !1, isOpen: isOpen, onToggle: onToggle, disabled: disabled = !1} = initialProps || {}, [isOpenState, setIsOpenState] = React.useState(void 0 !== defaultCollapsedDesktop ? !defaultCollapsedDesktop : isOpen || !1), wrapperRef = React.useRef(null), innerRef = React.useRef(null), sideMenuRef = React.useRef(null);
|
|
12984
|
-
// Local open state for when not controlled externally
|
|
12985
|
-
// Update local state when external state changes
|
|
12986
|
-
React.useEffect((() => {
|
|
12987
|
-
void 0 !== isOpen ? setIsOpenState(isOpen) : void 0 !== defaultCollapsedDesktop && setIsOpenState(!defaultCollapsedDesktop);
|
|
12988
|
-
}), [ isOpen, defaultCollapsedDesktop ]),
|
|
12989
|
-
// Set initial height on mount
|
|
12990
|
-
React.useEffect((() => {
|
|
12991
|
-
const shouldCollapse = window.innerWidth < 768 ? collapsible : collapsibleDesktop, currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
|
|
12992
|
-
if (shouldCollapse && wrapperRef.current && innerRef.current) {
|
|
12993
|
-
// Use setTimeout to ensure DOM is fully rendered
|
|
12994
|
-
const timeoutId = setTimeout((() => {
|
|
12995
|
-
wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
|
|
12996
|
-
}), 0);
|
|
12997
|
-
return () => clearTimeout(timeoutId);
|
|
12998
|
-
}
|
|
12999
|
-
!shouldCollapse && wrapperRef.current && (wrapperRef.current.style.height = "auto");
|
|
13000
|
-
}), [ collapsible, collapsibleDesktop, isOpen, isOpenState ]),
|
|
13001
|
-
// Handle responsive behavior - vertical collapse for both mobile and desktop
|
|
13002
|
-
React.useEffect((() => {
|
|
13003
|
-
const handleResize = () => {
|
|
13004
|
-
if (window.innerWidth < 768 ? collapsible : collapsibleDesktop) {
|
|
13005
|
-
if (wrapperRef.current && innerRef.current) {
|
|
13006
|
-
// Set proper height for vertical animation (both mobile and desktop)
|
|
13007
|
-
const currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
|
|
13008
|
-
// Use requestAnimationFrame to ensure DOM is ready
|
|
13009
|
-
requestAnimationFrame((() => {
|
|
13010
|
-
wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
|
|
13011
|
-
}));
|
|
13012
|
-
}
|
|
13013
|
-
} else
|
|
13014
|
-
// Not collapsible - always show content
|
|
13015
|
-
wrapperRef.current && (wrapperRef.current.style.height = "auto");
|
|
13016
|
-
}, timeoutId = setTimeout(handleResize, 0);
|
|
13017
|
-
// Initial call with a small delay to ensure DOM is ready
|
|
13018
|
-
return window.addEventListener("resize", handleResize), () => {
|
|
13019
|
-
clearTimeout(timeoutId), window.removeEventListener("resize", handleResize);
|
|
13020
|
-
};
|
|
13021
|
-
}), [ collapsible, collapsibleDesktop, isOpen, onToggle, isOpenState ]),
|
|
13022
|
-
// Update wrapper height when open state changes (both mobile and desktop)
|
|
13023
|
-
React.useEffect((() => {
|
|
13024
|
-
const shouldCollapse = window.innerWidth < 768 ? collapsible : collapsibleDesktop;
|
|
13025
|
-
if (shouldCollapse && wrapperRef.current && innerRef.current) {
|
|
13026
|
-
const currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
|
|
13027
|
-
// Use requestAnimationFrame to ensure DOM is ready
|
|
13028
|
-
requestAnimationFrame((() => {
|
|
13029
|
-
wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
|
|
13030
|
-
}));
|
|
13031
|
-
} else !shouldCollapse && wrapperRef.current && (
|
|
13032
|
-
// Not collapsible - always show content
|
|
13033
|
-
wrapperRef.current.style.height = "auto");
|
|
13034
|
-
}), [ isOpen, isOpenState, collapsible, collapsibleDesktop ]);
|
|
13035
|
-
/**
|
|
13036
|
-
* Generate side menu class based on properties
|
|
13037
|
-
* @param props - Side menu properties
|
|
13038
|
-
* @returns Class string
|
|
13039
|
-
*/
|
|
13040
|
-
const handleToggle = () => {
|
|
13041
|
-
if (disabled) return;
|
|
13042
|
-
const newState = void 0 !== isOpen ? !isOpen : !isOpenState;
|
|
13043
|
-
"function" == typeof onToggle ?
|
|
13044
|
-
// Controlled component
|
|
13045
|
-
onToggle(newState) :
|
|
13046
|
-
// Uncontrolled component
|
|
13047
|
-
setIsOpenState(newState);
|
|
13048
|
-
}, getCurrentOpenState = () => void 0 !== isOpen ? isOpen : isOpenState;
|
|
13049
|
-
/**
|
|
13050
|
-
* Generate wrapper class
|
|
13051
|
-
* @returns Class string
|
|
13052
|
-
*/ return {
|
|
13053
|
-
isOpenState: getCurrentOpenState(),
|
|
13054
|
-
wrapperRef: wrapperRef,
|
|
13055
|
-
innerRef: innerRef,
|
|
13056
|
-
sideMenuRef: sideMenuRef,
|
|
13057
|
-
generateSideMenuClass: props => {
|
|
13058
|
-
const {className: className = "", isOpen: isOpen = !1} = props, openClass = isOpen ? SIDE_MENU.CLASSES.IS_OPEN : "";
|
|
13059
|
-
return `${SIDE_MENU.CLASSES.BASE} ${openClass} ${className}`.trim();
|
|
13060
|
-
},
|
|
13061
|
-
generateWrapperClass: () => SIDE_MENU.CLASSES.WRAPPER,
|
|
13062
|
-
handleToggle: handleToggle,
|
|
13063
|
-
handleDesktopCollapse: () => {
|
|
13064
|
-
handleToggle();
|
|
13047
|
+
const classes = [ `o-grid__col o-grid__col--md-${size}` ];
|
|
13048
|
+
// Handle mobile stacking order
|
|
13049
|
+
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")),
|
|
13050
|
+
customClass && classes.push(customClass), classes.join(" ");
|
|
13065
13051
|
},
|
|
13066
|
-
|
|
13052
|
+
hasBackgroundImage: hasBackgroundImage,
|
|
13053
|
+
hasForegroundImage: hasForegroundImage,
|
|
13054
|
+
useGridLayout: useGridLayout,
|
|
13055
|
+
heroRef: heroRef,
|
|
13056
|
+
videoRef: videoRef,
|
|
13057
|
+
applyParallaxEffect: applyParallaxEffect,
|
|
13058
|
+
removeParallaxEffect: removeParallaxEffect,
|
|
13059
|
+
backgroundSlider: backgroundSlider,
|
|
13060
|
+
hasBackgroundSlider: hasBackgroundSlider
|
|
13067
13061
|
};
|
|
13068
13062
|
}
|
|
13069
13063
|
|
|
13070
13064
|
/**
|
|
13071
|
-
*
|
|
13072
|
-
* @param initialProps - Initial
|
|
13073
|
-
* @returns
|
|
13074
|
-
*/ function
|
|
13075
|
-
// Default side menu item properties
|
|
13065
|
+
* Hook for River component functionality
|
|
13066
|
+
* @param initialProps - Initial river props
|
|
13067
|
+
* @returns River methods and state
|
|
13068
|
+
*/ function useRiver(initialProps) {
|
|
13076
13069
|
const defaultProps = {
|
|
13077
|
-
|
|
13078
|
-
|
|
13070
|
+
center: !1,
|
|
13071
|
+
breakout: !1,
|
|
13072
|
+
reverse: !1,
|
|
13073
|
+
imageAlt: "Image",
|
|
13074
|
+
showOverlay: !0,
|
|
13079
13075
|
...initialProps
|
|
13080
13076
|
};
|
|
13081
13077
|
/**
|
|
13082
|
-
*
|
|
13083
|
-
* @returns Class string
|
|
13078
|
+
* Check if the river has a background image
|
|
13084
13079
|
*/ return {
|
|
13085
|
-
|
|
13086
|
-
|
|
13087
|
-
|
|
13088
|
-
|
|
13080
|
+
generateRiverClassNames: (baseClassName = "") => {
|
|
13081
|
+
const classes = [ RIVER.SELECTORS.RIVER.replace(".", "") ];
|
|
13082
|
+
// Add layout classes
|
|
13083
|
+
return defaultProps.center && classes.push(RIVER.CLASSES.CENTER), defaultProps.breakout && classes.push(RIVER.CLASSES.BREAKOUT),
|
|
13084
|
+
defaultProps.reverse && classes.push(RIVER.CLASSES.REVERSE), baseClassName && classes.push(baseClassName),
|
|
13085
|
+
classes.join(" ");
|
|
13089
13086
|
},
|
|
13090
|
-
|
|
13091
|
-
|
|
13092
|
-
|
|
13087
|
+
generateContentClass: () => RIVER.SELECTORS.CONTENT.replace(".", ""),
|
|
13088
|
+
generateVisualClass: () => RIVER.SELECTORS.VISUAL.replace(".", ""),
|
|
13089
|
+
hasBackgroundImage: !!defaultProps.backgroundImageSrc,
|
|
13090
|
+
hasForegroundImage: !!defaultProps.imageSrc,
|
|
13091
|
+
textContent: "string" == typeof defaultProps.text ? [ defaultProps.text ] : defaultProps.text || []
|
|
13093
13092
|
};
|
|
13094
13093
|
}
|
|
13095
13094
|
|
|
13096
13095
|
/**
|
|
13097
|
-
*
|
|
13098
|
-
*
|
|
13099
|
-
* @
|
|
13100
|
-
|
|
13101
|
-
|
|
13102
|
-
|
|
13103
|
-
|
|
13104
|
-
|
|
13105
|
-
|
|
13106
|
-
|
|
13107
|
-
|
|
13108
|
-
|
|
13109
|
-
|
|
13110
|
-
}
|
|
13111
|
-
|
|
13112
|
-
|
|
13113
|
-
|
|
13114
|
-
|
|
13115
|
-
|
|
13116
|
-
|
|
13117
|
-
|
|
13118
|
-
|
|
13119
|
-
|
|
13120
|
-
|
|
13121
|
-
|
|
13122
|
-
|
|
13123
|
-
|
|
13124
|
-
|
|
13125
|
-
|
|
13126
|
-
|
|
13127
|
-
|
|
13128
|
-
|
|
13129
|
-
|
|
13130
|
-
* @param varNames - Variable names to remove
|
|
13131
|
-
* @param element - Target element (defaults to document.documentElement)
|
|
13132
|
-
*/ function removeCSSVariables(varNames, element) {
|
|
13133
|
-
if ("undefined" == typeof window) return;
|
|
13134
|
-
// SSR safety
|
|
13135
|
-
const target = element || document.documentElement;
|
|
13136
|
-
varNames.forEach((varName => {
|
|
13137
|
-
target.style.removeProperty(varName);
|
|
13138
|
-
}));
|
|
13139
|
-
}
|
|
13140
|
-
|
|
13141
|
-
/**
|
|
13142
|
-
* Get CSS variable value from an element
|
|
13143
|
-
*
|
|
13144
|
-
* @param varName - Variable name to get
|
|
13145
|
-
* @param element - Target element (defaults to document.documentElement)
|
|
13146
|
-
* @returns Variable value or null if not found
|
|
13147
|
-
*/ function getCSSVariable(varName, element) {
|
|
13148
|
-
if ("undefined" == typeof window) return null;
|
|
13149
|
-
// SSR safety
|
|
13150
|
-
const target = element || document.documentElement;
|
|
13151
|
-
return getComputedStyle(target).getPropertyValue(varName).trim() || null;
|
|
13152
|
-
}
|
|
13153
|
-
|
|
13154
|
-
/**
|
|
13155
|
-
* Convert CSS variable object to inline style object
|
|
13156
|
-
*
|
|
13157
|
-
* @example
|
|
13158
|
-
* const vars = { '--atomix-button-bg': '#000' }
|
|
13159
|
-
* const style = cssVarsToStyle(vars)
|
|
13160
|
-
* // Returns: { '--atomix-button-bg': '#000' } as React.CSSProperties
|
|
13161
|
-
*/ function cssVarsToStyle(vars) {
|
|
13162
|
-
var _context;
|
|
13163
|
-
return _reduceInstanceProperty(_context = Object.entries(vars)).call(_context, ((acc, [key, value]) => (acc[key] = "number" == typeof value ? `${value}px` : value,
|
|
13164
|
-
acc)), {});
|
|
13165
|
-
}
|
|
13166
|
-
|
|
13167
|
-
/**
|
|
13168
|
-
* Merge multiple CSS variable objects
|
|
13169
|
-
* Later objects override earlier ones
|
|
13170
|
-
*/ function mergeCSSVars(...varObjects) {
|
|
13171
|
-
return _reduceInstanceProperty(varObjects).call(varObjects, ((acc, vars) => (vars && Object.assign(acc, vars),
|
|
13172
|
-
acc)), {});
|
|
13173
|
-
}
|
|
13174
|
-
|
|
13175
|
-
/**
|
|
13176
|
-
* Validate CSS variable name format
|
|
13177
|
-
*/ function isValidCSSVariableName(name) {
|
|
13178
|
-
return /^--[a-z0-9-]+$/.test(name);
|
|
13179
|
-
}
|
|
13180
|
-
|
|
13181
|
-
/**
|
|
13182
|
-
* Extract component name from CSS variable name
|
|
13183
|
-
*
|
|
13184
|
-
* @example
|
|
13185
|
-
* extractComponentName('--atomix-button-bg')
|
|
13186
|
-
* // Returns: 'button'
|
|
13187
|
-
*/ function extractComponentName(varName, prefix = "atomix") {
|
|
13188
|
-
const regex = new RegExp(`^--${prefix}-([a-z0-9]+)-`), match = varName.match(regex);
|
|
13189
|
-
return match ? match[1] ?? null : null;
|
|
13190
|
-
}
|
|
13191
|
-
|
|
13192
|
-
/**
|
|
13193
|
-
* Component Utilities
|
|
13194
|
-
*
|
|
13195
|
-
* Helper functions for component development with the new customization system
|
|
13196
|
-
*/
|
|
13197
|
-
/**
|
|
13198
|
-
* Merge multiple class names
|
|
13199
|
-
*/ function mergeClassNames(...classes) {
|
|
13200
|
-
return classes.filter(Boolean).join(" ");
|
|
13096
|
+
* Navbar state and functionality
|
|
13097
|
+
* @param initialProps - Initial navbar properties
|
|
13098
|
+
* @returns Navbar state and methods
|
|
13099
|
+
*/ function useNavbar(initialProps) {
|
|
13100
|
+
// Default navbar properties
|
|
13101
|
+
const defaultProps = {
|
|
13102
|
+
position: "static",
|
|
13103
|
+
collapsible: !0,
|
|
13104
|
+
backdrop: !1,
|
|
13105
|
+
closeOnOutsideClick: !0,
|
|
13106
|
+
closeOnEscape: !0,
|
|
13107
|
+
"aria-label": "Main navigation",
|
|
13108
|
+
...initialProps
|
|
13109
|
+
}, [isExpanded, setIsExpanded] = React.useState(defaultProps.expanded || !1);
|
|
13110
|
+
// Local expanded state for when not controlled externally
|
|
13111
|
+
return {
|
|
13112
|
+
defaultProps: defaultProps,
|
|
13113
|
+
isExpanded: isExpanded,
|
|
13114
|
+
setIsExpanded: setIsExpanded,
|
|
13115
|
+
generateNavbarClass: props => {
|
|
13116
|
+
const {position: position = defaultProps.position, variant: variant, collapsible: collapsible = defaultProps.collapsible, className: className = ""} = props;
|
|
13117
|
+
return `c-navbar ${"static" !== position ? `c-navbar--${position}` : ""} ${variant ? `c-navbar--${variant}` : ""} ${collapsible ? "c-navbar--collapsible" : ""} ${className}`.trim();
|
|
13118
|
+
},
|
|
13119
|
+
generateContainerStyle: width => width ? {
|
|
13120
|
+
maxWidth: width
|
|
13121
|
+
} : {},
|
|
13122
|
+
generateCollapseClass: expanded => ("c-navbar__collapse " + (expanded ? "is-expanded" : "")).trim(),
|
|
13123
|
+
toggleExpanded: () => {
|
|
13124
|
+
const newState = !isExpanded;
|
|
13125
|
+
setIsExpanded(newState), defaultProps.onToggle && defaultProps.onToggle(newState);
|
|
13126
|
+
},
|
|
13127
|
+
getExpandedState: controlled => void 0 !== controlled ? controlled : isExpanded
|
|
13128
|
+
};
|
|
13201
13129
|
}
|
|
13202
13130
|
|
|
13203
13131
|
/**
|
|
13204
|
-
*
|
|
13205
|
-
|
|
13206
|
-
|
|
13207
|
-
|
|
13208
|
-
|
|
13209
|
-
|
|
13210
|
-
|
|
13211
|
-
|
|
13132
|
+
* Nav state and functionality
|
|
13133
|
+
* @param initialProps - Initial nav properties
|
|
13134
|
+
* @returns Nav state and methods
|
|
13135
|
+
*/ function useNav(initialProps) {
|
|
13136
|
+
// Default nav properties
|
|
13137
|
+
const defaultProps = {
|
|
13138
|
+
alignment: "start",
|
|
13139
|
+
variant: "default",
|
|
13140
|
+
...initialProps
|
|
13141
|
+
};
|
|
13142
|
+
/**
|
|
13143
|
+
* Generate nav class based on properties
|
|
13144
|
+
* @param props - Nav properties
|
|
13145
|
+
* @returns Class string
|
|
13146
|
+
*/ return {
|
|
13147
|
+
defaultProps: defaultProps,
|
|
13148
|
+
generateNavClass: props => {
|
|
13149
|
+
const {alignment: alignment = defaultProps.alignment, variant: variant = defaultProps.variant, className: className = ""} = props;
|
|
13150
|
+
return `c-nav ${"start" !== alignment ? `c-nav--${alignment}` : ""} ${"default" !== variant ? `c-nav--${variant}` : ""} ${className}`.trim();
|
|
13212
13151
|
}
|
|
13213
|
-
}
|
|
13152
|
+
};
|
|
13214
13153
|
}
|
|
13215
13154
|
|
|
13216
13155
|
/**
|
|
13217
|
-
*
|
|
13218
|
-
|
|
13219
|
-
|
|
13220
|
-
|
|
13221
|
-
|
|
13222
|
-
|
|
13223
|
-
|
|
13224
|
-
|
|
13225
|
-
|
|
13226
|
-
|
|
13227
|
-
|
|
13228
|
-
|
|
13229
|
-
|
|
13230
|
-
|
|
13231
|
-
|
|
13232
|
-
|
|
13233
|
-
|
|
13234
|
-
|
|
13156
|
+
* Nav item state and functionality
|
|
13157
|
+
* @param initialProps - Initial nav item properties
|
|
13158
|
+
* @returns Nav item state and methods
|
|
13159
|
+
*/ function useNavItem(initialProps) {
|
|
13160
|
+
// Default nav item properties
|
|
13161
|
+
const defaultProps = {
|
|
13162
|
+
dropdown: !1,
|
|
13163
|
+
megaMenu: !1,
|
|
13164
|
+
active: !1,
|
|
13165
|
+
...initialProps
|
|
13166
|
+
};
|
|
13167
|
+
/**
|
|
13168
|
+
* Generate nav item class based on properties
|
|
13169
|
+
* @param props - Nav item properties
|
|
13170
|
+
* @returns Class string
|
|
13171
|
+
*/ return {
|
|
13172
|
+
defaultProps: defaultProps,
|
|
13173
|
+
generateNavItemClass: props => {
|
|
13174
|
+
const {dropdown: dropdown = defaultProps.dropdown, megaMenu: megaMenu = defaultProps.megaMenu, active: active = defaultProps.active, disabled: disabled = defaultProps.disabled, className: className = ""} = props;
|
|
13175
|
+
// Apply dropdown class only for regular dropdowns, not mega menus
|
|
13176
|
+
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();
|
|
13177
|
+
},
|
|
13178
|
+
generateNavLinkClass: (active = !1, disabled = !1, className = "") => `c-nav__link ${active ? NAV.CLASSES.ACTIVE : ""} ${disabled ? "c-nav__link--disabled" : ""} ${className}`.trim(),
|
|
13179
|
+
handleClick: handler => e => {
|
|
13180
|
+
!defaultProps.disabled && handler ? handler() : e.preventDefault();
|
|
13235
13181
|
}
|
|
13236
13182
|
};
|
|
13237
13183
|
}
|
|
13238
13184
|
|
|
13239
13185
|
/**
|
|
13240
|
-
*
|
|
13241
|
-
|
|
13242
|
-
|
|
13186
|
+
* Nav dropdown state and functionality
|
|
13187
|
+
* @param initialProps - Initial dropdown properties
|
|
13188
|
+
* @returns Dropdown state and methods
|
|
13189
|
+
*/ function useNavDropdown(initialProps) {
|
|
13190
|
+
// Default dropdown properties
|
|
13191
|
+
const defaultProps = {
|
|
13192
|
+
alignment: "start",
|
|
13193
|
+
megaMenu: !1,
|
|
13194
|
+
...initialProps
|
|
13195
|
+
}, isInFixedBottomNavbar = () => null !== document.querySelector(".c-navbar--fixed-bottom");
|
|
13196
|
+
/**
|
|
13197
|
+
* Generate dropdown menu class based on properties
|
|
13198
|
+
* @param props - Dropdown properties
|
|
13199
|
+
* @returns Class string
|
|
13200
|
+
*/ return {
|
|
13201
|
+
defaultProps: defaultProps,
|
|
13202
|
+
generateDropdownMenuClass: props => {
|
|
13203
|
+
const {alignment: alignment = defaultProps.alignment, megaMenu: megaMenu = defaultProps.megaMenu, className: className = ""} = props, baseClass = megaMenu ? NAV.SELECTORS.MEGA_MENU.replace(".", "") : NAV.SELECTORS.DROPDOWN_MENU.replace(".", "");
|
|
13204
|
+
// Select the base class based on mega menu or regular dropdown
|
|
13205
|
+
// Add alignment class if not default 'start'
|
|
13206
|
+
let alignmentClass = "";
|
|
13207
|
+
return "center" === alignment ? alignmentClass = `${baseClass}--center` : "end" === alignment && (alignmentClass = `${baseClass}--end`),
|
|
13208
|
+
`${baseClass} ${alignmentClass} ${className}`.trim();
|
|
13209
|
+
},
|
|
13210
|
+
isInFixedBottomNavbar: isInFixedBottomNavbar,
|
|
13211
|
+
getIconName: (isMegaMenu = !1) => isInFixedBottomNavbar() ? "CaretUp" : "CaretDown"
|
|
13212
|
+
};
|
|
13243
13213
|
}
|
|
13244
13214
|
|
|
13245
13215
|
/**
|
|
13246
|
-
*
|
|
13247
|
-
|
|
13248
|
-
|
|
13249
|
-
|
|
13250
|
-
|
|
13251
|
-
|
|
13252
|
-
|
|
13253
|
-
|
|
13216
|
+
* SideMenu state and functionality
|
|
13217
|
+
* @param initialProps - Initial side menu properties
|
|
13218
|
+
* @returns SideMenu state and methods
|
|
13219
|
+
*/ function useSideMenu(initialProps) {
|
|
13220
|
+
const {collapsible: collapsible = !0, collapsibleDesktop: collapsibleDesktop = !1, defaultCollapsedDesktop: defaultCollapsedDesktop = !1, isOpen: isOpen, onToggle: onToggle, disabled: disabled = !1} = initialProps || {}, [isOpenState, setIsOpenState] = React.useState(void 0 !== defaultCollapsedDesktop ? !defaultCollapsedDesktop : isOpen || !1), wrapperRef = React.useRef(null), innerRef = React.useRef(null), sideMenuRef = React.useRef(null);
|
|
13221
|
+
// Local open state for when not controlled externally
|
|
13222
|
+
// Update local state when external state changes
|
|
13223
|
+
React.useEffect((() => {
|
|
13224
|
+
void 0 !== isOpen ? setIsOpenState(isOpen) : void 0 !== defaultCollapsedDesktop && setIsOpenState(!defaultCollapsedDesktop);
|
|
13225
|
+
}), [ isOpen, defaultCollapsedDesktop ]),
|
|
13226
|
+
// Set initial height on mount
|
|
13227
|
+
React.useEffect((() => {
|
|
13228
|
+
const shouldCollapse = window.innerWidth < 768 ? collapsible : collapsibleDesktop, currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
|
|
13229
|
+
if (shouldCollapse && wrapperRef.current && innerRef.current) {
|
|
13230
|
+
// Use setTimeout to ensure DOM is fully rendered
|
|
13231
|
+
const timeoutId = setTimeout((() => {
|
|
13232
|
+
wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
|
|
13233
|
+
}), 0);
|
|
13234
|
+
return () => clearTimeout(timeoutId);
|
|
13254
13235
|
}
|
|
13236
|
+
!shouldCollapse && wrapperRef.current && (wrapperRef.current.style.height = "auto");
|
|
13237
|
+
}), [ collapsible, collapsibleDesktop, isOpen, isOpenState ]),
|
|
13238
|
+
// Handle responsive behavior - vertical collapse for both mobile and desktop
|
|
13239
|
+
React.useEffect((() => {
|
|
13240
|
+
const handleResize = () => {
|
|
13241
|
+
if (window.innerWidth < 768 ? collapsible : collapsibleDesktop) {
|
|
13242
|
+
if (wrapperRef.current && innerRef.current) {
|
|
13243
|
+
// Set proper height for vertical animation (both mobile and desktop)
|
|
13244
|
+
const currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
|
|
13245
|
+
// Use requestAnimationFrame to ensure DOM is ready
|
|
13246
|
+
requestAnimationFrame((() => {
|
|
13247
|
+
wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
|
|
13248
|
+
}));
|
|
13249
|
+
}
|
|
13250
|
+
} else
|
|
13251
|
+
// Not collapsible - always show content
|
|
13252
|
+
wrapperRef.current && (wrapperRef.current.style.height = "auto");
|
|
13253
|
+
}, timeoutId = setTimeout(handleResize, 0);
|
|
13254
|
+
// Initial call with a small delay to ensure DOM is ready
|
|
13255
|
+
return window.addEventListener("resize", handleResize), () => {
|
|
13256
|
+
clearTimeout(timeoutId), window.removeEventListener("resize", handleResize);
|
|
13257
|
+
};
|
|
13258
|
+
}), [ collapsible, collapsibleDesktop, isOpen, onToggle, isOpenState ]),
|
|
13259
|
+
// Update wrapper height when open state changes (both mobile and desktop)
|
|
13260
|
+
React.useEffect((() => {
|
|
13261
|
+
const shouldCollapse = window.innerWidth < 768 ? collapsible : collapsibleDesktop;
|
|
13262
|
+
if (shouldCollapse && wrapperRef.current && innerRef.current) {
|
|
13263
|
+
const currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
|
|
13264
|
+
// Use requestAnimationFrame to ensure DOM is ready
|
|
13265
|
+
requestAnimationFrame((() => {
|
|
13266
|
+
wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
|
|
13267
|
+
}));
|
|
13268
|
+
} else !shouldCollapse && wrapperRef.current && (
|
|
13269
|
+
// Not collapsible - always show content
|
|
13270
|
+
wrapperRef.current.style.height = "auto");
|
|
13271
|
+
}), [ isOpen, isOpenState, collapsible, collapsibleDesktop ]);
|
|
13272
|
+
/**
|
|
13273
|
+
* Generate side menu class based on properties
|
|
13274
|
+
* @param props - Side menu properties
|
|
13275
|
+
* @returns Class string
|
|
13276
|
+
*/
|
|
13277
|
+
const handleToggle = () => {
|
|
13278
|
+
if (disabled) return;
|
|
13279
|
+
const newState = void 0 !== isOpen ? !isOpen : !isOpenState;
|
|
13280
|
+
"function" == typeof onToggle ?
|
|
13281
|
+
// Controlled component
|
|
13282
|
+
onToggle(newState) :
|
|
13283
|
+
// Uncontrolled component
|
|
13284
|
+
setIsOpenState(newState);
|
|
13285
|
+
}, getCurrentOpenState = () => void 0 !== isOpen ? isOpen : isOpenState;
|
|
13286
|
+
/**
|
|
13287
|
+
* Generate wrapper class
|
|
13288
|
+
* @returns Class string
|
|
13289
|
+
*/ return {
|
|
13290
|
+
isOpenState: getCurrentOpenState(),
|
|
13291
|
+
wrapperRef: wrapperRef,
|
|
13292
|
+
innerRef: innerRef,
|
|
13293
|
+
sideMenuRef: sideMenuRef,
|
|
13294
|
+
generateSideMenuClass: props => {
|
|
13295
|
+
const {className: className = "", isOpen: isOpen = !1} = props, openClass = isOpen ? SIDE_MENU.CLASSES.IS_OPEN : "";
|
|
13296
|
+
return `${SIDE_MENU.CLASSES.BASE} ${openClass} ${className}`.trim();
|
|
13297
|
+
},
|
|
13298
|
+
generateWrapperClass: () => SIDE_MENU.CLASSES.WRAPPER,
|
|
13299
|
+
handleToggle: handleToggle,
|
|
13300
|
+
handleDesktopCollapse: () => {
|
|
13301
|
+
handleToggle();
|
|
13302
|
+
},
|
|
13303
|
+
getCurrentOpenState: getCurrentOpenState
|
|
13255
13304
|
};
|
|
13256
13305
|
}
|
|
13257
13306
|
|
|
13258
13307
|
/**
|
|
13259
|
-
*
|
|
13260
|
-
|
|
13261
|
-
|
|
13262
|
-
|
|
13263
|
-
|
|
13264
|
-
|
|
13265
|
-
|
|
13266
|
-
|
|
13267
|
-
|
|
13268
|
-
|
|
13269
|
-
|
|
13270
|
-
|
|
13308
|
+
* SideMenuItem state and functionality
|
|
13309
|
+
* @param initialProps - Initial side menu item properties
|
|
13310
|
+
* @returns SideMenuItem state and methods
|
|
13311
|
+
*/ function useSideMenuItem(initialProps) {
|
|
13312
|
+
// Default side menu item properties
|
|
13313
|
+
const defaultProps = {
|
|
13314
|
+
active: !1,
|
|
13315
|
+
disabled: !1,
|
|
13316
|
+
...initialProps
|
|
13317
|
+
};
|
|
13318
|
+
/**
|
|
13319
|
+
* Generate side menu item class based on properties
|
|
13320
|
+
* @returns Class string
|
|
13321
|
+
*/ return {
|
|
13322
|
+
defaultProps: defaultProps,
|
|
13323
|
+
generateSideMenuItemClass: () => {
|
|
13324
|
+
const {active: active = defaultProps.active, disabled: disabled = defaultProps.disabled, className: className = ""} = defaultProps, activeClass = active ? SIDE_MENU.CLASSES.ACTIVE : "", disabledClass = disabled ? SIDE_MENU.CLASSES.DISABLED : "";
|
|
13325
|
+
return `${SIDE_MENU.CLASSES.LINK} ${activeClass} ${disabledClass} ${className}`.trim();
|
|
13326
|
+
},
|
|
13327
|
+
handleClick: handler => e => {
|
|
13328
|
+
defaultProps.disabled ? e.preventDefault() : handler && handler(e);
|
|
13271
13329
|
}
|
|
13272
13330
|
};
|
|
13273
13331
|
}
|
|
13274
13332
|
|
|
13275
|
-
/**
|
|
13276
|
-
* Generate a UUID v4
|
|
13277
|
-
*/ function generateUUID() {
|
|
13278
|
-
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c => {
|
|
13279
|
-
const r = 16 * Math.random() | 0;
|
|
13280
|
-
return ("x" === c ? r : 3 & r | 8).toString(16);
|
|
13281
|
-
}));
|
|
13282
|
-
}
|
|
13283
|
-
|
|
13284
|
-
/**
|
|
13285
|
-
* Check if a URL is a YouTube URL
|
|
13286
|
-
*/ function isYouTubeUrl(url) {
|
|
13287
|
-
return /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+/.test(url);
|
|
13288
|
-
}
|
|
13289
|
-
|
|
13290
|
-
/**
|
|
13291
|
-
* Extract YouTube video ID from URL
|
|
13292
|
-
*/ function extractYouTubeId(url) {
|
|
13293
|
-
if (!isYouTubeUrl(url)) return null;
|
|
13294
|
-
const patterns = [ /(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([^&\n?#]+)/, /youtube\.com\/.*[?&]v=([^&\n?#]+)/ ];
|
|
13295
|
-
for (const pattern of patterns) {
|
|
13296
|
-
const match = url.match(pattern);
|
|
13297
|
-
if (match && match[1]) return match[1];
|
|
13298
|
-
}
|
|
13299
|
-
return null;
|
|
13300
|
-
}
|
|
13301
|
-
|
|
13302
13333
|
/**
|
|
13303
13334
|
* Font Preloading Utilities
|
|
13304
13335
|
*
|
|
@@ -13664,48 +13695,11 @@ var composablesImport = Object.freeze({
|
|
|
13664
13695
|
DeviceDetector: DeviceDetector,
|
|
13665
13696
|
MOBILE_OPTIMIZED_BREAKPOINTS: MOBILE_OPTIMIZED_BREAKPOINTS,
|
|
13666
13697
|
PERFORMANCE_PRESET: PERFORMANCE_PRESET,
|
|
13667
|
-
PerformanceOverlay: function({metrics: metrics}) {
|
|
13668
|
-
return null;
|
|
13669
|
-
// Performance overlay removed - will be implemented as separate component
|
|
13670
|
-
}
|
|
13671
|
-
/**
|
|
13672
|
-
* Utility to get quality multipliers for glass parameters
|
|
13673
|
-
*/ ,
|
|
13674
13698
|
QUALITY_PRESET: QUALITY_PRESET,
|
|
13675
13699
|
createBreakpoints: createBreakpoints$1,
|
|
13676
13700
|
getDefaultBreakpoints: getDefaultBreakpoints,
|
|
13677
13701
|
getDevicePreset: getDevicePreset,
|
|
13678
13702
|
getMobileOptimizedParams: getMobileOptimizedParams,
|
|
13679
|
-
getQualityMultipliers: function(quality) {
|
|
13680
|
-
switch (quality) {
|
|
13681
|
-
case "low":
|
|
13682
|
-
return {
|
|
13683
|
-
distortionOctaves: 2,
|
|
13684
|
-
displacementScale: .6,
|
|
13685
|
-
blurAmount: .7,
|
|
13686
|
-
animationSpeed: .8,
|
|
13687
|
-
chromaticIntensity: .5
|
|
13688
|
-
};
|
|
13689
|
-
|
|
13690
|
-
case "medium":
|
|
13691
|
-
return {
|
|
13692
|
-
distortionOctaves: 4,
|
|
13693
|
-
displacementScale: .85,
|
|
13694
|
-
blurAmount: .9,
|
|
13695
|
-
animationSpeed: .95,
|
|
13696
|
-
chromaticIntensity: .75
|
|
13697
|
-
};
|
|
13698
|
-
|
|
13699
|
-
case "high":
|
|
13700
|
-
return {
|
|
13701
|
-
distortionOctaves: 5,
|
|
13702
|
-
displacementScale: 1,
|
|
13703
|
-
blurAmount: 1,
|
|
13704
|
-
animationSpeed: 1,
|
|
13705
|
-
chromaticIntensity: 1
|
|
13706
|
-
};
|
|
13707
|
-
}
|
|
13708
|
-
},
|
|
13709
13703
|
useAccordion: useAccordion,
|
|
13710
13704
|
useAtomixGlass: useAtomixGlass,
|
|
13711
13705
|
useBadge: useBadge,
|
|
@@ -14008,12 +14002,7 @@ const SelectComponentBase = ({options: options, value: value, onChange: onChange
|
|
|
14008
14002
|
});
|
|
14009
14003
|
// Handle item selection
|
|
14010
14004
|
if (glass) {
|
|
14011
|
-
|
|
14012
|
-
const defaultGlassProps = {
|
|
14013
|
-
displacementScale: 60,
|
|
14014
|
-
blurAmount: 10,
|
|
14015
|
-
mode: "shader"
|
|
14016
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
14005
|
+
const defaultGlassProps = GLASS_DEFAULTS.SELECT, glassProps = !0 === glass ? defaultGlassProps : {
|
|
14017
14006
|
...defaultGlassProps,
|
|
14018
14007
|
...glass
|
|
14019
14008
|
};
|
|
@@ -14063,15 +14052,7 @@ const Radio = React.memo((({label: label, checked: checked = !1, onChange: onCh
|
|
|
14063
14052
|
}) ]
|
|
14064
14053
|
});
|
|
14065
14054
|
if (glass) {
|
|
14066
|
-
|
|
14067
|
-
const defaultGlassProps = {
|
|
14068
|
-
displacementScale: 40,
|
|
14069
|
-
blurAmount: 1,
|
|
14070
|
-
saturation: 160,
|
|
14071
|
-
aberrationIntensity: .3,
|
|
14072
|
-
borderRadius: 6,
|
|
14073
|
-
mode: "shader"
|
|
14074
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
14055
|
+
const defaultGlassProps = GLASS_DEFAULTS.RADIO, glassProps = !0 === glass ? defaultGlassProps : {
|
|
14075
14056
|
...defaultGlassProps,
|
|
14076
14057
|
...glass
|
|
14077
14058
|
};
|
|
@@ -14129,15 +14110,7 @@ const Textarea = React.memo( React.forwardRef((({value: value, defaultValue: de
|
|
|
14129
14110
|
} : style
|
|
14130
14111
|
});
|
|
14131
14112
|
if (glass) {
|
|
14132
|
-
|
|
14133
|
-
const defaultGlassProps = {
|
|
14134
|
-
displacementScale: 60,
|
|
14135
|
-
blurAmount: 1,
|
|
14136
|
-
saturation: 180,
|
|
14137
|
-
aberrationIntensity: 1,
|
|
14138
|
-
borderRadius: 8,
|
|
14139
|
-
mode: "shader"
|
|
14140
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
14113
|
+
const defaultGlassProps = GLASS_DEFAULTS.TEXTAREA, glassProps = !0 === glass ? defaultGlassProps : {
|
|
14141
14114
|
...defaultGlassProps,
|
|
14142
14115
|
...glass
|
|
14143
14116
|
};
|
|
@@ -15260,12 +15233,7 @@ const Messages = ({messages: messages = [], otherAvatar: otherAvatar, selfAvatar
|
|
|
15260
15233
|
};
|
|
15261
15234
|
})({
|
|
15262
15235
|
onSendMessage: onSendMessage
|
|
15263
|
-
}), messagesId = id || `messages-${Math.random().toString(36).substr(2, 9)}`, inputId = `${messagesId}-input`, defaultGlassProps = {
|
|
15264
|
-
displacementScale: 150,
|
|
15265
|
-
borderRadius: 12,
|
|
15266
|
-
elasticity: 0,
|
|
15267
|
-
aberrationIntensity: 2
|
|
15268
|
-
}, messagesClasses = `${MESSAGES.CLASSES.BASE} ${glass ? "c-messages--glass" : ""} ${disabled ? "is-disabled" : ""} ${className}`, messagesContent = jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
15236
|
+
}), 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 = jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
15269
15237
|
children: [ jsxRuntime.jsx("div", {
|
|
15270
15238
|
className: MESSAGES.CLASSES.BODY,
|
|
15271
15239
|
style: bodyHeight ? {
|
|
@@ -15625,12 +15593,11 @@ const ModalImpl = React.memo((({children: children, isOpen: isOpen = !1, onOpen
|
|
|
15625
15593
|
children: glass ?
|
|
15626
15594
|
// Default glass settings for modals
|
|
15627
15595
|
(() => {
|
|
15596
|
+
// Default glass settings for modals
|
|
15628
15597
|
const defaultGlassProps = {
|
|
15629
|
-
|
|
15630
|
-
|
|
15631
|
-
|
|
15632
|
-
mode: "shader",
|
|
15633
|
-
shaderMode: "premiumGlass"
|
|
15598
|
+
...GLASS_DEFAULTS.MODAL,
|
|
15599
|
+
// displacementScale driven by modal content height at runtime
|
|
15600
|
+
displacementScale: document.querySelector(".c-modal---glass .c-modal__content")?.clientHeight
|
|
15634
15601
|
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
15635
15602
|
...defaultGlassProps,
|
|
15636
15603
|
...glass
|
|
@@ -15678,12 +15645,7 @@ const Modal = ModalWithSubcomponents, Nav = React.forwardRef((({children: child
|
|
|
15678
15645
|
}))
|
|
15679
15646
|
});
|
|
15680
15647
|
if (glass) {
|
|
15681
|
-
const defaultGlassProps = {
|
|
15682
|
-
displacementScale: 60,
|
|
15683
|
-
blurAmount: 1.5,
|
|
15684
|
-
borderRadius: 8,
|
|
15685
|
-
mode: "shader"
|
|
15686
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
15648
|
+
const defaultGlassProps = GLASS_DEFAULTS.NAV, glassProps = !0 === glass ? defaultGlassProps : {
|
|
15687
15649
|
...defaultGlassProps,
|
|
15688
15650
|
...glass
|
|
15689
15651
|
};
|
|
@@ -15709,24 +15671,7 @@ const Modal = ModalWithSubcomponents, Nav = React.forwardRef((({children: child
|
|
|
15709
15671
|
* </NavDropdown>
|
|
15710
15672
|
* </Nav>
|
|
15711
15673
|
* ```
|
|
15712
|
-
*/
|
|
15713
|
-
/**
|
|
15714
|
-
* Utility to merge multiple React refs into one
|
|
15715
|
-
*/
|
|
15716
|
-
function setRef(ref, value) {
|
|
15717
|
-
"function" == typeof ref ? ref(value) : ref && (
|
|
15718
|
-
// This is safe because we're checking that ref exists first
|
|
15719
|
-
ref.current = value);
|
|
15720
|
-
}
|
|
15721
|
-
|
|
15722
|
-
/**
|
|
15723
|
-
* Combines two React refs into a single ref function
|
|
15724
|
-
* This is used when you need to use and forward a ref at the same time
|
|
15725
|
-
*/ function useForkRef(refA, refB) {
|
|
15726
|
-
return React__default.default.useMemo((() => null == refA && null == refB ? null : refValue => {
|
|
15727
|
-
setRef(refA, refValue), setRef(refB, refValue);
|
|
15728
|
-
}), [ refA, refB ]);
|
|
15729
|
-
}
|
|
15674
|
+
*/ Nav.displayName = "Nav";
|
|
15730
15675
|
|
|
15731
15676
|
/**
|
|
15732
15677
|
* NavItem component represents a single navigation item that can be a link, dropdown trigger, or mega menu trigger.
|
|
@@ -15755,8 +15700,7 @@ function setRef(ref, value) {
|
|
|
15755
15700
|
* </MegaMenu>
|
|
15756
15701
|
* </NavItem>
|
|
15757
15702
|
* ```
|
|
15758
|
-
*/
|
|
15759
|
-
|
|
15703
|
+
*/
|
|
15760
15704
|
const NavItem = React.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) => {
|
|
15761
15705
|
const {generateNavItemClass: generateNavItemClass, generateNavLinkClass: generateNavLinkClass, handleClick: handleClick} = useNavItem({
|
|
15762
15706
|
dropdown: dropdown,
|
|
@@ -15929,14 +15873,7 @@ const Navbar = React.forwardRef((({brand: brand, children: children, variant: v
|
|
|
15929
15873
|
});
|
|
15930
15874
|
// Generate the container style
|
|
15931
15875
|
if (glass) {
|
|
15932
|
-
const defaultGlassProps = {
|
|
15933
|
-
displacementScale: 30,
|
|
15934
|
-
blurAmount: 2,
|
|
15935
|
-
borderRadius: 0,
|
|
15936
|
-
elasticity: 0,
|
|
15937
|
-
mode: "shader",
|
|
15938
|
-
shaderVariant: "premiumGlass"
|
|
15939
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
15876
|
+
const defaultGlassProps = GLASS_DEFAULTS.NAVBAR, glassProps = !0 === glass ? defaultGlassProps : {
|
|
15940
15877
|
...defaultGlassProps,
|
|
15941
15878
|
...glass
|
|
15942
15879
|
}, isFixed = "fixed" === position || "fixed-bottom" === position;
|
|
@@ -16294,12 +16231,7 @@ const SideMenu = React.forwardRef((({title: title, children: children, menuItem
|
|
|
16294
16231
|
}) ]
|
|
16295
16232
|
});
|
|
16296
16233
|
if (glass) {
|
|
16297
|
-
const defaultGlassProps = {
|
|
16298
|
-
displacementScale: 70,
|
|
16299
|
-
blurAmount: 2,
|
|
16300
|
-
borderRadius: 12,
|
|
16301
|
-
mode: "shader"
|
|
16302
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
16234
|
+
const defaultGlassProps = GLASS_DEFAULTS.SIDE_MENU, glassProps = !0 === glass ? defaultGlassProps : {
|
|
16303
16235
|
...defaultGlassProps,
|
|
16304
16236
|
...glass
|
|
16305
16237
|
};
|
|
@@ -17896,14 +17828,7 @@ const PopoverContext = React.createContext({
|
|
|
17896
17828
|
children: [ glass ?
|
|
17897
17829
|
// Default glass settings for popovers
|
|
17898
17830
|
(() => {
|
|
17899
|
-
const defaultGlassProps = {
|
|
17900
|
-
displacementScale: 50,
|
|
17901
|
-
blurAmount: 1,
|
|
17902
|
-
saturation: 160,
|
|
17903
|
-
aberrationIntensity: .5,
|
|
17904
|
-
borderRadius: 8,
|
|
17905
|
-
mode: "shader"
|
|
17906
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
17831
|
+
const defaultGlassProps = GLASS_DEFAULTS.POPOVER, glassProps = !0 === glass ? defaultGlassProps : {
|
|
17907
17832
|
...defaultGlassProps,
|
|
17908
17833
|
...glass
|
|
17909
17834
|
};
|
|
@@ -18128,15 +18053,7 @@ const calculateStarValue = (e, starValue, allowHalf) => {
|
|
|
18128
18053
|
});
|
|
18129
18054
|
// Generate stars
|
|
18130
18055
|
if (glass) {
|
|
18131
|
-
|
|
18132
|
-
const defaultGlassProps = {
|
|
18133
|
-
displacementScale: 60,
|
|
18134
|
-
blurAmount: 1,
|
|
18135
|
-
saturation: 160,
|
|
18136
|
-
aberrationIntensity: .5,
|
|
18137
|
-
borderRadius: 8,
|
|
18138
|
-
mode: "shader"
|
|
18139
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
18056
|
+
const defaultGlassProps = GLASS_DEFAULTS.RATING, glassProps = !0 === glass ? defaultGlassProps : {
|
|
18140
18057
|
...defaultGlassProps,
|
|
18141
18058
|
...glass
|
|
18142
18059
|
};
|
|
@@ -18292,12 +18209,7 @@ const Progress = React.memo( React.forwardRef((({value: value, variant: variant
|
|
|
18292
18209
|
})
|
|
18293
18210
|
});
|
|
18294
18211
|
if (glass) {
|
|
18295
|
-
const defaultGlassProps = {
|
|
18296
|
-
displacementScale: 30,
|
|
18297
|
-
blurAmount: .5,
|
|
18298
|
-
borderRadius: 8,
|
|
18299
|
-
mode: "shader"
|
|
18300
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
18212
|
+
const defaultGlassProps = GLASS_DEFAULTS.PROGRESS, glassProps = !0 === glass ? defaultGlassProps : {
|
|
18301
18213
|
...defaultGlassProps,
|
|
18302
18214
|
...glass
|
|
18303
18215
|
};
|
|
@@ -18946,15 +18858,7 @@ const Steps = ({items: items, activeIndex: activeIndex = 0, vertical: vertical =
|
|
|
18946
18858
|
children: content
|
|
18947
18859
|
});
|
|
18948
18860
|
if (glass) {
|
|
18949
|
-
|
|
18950
|
-
const defaultGlassProps = {
|
|
18951
|
-
displacementScale: 60,
|
|
18952
|
-
blurAmount: 1,
|
|
18953
|
-
saturation: 160,
|
|
18954
|
-
aberrationIntensity: .5,
|
|
18955
|
-
borderRadius: 8,
|
|
18956
|
-
mode: "shader"
|
|
18957
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
18861
|
+
const defaultGlassProps = GLASS_DEFAULTS.STEPS, glassProps = !0 === glass ? defaultGlassProps : {
|
|
18958
18862
|
...defaultGlassProps,
|
|
18959
18863
|
...glass
|
|
18960
18864
|
};
|
|
@@ -19158,14 +19062,7 @@ const TabsComponentBase = ({items: items, activeIndex: activeIndex = TAB.DEFAULT
|
|
|
19158
19062
|
});
|
|
19159
19063
|
if (glass) {
|
|
19160
19064
|
// Default glass settings for tabs
|
|
19161
|
-
const defaultGlassProps = {
|
|
19162
|
-
displacementScale: 60,
|
|
19163
|
-
blurAmount: 1,
|
|
19164
|
-
saturation: 160,
|
|
19165
|
-
aberrationIntensity: .5,
|
|
19166
|
-
borderRadius: 8,
|
|
19167
|
-
mode: "shader"
|
|
19168
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
19065
|
+
const defaultGlassProps = GLASS_DEFAULTS.TABS, glassProps = !0 === glass ? defaultGlassProps : {
|
|
19169
19066
|
...defaultGlassProps,
|
|
19170
19067
|
...glass
|
|
19171
19068
|
};
|
|
@@ -19401,15 +19298,7 @@ const Toggle = ({checked: controlledChecked, defaultChecked: defaultChecked = !1
|
|
|
19401
19298
|
})
|
|
19402
19299
|
});
|
|
19403
19300
|
if (glass) {
|
|
19404
|
-
|
|
19405
|
-
const defaultGlassProps = {
|
|
19406
|
-
displacementScale: 60,
|
|
19407
|
-
blurAmount: 1,
|
|
19408
|
-
saturation: 160,
|
|
19409
|
-
aberrationIntensity: .5,
|
|
19410
|
-
borderRadius: 8,
|
|
19411
|
-
mode: "shader"
|
|
19412
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
19301
|
+
const defaultGlassProps = GLASS_DEFAULTS.TOGGLE, glassProps = !0 === glass ? defaultGlassProps : {
|
|
19413
19302
|
...defaultGlassProps,
|
|
19414
19303
|
...glass
|
|
19415
19304
|
};
|
|
@@ -19597,10 +19486,7 @@ const Tooltip = React.memo((({content: content, children: children, position: p
|
|
|
19597
19486
|
}), content ]
|
|
19598
19487
|
});
|
|
19599
19488
|
if (glass) {
|
|
19600
|
-
const defaultGlassProps = {
|
|
19601
|
-
displacementScale: 100,
|
|
19602
|
-
blurAmount: 3
|
|
19603
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
19489
|
+
const defaultGlassProps = GLASS_DEFAULTS.TOOLTIP, glassProps = !0 === glass ? defaultGlassProps : {
|
|
19604
19490
|
...defaultGlassProps,
|
|
19605
19491
|
...glass
|
|
19606
19492
|
};
|
|
@@ -20776,6 +20662,8 @@ var components = Object.freeze({
|
|
|
20776
20662
|
FOOTER: FOOTER,
|
|
20777
20663
|
FORM: FORM,
|
|
20778
20664
|
FORM_GROUP: FORM_GROUP,
|
|
20665
|
+
GLASS_BORDER_GRADIENT: GLASS_BORDER_GRADIENT,
|
|
20666
|
+
GLASS_DEFAULTS: GLASS_DEFAULTS,
|
|
20779
20667
|
HERO: HERO,
|
|
20780
20668
|
INPUT: INPUT,
|
|
20781
20669
|
LIST: LIST,
|
|
@@ -28340,6 +28228,7 @@ exports.EDGE_PANEL = EDGE_PANEL, exports.EdgePanel = EdgePanel, exports.Elevatio
|
|
|
28340
28228
|
exports.FOOTER = FOOTER, exports.FORM = FORM, exports.FORM_GROUP = FORM_GROUP, exports.Footer = Footer,
|
|
28341
28229
|
exports.FooterLink = FooterLink, exports.FooterSection = FooterSection, exports.FooterSocialLink = FooterSocialLink,
|
|
28342
28230
|
exports.Form = Form, exports.FormGroup = FormGroup, exports.FunnelChart = FunnelChart,
|
|
28231
|
+
exports.GLASS_BORDER_GRADIENT = GLASS_BORDER_GRADIENT, exports.GLASS_DEFAULTS = GLASS_DEFAULTS,
|
|
28343
28232
|
exports.GaugeChart = GaugeChart, exports.Grid = Grid, exports.GridCol = GridCol,
|
|
28344
28233
|
exports.HERO = HERO, exports.HeatmapChart = HeatmapChart, exports.Hero = Hero, exports.INPUT = INPUT,
|
|
28345
28234
|
exports.INPUT_CSS_VARS = INPUT_CSS_VARS, exports.Icon = Icon, exports.Input = Input,
|