@shohojdhara/atomix 0.4.7 → 0.4.9
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/atomix.config.ts +58 -1
- package/dist/atomix.css +172 -157
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +4 -4
- package/dist/atomix.min.css.map +1 -1
- package/dist/charts.d.ts +33 -0
- package/dist/charts.js +1274 -164
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +33 -10
- package/dist/core.js +1099 -83
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +33 -0
- package/dist/forms.js +2106 -1050
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +42 -1
- package/dist/heavy.js +1663 -638
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +442 -270
- package/dist/index.esm.js +1947 -680
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1982 -712
- 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 +6 -3
- package/scripts/atomix-cli.js +136 -1827
- package/scripts/cli/__tests__/basic.test.js +3 -2
- package/scripts/cli/__tests__/clean.test.js +278 -0
- package/scripts/cli/__tests__/component-validator.test.js +433 -0
- package/scripts/cli/__tests__/generator.test.js +613 -0
- package/scripts/cli/__tests__/glass-motion.test.js +256 -0
- package/scripts/cli/__tests__/integration.test.js +719 -108
- package/scripts/cli/__tests__/migrate.test.js +74 -0
- package/scripts/cli/__tests__/security.test.js +206 -0
- package/scripts/cli/__tests__/test-setup.js +3 -1
- package/scripts/cli/__tests__/theme-bridge.test.js +507 -0
- package/scripts/cli/__tests__/token-provider.test.js +361 -0
- package/scripts/cli/__tests__/utils.test.js +5 -5
- package/scripts/cli/commands/benchmark.js +105 -0
- package/scripts/cli/commands/build-theme.js +115 -0
- package/scripts/cli/commands/clean.js +109 -0
- package/scripts/cli/commands/doctor.js +88 -0
- package/scripts/cli/commands/generate.js +218 -0
- package/scripts/cli/commands/init.js +73 -0
- package/scripts/cli/commands/migrate.js +106 -0
- package/scripts/cli/commands/sync-tokens.js +206 -0
- package/scripts/cli/commands/theme-bridge.js +248 -0
- package/scripts/cli/commands/tokens.js +157 -0
- package/scripts/cli/commands/validate.js +194 -0
- package/scripts/cli/internal/ai-engine.js +156 -0
- package/scripts/cli/internal/compiler.js +114 -0
- package/scripts/cli/internal/component-validator.js +443 -0
- package/scripts/cli/internal/config-loader.js +162 -0
- package/scripts/cli/internal/filesystem.js +158 -0
- package/scripts/cli/internal/generator.js +430 -0
- package/scripts/cli/internal/glass-generator.js +398 -0
- package/scripts/cli/internal/hook-generator.js +369 -0
- package/scripts/cli/internal/hooks.js +61 -0
- package/scripts/cli/internal/itcss-generator.js +565 -0
- package/scripts/cli/internal/motion-generator.js +679 -0
- package/scripts/cli/internal/template-engine.js +301 -0
- package/scripts/cli/internal/theme-bridge.js +664 -0
- package/scripts/cli/internal/tokens/engine.js +122 -0
- package/scripts/cli/internal/tokens/provider.js +34 -0
- package/scripts/cli/internal/tokens/providers/figma.js +50 -0
- package/scripts/cli/internal/tokens/providers/style-dictionary.js +48 -0
- package/scripts/cli/internal/tokens/providers/w3c.js +48 -0
- package/scripts/cli/internal/tokens/token-provider.js +443 -0
- package/scripts/cli/internal/tokens/token-validator.js +513 -0
- package/scripts/cli/internal/validator.js +276 -0
- package/scripts/cli/internal/wizard.js +115 -0
- package/scripts/cli/mappings.js +23 -0
- package/scripts/cli/migration-tools.js +164 -94
- package/scripts/cli/plugins/style-dictionary.js +46 -0
- package/scripts/cli/templates/README.md +525 -95
- package/scripts/cli/templates/common-templates.js +40 -14
- package/scripts/cli/templates/components/react-component.ts +282 -0
- package/scripts/cli/templates/config/project-config.ts +112 -0
- package/scripts/cli/templates/hooks/use-component.ts +477 -0
- package/scripts/cli/templates/index.js +19 -4
- package/scripts/cli/templates/index.ts +171 -0
- package/scripts/cli/templates/next-templates.js +72 -0
- package/scripts/cli/templates/react-templates.js +70 -126
- package/scripts/cli/templates/scss-templates.js +35 -35
- package/scripts/cli/templates/stories/storybook-story.ts +241 -0
- package/scripts/cli/templates/styles/scss-component.ts +255 -0
- package/scripts/cli/templates/tests/vitest-test.ts +229 -0
- package/scripts/cli/templates/token-templates.js +337 -1
- package/scripts/cli/templates/tokens/token-generators.ts +1088 -0
- package/scripts/cli/templates/types/component-types.ts +145 -0
- package/scripts/cli/templates/utils/testing-utils.ts +144 -0
- package/scripts/cli/templates/vanilla-templates.js +39 -0
- package/scripts/cli/token-manager.js +8 -2
- package/scripts/cli/utils/cache-manager.js +240 -0
- package/scripts/cli/utils/detector.js +46 -0
- package/scripts/cli/utils/diagnostics.js +289 -0
- package/scripts/cli/utils/error.js +89 -0
- package/scripts/cli/utils/helpers.js +67 -0
- package/scripts/cli/utils/logger.js +75 -0
- package/scripts/cli/utils/security.js +302 -0
- package/scripts/cli/utils/telemetry.js +115 -0
- package/scripts/cli/utils/validation.js +37 -0
- package/scripts/cli/utils.js +28 -341
- package/src/components/Accordion/Accordion.stories.tsx +0 -18
- package/src/components/Accordion/Accordion.test.tsx +0 -17
- package/src/components/Accordion/Accordion.tsx +0 -4
- package/src/components/AtomixGlass/AtomixGlass.test.tsx +37 -3
- package/src/components/AtomixGlass/AtomixGlass.tsx +143 -31
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +129 -31
- package/src/components/AtomixGlass/PerformanceDashboard.tsx +219 -0
- package/src/components/AtomixGlass/README.md +25 -10
- package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +216 -0
- package/src/components/AtomixGlass/animation-system.ts +578 -0
- package/src/components/AtomixGlass/shader-utils.ts +4 -1
- package/src/components/AtomixGlass/stories/Overview.stories.tsx +157 -6
- package/src/components/AtomixGlass/stories/Phase1-Animation.stories.tsx +653 -0
- package/src/components/AtomixGlass/stories/Phase1-Test.stories.tsx +95 -0
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +51 -51
- package/src/components/AtomixGlass/stories/shared-components.tsx +6 -0
- package/src/components/Avatar/Avatar.tsx +1 -1
- package/src/components/Button/Button.stories.disabled-link.tsx +10 -0
- package/src/components/Button/Button.stories.tsx +10 -0
- package/src/components/Button/Button.test.tsx +16 -11
- package/src/components/Button/Button.tsx +4 -4
- package/src/components/Card/Card.tsx +1 -1
- package/src/components/Dropdown/Dropdown.tsx +12 -12
- package/src/components/Form/Select.tsx +62 -3
- package/src/components/Modal/Modal.tsx +14 -3
- package/src/components/Navigation/Navbar/Navbar.tsx +44 -0
- package/src/components/Slider/Slider.stories.tsx +3 -3
- package/src/components/Slider/Slider.tsx +38 -0
- package/src/components/Steps/Steps.tsx +3 -3
- package/src/components/Tabs/Tabs.tsx +77 -8
- package/src/components/Testimonial/Testimonial.tsx +1 -1
- package/src/components/TypedButton/TypedButton.stories.tsx +59 -0
- package/src/components/TypedButton/TypedButton.tsx +39 -0
- package/src/components/TypedButton/index.ts +2 -0
- package/src/components/VideoPlayer/VideoPlayer.tsx +11 -4
- package/src/lib/composables/index.ts +4 -7
- package/src/lib/composables/types.ts +45 -0
- package/src/lib/composables/useAccordion.ts +0 -7
- package/src/lib/composables/useAtomixGlass.ts +148 -6
- package/src/lib/composables/useAtomixGlassStyles.ts +9 -7
- package/src/lib/composables/useChartExport.ts +3 -13
- package/src/lib/composables/useDropdown.ts +66 -0
- package/src/lib/composables/useFocusTrap.ts +80 -0
- package/src/lib/composables/usePerformanceMonitor.ts +448 -0
- package/src/lib/composables/useResponsiveGlass.presets.ts +192 -0
- package/src/lib/composables/useResponsiveGlass.ts +441 -0
- package/src/lib/composables/useTooltip.ts +16 -0
- package/src/lib/composables/useTypedButton.ts +66 -0
- package/src/lib/config/index.ts +62 -5
- package/src/lib/constants/components.ts +62 -7
- package/src/lib/theme/devtools/__tests__/useHistory.test.tsx +150 -0
- package/src/lib/theme/tokens/centralized-tokens.ts +120 -0
- package/src/lib/theme/utils/__tests__/domUtils.test.ts +101 -0
- package/src/lib/types/components.ts +37 -11
- package/src/lib/types/glass.ts +35 -0
- package/src/lib/types/index.ts +1 -0
- package/src/lib/utils/displacement-generator.ts +1 -1
- package/src/styles/01-settings/_settings.testtypecheck.scss +53 -0
- package/src/styles/01-settings/_settings.typedbutton.scss +53 -0
- package/src/styles/06-components/_components.atomix-glass.scss +17 -21
- package/src/styles/06-components/_components.edge-panel.scss +1 -5
- package/src/styles/06-components/_components.modal.scss +1 -4
- package/src/styles/06-components/_components.navbar.scss +1 -1
- package/src/styles/06-components/_components.testbutton.scss +212 -0
- package/src/styles/06-components/_components.testtypecheck.scss +212 -0
- package/src/styles/06-components/_components.tooltip.scss +9 -5
- package/src/styles/06-components/_components.typedbutton.scss +212 -0
- package/src/styles/99-utilities/_index.scss +1 -0
- package/src/styles/99-utilities/_utilities.text.scss +1 -1
- package/src/styles/99-utilities/_utilities.touch-target.scss +36 -0
- package/scripts/cli/component-generator.js +0 -564
- package/scripts/cli/interactive-init.js +0 -357
- package/src/styles/06-components/old.chart.styles.scss +0 -2788
package/dist/core.js
CHANGED
|
@@ -92,7 +92,7 @@ var match, version, createPropertyDescriptor$2 = function(bitmap, value) {
|
|
|
92
92
|
return "object" == typeof it ? null !== it : isCallable$7(it);
|
|
93
93
|
}, path$3 = {}, path$2 = path$3, globalThis$a = globalThis_1, isCallable$6 = isCallable$8, aFunction = function(variable) {
|
|
94
94
|
return isCallable$6(variable) ? variable : void 0;
|
|
95
|
-
}, navigator = globalThis_1.navigator, userAgent$1 = navigator && navigator.userAgent, globalThis$8 = globalThis_1, userAgent = userAgent$1 ? String(userAgent$1) : "", process$1 = globalThis$8.process, Deno = globalThis$8.Deno, versions = process$1 && process$1.versions || Deno && Deno.version, v8 = versions && versions.v8;
|
|
95
|
+
}, navigator$1 = globalThis_1.navigator, userAgent$1 = navigator$1 && navigator$1.userAgent, globalThis$8 = globalThis_1, userAgent = userAgent$1 ? String(userAgent$1) : "", process$1 = globalThis$8.process, Deno = globalThis$8.Deno, versions = process$1 && process$1.versions || Deno && Deno.version, v8 = versions && versions.v8;
|
|
96
96
|
|
|
97
97
|
v8 && (
|
|
98
98
|
// in old Chrome, versions of V8 isn't V8 = Chrome / 10
|
|
@@ -554,20 +554,29 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
554
554
|
SHADER: "c-atomix-glass--shader"
|
|
555
555
|
},
|
|
556
556
|
DEFAULTS: {
|
|
557
|
-
DISPLACEMENT_SCALE:
|
|
558
|
-
BLUR_AMOUNT:
|
|
557
|
+
DISPLACEMENT_SCALE: 70,
|
|
558
|
+
BLUR_AMOUNT: 0,
|
|
559
559
|
SATURATION: 140,
|
|
560
|
-
ABERRATION_INTENSITY: 2
|
|
561
|
-
ELASTICITY: .
|
|
562
|
-
CORNER_RADIUS:
|
|
560
|
+
ABERRATION_INTENSITY: 2,
|
|
561
|
+
ELASTICITY: .15,
|
|
562
|
+
CORNER_RADIUS: 20,
|
|
563
563
|
// Default border-radius matching design system
|
|
564
|
-
PADDING: "0
|
|
564
|
+
PADDING: "0",
|
|
565
565
|
MODE: "standard",
|
|
566
566
|
OVER_LIGHT: !1,
|
|
567
|
-
ENABLE_OVER_LIGHT_LAYERS: !0
|
|
567
|
+
ENABLE_OVER_LIGHT_LAYERS: !0,
|
|
568
|
+
// Phase 1: Time-Based Animation System defaults
|
|
569
|
+
WITH_TIME_ANIMATION: !0,
|
|
570
|
+
ANIMATION_SPEED: 1,
|
|
571
|
+
// Phase 1: Multi-Layer Distortion System defaults
|
|
572
|
+
WITH_MULTI_LAYER_DISTORTION: !1,
|
|
573
|
+
DISTORTION_OCTAVES: 5,
|
|
574
|
+
DISTORTION_LACUNARITY: 2,
|
|
575
|
+
DISTORTION_GAIN: .5,
|
|
576
|
+
DISTORTION_QUALITY: "high"
|
|
568
577
|
},
|
|
569
578
|
CONSTANTS: {
|
|
570
|
-
ACTIVATION_ZONE:
|
|
579
|
+
ACTIVATION_ZONE: 200,
|
|
571
580
|
LERP_FACTOR: .08,
|
|
572
581
|
SMOOTHSTEP_POWER: 2.5,
|
|
573
582
|
MIN_BLUR: .1,
|
|
@@ -727,6 +736,44 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
727
736
|
// Saturation constants
|
|
728
737
|
SATURATION: {
|
|
729
738
|
HIGH_CONTRAST: 200
|
|
739
|
+
},
|
|
740
|
+
// Phase 1: Animation System Constants
|
|
741
|
+
ANIMATION: {
|
|
742
|
+
// Breathing effect timing (in milliseconds)
|
|
743
|
+
BREATHING_CYCLE: 2e3,
|
|
744
|
+
// 2-second breathing cycle
|
|
745
|
+
// Flow animation speed
|
|
746
|
+
FLOW_SPEED_X: .1,
|
|
747
|
+
// Horizontal flow speed
|
|
748
|
+
FLOW_SPEED_Y: .15,
|
|
749
|
+
// Vertical flow speed
|
|
750
|
+
// Wave propagation
|
|
751
|
+
WAVE_SPEED: .05,
|
|
752
|
+
// Radial wave speed
|
|
753
|
+
WAVE_AMPLITUDE: .02
|
|
754
|
+
},
|
|
755
|
+
// Phase 1: Multi-Layer Distortion Quality Presets
|
|
756
|
+
DISTORTION_QUALITY_PRESETS: {
|
|
757
|
+
low: {
|
|
758
|
+
octaves: 2,
|
|
759
|
+
lacunarity: 2,
|
|
760
|
+
gain: .5
|
|
761
|
+
},
|
|
762
|
+
medium: {
|
|
763
|
+
octaves: 4,
|
|
764
|
+
lacunarity: 2,
|
|
765
|
+
gain: .5
|
|
766
|
+
},
|
|
767
|
+
high: {
|
|
768
|
+
octaves: 5,
|
|
769
|
+
lacunarity: 2,
|
|
770
|
+
gain: .5
|
|
771
|
+
},
|
|
772
|
+
ultra: {
|
|
773
|
+
octaves: 7,
|
|
774
|
+
lacunarity: 2,
|
|
775
|
+
gain: .5
|
|
776
|
+
}
|
|
730
777
|
}
|
|
731
778
|
}
|
|
732
779
|
}, {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateDistance = (pos1, pos2) => {
|
|
@@ -805,7 +852,7 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
805
852
|
// Silently handle errors
|
|
806
853
|
}
|
|
807
854
|
return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
|
|
808
|
-
}, lerp = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
|
|
855
|
+
}, lerp$1 = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
|
|
809
856
|
switch (mode) {
|
|
810
857
|
case "standard":
|
|
811
858
|
return displacementMap;
|
|
@@ -975,20 +1022,19 @@ let idCounter = 0;
|
|
|
975
1022
|
const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({children: children, className: className = "", style: style, displacementScale: displacementScale = 25, blurAmount: blurAmount = .0625, saturation: saturation = 180, aberrationIntensity: aberrationIntensity = 2, mouseOffset: mouseOffset = {
|
|
976
1023
|
x: 0,
|
|
977
1024
|
y: 0
|
|
978
|
-
},
|
|
979
|
-
x: 0,
|
|
980
|
-
y: 0
|
|
981
|
-
}, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isHovered: isHovered = !1, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0, padding: padding = "0 0", glassSize: glassSize = {
|
|
1025
|
+
}, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0, padding: padding = "0 0", glassSize: glassSize = {
|
|
982
1026
|
width: 0,
|
|
983
1027
|
height: 0
|
|
984
|
-
}, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1,
|
|
1028
|
+
}, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1,
|
|
1029
|
+
// Phase 1: Animation System props
|
|
1030
|
+
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) => {
|
|
985
1031
|
// Generate a stable, deterministic ID for SSR compatibility
|
|
986
1032
|
// Use a module-level counter that's consistent across server and client
|
|
987
|
-
const filterId = useMemo((() => "atomix-glass-filter-" + ++idCounter), []), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null);
|
|
1033
|
+
const filterId = useMemo((() => "atomix-glass-filter-" + ++idCounter), []), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null), shaderUpdateTimeoutRef = useRef(null), animationFrameRef = useRef(null);
|
|
988
1034
|
// Lazy load shader utilities only when shader mode is needed
|
|
989
1035
|
useEffect((() => {
|
|
990
1036
|
"shader" === mode ?
|
|
991
|
-
// Dynamic import shader utilities
|
|
1037
|
+
// Dynamic import shader utilities with animation support
|
|
992
1038
|
Promise.resolve().then((() => shaderUtils)).then((shaderUtils => {
|
|
993
1039
|
shaderUtilsRef.current = {
|
|
994
1040
|
ShaderDisplacementGenerator: shaderUtils.ShaderDisplacementGenerator,
|
|
@@ -1003,7 +1049,7 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
|
|
|
1003
1049
|
// Generate shader map with debouncing and caching
|
|
1004
1050
|
useEffect((() => {
|
|
1005
1051
|
// Enhanced validation for shader mode
|
|
1006
|
-
if ("shader" === mode && glassSize && validateGlassSize(glassSize)
|
|
1052
|
+
if ("shader" === mode && glassSize && validateGlassSize(glassSize)) {
|
|
1007
1053
|
// Create cache key from size and variant
|
|
1008
1054
|
const cacheKey = `${glassSize.width}x${glassSize.height}-${shaderVariant}`, cachedUrl = (key => {
|
|
1009
1055
|
const entry = sharedShaderCache.get(key);
|
|
@@ -1025,11 +1071,9 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
|
|
|
1025
1071
|
width: glassSize.width,
|
|
1026
1072
|
height: glassSize.height,
|
|
1027
1073
|
fragment: selectedShader
|
|
1028
|
-
}),
|
|
1029
|
-
// Defer shader generation with longer delay to avoid blocking
|
|
1030
|
-
setTimeout((() => {
|
|
1074
|
+
}), shaderUpdateTimeoutRef.current = setTimeout((() => {
|
|
1031
1075
|
const url = shaderGeneratorRef.current?.updateShader() || "";
|
|
1032
|
-
((key, url) => {
|
|
1076
|
+
url && ((key, url) => {
|
|
1033
1077
|
// Evict oldest entries if at capacity
|
|
1034
1078
|
if (sharedShaderCache.size >= 15) {
|
|
1035
1079
|
const entries = Array.from(sharedShaderCache.entries());
|
|
@@ -1061,7 +1105,8 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
|
|
|
1061
1105
|
// Cleanup function with error handling
|
|
1062
1106
|
return () => {
|
|
1063
1107
|
shaderDebounceTimeoutRef.current && (clearTimeout(shaderDebounceTimeoutRef.current),
|
|
1064
|
-
shaderDebounceTimeoutRef.current = null)
|
|
1108
|
+
shaderDebounceTimeoutRef.current = null), shaderUpdateTimeoutRef.current && (clearTimeout(shaderUpdateTimeoutRef.current),
|
|
1109
|
+
shaderUpdateTimeoutRef.current = null);
|
|
1065
1110
|
try {
|
|
1066
1111
|
shaderGeneratorRef.current?.destroy();
|
|
1067
1112
|
} catch (error) {
|
|
@@ -1070,7 +1115,37 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
|
|
|
1070
1115
|
shaderGeneratorRef.current = null;
|
|
1071
1116
|
}
|
|
1072
1117
|
};
|
|
1073
|
-
}), [ mode, glassSize, shaderVariant ])
|
|
1118
|
+
}), [ mode, glassSize, shaderVariant ]),
|
|
1119
|
+
// Phase 1: Time-Based Animation Loop - Continuous shader regeneration
|
|
1120
|
+
useEffect((() => {
|
|
1121
|
+
// Only run animations in shader mode with time animation enabled
|
|
1122
|
+
if ("shader" !== mode || !withTimeAnimation || effectiveReducedMotion || effectiveWithoutEffects)
|
|
1123
|
+
// Cancel any existing animation frame
|
|
1124
|
+
return void (null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
|
|
1125
|
+
animationFrameRef.current = null));
|
|
1126
|
+
const baseFps = "ultra" === distortionQuality ? 60 : "high" === distortionQuality ? 30 : "medium" === distortionQuality ? 24 : 20, effectiveSpeed = Math.max(.5, Math.min(2, animationSpeed || 1)), complexity = withMultiLayerDistortion ? Math.max(1, (distortionOctaves || 3) / 3 + .25 * Math.max(0, (distortionLacunarity || 2) - 2) + Math.max(0, (distortionGain || .5) - .5)) : 1, frameInterval = 1e3 / Math.max(12, Math.min(60, Math.round(baseFps * effectiveSpeed / complexity)));
|
|
1127
|
+
let lastUpdate = 0, isCancelled = !1;
|
|
1128
|
+
const animate = currentTime => {
|
|
1129
|
+
if (!isCancelled) {
|
|
1130
|
+
if (currentTime - lastUpdate >= frameInterval && shaderGeneratorRef.current) {
|
|
1131
|
+
lastUpdate = currentTime;
|
|
1132
|
+
try {
|
|
1133
|
+
const animatedShaderUrl = shaderGeneratorRef.current.updateShader();
|
|
1134
|
+
animatedShaderUrl && setShaderMapUrl(animatedShaderUrl);
|
|
1135
|
+
} catch (error) {
|
|
1136
|
+
console.warn("AtomixGlassContainer: Error in animation loop", error);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
animationFrameRef.current = requestAnimationFrame(animate);
|
|
1140
|
+
}
|
|
1141
|
+
};
|
|
1142
|
+
// Start animation loop
|
|
1143
|
+
// Cleanup animation on unmount or dependency change
|
|
1144
|
+
return animationFrameRef.current = requestAnimationFrame(animate), () => {
|
|
1145
|
+
isCancelled = !0, null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
|
|
1146
|
+
animationFrameRef.current = null);
|
|
1147
|
+
};
|
|
1148
|
+
}), [ mode, withTimeAnimation, animationSpeed, displacementScale, withMultiLayerDistortion, distortionOctaves, distortionLacunarity, distortionGain, distortionQuality, effectiveReducedMotion, effectiveWithoutEffects, glassSize ]);
|
|
1074
1149
|
// Removed forced reflow to avoid layout thrash and potential feedback sizing loops
|
|
1075
1150
|
const [rectCache, setRectCache] = useState(null);
|
|
1076
1151
|
useEffect((() => {
|
|
@@ -1122,21 +1197,18 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
|
|
|
1122
1197
|
backdropFilter: `blur(${blurAmount}px) saturate(${saturation}%) contrast(1.05) brightness(1.05)`
|
|
1123
1198
|
};
|
|
1124
1199
|
}
|
|
1125
|
-
}), [ liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion, effectiveWithoutEffects, withLiquidBlur ]), containerVars = useMemo((() => {
|
|
1200
|
+
}), [ liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion, effectiveWithoutEffects, withLiquidBlur, overLightConfig ]), containerVars = useMemo((() => {
|
|
1126
1201
|
try {
|
|
1127
1202
|
// Safe extraction of mouse offset values
|
|
1128
1203
|
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;
|
|
1129
1204
|
return {
|
|
1130
|
-
"--atomix-glass-container-width": `${glassSize?.width}`,
|
|
1131
|
-
"--atomix-glass-container-height": `${glassSize?.height}`,
|
|
1132
|
-
"--atomix-glass-container-padding": padding || "0 0",
|
|
1133
1205
|
"--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px`,
|
|
1134
1206
|
"--atomix-glass-container-backdrop": backdropStyle?.backdropFilter || "none",
|
|
1135
1207
|
"--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",
|
|
1136
1208
|
"--atomix-glass-container-shadow-opacity": effectiveWithoutEffects ? 0 : 1,
|
|
1137
1209
|
// Background and shadow values use design token-aligned RGB values
|
|
1138
1210
|
"--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",
|
|
1139
|
-
"--atomix-glass-container-text-shadow": overLight ? "0px 2px
|
|
1211
|
+
"--atomix-glass-container-text-shadow": overLight ? "0px 1px 2px rgba(255, 255, 255, 0.15)" : "0px 2px 12px rgba(0, 0, 0, 0.4)",
|
|
1140
1212
|
"--atomix-glass-container-box-shadow": overLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)"
|
|
1141
1213
|
};
|
|
1142
1214
|
} catch (error) {
|
|
@@ -1151,7 +1223,7 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
|
|
|
1151
1223
|
"--atomix-glass-container-text-shadow": "none"
|
|
1152
1224
|
};
|
|
1153
1225
|
}
|
|
1154
|
-
}), [
|
|
1226
|
+
}), [ borderRadius, backdropStyle, mouseOffset, overLight, effectiveWithoutEffects, overLightConfig ]);
|
|
1155
1227
|
return jsx("div", {
|
|
1156
1228
|
ref: el => {
|
|
1157
1229
|
// Apply force no-transition
|
|
@@ -1180,10 +1252,6 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
|
|
|
1180
1252
|
aberrationIntensity: "number" != typeof aberrationIntensity || isNaN(aberrationIntensity) ? 0 : aberrationIntensity,
|
|
1181
1253
|
shaderMapUrl: shaderMapUrl
|
|
1182
1254
|
}), jsx("div", {
|
|
1183
|
-
ref: el => {
|
|
1184
|
-
el && (el.style.setProperty("transition-duration", "0s", "important"), el.style.setProperty("animation-duration", "0s", "important"),
|
|
1185
|
-
el.style.setProperty("transition-delay", "0s", "important"));
|
|
1186
|
-
},
|
|
1187
1255
|
className: ATOMIX_GLASS.FILTER_OVERLAY_CLASS,
|
|
1188
1256
|
style: {
|
|
1189
1257
|
filter: `url(#${filterId})`
|
|
@@ -1288,7 +1356,7 @@ class {
|
|
|
1288
1356
|
}
|
|
1289
1357
|
}, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
|
|
1290
1358
|
if (!wrapperElement && !containerElement) return;
|
|
1291
|
-
const {mouseOffset: mouseOffset, globalMousePosition: globalMousePosition, glassSize: glassSize, isHovered: isHovered, isActive: isActive, isOverLight: isOverLight, baseOverLightConfig: baseOverLightConfig, effectiveBorderRadius: effectiveBorderRadius, effectiveWithoutEffects: effectiveWithoutEffects, effectiveReducedMotion: effectiveReducedMotion, elasticity: elasticity, directionalScale: directionalScale, onClick: onClick, withLiquidBlur: withLiquidBlur, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING} = params, mouseInfluence = calculateMouseInfluence(mouseOffset), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1, overLightConfig = {
|
|
1359
|
+
const {mouseOffset: mouseOffset, globalMousePosition: globalMousePosition, glassSize: glassSize, isHovered: isHovered, isActive: isActive, isOverLight: isOverLight, baseOverLightConfig: baseOverLightConfig, effectiveBorderRadius: effectiveBorderRadius, effectiveWithoutEffects: effectiveWithoutEffects, effectiveReducedMotion: effectiveReducedMotion, elasticity: elasticity, directionalScale: directionalScale, onClick: onClick, withLiquidBlur: withLiquidBlur, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, isFixedOrSticky: isFixedOrSticky = !1} = params, mouseInfluence = calculateMouseInfluence(mouseOffset), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1, overLightConfig = {
|
|
1292
1360
|
opacity: baseOverLightConfig.opacity * hoverIntensity * activeIntensity,
|
|
1293
1361
|
contrast: Math.min(1.6, baseOverLightConfig.contrast + .1 * mouseInfluence),
|
|
1294
1362
|
brightness: Math.min(1.1, baseOverLightConfig.brightness + .05 * mouseInfluence),
|
|
@@ -1378,7 +1446,7 @@ class {
|
|
|
1378
1446
|
}
|
|
1379
1447
|
// Update Container Styles (containerVars)
|
|
1380
1448
|
if (containerElement) {
|
|
1381
|
-
const mx = mouseOffset.x, my = mouseOffset.y, EDGE_BLUR_MULTIPLIER =
|
|
1449
|
+
const mx = mouseOffset.x, my = mouseOffset.y, EDGE_BLUR_MULTIPLIER = .5, CENTER_BLUR_MULTIPLIER = .2, FLOW_BLUR_MULTIPLIER = .3, MOUSE_INFLUENCE_BLUR_FACTOR = .4, EDGE_INTENSITY_MOUSE_FACTOR = .15, CENTER_INTENSITY_MOUSE_FACTOR = .1, MAX_BLUR_RELATIVE = 2, rect = containerElement.getBoundingClientRect();
|
|
1382
1450
|
let liquidBlur = {
|
|
1383
1451
|
baseBlur: blurAmount,
|
|
1384
1452
|
edgeBlur: blurAmount * EDGE_BLUR_MULTIPLIER,
|
|
@@ -1400,22 +1468,155 @@ class {
|
|
|
1400
1468
|
backdropFilterString = !withLiquidBlur || effectiveReducedMotion || effectiveWithoutEffects || area > 18e4 ? `blur(${clampBlur(Math.max(liquidBlur.baseBlur, .8 * liquidBlur.edgeBlur, 1.1 * liquidBlur.centerBlur, .9 * liquidBlur.flowBlur))}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig.contrast}) brightness(${overLightConfig.brightness})` : `blur(${clampBlur(.4 * liquidBlur.baseBlur + .25 * liquidBlur.edgeBlur + .15 * liquidBlur.centerBlur + .2 * liquidBlur.flowBlur)}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig.contrast}) brightness(${overLightConfig.brightness})`;
|
|
1401
1469
|
// Container variables
|
|
1402
1470
|
const style = containerElement.style;
|
|
1403
|
-
style.setProperty("--atomix-glass-container-width", `${glassSize.width}`
|
|
1471
|
+
style.setProperty("--atomix-glass-container-width", isFixedOrSticky ? `${glassSize.width}` : "100%"),
|
|
1472
|
+
style.setProperty("--atomix-glass-container-height", isFixedOrSticky ? `${glassSize.height}` : "100%"),
|
|
1404
1473
|
style.setProperty("--atomix-glass-container-padding", padding), style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
|
|
1405
1474
|
style.setProperty("--atomix-glass-container-backdrop", backdropFilterString),
|
|
1406
1475
|
// Shadows
|
|
1407
1476
|
style.setProperty("--atomix-glass-container-shadow", isOverLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${(.4 + .002 * mx) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 -1px 0 rgba(0, 0, 0, ${(.2 + .001 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 0 20px rgba(0, 0, 0, ${(.08 + .001 * Math.abs(mx + my)) * (overLightConfig.shadowIntensity || 1)})`, `0 2px 12px rgba(0, 0, 0, ${(.12 + .002 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})` ].join(", ") : "0 0 20px rgba(0, 0, 0, 0.15) inset, 0 4px 8px rgba(0, 0, 0, 0.08) inset"),
|
|
1408
1477
|
style.setProperty("--atomix-glass-container-shadow-opacity", effectiveWithoutEffects ? "0" : "1"),
|
|
1409
1478
|
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"),
|
|
1410
|
-
style.setProperty("--atomix-glass-container-text-shadow", isOverLight ? "0px 2px
|
|
1479
|
+
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)"),
|
|
1411
1480
|
style.setProperty("--atomix-glass-container-box-shadow", isOverLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)");
|
|
1412
1481
|
}
|
|
1413
|
-
}
|
|
1482
|
+
};
|
|
1414
1483
|
|
|
1415
1484
|
/**
|
|
1416
1485
|
* Updates the styles of the AtomixGlass wrapper and container elements imperatively
|
|
1417
1486
|
* to avoid React re-renders on mouse movement.
|
|
1418
|
-
*/
|
|
1487
|
+
*/
|
|
1488
|
+
/**
|
|
1489
|
+
* Animation System for AtomixGlass Component
|
|
1490
|
+
*
|
|
1491
|
+
* Implements Phase 1 features from the AtomixGlass Feature Implementation Roadmap:
|
|
1492
|
+
* - Feature 1.1: Time-Based Animation System
|
|
1493
|
+
* - Feature 1.2: Multi-Layer Distortion System (FBM)
|
|
1494
|
+
*
|
|
1495
|
+
* @packageDocumentation
|
|
1496
|
+
*/
|
|
1497
|
+
// ============================================================================
|
|
1498
|
+
// Noise Functions for FBM (Feature 1.2)
|
|
1499
|
+
// ============================================================================
|
|
1500
|
+
/**
|
|
1501
|
+
* Perlin noise implementation for smooth gradient noise
|
|
1502
|
+
*
|
|
1503
|
+
* @param x - X coordinate
|
|
1504
|
+
* @param y - Y coordinate
|
|
1505
|
+
* @returns Noise value in range [0, 1]
|
|
1506
|
+
*/
|
|
1507
|
+
function perlinNoise(x, y) {
|
|
1508
|
+
// Simplified Perlin noise using pseudo-random gradients
|
|
1509
|
+
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);
|
|
1510
|
+
// Scale to [0, 1] range
|
|
1511
|
+
return (lerp(lerpX1, lerpX2, v) + 1) / 2;
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
// ============================================================================
|
|
1515
|
+
// Fractal Brownian Motion (FBM) Engine (Feature 1.2)
|
|
1516
|
+
// ============================================================================
|
|
1517
|
+
/**
|
|
1518
|
+
* Creates an FBM engine with configurable parameters
|
|
1519
|
+
*
|
|
1520
|
+
* @param config - FBM configuration (octaves, lacunarity, gain)
|
|
1521
|
+
* @returns Object with fbm function
|
|
1522
|
+
*
|
|
1523
|
+
* @example
|
|
1524
|
+
* ```typescript
|
|
1525
|
+
* const fbmEngine = createFBMEngine({ octaves: 5, lacunarity: 2, gain: 0.5 });
|
|
1526
|
+
*
|
|
1527
|
+
* // Generate noise at position (0.5, 0.5) with time animation
|
|
1528
|
+
* const noiseValue = fbmEngine.fbm(0.5, 0.5, Date.now());
|
|
1529
|
+
* ```
|
|
1530
|
+
*/ function createFBMEngine(config) {
|
|
1531
|
+
/**
|
|
1532
|
+
* Fractal Brownian Motion function
|
|
1533
|
+
* Combines multiple octaves of noise for complex, natural patterns
|
|
1534
|
+
*
|
|
1535
|
+
* @param x - X coordinate
|
|
1536
|
+
* @param y - Y coordinate
|
|
1537
|
+
* @param time - Optional time value for animation
|
|
1538
|
+
* @returns FBM noise value in range [0, 1]
|
|
1539
|
+
*/
|
|
1540
|
+
const fbm = (x, y, time = 0) => {
|
|
1541
|
+
let value = 0, amplitude = .5, frequency = 1, phase = .001 * time;
|
|
1542
|
+
// Convert to seconds for reasonable animation speed
|
|
1543
|
+
for (let i = 0; i < config.octaves; i++)
|
|
1544
|
+
// Apply time-based phase shift to all octaves
|
|
1545
|
+
value += perlinNoise(x * frequency + phase, y * frequency + phase) * amplitude,
|
|
1546
|
+
frequency *= config.lacunarity, // Increase frequency
|
|
1547
|
+
amplitude *= config.gain;
|
|
1548
|
+
return value;
|
|
1549
|
+
};
|
|
1550
|
+
/**
|
|
1551
|
+
* Get FBM with simple time factor
|
|
1552
|
+
*/ return {
|
|
1553
|
+
fbm: fbm,
|
|
1554
|
+
fbmWithTime: (x, y, time) => fbm(x, y, time)
|
|
1555
|
+
};
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
/**
|
|
1559
|
+
* Gets optimal FBM config based on quality preset
|
|
1560
|
+
*
|
|
1561
|
+
* @param quality - Quality preset level
|
|
1562
|
+
* @returns FBM configuration for the quality level
|
|
1563
|
+
*/ const fbmEngineCache = new Map;
|
|
1564
|
+
|
|
1565
|
+
// ============================================================================
|
|
1566
|
+
// Shader Utility Functions for Time-Based Effects
|
|
1567
|
+
// ============================================================================
|
|
1568
|
+
/**
|
|
1569
|
+
* Liquid glass distortion with time-based animation
|
|
1570
|
+
* Uses FBM to create organic, flowing liquid effects
|
|
1571
|
+
*
|
|
1572
|
+
* @param uv - UV coordinates (normalized 0-1)
|
|
1573
|
+
* @param time - Elapsed time in milliseconds
|
|
1574
|
+
* @param config - FBM configuration
|
|
1575
|
+
* @returns Distorted UV coordinates
|
|
1576
|
+
*/ function liquidGlassWithTime(uv, time, config) {
|
|
1577
|
+
const configKey = `${config.octaves}-${config.lacunarity}-${config.gain}`;
|
|
1578
|
+
let fbmEngine = fbmEngineCache.get(configKey);
|
|
1579
|
+
fbmEngine || (fbmEngine = createFBMEngine(config), fbmEngineCache.set(configKey, fbmEngine));
|
|
1580
|
+
// Animate noise with time
|
|
1581
|
+
const animatedNoise = fbmEngine.fbmWithTime(2 * uv.x + 1e-4 * time, 2 * uv.y + 15e-5 * time, time);
|
|
1582
|
+
return {
|
|
1583
|
+
x: uv.x + .04 * (animatedNoise - .5),
|
|
1584
|
+
y: uv.y + .04 * (animatedNoise - .5)
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
// ============================================================================
|
|
1589
|
+
// Helper Functions
|
|
1590
|
+
// ============================================================================
|
|
1591
|
+
/**
|
|
1592
|
+
* Fade curve for smooth interpolation (Perlin's fade function)
|
|
1593
|
+
*/ function fade(t) {
|
|
1594
|
+
return t * t * t * (t * (6 * t - 15) + 10);
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1597
|
+
/**
|
|
1598
|
+
* Linear interpolation
|
|
1599
|
+
*/ function lerp(a, b, t) {
|
|
1600
|
+
return a + t * (b - a);
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
/**
|
|
1604
|
+
* Gradient calculation for Perlin noise
|
|
1605
|
+
*/ function grad(hash, x, y) {
|
|
1606
|
+
const h = 15 & hash, u = h < 8 ? x : y, v = h < 4 ? y : 12 === h || 14 === h ? x : 0;
|
|
1607
|
+
return (1 & h ? -u : u) + (2 & h ? -v : v);
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
/**
|
|
1611
|
+
* Permutation table for Perlin noise
|
|
1612
|
+
*/ const p = (() => {
|
|
1613
|
+
const permutation = [];
|
|
1614
|
+
for (let i = 0; i < 256; i++) permutation[i] = Math.floor(256 * Math.random());
|
|
1615
|
+
// Duplicate for overflow handling
|
|
1616
|
+
return [ ...permutation, ...permutation ];
|
|
1617
|
+
})(), {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
|
|
1618
|
+
|
|
1619
|
+
const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new WeakMap, setCachedBackgroundDetection = (parentElement, overLightConfig, result, threshold) => {
|
|
1419
1620
|
parentElement && backgroundDetectionCache.set(parentElement, {
|
|
1420
1621
|
result: result,
|
|
1421
1622
|
timestamp: Date.now(),
|
|
@@ -1428,7 +1629,9 @@ class {
|
|
|
1428
1629
|
* Composable hook for AtomixGlass component logic
|
|
1429
1630
|
* Manages all state, calculations, and event handlers
|
|
1430
1631
|
*/
|
|
1431
|
-
function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef: wrapperRef, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, elasticity: elasticity = .05, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1,
|
|
1632
|
+
function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef: wrapperRef, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, elasticity: elasticity = .05, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, children: children, blurAmount: blurAmount, saturation: saturation, padding: padding, withLiquidBlur: withLiquidBlur, isFixedOrSticky: isFixedOrSticky = !1, withTimeAnimation:
|
|
1633
|
+
// Phase 1: Animation System Props
|
|
1634
|
+
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}) {
|
|
1432
1635
|
// State
|
|
1433
1636
|
const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1), cachedRectRef = useRef(null), internalGlobalMousePositionRef = useRef({
|
|
1434
1637
|
x: 0,
|
|
@@ -1442,7 +1645,47 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
1442
1645
|
}), targetGlobalMousePositionRef = useRef({
|
|
1443
1646
|
x: 0,
|
|
1444
1647
|
y: 0
|
|
1445
|
-
}), lerpRafRef = useRef(null), lerpActiveRef = useRef(!1), [dynamicBorderRadius, setDynamicCornerRadius] = useState(CONSTANTS.DEFAULT_CORNER_RADIUS), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1),
|
|
1648
|
+
}), lerpRafRef = useRef(null), lerpActiveRef = useRef(!1), [dynamicBorderRadius, setDynamicCornerRadius] = useState(CONSTANTS.DEFAULT_CORNER_RADIUS), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1), animationFrameIdRef = useRef(null), animationStartTimeRef = useRef(0), elapsedTimeRef = useRef(0), shaderTimeRef = useRef(0), fbmConfig = useMemo((() => {
|
|
1649
|
+
// If quality preset is provided, use it as base
|
|
1650
|
+
const preset = (quality = distortionQuality, ATOMIX_GLASS.CONSTANTS.DISTORTION_QUALITY_PRESETS[quality]);
|
|
1651
|
+
// Override with custom values if provided
|
|
1652
|
+
var quality;
|
|
1653
|
+
return {
|
|
1654
|
+
octaves: distortionOctaves ?? preset.octaves,
|
|
1655
|
+
lacunarity: distortionLacunarity ?? preset.lacunarity,
|
|
1656
|
+
gain: distortionGain ?? preset.gain
|
|
1657
|
+
};
|
|
1658
|
+
}), [ distortionQuality, distortionOctaves, distortionLacunarity, distortionGain ]), fbmEngine = useMemo((() => withMultiLayerDistortion ? createFBMEngine(fbmConfig) : null), [ withMultiLayerDistortion, fbmConfig ]), effectiveReducedMotion = useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveWithTimeAnimation = useMemo((() => withTimeAnimation && !effectiveReducedMotion), [ withTimeAnimation, effectiveReducedMotion ]);
|
|
1659
|
+
/**
|
|
1660
|
+
* Animation loop for time-based effects
|
|
1661
|
+
*/
|
|
1662
|
+
useEffect((() => {
|
|
1663
|
+
if (!effectiveWithTimeAnimation || "undefined" == typeof window) return;
|
|
1664
|
+
let lastFrameTime = performance.now();
|
|
1665
|
+
/**
|
|
1666
|
+
* Animation frame handler
|
|
1667
|
+
*/ const animate = currentTime => {
|
|
1668
|
+
// Calculate delta time
|
|
1669
|
+
const deltaTime = currentTime - lastFrameTime;
|
|
1670
|
+
lastFrameTime = currentTime;
|
|
1671
|
+
// Apply animation speed multiplier
|
|
1672
|
+
const scaledDelta = deltaTime * animationSpeed;
|
|
1673
|
+
elapsedTimeRef.current += scaledDelta, shaderTimeRef.current = elapsedTimeRef.current,
|
|
1674
|
+
// Continue animation loop
|
|
1675
|
+
animationFrameIdRef.current = requestAnimationFrame(animate);
|
|
1676
|
+
};
|
|
1677
|
+
// Start animation
|
|
1678
|
+
// Cleanup
|
|
1679
|
+
return animationStartTimeRef.current = performance.now(), animationFrameIdRef.current = requestAnimationFrame(animate),
|
|
1680
|
+
() => {
|
|
1681
|
+
null !== animationFrameIdRef.current && (cancelAnimationFrame(animationFrameIdRef.current),
|
|
1682
|
+
animationFrameIdRef.current = null);
|
|
1683
|
+
};
|
|
1684
|
+
}), [ effectiveWithTimeAnimation, animationSpeed ]);
|
|
1685
|
+
/**
|
|
1686
|
+
* Get current shader time for animations
|
|
1687
|
+
*/
|
|
1688
|
+
const getShaderTime = useCallback((() => shaderTimeRef.current), []), applyTimeBasedDistortion = useCallback((uv => effectiveWithTimeAnimation && fbmEngine ? liquidGlassWithTime(uv, shaderTimeRef.current, fbmConfig) : uv), [ effectiveWithTimeAnimation, fbmEngine, fbmConfig ]), effectiveBorderRadius = useMemo((() => void 0 !== borderRadius ? Math.max(0, borderRadius) : Math.max(0, dynamicBorderRadius)), [ borderRadius, dynamicBorderRadius ]), {glassSize: glassSize} = function({glassRef: glassRef, effectiveBorderRadius: effectiveBorderRadius, cachedRectRef: cachedRectRef}) {
|
|
1446
1689
|
const [glassSize, setGlassSize] = useState({
|
|
1447
1690
|
width: 270,
|
|
1448
1691
|
height: 69
|
|
@@ -1501,7 +1744,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
1501
1744
|
glassRef: glassRef,
|
|
1502
1745
|
effectiveBorderRadius: effectiveBorderRadius,
|
|
1503
1746
|
cachedRectRef: cachedRectRef
|
|
1504
|
-
}),
|
|
1747
|
+
}), effectiveHighContrast = useMemo((() => highContrast || userPrefersHighContrast), [ highContrast, userPrefersHighContrast ]), effectiveWithoutEffects = useMemo((() => withoutEffects || effectiveReducedMotion), [ withoutEffects, effectiveReducedMotion ]), globalMousePosition = externalGlobalMousePosition || internalGlobalMousePositionRef.current, mouseOffset = externalMouseOffset || internalMouseOffsetRef.current;
|
|
1748
|
+
/**
|
|
1749
|
+
* Apply time-based distortion to UV coordinates
|
|
1750
|
+
*/
|
|
1505
1751
|
// Extract border-radius from children
|
|
1506
1752
|
useEffect((() => {
|
|
1507
1753
|
const extractRadius = () => {
|
|
@@ -1704,6 +1950,8 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
1704
1950
|
lerpActiveRef.current = !0;
|
|
1705
1951
|
const LERP_T = CONSTANTS.LERP_FACTOR, tick = () => {
|
|
1706
1952
|
if (!lerpActiveRef.current) return;
|
|
1953
|
+
// Add ref validity check to prevent memory leaks
|
|
1954
|
+
if (!glassRef.current || !wrapperRef?.current) return void (lerpActiveRef.current = !1);
|
|
1707
1955
|
const cur = internalMouseOffsetRef.current, tgt = targetMouseOffsetRef.current, dx = tgt.x - cur.x, dy = tgt.y - cur.y;
|
|
1708
1956
|
// If we're close enough, snap and park
|
|
1709
1957
|
if (Math.abs(dx) < .05 && Math.abs(dy) < .05) internalMouseOffsetRef.current = {
|
|
@@ -1712,17 +1960,17 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
1712
1960
|
...targetGlobalMousePositionRef.current
|
|
1713
1961
|
}; else {
|
|
1714
1962
|
internalMouseOffsetRef.current = {
|
|
1715
|
-
x: lerp(cur.x, tgt.x, LERP_T),
|
|
1716
|
-
y: lerp(cur.y, tgt.y, LERP_T)
|
|
1963
|
+
x: lerp$1(cur.x, tgt.x, LERP_T),
|
|
1964
|
+
y: lerp$1(cur.y, tgt.y, LERP_T)
|
|
1717
1965
|
};
|
|
1718
1966
|
const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
|
|
1719
1967
|
internalGlobalMousePositionRef.current = {
|
|
1720
|
-
x: lerp(curG.x, tgtG.x, LERP_T),
|
|
1721
|
-
y: lerp(curG.y, tgtG.y, LERP_T)
|
|
1968
|
+
x: lerp$1(curG.x, tgtG.x, LERP_T),
|
|
1969
|
+
y: lerp$1(curG.y, tgtG.y, LERP_T)
|
|
1722
1970
|
};
|
|
1723
1971
|
}
|
|
1724
1972
|
// Imperative style update with the smoothed values
|
|
1725
|
-
updateAtomixGlassStyles(wrapperRef
|
|
1973
|
+
updateAtomixGlassStyles(wrapperRef.current, glassRef.current, {
|
|
1726
1974
|
mouseOffset: internalMouseOffsetRef.current,
|
|
1727
1975
|
globalMousePosition: internalGlobalMousePositionRef.current,
|
|
1728
1976
|
glassSize: glassSize,
|
|
@@ -1739,12 +1987,13 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
1739
1987
|
withLiquidBlur: withLiquidBlur,
|
|
1740
1988
|
blurAmount: blurAmount,
|
|
1741
1989
|
saturation: saturation,
|
|
1742
|
-
padding: padding
|
|
1990
|
+
padding: padding,
|
|
1991
|
+
isFixedOrSticky: isFixedOrSticky
|
|
1743
1992
|
}), lerpRafRef.current = requestAnimationFrame(tick);
|
|
1744
1993
|
};
|
|
1745
1994
|
// 0.08 – lower = more viscous
|
|
1746
1995
|
lerpRafRef.current = requestAnimationFrame(tick);
|
|
1747
|
-
}), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding ]), stopLerpLoop = useCallback((() => {
|
|
1996
|
+
}), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding, isFixedOrSticky ]), stopLerpLoop = useCallback((() => {
|
|
1748
1997
|
lerpActiveRef.current = !1, null !== lerpRafRef.current && (cancelAnimationFrame(lerpRafRef.current),
|
|
1749
1998
|
lerpRafRef.current = null);
|
|
1750
1999
|
}), []);
|
|
@@ -1812,6 +2061,8 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
1812
2061
|
// This is now static (refs or props) unless prop changes
|
|
1813
2062
|
overLightConfig: overLightConfig,
|
|
1814
2063
|
transformStyle: transformStyle,
|
|
2064
|
+
getShaderTime: getShaderTime,
|
|
2065
|
+
applyTimeBasedDistortion: applyTimeBasedDistortion,
|
|
1815
2066
|
handleMouseEnter: handleMouseEnter,
|
|
1816
2067
|
handleMouseLeave: handleMouseLeave,
|
|
1817
2068
|
handleMouseDown: handleMouseDown,
|
|
@@ -1820,6 +2071,358 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
1820
2071
|
};
|
|
1821
2072
|
}
|
|
1822
2073
|
|
|
2074
|
+
/**
|
|
2075
|
+
* Default responsive breakpoints configuration
|
|
2076
|
+
*
|
|
2077
|
+
* These breakpoints are optimized for glass effect performance across device classes:
|
|
2078
|
+
* - Mobile: Reduced complexity for 60 FPS target
|
|
2079
|
+
* - Tablet: Balanced quality and performance
|
|
2080
|
+
* - Desktop: Full fidelity effects
|
|
2081
|
+
*/ const DEFAULT_BREAKPOINTS = {
|
|
2082
|
+
mobile: {
|
|
2083
|
+
maxWidth: 640,
|
|
2084
|
+
params: {
|
|
2085
|
+
distortionOctaves: 3,
|
|
2086
|
+
displacementScale: .7,
|
|
2087
|
+
blurAmount: .8,
|
|
2088
|
+
animationSpeed: .8,
|
|
2089
|
+
chromaticIntensity: .5
|
|
2090
|
+
}
|
|
2091
|
+
},
|
|
2092
|
+
tablet: {
|
|
2093
|
+
minWidth: 641,
|
|
2094
|
+
maxWidth: 1024,
|
|
2095
|
+
params: {
|
|
2096
|
+
distortionOctaves: 4,
|
|
2097
|
+
displacementScale: .85,
|
|
2098
|
+
blurAmount: .9,
|
|
2099
|
+
animationSpeed: .9,
|
|
2100
|
+
chromaticIntensity: .75
|
|
2101
|
+
}
|
|
2102
|
+
},
|
|
2103
|
+
desktop: {
|
|
2104
|
+
minWidth: 1025,
|
|
2105
|
+
params: {
|
|
2106
|
+
distortionOctaves: 5,
|
|
2107
|
+
displacementScale: 1,
|
|
2108
|
+
blurAmount: 1,
|
|
2109
|
+
animationSpeed: 1,
|
|
2110
|
+
chromaticIntensity: 1
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
};
|
|
2114
|
+
|
|
2115
|
+
/**
|
|
2116
|
+
* Device performance tier detection
|
|
2117
|
+
*
|
|
2118
|
+
* Uses Device Memory API and Hardware Concurrency API to classify devices
|
|
2119
|
+
* into performance tiers for automatic quality adjustment.
|
|
2120
|
+
*
|
|
2121
|
+
* @returns Performance tier classification
|
|
2122
|
+
*/
|
|
2123
|
+
/**
|
|
2124
|
+
* PerformanceDashboard - Real-time performance monitoring overlay
|
|
2125
|
+
*
|
|
2126
|
+
* Displays:
|
|
2127
|
+
* - Current FPS with color coding
|
|
2128
|
+
* - Frame time statistics
|
|
2129
|
+
* - Quality level indicator
|
|
2130
|
+
* - GPU memory usage (if available)
|
|
2131
|
+
* - Auto-scaling status
|
|
2132
|
+
*/
|
|
2133
|
+
const PerformanceDashboard = ({metrics: metrics, isVisible: isVisible = !0, onClose: onClose}) => {
|
|
2134
|
+
// Get color for FPS display
|
|
2135
|
+
const getFpsColor = fps => fps >= 58 ? "#4ade80" : // Green - good
|
|
2136
|
+
fps >= 45 ? "#fbbf24" : "#ef4444" // Red - critical
|
|
2137
|
+
, dashboardStyle = useMemo((() => ({
|
|
2138
|
+
position: "fixed",
|
|
2139
|
+
top: "16px",
|
|
2140
|
+
right: "16px",
|
|
2141
|
+
padding: "12px 16px",
|
|
2142
|
+
backgroundColor: "rgba(17, 24, 39, 0.95)",
|
|
2143
|
+
borderRadius: "8px",
|
|
2144
|
+
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
|
|
2145
|
+
fontFamily: "monospace",
|
|
2146
|
+
fontSize: "12px",
|
|
2147
|
+
color: "#fff",
|
|
2148
|
+
zIndex: 9999,
|
|
2149
|
+
minWidth: "200px",
|
|
2150
|
+
backdropFilter: "blur(8px)",
|
|
2151
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
2152
|
+
transition: "opacity 0.3s ease",
|
|
2153
|
+
opacity: isVisible ? 1 : 0,
|
|
2154
|
+
pointerEvents: isVisible ? "auto" : "none"
|
|
2155
|
+
})), [ isVisible ]), headerStyle = useMemo((() => ({
|
|
2156
|
+
display: "flex",
|
|
2157
|
+
justifyContent: "space-between",
|
|
2158
|
+
alignItems: "center",
|
|
2159
|
+
marginBottom: "8px",
|
|
2160
|
+
paddingBottom: "8px",
|
|
2161
|
+
borderBottom: "1px solid rgba(255, 255, 255, 0.1)"
|
|
2162
|
+
})), []), titleStyle = useMemo((() => ({
|
|
2163
|
+
fontWeight: "bold",
|
|
2164
|
+
fontSize: "13px",
|
|
2165
|
+
color: "#fff"
|
|
2166
|
+
})), []), closeButtonStyle = useMemo((() => ({
|
|
2167
|
+
background: "transparent",
|
|
2168
|
+
border: "none",
|
|
2169
|
+
color: "#9ca3af",
|
|
2170
|
+
cursor: "pointer",
|
|
2171
|
+
fontSize: "16px",
|
|
2172
|
+
padding: "0",
|
|
2173
|
+
lineHeight: "1"
|
|
2174
|
+
})), []), metricRowStyle = useMemo((() => ({
|
|
2175
|
+
display: "flex",
|
|
2176
|
+
justifyContent: "space-between",
|
|
2177
|
+
alignItems: "center",
|
|
2178
|
+
marginBottom: "6px"
|
|
2179
|
+
})), []), labelStyle = useMemo((() => ({
|
|
2180
|
+
color: "#9ca3af",
|
|
2181
|
+
marginRight: "12px"
|
|
2182
|
+
})), []), valueStyle = useMemo((() => ({
|
|
2183
|
+
fontWeight: "bold"
|
|
2184
|
+
})), []);
|
|
2185
|
+
// Get quality level badge color
|
|
2186
|
+
return isVisible ? jsxs("div", {
|
|
2187
|
+
style: dashboardStyle,
|
|
2188
|
+
children: [ jsxs("div", {
|
|
2189
|
+
style: headerStyle,
|
|
2190
|
+
children: [ jsx("span", {
|
|
2191
|
+
style: titleStyle,
|
|
2192
|
+
children: "Performance Monitor"
|
|
2193
|
+
}), onClose && jsx("button", {
|
|
2194
|
+
style: closeButtonStyle,
|
|
2195
|
+
onClick: onClose,
|
|
2196
|
+
"aria-label": "Close performance dashboard",
|
|
2197
|
+
children: "×"
|
|
2198
|
+
}) ]
|
|
2199
|
+
}), jsxs("div", {
|
|
2200
|
+
style: metricRowStyle,
|
|
2201
|
+
children: [ jsx("span", {
|
|
2202
|
+
style: labelStyle,
|
|
2203
|
+
children: "FPS"
|
|
2204
|
+
}), jsx("span", {
|
|
2205
|
+
style: {
|
|
2206
|
+
...valueStyle,
|
|
2207
|
+
color: getFpsColor(metrics.fps)
|
|
2208
|
+
},
|
|
2209
|
+
children: Math.round(metrics.fps)
|
|
2210
|
+
}) ]
|
|
2211
|
+
}), jsxs("div", {
|
|
2212
|
+
style: metricRowStyle,
|
|
2213
|
+
children: [ jsx("span", {
|
|
2214
|
+
style: labelStyle,
|
|
2215
|
+
children: "Frame Time"
|
|
2216
|
+
}), jsxs("span", {
|
|
2217
|
+
style: valueStyle,
|
|
2218
|
+
children: [ metrics.frameTime.toFixed(2), "ms" ]
|
|
2219
|
+
}) ]
|
|
2220
|
+
}), jsxs("div", {
|
|
2221
|
+
style: metricRowStyle,
|
|
2222
|
+
children: [ jsx("span", {
|
|
2223
|
+
style: labelStyle,
|
|
2224
|
+
children: "Quality"
|
|
2225
|
+
}), jsx("span", {
|
|
2226
|
+
style: {
|
|
2227
|
+
...valueStyle,
|
|
2228
|
+
color: (quality => {
|
|
2229
|
+
switch (quality) {
|
|
2230
|
+
case "high":
|
|
2231
|
+
return "#4ade80";
|
|
2232
|
+
|
|
2233
|
+
case "medium":
|
|
2234
|
+
return "#fbbf24";
|
|
2235
|
+
|
|
2236
|
+
case "low":
|
|
2237
|
+
return "#ef4444";
|
|
2238
|
+
|
|
2239
|
+
default:
|
|
2240
|
+
return "#9ca3af";
|
|
2241
|
+
}
|
|
2242
|
+
})(metrics.qualityLevel),
|
|
2243
|
+
textTransform: "uppercase",
|
|
2244
|
+
fontSize: "11px"
|
|
2245
|
+
},
|
|
2246
|
+
children: metrics.qualityLevel
|
|
2247
|
+
}) ]
|
|
2248
|
+
}), metrics.gpuMemory && jsxs("div", {
|
|
2249
|
+
style: metricRowStyle,
|
|
2250
|
+
children: [ jsx("span", {
|
|
2251
|
+
style: labelStyle,
|
|
2252
|
+
children: "GPU Memory"
|
|
2253
|
+
}), jsxs("span", {
|
|
2254
|
+
style: valueStyle,
|
|
2255
|
+
children: [ "~", Math.round(metrics.gpuMemory / 1024), "MB" ]
|
|
2256
|
+
}) ]
|
|
2257
|
+
}), metrics.isAutoScaling && jsx("div", {
|
|
2258
|
+
style: {
|
|
2259
|
+
marginTop: "8px",
|
|
2260
|
+
paddingTop: "8px",
|
|
2261
|
+
borderTop: "1px solid rgba(255, 255, 255, 0.1)",
|
|
2262
|
+
fontSize: "10px",
|
|
2263
|
+
color: "#6b7280",
|
|
2264
|
+
textAlign: "center"
|
|
2265
|
+
},
|
|
2266
|
+
children: "Auto-scaling active"
|
|
2267
|
+
}), jsxs("div", {
|
|
2268
|
+
style: {
|
|
2269
|
+
marginTop: "8px",
|
|
2270
|
+
paddingTop: "8px",
|
|
2271
|
+
borderTop: "1px solid rgba(255, 255, 255, 0.1)",
|
|
2272
|
+
display: "flex",
|
|
2273
|
+
alignItems: "center",
|
|
2274
|
+
gap: "6px"
|
|
2275
|
+
},
|
|
2276
|
+
children: [ jsx("div", {
|
|
2277
|
+
style: {
|
|
2278
|
+
width: "8px",
|
|
2279
|
+
height: "8px",
|
|
2280
|
+
borderRadius: "50%",
|
|
2281
|
+
backgroundColor: getFpsColor(metrics.fps),
|
|
2282
|
+
animation: metrics.fps < 45 ? "pulse 1s infinite" : "none"
|
|
2283
|
+
}
|
|
2284
|
+
}), jsx("span", {
|
|
2285
|
+
style: {
|
|
2286
|
+
fontSize: "10px",
|
|
2287
|
+
color: metrics.fps >= 58 ? "#4ade80" : metrics.fps >= 45 ? "#fbbf24" : "#ef4444"
|
|
2288
|
+
},
|
|
2289
|
+
children: metrics.fps >= 58 ? "Optimal" : metrics.fps >= 45 ? "Warning" : "Critical"
|
|
2290
|
+
}) ]
|
|
2291
|
+
}) ]
|
|
2292
|
+
}) : null;
|
|
2293
|
+
};
|
|
2294
|
+
|
|
2295
|
+
// Add pulse animation for critical FPS
|
|
2296
|
+
if ("undefined" != typeof document) {
|
|
2297
|
+
const styleSheet = document.createElement("style");
|
|
2298
|
+
styleSheet.textContent = "\n @keyframes pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n ",
|
|
2299
|
+
document.head.appendChild(styleSheet);
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2302
|
+
/**
|
|
2303
|
+
* Mobile optimization presets
|
|
2304
|
+
*
|
|
2305
|
+
* These presets adjust glass effect parameters based on device performance tier
|
|
2306
|
+
* to ensure smooth animations and responsive interactions.
|
|
2307
|
+
*/
|
|
2308
|
+
/**
|
|
2309
|
+
* Performance preset - Maximum FPS, reduced quality
|
|
2310
|
+
* Best for low-end devices or when battery saving is priority
|
|
2311
|
+
*/ const PERFORMANCE_PRESET = {
|
|
2312
|
+
distortionOctaves: 2,
|
|
2313
|
+
// Minimal FBM layers
|
|
2314
|
+
displacementScale: 50,
|
|
2315
|
+
// Subtle displacement
|
|
2316
|
+
blurAmount: 5,
|
|
2317
|
+
// Light blur
|
|
2318
|
+
saturation: 80,
|
|
2319
|
+
// Reduced saturation
|
|
2320
|
+
aberrationIntensity: .3,
|
|
2321
|
+
// Minimal chromatic aberration
|
|
2322
|
+
animationSpeed: .8,
|
|
2323
|
+
// Slightly slower for performance
|
|
2324
|
+
chromaticIntensity: .3,
|
|
2325
|
+
// Low chromatic effect
|
|
2326
|
+
distortionLacunarity: 1.5,
|
|
2327
|
+
// Simpler noise pattern
|
|
2328
|
+
distortionGain: .3
|
|
2329
|
+
}, BALANCED_PRESET = {
|
|
2330
|
+
distortionOctaves: 3,
|
|
2331
|
+
// Moderate FBM layers
|
|
2332
|
+
displacementScale: 75,
|
|
2333
|
+
// Medium displacement
|
|
2334
|
+
blurAmount: 8,
|
|
2335
|
+
// Moderate blur
|
|
2336
|
+
saturation: 90,
|
|
2337
|
+
// Near-full saturation
|
|
2338
|
+
aberrationIntensity: .5,
|
|
2339
|
+
// Moderate chromatic aberration
|
|
2340
|
+
animationSpeed: 1,
|
|
2341
|
+
// Normal speed
|
|
2342
|
+
chromaticIntensity: .5,
|
|
2343
|
+
// Moderate chromatic effect
|
|
2344
|
+
distortionLacunarity: 2,
|
|
2345
|
+
// Standard noise pattern
|
|
2346
|
+
distortionGain: .4
|
|
2347
|
+
}, QUALITY_PRESET = {
|
|
2348
|
+
distortionOctaves: 4,
|
|
2349
|
+
// More FBM layers for detail
|
|
2350
|
+
displacementScale: 100,
|
|
2351
|
+
// Stronger displacement
|
|
2352
|
+
blurAmount: 12,
|
|
2353
|
+
// Smoother blur
|
|
2354
|
+
saturation: 100,
|
|
2355
|
+
// Full saturation
|
|
2356
|
+
aberrationIntensity: .7,
|
|
2357
|
+
// Pronounced chromatic aberration
|
|
2358
|
+
animationSpeed: 1.2,
|
|
2359
|
+
// Slightly faster for drama
|
|
2360
|
+
chromaticIntensity: .7,
|
|
2361
|
+
// Strong chromatic effect
|
|
2362
|
+
distortionLacunarity: 2.2,
|
|
2363
|
+
// Richer noise pattern
|
|
2364
|
+
distortionGain: .5
|
|
2365
|
+
}, MOBILE_OPTIMIZED_BREAKPOINTS = {
|
|
2366
|
+
/** Desktop - Full quality */
|
|
2367
|
+
desktop: {
|
|
2368
|
+
minWidth: 1024,
|
|
2369
|
+
params: {
|
|
2370
|
+
distortionOctaves: 6,
|
|
2371
|
+
displacementScale: 150,
|
|
2372
|
+
blurAmount: 15,
|
|
2373
|
+
saturation: 100,
|
|
2374
|
+
aberrationIntensity: 1,
|
|
2375
|
+
animationSpeed: 1,
|
|
2376
|
+
chromaticIntensity: 1,
|
|
2377
|
+
distortionLacunarity: 2.5,
|
|
2378
|
+
distortionGain: .6
|
|
2379
|
+
}
|
|
2380
|
+
},
|
|
2381
|
+
/** Laptop - High quality */
|
|
2382
|
+
laptop: {
|
|
2383
|
+
minWidth: 768,
|
|
2384
|
+
params: {
|
|
2385
|
+
...QUALITY_PRESET,
|
|
2386
|
+
distortionOctaves: 5,
|
|
2387
|
+
displacementScale: 120
|
|
2388
|
+
}
|
|
2389
|
+
},
|
|
2390
|
+
/** Tablet - Balanced quality */
|
|
2391
|
+
tablet: {
|
|
2392
|
+
minWidth: 640,
|
|
2393
|
+
params: {
|
|
2394
|
+
...BALANCED_PRESET,
|
|
2395
|
+
distortionOctaves: 4,
|
|
2396
|
+
displacementScale: 90
|
|
2397
|
+
}
|
|
2398
|
+
},
|
|
2399
|
+
/** Mobile - Performance optimized */
|
|
2400
|
+
mobile: {
|
|
2401
|
+
maxWidth: 639,
|
|
2402
|
+
params: {
|
|
2403
|
+
...PERFORMANCE_PRESET,
|
|
2404
|
+
distortionOctaves: 3,
|
|
2405
|
+
displacementScale: 75,
|
|
2406
|
+
blurAmount: 6
|
|
2407
|
+
}
|
|
2408
|
+
},
|
|
2409
|
+
/** Small mobile - Maximum performance */
|
|
2410
|
+
mobileSmall: {
|
|
2411
|
+
maxWidth: 375,
|
|
2412
|
+
params: {
|
|
2413
|
+
...PERFORMANCE_PRESET,
|
|
2414
|
+
distortionOctaves: 2,
|
|
2415
|
+
displacementScale: 50,
|
|
2416
|
+
blurAmount: 4,
|
|
2417
|
+
saturation: 70
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
};
|
|
2421
|
+
|
|
2422
|
+
/**
|
|
2423
|
+
* Balanced preset - Good quality with reasonable performance
|
|
2424
|
+
* Default preset for most mobile devices
|
|
2425
|
+
*/
|
|
1823
2426
|
/**
|
|
1824
2427
|
* AtomixGlass - A high-performance glass morphism component with liquid distortion effects
|
|
1825
2428
|
*
|
|
@@ -1834,6 +2437,8 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
1834
2437
|
* - Focus ring support for keyboard navigation
|
|
1835
2438
|
* - Responsive breakpoints for mobile optimization
|
|
1836
2439
|
* - Enhanced ARIA attributes for screen readers
|
|
2440
|
+
* - Time-based animation system with FBM distortion
|
|
2441
|
+
* - Device preset optimization for performance/quality balance
|
|
1837
2442
|
*
|
|
1838
2443
|
* Design System Compliance:
|
|
1839
2444
|
* - Uses design tokens for opacity, spacing, and colors
|
|
@@ -1890,8 +2495,15 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
1890
2495
|
* <AtomixGlass overLight="auto" debugOverLight={true}>
|
|
1891
2496
|
* <div>Content with debug logging enabled</div>
|
|
1892
2497
|
* </AtomixGlass>
|
|
1893
|
-
|
|
1894
|
-
|
|
2498
|
+
*
|
|
2499
|
+
* @example
|
|
2500
|
+
* // Performance-optimized for mobile devices
|
|
2501
|
+
* <AtomixGlass devicePreset="performance" disableResponsiveBreakpoints={false}>
|
|
2502
|
+
* <div>Mobile-optimized glass effect</div>
|
|
2503
|
+
* </AtomixGlass>
|
|
2504
|
+
*/
|
|
2505
|
+
function AtomixGlass({children: children, displacementScale: displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, aberrationIntensity: aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer = null, className: className = "", padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, style: style = {}, mode: mode = ATOMIX_GLASS.DEFAULTS.MODE, onClick: onClick, shaderVariant: shaderVariant = "liquidGlass", "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, role: role, tabIndex: tabIndex, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, withLiquidBlur: withLiquidBlur = !1, withBorder: withBorder = !0, withOverLightLayers: withOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS, debugPerformance: debugPerformance = !1, debugOverLight: debugOverLight = !1, height: height, width: width, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", devicePreset: devicePreset = "balanced", disableResponsiveBreakpoints: disableResponsiveBreakpoints = !1, ...rest}) {
|
|
2506
|
+
const glassRef = useRef(null), contentRef = useRef(null), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = "fixed" === restStyle.position || "sticky" === restStyle.position, {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveBorderRadius: effectiveBorderRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveWithoutEffects: effectiveWithoutEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, getShaderTime: getShaderTime, applyTimeBasedDistortion: applyTimeBasedDistortion, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
|
|
1895
2507
|
glassRef: glassRef,
|
|
1896
2508
|
contentRef: contentRef,
|
|
1897
2509
|
borderRadius: borderRadius,
|
|
@@ -1904,7 +2516,6 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
1904
2516
|
withoutEffects: withoutEffects,
|
|
1905
2517
|
elasticity: elasticity,
|
|
1906
2518
|
onClick: onClick,
|
|
1907
|
-
debugBorderRadius: debugBorderRadius,
|
|
1908
2519
|
debugOverLight: debugOverLight,
|
|
1909
2520
|
debugPerformance: debugPerformance,
|
|
1910
2521
|
children: children,
|
|
@@ -1912,8 +2523,390 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
1912
2523
|
saturation: saturation,
|
|
1913
2524
|
withLiquidBlur: withLiquidBlur,
|
|
1914
2525
|
padding: padding,
|
|
1915
|
-
style: style
|
|
1916
|
-
|
|
2526
|
+
style: style,
|
|
2527
|
+
isFixedOrSticky: isFixedOrSticky,
|
|
2528
|
+
// Phase 1: Animation System props
|
|
2529
|
+
withTimeAnimation: withTimeAnimation,
|
|
2530
|
+
animationSpeed: animationSpeed,
|
|
2531
|
+
withMultiLayerDistortion: withMultiLayerDistortion,
|
|
2532
|
+
distortionOctaves: distortionOctaves,
|
|
2533
|
+
distortionLacunarity: distortionLacunarity,
|
|
2534
|
+
distortionGain: distortionGain,
|
|
2535
|
+
distortionQuality: distortionQuality
|
|
2536
|
+
});
|
|
2537
|
+
// Re-calculate only when devicePreset changes
|
|
2538
|
+
// Responsive breakpoint system - automatically adjusts parameters based on viewport
|
|
2539
|
+
!
|
|
2540
|
+
/**
|
|
2541
|
+
* Responsive Glass Parameters Hook
|
|
2542
|
+
*
|
|
2543
|
+
* Automatically adjusts glass effect parameters based on:
|
|
2544
|
+
* 1. Screen size (mobile/tablet/desktop breakpoints)
|
|
2545
|
+
* 2. Device performance (RAM and CPU detection)
|
|
2546
|
+
* 3. Custom breakpoint configuration
|
|
2547
|
+
*
|
|
2548
|
+
* Features:
|
|
2549
|
+
* - Debounced resize handling
|
|
2550
|
+
* - Performance-based quality adjustment
|
|
2551
|
+
* - Smooth parameter transitions
|
|
2552
|
+
* - Debug mode for development
|
|
2553
|
+
*
|
|
2554
|
+
* @example
|
|
2555
|
+
* ```typescript
|
|
2556
|
+
* const { responsiveParams, currentBreakpoint } = useResponsiveGlass({
|
|
2557
|
+
* baseParams: {
|
|
2558
|
+
* distortionOctaves: 5,
|
|
2559
|
+
* displacementScale: 20,
|
|
2560
|
+
* blurAmount: 10,
|
|
2561
|
+
* },
|
|
2562
|
+
* debug: true,
|
|
2563
|
+
* });
|
|
2564
|
+
* ```
|
|
2565
|
+
*
|
|
2566
|
+
* @param options Hook configuration options
|
|
2567
|
+
* @returns Responsive parameters and metadata
|
|
2568
|
+
*/
|
|
2569
|
+
function({baseParams: baseParams, breakpoints: breakpoints = DEFAULT_BREAKPOINTS, enabled: enabled = !0, enablePerformanceAdjustment: enablePerformanceAdjustment = !0, debug: debug = !1}) {
|
|
2570
|
+
const [responsiveParams, setResponsiveParams] = useState(baseParams), [currentBreakpoint, setCurrentBreakpoint] = useState("desktop"), [performanceTier, setPerformanceTier] = useState("high"), [isActive, setIsActive] = useState(enabled), baseParamsRef = useRef(baseParams), breakpointsRef = useRef(breakpoints);
|
|
2571
|
+
// Update refs when props change
|
|
2572
|
+
baseParamsRef.current = baseParams, breakpointsRef.current = breakpoints;
|
|
2573
|
+
/**
|
|
2574
|
+
* Calculate and apply responsive parameters
|
|
2575
|
+
*/
|
|
2576
|
+
const calculateParams = useCallback((() => {
|
|
2577
|
+
if (!enabled || "undefined" == typeof window) return setIsActive(!1), setResponsiveParams(baseParamsRef.current),
|
|
2578
|
+
void setCurrentBreakpoint("disabled");
|
|
2579
|
+
setIsActive(!0);
|
|
2580
|
+
// Get current screen width
|
|
2581
|
+
const width = window.innerWidth, {name: name, params: breakpointParams} = ((width, breakpoints) => {
|
|
2582
|
+
// Convert breakpoints to array and sort by minWidth descending
|
|
2583
|
+
const sortedBreakpoints = Object.entries(breakpoints).filter((([_, bp]) => void 0 !== bp.minWidth)).sort(((a, b) => (b[1].minWidth || 0) - (a[1].minWidth || 0)));
|
|
2584
|
+
// Find first breakpoint where width >= minWidth
|
|
2585
|
+
for (const [name, bp] of sortedBreakpoints) if (width >= (bp.minWidth || 0)) return {
|
|
2586
|
+
name: name,
|
|
2587
|
+
params: bp.params
|
|
2588
|
+
};
|
|
2589
|
+
// If no minWidth matched, check maxWidth breakpoints
|
|
2590
|
+
const maxWidthBreakpoints = Object.entries(breakpoints).filter((([_, bp]) => void 0 !== bp.maxWidth)).sort(((a, b) => (a[1].maxWidth || 1 / 0) - (b[1].maxWidth || 1 / 0)));
|
|
2591
|
+
for (const [name, bp] of maxWidthBreakpoints) if (width <= (bp.maxWidth || 1 / 0)) return {
|
|
2592
|
+
name: name,
|
|
2593
|
+
params: bp.params
|
|
2594
|
+
};
|
|
2595
|
+
// Fallback to first available breakpoint
|
|
2596
|
+
const entries = Object.entries(breakpoints);
|
|
2597
|
+
if (0 === entries.length)
|
|
2598
|
+
// Ultimate fallback - return sensible defaults
|
|
2599
|
+
return {
|
|
2600
|
+
name: "desktop",
|
|
2601
|
+
params: {
|
|
2602
|
+
distortionOctaves: 5,
|
|
2603
|
+
displacementScale: 1,
|
|
2604
|
+
blurAmount: 1
|
|
2605
|
+
}
|
|
2606
|
+
};
|
|
2607
|
+
const firstEntry = entries[0];
|
|
2608
|
+
if (!firstEntry) return {
|
|
2609
|
+
name: "desktop",
|
|
2610
|
+
params: {
|
|
2611
|
+
distortionOctaves: 5,
|
|
2612
|
+
displacementScale: 1,
|
|
2613
|
+
blurAmount: 1
|
|
2614
|
+
}
|
|
2615
|
+
};
|
|
2616
|
+
const [fallbackName, fallbackBreakpoint] = firstEntry;
|
|
2617
|
+
return {
|
|
2618
|
+
name: fallbackName,
|
|
2619
|
+
params: fallbackBreakpoint.params
|
|
2620
|
+
};
|
|
2621
|
+
})(width, breakpointsRef.current);
|
|
2622
|
+
// Determine current breakpoint
|
|
2623
|
+
setCurrentBreakpoint(name);
|
|
2624
|
+
// Merge base params with breakpoint params
|
|
2625
|
+
let mergedParams = ((baseParams, breakpointParams) => {
|
|
2626
|
+
const result = {
|
|
2627
|
+
...baseParams
|
|
2628
|
+
}, scaleProperties = [ "displacementScale", "blurAmount", "saturation", "aberrationIntensity", "animationSpeed", "chromaticIntensity" ];
|
|
2629
|
+
// Apply scaling for specific properties
|
|
2630
|
+
for (const prop of scaleProperties) void 0 !== breakpointParams[prop] && void 0 !== baseParams[prop] && (result[prop] = baseParams[prop] * breakpointParams[prop]);
|
|
2631
|
+
// Override properties that should be set directly (not scaled)
|
|
2632
|
+
const overrideProperties = [ "distortionOctaves", "distortionLacunarity", "distortionGain" ];
|
|
2633
|
+
for (const prop of overrideProperties) void 0 !== breakpointParams[prop] && (result[prop] = breakpointParams[prop]);
|
|
2634
|
+
return result;
|
|
2635
|
+
})(baseParamsRef.current, breakpointParams);
|
|
2636
|
+
// Apply performance adjustments if enabled
|
|
2637
|
+
if (enablePerformanceAdjustment) {
|
|
2638
|
+
const tier = (() => {
|
|
2639
|
+
// Check if we're in a browser environment
|
|
2640
|
+
if ("undefined" == typeof window || "undefined" == typeof navigator) return "high"; // Default to high for SSR
|
|
2641
|
+
// Device Memory API (Chrome, Edge, Opera)
|
|
2642
|
+
// Returns RAM in GB: 0.25, 0.5, 1, 2, 4, 8
|
|
2643
|
+
const deviceMemory = navigator.deviceMemory || 4, hardwareConcurrency = navigator.hardwareConcurrency || 4;
|
|
2644
|
+
// Hardware Concurrency API (logical CPU cores)
|
|
2645
|
+
// Low-end: ≤2GB RAM OR ≤2 CPU cores
|
|
2646
|
+
return deviceMemory <= 2 || hardwareConcurrency <= 2 ? "low" :
|
|
2647
|
+
// High-end: ≥4GB RAM AND ≥4 CPU cores
|
|
2648
|
+
deviceMemory >= 4 && hardwareConcurrency >= 4 ? "high" : "medium";
|
|
2649
|
+
})();
|
|
2650
|
+
setPerformanceTier(tier), mergedParams = ((baseParams, performanceTier) => {
|
|
2651
|
+
if ("high" === performanceTier) return baseParams;
|
|
2652
|
+
// No adjustment needed
|
|
2653
|
+
const multiplier = "low" === performanceTier ? .7 : .85;
|
|
2654
|
+
return {
|
|
2655
|
+
...baseParams,
|
|
2656
|
+
distortionOctaves: Math.max(2, Math.round((baseParams.distortionOctaves || 5) * multiplier)),
|
|
2657
|
+
displacementScale: (baseParams.displacementScale || 1) * multiplier,
|
|
2658
|
+
blurAmount: (baseParams.blurAmount || 1) * multiplier,
|
|
2659
|
+
animationSpeed: (baseParams.animationSpeed || 1) * multiplier,
|
|
2660
|
+
chromaticIntensity: (baseParams.chromaticIntensity || 1) * multiplier
|
|
2661
|
+
};
|
|
2662
|
+
})(mergedParams, tier);
|
|
2663
|
+
}
|
|
2664
|
+
setResponsiveParams(mergedParams);
|
|
2665
|
+
}), [ enabled, enablePerformanceAdjustment, debug ]), debouncedCalculate = (func => {
|
|
2666
|
+
const timeoutRef = useRef(null);
|
|
2667
|
+
return useEffect((() => () => {
|
|
2668
|
+
timeoutRef.current && clearTimeout(timeoutRef.current);
|
|
2669
|
+
}), []), useCallback(((...args) => {
|
|
2670
|
+
timeoutRef.current && clearTimeout(timeoutRef.current), timeoutRef.current = setTimeout((() => {
|
|
2671
|
+
func(...args);
|
|
2672
|
+
}), 200);
|
|
2673
|
+
}), [ func, 200 ]);
|
|
2674
|
+
})(calculateParams);
|
|
2675
|
+
/**
|
|
2676
|
+
* Debounced parameter calculation for resize events
|
|
2677
|
+
*/
|
|
2678
|
+
/**
|
|
2679
|
+
* Handle window resize
|
|
2680
|
+
*/
|
|
2681
|
+
useEffect((() => {
|
|
2682
|
+
if (enabled)
|
|
2683
|
+
// Cleanup
|
|
2684
|
+
// Initial calculation
|
|
2685
|
+
return calculateParams(),
|
|
2686
|
+
// Listen for resize events
|
|
2687
|
+
window.addEventListener("resize", debouncedCalculate), () => {
|
|
2688
|
+
window.removeEventListener("resize", debouncedCalculate);
|
|
2689
|
+
};
|
|
2690
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2691
|
+
}), [ enabled ]), useCallback((() => {
|
|
2692
|
+
calculateParams();
|
|
2693
|
+
}), [ calculateParams ]);
|
|
2694
|
+
}
|
|
2695
|
+
/**
|
|
2696
|
+
* Get GPU memory info if available (Chrome DevTools only)
|
|
2697
|
+
*/ ({
|
|
2698
|
+
baseParams: {
|
|
2699
|
+
...useMemo((() =>
|
|
2700
|
+
/**
|
|
2701
|
+
* Get preset by name
|
|
2702
|
+
*/
|
|
2703
|
+
function(presetName) {
|
|
2704
|
+
switch (presetName) {
|
|
2705
|
+
case "performance":
|
|
2706
|
+
return PERFORMANCE_PRESET;
|
|
2707
|
+
|
|
2708
|
+
case "balanced":
|
|
2709
|
+
default:
|
|
2710
|
+
return BALANCED_PRESET;
|
|
2711
|
+
|
|
2712
|
+
case "quality":
|
|
2713
|
+
return QUALITY_PRESET;
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
/**
|
|
2717
|
+
* Mobile-optimized responsive breakpoints
|
|
2718
|
+
* Automatically applies appropriate presets based on viewport size
|
|
2719
|
+
*/ (devicePreset)), [ devicePreset ]),
|
|
2720
|
+
distortionOctaves: Math.round((displacementScale || ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE) / 25),
|
|
2721
|
+
displacementScale: displacementScale || ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE,
|
|
2722
|
+
blurAmount: blurAmount || ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT,
|
|
2723
|
+
saturation: saturation || ATOMIX_GLASS.DEFAULTS.SATURATION,
|
|
2724
|
+
aberrationIntensity: aberrationIntensity || ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY,
|
|
2725
|
+
animationSpeed: 1,
|
|
2726
|
+
chromaticIntensity: aberrationIntensity || ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY
|
|
2727
|
+
},
|
|
2728
|
+
breakpoints: MOBILE_OPTIMIZED_BREAKPOINTS,
|
|
2729
|
+
enabled: !disableResponsiveBreakpoints && "undefined" != typeof window,
|
|
2730
|
+
// Enable unless disabled
|
|
2731
|
+
debug: !1
|
|
2732
|
+
});
|
|
2733
|
+
// Performance monitoring - tracks FPS, frame time, memory usage
|
|
2734
|
+
const {metrics: performanceMetrics, recommendedQuality: recommendedQuality, isUnderperforming: isUnderperforming, setQualityLevel: setQualityLevel, toggleMonitoring: toggleMonitoring} =
|
|
2735
|
+
/**
|
|
2736
|
+
* Performance Monitor Hook
|
|
2737
|
+
*
|
|
2738
|
+
* Real-time performance tracking with automatic quality scaling.
|
|
2739
|
+
* Monitors FPS, frame time, and GPU memory to optimize glass effects.
|
|
2740
|
+
*
|
|
2741
|
+
* Features:
|
|
2742
|
+
* - Real-time FPS measurement
|
|
2743
|
+
* - Frame timing analysis
|
|
2744
|
+
* - Automatic quality scaling
|
|
2745
|
+
* - Debug overlay option
|
|
2746
|
+
* - Manual override capability
|
|
2747
|
+
*
|
|
2748
|
+
* @example
|
|
2749
|
+
* ```typescript
|
|
2750
|
+
* const { metrics, recommendedQuality, setQualityLevel } = usePerformanceMonitor({
|
|
2751
|
+
* targetFps: 60,
|
|
2752
|
+
* minFps: 45,
|
|
2753
|
+
* debug: true,
|
|
2754
|
+
* });
|
|
2755
|
+
* ```
|
|
2756
|
+
*
|
|
2757
|
+
* @param config Monitor configuration
|
|
2758
|
+
* @returns Performance metrics and controls
|
|
2759
|
+
*/
|
|
2760
|
+
function(config = {}) {
|
|
2761
|
+
const {enabled: enabled = !0, targetFps: targetFps = 60, minFps: minFps = 45, scaleUpThreshold: scaleUpThreshold = 58, lowFpsFrames: lowFpsFrames = 3, highFpsFrames: highFpsFrames = 10, debug: debug = !1, showOverlay: showOverlay = !1} = config, [metrics, setMetrics] = useState({
|
|
2762
|
+
fps: 0,
|
|
2763
|
+
frameTime: 0,
|
|
2764
|
+
gpuMemory: null,
|
|
2765
|
+
qualityLevel: "medium",
|
|
2766
|
+
timestamp: 0,
|
|
2767
|
+
isAutoScaling: !0,
|
|
2768
|
+
lowFpsCount: 0
|
|
2769
|
+
}), [manualOverride, setManualOverride] = useState(!1), [isEnabled, setIsEnabled] = useState(enabled), frameCountRef = useRef(0), lastFpsUpdateRef = useRef(0), lastFrameTimeRef = useRef(0), animationFrameRef = useRef(null), lowFpsCountRef = useRef(0), highFpsCountRef = useRef(0), qualityLevelRef = useRef("medium"), updateMetrics = useCallback((newMetrics => {
|
|
2770
|
+
setMetrics((prev => ({
|
|
2771
|
+
...prev,
|
|
2772
|
+
...newMetrics,
|
|
2773
|
+
timestamp: performance.now()
|
|
2774
|
+
})));
|
|
2775
|
+
}), []), applyAutoScaling = useCallback((currentFps => {
|
|
2776
|
+
if (manualOverride) return;
|
|
2777
|
+
const currentQuality = qualityLevelRef.current;
|
|
2778
|
+
// Check for low FPS
|
|
2779
|
+
if (currentFps < minFps) lowFpsCountRef.current++, highFpsCountRef.current = 0,
|
|
2780
|
+
// Scale down after N consecutive low-FPS frames
|
|
2781
|
+
lowFpsCountRef.current >= lowFpsFrames && "low" !== currentQuality && (qualityLevelRef.current = "low",
|
|
2782
|
+
updateMetrics({
|
|
2783
|
+
qualityLevel: "low",
|
|
2784
|
+
lowFpsCount: lowFpsCountRef.current
|
|
2785
|
+
})); else if (currentFps >= scaleUpThreshold) {
|
|
2786
|
+
// Scale up after N consecutive high-FPS frames
|
|
2787
|
+
if (highFpsCountRef.current++, lowFpsCountRef.current = 0, highFpsCountRef.current >= highFpsFrames) {
|
|
2788
|
+
const newQuality = "low" === currentQuality ? "medium" : "high";
|
|
2789
|
+
qualityLevelRef.current = newQuality, updateMetrics({
|
|
2790
|
+
qualityLevel: newQuality,
|
|
2791
|
+
lowFpsCount: 0
|
|
2792
|
+
}), highFpsCountRef.current = 0;
|
|
2793
|
+
}
|
|
2794
|
+
} else
|
|
2795
|
+
// FPS in normal range, reset counters
|
|
2796
|
+
lowFpsCountRef.current = 0, highFpsCountRef.current = 0;
|
|
2797
|
+
}), [ manualOverride, minFps, scaleUpThreshold, lowFpsFrames, highFpsFrames, debug, updateMetrics ]), measureFrame = useCallback((currentTime => {
|
|
2798
|
+
if (!isEnabled) return;
|
|
2799
|
+
frameCountRef.current++;
|
|
2800
|
+
// Calculate frame time
|
|
2801
|
+
const frameTime = currentTime - lastFrameTimeRef.current;
|
|
2802
|
+
// Update FPS every 100ms for responsiveness
|
|
2803
|
+
if (lastFrameTimeRef.current = currentTime, currentTime - lastFpsUpdateRef.current >= 100) {
|
|
2804
|
+
const elapsed = currentTime - lastFpsUpdateRef.current, fps = Math.round(1e3 * frameCountRef.current / elapsed);
|
|
2805
|
+
// Apply auto-scaling
|
|
2806
|
+
applyAutoScaling(fps), updateMetrics({
|
|
2807
|
+
fps: fps,
|
|
2808
|
+
frameTime: frameTime,
|
|
2809
|
+
qualityLevel: qualityLevelRef.current,
|
|
2810
|
+
lowFpsCount: lowFpsCountRef.current
|
|
2811
|
+
}),
|
|
2812
|
+
// Reset for next measurement period
|
|
2813
|
+
frameCountRef.current = 0, lastFpsUpdateRef.current = currentTime;
|
|
2814
|
+
}
|
|
2815
|
+
// Continue measurement loop
|
|
2816
|
+
animationFrameRef.current = requestAnimationFrame(measureFrame);
|
|
2817
|
+
}), [ isEnabled, applyAutoScaling, updateMetrics ]);
|
|
2818
|
+
/**
|
|
2819
|
+
* Initialize GPU memory tracking
|
|
2820
|
+
*/
|
|
2821
|
+
useEffect((() => {
|
|
2822
|
+
if (!isEnabled || "undefined" == typeof window) return;
|
|
2823
|
+
let mounted = !0;
|
|
2824
|
+
return (async () => {
|
|
2825
|
+
const memory = await new Promise((resolve => {
|
|
2826
|
+
// Check for WebGL debug renderer info
|
|
2827
|
+
if ("undefined" != typeof window && "undefined" != typeof document) try {
|
|
2828
|
+
const canvas = document.createElement("canvas"), gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
|
|
2829
|
+
if (gl) {
|
|
2830
|
+
const debugInfo = gl.getExtension("WEBGL_debug_renderer_info");
|
|
2831
|
+
if (debugInfo) {
|
|
2832
|
+
var _context, _context2, _context3;
|
|
2833
|
+
// Note: Actual memory info is not directly available via WebGL
|
|
2834
|
+
// We estimate based on renderer
|
|
2835
|
+
const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
|
|
2836
|
+
// Rough estimation based on renderer type
|
|
2837
|
+
return void ((null == (_context = renderer) ? void 0 : Function.call.bind(_includesInstanceProperty(_context), _context))?.("Integrated") ? resolve(256) : (null == (_context2 = renderer) ? void 0 : Function.call.bind(_includesInstanceProperty(_context2), _context2))?.("AMD") || (null == (_context3 = renderer) ? void 0 : Function.call.bind(_includesInstanceProperty(_context3), _context3))?.("NVIDIA") ? resolve(512) : resolve(null));
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
} catch (e) {
|
|
2841
|
+
// WebGL not available or error occurred
|
|
2842
|
+
}
|
|
2843
|
+
resolve(null);
|
|
2844
|
+
}));
|
|
2845
|
+
mounted && updateMetrics({
|
|
2846
|
+
gpuMemory: memory
|
|
2847
|
+
});
|
|
2848
|
+
})(), () => {
|
|
2849
|
+
mounted = !1;
|
|
2850
|
+
};
|
|
2851
|
+
}), [ isEnabled, updateMetrics ]),
|
|
2852
|
+
/**
|
|
2853
|
+
* Start/stop monitoring based on enabled state
|
|
2854
|
+
*/
|
|
2855
|
+
useEffect((() => {
|
|
2856
|
+
if (isEnabled)
|
|
2857
|
+
// Cleanup
|
|
2858
|
+
// Initialize
|
|
2859
|
+
return lastFpsUpdateRef.current = performance.now(), lastFrameTimeRef.current = performance.now(),
|
|
2860
|
+
animationFrameRef.current = requestAnimationFrame(measureFrame), () => {
|
|
2861
|
+
null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
|
|
2862
|
+
animationFrameRef.current = null);
|
|
2863
|
+
};
|
|
2864
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2865
|
+
null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
|
|
2866
|
+
animationFrameRef.current = null);
|
|
2867
|
+
}), [ isEnabled ]);
|
|
2868
|
+
// measureFrame is stable via useCallback, avoid re-creating RAF loop
|
|
2869
|
+
/**
|
|
2870
|
+
* Manually set quality level (disables auto-scaling)
|
|
2871
|
+
*/
|
|
2872
|
+
const setQualityLevel = useCallback((level => {
|
|
2873
|
+
setManualOverride(!0), qualityLevelRef.current = level, updateMetrics({
|
|
2874
|
+
qualityLevel: level,
|
|
2875
|
+
isAutoScaling: !1
|
|
2876
|
+
});
|
|
2877
|
+
}), [ updateMetrics, debug ]), resetAutoScaling = useCallback((() => {
|
|
2878
|
+
setManualOverride(!1), lowFpsCountRef.current = 0, highFpsCountRef.current = 0,
|
|
2879
|
+
updateMetrics({
|
|
2880
|
+
isAutoScaling: !0,
|
|
2881
|
+
lowFpsCount: 0
|
|
2882
|
+
});
|
|
2883
|
+
}), [ updateMetrics, debug ]), toggleMonitoring = useCallback((() => {
|
|
2884
|
+
setIsEnabled((prev => !prev));
|
|
2885
|
+
}), []);
|
|
2886
|
+
/**
|
|
2887
|
+
* Reset to auto-scaling mode
|
|
2888
|
+
*/ var fps, currentQuality;
|
|
2889
|
+
return {
|
|
2890
|
+
metrics: metrics,
|
|
2891
|
+
recommendedQuality: (fps = metrics.fps, currentQuality = metrics.qualityLevel, fps >= 58 ? "high" : fps >= 45 ? "high" === currentQuality ? "high" : "medium" : "low"),
|
|
2892
|
+
isUnderperforming: metrics.fps < minFps,
|
|
2893
|
+
setQualityLevel: setQualityLevel,
|
|
2894
|
+
resetAutoScaling: resetAutoScaling,
|
|
2895
|
+
toggleMonitoring: toggleMonitoring
|
|
2896
|
+
};
|
|
2897
|
+
}({
|
|
2898
|
+
enabled: !1,
|
|
2899
|
+
// We'll toggle manually based on prop
|
|
2900
|
+
debug: !1,
|
|
2901
|
+
showOverlay: !1
|
|
2902
|
+
});
|
|
2903
|
+
// Auto-start performance monitoring if enabled (only in development)
|
|
2904
|
+
React.useEffect((() => {
|
|
2905
|
+
"development" === process.env.NODE_ENV && window?.enablePerformanceMonitoring && toggleMonitoring();
|
|
2906
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2907
|
+
}), []);
|
|
2908
|
+
// Only run once on mount
|
|
2909
|
+
const isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, rootLayoutStyle = useMemo((() => {
|
|
1917
2910
|
if (!isFixedOrSticky) return {};
|
|
1918
2911
|
const {position: p, top: t, left: l, right: r, bottom: b} = restStyle;
|
|
1919
2912
|
return {
|
|
@@ -1933,7 +2926,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
1933
2926
|
bottom: b
|
|
1934
2927
|
}
|
|
1935
2928
|
};
|
|
1936
|
-
}), [ isFixedOrSticky, restStyle ])
|
|
2929
|
+
}), [ isFixedOrSticky, restStyle ]);
|
|
2930
|
+
// Calculate base style with transforms
|
|
2931
|
+
// When layout is hoisted to the root, strip those props from the container
|
|
2932
|
+
useMemo((() => {
|
|
1937
2933
|
if (isFixedOrSticky) {
|
|
1938
2934
|
const {position: _p, top: _t, left: _l, right: _r, bottom: _b, ...visualStyle} = restStyle;
|
|
1939
2935
|
return {
|
|
@@ -1949,18 +2945,20 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
1949
2945
|
transform: transformStyle
|
|
1950
2946
|
}
|
|
1951
2947
|
};
|
|
1952
|
-
}), [ isFixedOrSticky, restStyle, effectiveWithoutEffects, transformStyle ])
|
|
2948
|
+
}), [ isFixedOrSticky, restStyle, effectiveWithoutEffects, transformStyle ]);
|
|
2949
|
+
// Build className with state modifiers
|
|
2950
|
+
const componentClassName = [ ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`, effectiveWithoutEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`, className ].filter(Boolean).join(" "), positionStyles = useMemo((() => ({
|
|
1953
2951
|
position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
|
|
1954
2952
|
top: isFixedOrSticky ? 0 : restStyle.top || 0,
|
|
1955
2953
|
left: isFixedOrSticky ? 0 : restStyle.left || 0
|
|
1956
2954
|
})), [ isFixedOrSticky, restStyle.position, restStyle.top, restStyle.left ]), adjustedSize = useMemo((() => {
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
};
|
|
2955
|
+
// Keep a reference to positionStyles to avoid unused-variable lint,
|
|
2956
|
+
// but sizing is driven by explicit width/height or measured size.
|
|
2957
|
+
positionStyles.position;
|
|
2958
|
+
const resolveLength = (value, measured) => void 0 !== value ? "number" == typeof value ? `${value}px` : value : measured > 0 ? `${measured}px` : "100%", effectiveWidth = width ?? restStyle.width, effectiveHeight = height ?? restStyle.height;
|
|
1961
2959
|
return {
|
|
1962
|
-
width:
|
|
1963
|
-
height:
|
|
2960
|
+
width: resolveLength(effectiveWidth, glassSize.width),
|
|
2961
|
+
height: resolveLength(effectiveHeight, glassSize.height)
|
|
1964
2962
|
};
|
|
1965
2963
|
}), [ width, height, restStyle.width, restStyle.height, positionStyles.position, glassSize.width, glassSize.height ]), gradientValues = useMemo((() => {
|
|
1966
2964
|
const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT;
|
|
@@ -2009,9 +3007,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
2009
3007
|
},
|
|
2010
3008
|
"--atomix-glass-radius": `${effectiveBorderRadius}px`,
|
|
2011
3009
|
"--atomix-glass-transform": transformStyle || "none",
|
|
2012
|
-
|
|
2013
|
-
"--atomix-glass-
|
|
2014
|
-
"--atomix-glass-
|
|
3010
|
+
// Internal decorative layers are positioned relative to the root;
|
|
3011
|
+
"--atomix-glass-position": rootLayoutStyle.position,
|
|
3012
|
+
"--atomix-glass-top": `${isFixedOrSticky ? rootLayoutStyle.top : 0}px`,
|
|
3013
|
+
"--atomix-glass-left": `${isFixedOrSticky ? rootLayoutStyle.left : 0}px`,
|
|
2015
3014
|
"--atomix-glass-width": adjustedSize.width,
|
|
2016
3015
|
"--atomix-glass-height": adjustedSize.height,
|
|
2017
3016
|
"--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
|
|
@@ -2031,10 +3030,12 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
2031
3030
|
"--atomix-glass-overlay-highlight-opacity": opacityValues.over * ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER,
|
|
2032
3031
|
"--atomix-glass-overlay-highlight-bg": `radial-gradient(circle at ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_X}% ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_Y}%, rgba(255, 255, 255, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.WHITE_OPACITY}) 0%, transparent ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.STOP}%)`
|
|
2033
3032
|
};
|
|
2034
|
-
}), [ gradientValues, opacityValues, effectiveBorderRadius, transformStyle,
|
|
3033
|
+
}), [ gradientValues, opacityValues, effectiveBorderRadius, transformStyle, adjustedSize, isOverLight, overLightConfig.borderOpacity, customZIndex, rootLayoutStyle, isFixedOrSticky ]), renderBackgroundLayer = layerType => jsx("div", {
|
|
2035
3034
|
className: [ ATOMIX_GLASS.BACKGROUND_LAYER_CLASS, "dark" === layerType ? ATOMIX_GLASS.BACKGROUND_LAYER_DARK_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_BLACK_CLASS, isOverLight ? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS ].filter(Boolean).join(" ")
|
|
2036
3035
|
});
|
|
2037
|
-
|
|
3036
|
+
// Calculate position and size styles for internal layers
|
|
3037
|
+
// When root is fixed/sticky, internal layers use absolute (relative to root)
|
|
3038
|
+
return jsxs("div", {
|
|
2038
3039
|
...rest,
|
|
2039
3040
|
className: componentClassName,
|
|
2040
3041
|
style: {
|
|
@@ -2051,7 +3052,12 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
2051
3052
|
ref: glassRef,
|
|
2052
3053
|
contentRef: contentRef,
|
|
2053
3054
|
className: className,
|
|
2054
|
-
style:
|
|
3055
|
+
style: {
|
|
3056
|
+
...restStyle,
|
|
3057
|
+
...!isFixedOrSticky && {
|
|
3058
|
+
position: "relative"
|
|
3059
|
+
}
|
|
3060
|
+
},
|
|
2055
3061
|
borderRadius: effectiveBorderRadius,
|
|
2056
3062
|
displacementScale: effectiveWithoutEffects ? 0 : "shader" === mode ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_DISPLACEMENT : isOverLight ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.OVER_LIGHT_DISPLACEMENT : displacementScale,
|
|
2057
3063
|
blurAmount: effectiveWithoutEffects ? 0 : blurAmount,
|
|
@@ -2082,11 +3088,19 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
2082
3088
|
},
|
|
2083
3089
|
onClick: onClick,
|
|
2084
3090
|
mode: mode,
|
|
2085
|
-
transform: baseStyle.transform,
|
|
2086
3091
|
effectiveWithoutEffects: effectiveWithoutEffects,
|
|
2087
3092
|
effectiveReducedMotion: effectiveReducedMotion,
|
|
2088
3093
|
shaderVariant: shaderVariant,
|
|
2089
3094
|
withLiquidBlur: withLiquidBlur,
|
|
3095
|
+
// Phase 1: Animation System props
|
|
3096
|
+
shaderTime: getShaderTime(),
|
|
3097
|
+
withTimeAnimation: withTimeAnimation,
|
|
3098
|
+
animationSpeed: animationSpeed,
|
|
3099
|
+
withMultiLayerDistortion: withMultiLayerDistortion,
|
|
3100
|
+
distortionOctaves: distortionOctaves,
|
|
3101
|
+
distortionLacunarity: distortionLacunarity,
|
|
3102
|
+
distortionGain: distortionGain,
|
|
3103
|
+
distortionQuality: distortionQuality,
|
|
2090
3104
|
children: children
|
|
2091
3105
|
}), Boolean(onClick) && jsxs(Fragment, {
|
|
2092
3106
|
children: [ jsx("div", {
|
|
@@ -2110,6 +3124,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
|
|
|
2110
3124
|
}), jsx("span", {
|
|
2111
3125
|
className: ATOMIX_GLASS.BORDER_2_CLASS
|
|
2112
3126
|
}) ]
|
|
3127
|
+
}), debugPerformance && performanceMetrics && jsx(PerformanceDashboard, {
|
|
3128
|
+
metrics: performanceMetrics,
|
|
3129
|
+
isVisible: !0,
|
|
3130
|
+
onClose: () => {}
|
|
2113
3131
|
}) ]
|
|
2114
3132
|
});
|
|
2115
3133
|
}
|
|
@@ -2176,7 +3194,7 @@ const AccordionBody = forwardRef((({children: children, className: className =
|
|
|
2176
3194
|
|
|
2177
3195
|
AccordionBody.displayName = "AccordionBody";
|
|
2178
3196
|
|
|
2179
|
-
const AccordionImpl = memo((({title: title, children: children, defaultOpen: defaultOpen = !1, isOpen: controlledOpen, onOpenChange: onOpenChange,
|
|
3197
|
+
const AccordionImpl = memo((({title: title, children: children, defaultOpen: defaultOpen = !1, isOpen: controlledOpen, onOpenChange: onOpenChange, disabled: disabled = !1, iconPosition: iconPosition = "right", icon: icon, className: className = "", style: style, glass: glass}) => {
|
|
2180
3198
|
// Generate unique IDs for accessibility
|
|
2181
3199
|
const instanceId = useId(), buttonId = `accordion-header-${instanceId}`, panelId = `accordion-panel-${instanceId}`, {state: state, toggle: toggle, updatePanelHeight: updatePanelHeight, panelRef: panelRef, contentRef: contentRef, generateClassNames: generateClassNames, generateHeaderClassNames: generateHeaderClassNames} =
|
|
2182
3200
|
/**
|
|
@@ -2220,9 +3238,7 @@ const AccordionImpl = memo((({title: title, children: children, defaultOpen: de
|
|
|
2220
3238
|
toggle: () => {
|
|
2221
3239
|
if (!defaultProps.disabled) {
|
|
2222
3240
|
const nextOpen = !isOpen;
|
|
2223
|
-
isControlled || setInternalOpen(nextOpen), defaultProps.onOpenChange?.(nextOpen)
|
|
2224
|
-
// Call legacy handlers
|
|
2225
|
-
nextOpen ? defaultProps.onOpen?.() : defaultProps.onClose?.();
|
|
3241
|
+
isControlled || setInternalOpen(nextOpen), defaultProps.onOpenChange?.(nextOpen);
|
|
2226
3242
|
}
|
|
2227
3243
|
},
|
|
2228
3244
|
updatePanelHeight: updatePanelHeight,
|
|
@@ -2236,9 +3252,7 @@ const AccordionImpl = memo((({title: title, children: children, defaultOpen: de
|
|
|
2236
3252
|
disabled: disabled,
|
|
2237
3253
|
iconPosition: iconPosition,
|
|
2238
3254
|
isOpen: controlledOpen,
|
|
2239
|
-
onOpenChange: onOpenChange
|
|
2240
|
-
onOpen: onOpen,
|
|
2241
|
-
onClose: onClose
|
|
3255
|
+
onOpenChange: onOpenChange
|
|
2242
3256
|
}), headerClassNames = generateHeaderClassNames(), panelClassNames = ACCORDION.SELECTORS.PANEL.replace(".", ""), hasCompoundComponents = React.Children.toArray(children).some((child => {
|
|
2243
3257
|
var _context;
|
|
2244
3258
|
|
|
@@ -2762,7 +3776,7 @@ class ThemeNaming {
|
|
|
2762
3776
|
ThemeNaming.prefix = "atomix";
|
|
2763
3777
|
|
|
2764
3778
|
const Button = React.memo( forwardRef((({label: label, children: children, onClick: onClick, variant: variant = "primary", size: size = "md", disabled: disabled = !1, loading: loading = !1, loadingText: loadingText, icon: icon, iconName: iconName, iconSize: iconSize = "sm", iconPosition: iconPosition = "start", iconOnly: iconOnly = !1, rounded: rounded = !1, fullWidth: fullWidth = !1, block: block = !1, active: active = !1, selected: selected = !1, type: type = "button", className: className = "", as: Component = "button", href: href, target: target, glass: glass, onHover: onHover, onFocus: onFocus, onBlur: onBlur, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, "aria-expanded": ariaExpanded, "aria-controls": ariaControls, tabIndex: tabIndex, style: style, linkComponent: linkComponent, ...props}, ref) => {
|
|
2765
|
-
const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href
|
|
3779
|
+
const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href), iconElement = iconName ? jsx(Icon, {
|
|
2766
3780
|
name: iconName,
|
|
2767
3781
|
size: iconSize
|
|
2768
3782
|
}) : icon, buttonClass = [ BUTTON.BASE_CLASS, ThemeNaming.variantClass("btn", variant), "md" !== size ? ThemeNaming.sizeClass("btn", size) : "", iconOnly ? ThemeNaming.stateClass("btn", "icon") : "", rounded ? ThemeNaming.stateClass("btn", "rounded") : "", isDisabled ? ThemeNaming.stateClass("btn", "disabled") : "", glass ? ThemeNaming.stateClass("btn", "glass") : "", loading ? BUTTON.CLASSES.LOADING : "", fullWidth ? BUTTON.CLASSES.FULL_WIDTH : "", block ? BUTTON.CLASSES.BLOCK : "", active ? BUTTON.CLASSES.ACTIVE : "", selected ? BUTTON.CLASSES.SELECTED : "", className ].filter(Boolean).join(" "), handleClickEvent = useCallback((event => {
|
|
@@ -2818,8 +3832,8 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
|
|
|
2818
3832
|
...buttonProps,
|
|
2819
3833
|
ref: ref,
|
|
2820
3834
|
// linkComponent usually forwards ref to anchor
|
|
2821
|
-
href: href,
|
|
2822
|
-
to: href,
|
|
3835
|
+
href: isDisabled ? void 0 : href,
|
|
3836
|
+
to: isDisabled ? void 0 : href,
|
|
2823
3837
|
target: target,
|
|
2824
3838
|
rel: "_blank" === target ? "noopener noreferrer" : void 0
|
|
2825
3839
|
};
|
|
@@ -2832,7 +3846,7 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
|
|
|
2832
3846
|
content = jsx("a", {
|
|
2833
3847
|
...buttonProps,
|
|
2834
3848
|
ref: ref,
|
|
2835
|
-
href: href,
|
|
3849
|
+
href: isDisabled ? void 0 : href,
|
|
2836
3850
|
target: target,
|
|
2837
3851
|
rel: "_blank" === target ? "noopener noreferrer" : void 0,
|
|
2838
3852
|
children: buttonContent
|
|
@@ -2874,7 +3888,7 @@ row: row = !1, flat: flat = !1,
|
|
|
2874
3888
|
// States
|
|
2875
3889
|
active: active = !1, disabled: disabled = !1, loading: loading = !1, selected: selected = !1, interactive: interactive = !1,
|
|
2876
3890
|
// Content
|
|
2877
|
-
header: header, image: image, imageAlt: imageAlt = "", title: title, text: text, actions: actions, icon: icon, footer: footer, children: children,
|
|
3891
|
+
header: header, image: image, imageAlt: imageAlt = "Card image", title: title, text: text, actions: actions, icon: icon, footer: footer, children: children,
|
|
2878
3892
|
// Interaction
|
|
2879
3893
|
onClick: onClick, onHover: onHover, onFocus: onFocus, href: href, target: target,
|
|
2880
3894
|
// Custom Link
|
|
@@ -3679,7 +4693,9 @@ const smoothStep = (a, b, t) => {
|
|
|
3679
4693
|
return this.canvasDPI;
|
|
3680
4694
|
}
|
|
3681
4695
|
},
|
|
3682
|
-
|
|
4696
|
+
createFBMEngine: createFBMEngine,
|
|
4697
|
+
fragmentShaders: fragmentShaders,
|
|
4698
|
+
liquidGlassWithTime: liquidGlassWithTime
|
|
3683
4699
|
}, Symbol.toStringTag, {
|
|
3684
4700
|
value: "Module"
|
|
3685
4701
|
}));
|