@shohojdhara/atomix 0.6.4 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/atomix.css +117 -38
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +1 -1
- package/dist/atomix.min.css.map +1 -1
- package/dist/atomix.umd.js +1 -1
- package/dist/atomix.umd.js.map +1 -1
- package/dist/atomix.umd.min.js +1 -1
- package/dist/charts.d.ts +30 -1
- package/dist/charts.js +625 -846
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +30 -1
- package/dist/core.js +659 -873
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +30 -1
- package/dist/forms.js +1171 -1402
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +31 -89
- package/dist/heavy.js +975 -1195
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +383 -140
- package/dist/index.esm.js +1567 -1679
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1556 -1667
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Accordion/Accordion.tsx +2 -5
- package/src/components/AtomixGlass/AtomixGlass.test.tsx +14 -16
- package/src/components/AtomixGlass/AtomixGlass.tsx +137 -364
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +32 -251
- package/src/components/AtomixGlass/GlassFilter.tsx +62 -68
- package/src/components/AtomixGlass/README.md +2 -1
- package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +19 -18
- package/src/components/AtomixGlass/glass-border-styles.test.ts +58 -0
- package/src/components/AtomixGlass/glass-border-styles.ts +136 -0
- package/src/components/AtomixGlass/glass-utils.ts +456 -22
- package/src/components/AtomixGlass/shader-utils.ts +19 -77
- package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +158 -537
- package/src/components/AtomixGlass/stories/Border.stories.tsx +149 -0
- package/src/components/AtomixGlass/stories/Examples.stories.tsx +229 -89
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +29 -340
- package/src/components/AtomixGlass/stories/argTypes.ts +30 -13
- package/src/components/AtomixGlass/stories/premium-presets.ts +206 -0
- package/src/components/AtomixGlass/stories/shared-components.tsx +52 -8
- package/src/components/Badge/Badge.tsx +4 -4
- package/src/components/Button/Button.tsx +2 -6
- package/src/components/Callout/Callout.test.tsx +4 -3
- package/src/components/Callout/Callout.tsx +2 -5
- package/src/components/Dropdown/Dropdown.tsx +3 -7
- package/src/components/Form/Checkbox.tsx +2 -8
- package/src/components/Form/Input.tsx +2 -9
- package/src/components/Form/Radio.tsx +2 -9
- package/src/components/Form/Select.test.tsx +6 -6
- package/src/components/Form/Select.tsx +2 -7
- package/src/components/Form/Textarea.stories.tsx +5 -5
- package/src/components/Form/Textarea.tsx +2 -9
- package/src/components/Messages/Messages.tsx +2 -8
- package/src/components/Modal/Modal.tsx +4 -5
- package/src/components/Navigation/Nav/Nav.tsx +2 -6
- package/src/components/Navigation/Navbar/Navbar.tsx +2 -9
- package/src/components/Navigation/SideMenu/SideMenu.tsx +2 -6
- package/src/components/Pagination/Pagination.tsx +2 -10
- package/src/components/Popover/Popover.tsx +2 -9
- package/src/components/Progress/Progress.tsx +2 -7
- package/src/components/Rating/Rating.tsx +2 -10
- package/src/components/Spinner/Spinner.tsx +2 -7
- package/src/components/Steps/Steps.tsx +2 -10
- package/src/components/Tabs/Tabs.tsx +2 -9
- package/src/components/Toggle/Toggle.tsx +2 -10
- package/src/components/Tooltip/Tooltip.tsx +2 -5
- package/src/lib/composables/useAtomixGlass.ts +42 -143
- package/src/lib/composables/useAtomixGlassStyles.ts +61 -77
- package/src/lib/composables/usePerformanceMonitor.ts +5 -66
- package/src/lib/constants/components.ts +363 -46
- package/src/lib/types/components.ts +33 -1
- package/src/styles/01-settings/_settings.atomix-glass.scss +66 -28
- package/src/styles/02-tools/_tools.button.scss +51 -42
- package/src/styles/02-tools/_tools.glass.scss +45 -3
- package/src/styles/06-components/_components.atomix-glass.scss +116 -79
- package/src/components/AtomixGlass/PerformanceDashboard.tsx +0 -171
- package/src/components/AtomixGlass/animation-system.ts +0 -578
- package/src/components/AtomixGlass/deprecated/AtomixGlass.deprecated.tsx +0 -390
package/dist/core.js
CHANGED
|
@@ -516,6 +516,62 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
516
516
|
SIZES: [ "xs", "sm", "md", "lg", "xl", "none" ],
|
|
517
517
|
DEFAULT: "md"
|
|
518
518
|
}
|
|
519
|
+
}, GLASS_DEFAULTS_BUTTON = {
|
|
520
|
+
displacementScale: 16,
|
|
521
|
+
saturation: 180,
|
|
522
|
+
elasticity: 0
|
|
523
|
+
}, GLASS_DEFAULTS_BADGE = {
|
|
524
|
+
displacementScale: 14,
|
|
525
|
+
borderRadius: 16,
|
|
526
|
+
elasticity: 0
|
|
527
|
+
}, GLASS_DEFAULTS_ACCORDION = {
|
|
528
|
+
displacementScale: 18,
|
|
529
|
+
elasticity: 0
|
|
530
|
+
}, GLASS_DEFAULTS_CALLOUT = {
|
|
531
|
+
displacementScale: 22,
|
|
532
|
+
borderRadius: 8,
|
|
533
|
+
elasticity: 0
|
|
534
|
+
}, GLASS_DEFAULTS_SPINNER = {
|
|
535
|
+
displacementScale: 12,
|
|
536
|
+
elasticity: 0
|
|
537
|
+
}, GLASS_BORDER_GRADIENT = {
|
|
538
|
+
BASE_ANGLE: 135,
|
|
539
|
+
ANGLE_MULTIPLIER: .5,
|
|
540
|
+
VELOCITY_ANGLE_MULTIPLIER: .5,
|
|
541
|
+
CHROMATIC_OFFSET: 1.5,
|
|
542
|
+
STOP_1: {
|
|
543
|
+
MIN: 10,
|
|
544
|
+
BASE: 33,
|
|
545
|
+
get MULTIPLIER() {
|
|
546
|
+
return .009 * this.BASE;
|
|
547
|
+
}
|
|
548
|
+
},
|
|
549
|
+
STOP_2: {
|
|
550
|
+
MAX: 90,
|
|
551
|
+
BASE: 66,
|
|
552
|
+
get MULTIPLIER() {
|
|
553
|
+
return .006 * this.BASE;
|
|
554
|
+
}
|
|
555
|
+
},
|
|
556
|
+
OPACITY: {
|
|
557
|
+
/** Matches $glass-border-1-opacity (0.08) */
|
|
558
|
+
BASE_1: .08,
|
|
559
|
+
get BASE_2() {
|
|
560
|
+
return 3.33 * this.BASE_1;
|
|
561
|
+
},
|
|
562
|
+
get BASE_3() {
|
|
563
|
+
return 2.66 * this.BASE_1;
|
|
564
|
+
},
|
|
565
|
+
get BASE_4() {
|
|
566
|
+
return 5 * this.BASE_1;
|
|
567
|
+
},
|
|
568
|
+
get MULTIPLIER_LOW() {
|
|
569
|
+
return .066 * this.BASE_1;
|
|
570
|
+
},
|
|
571
|
+
get MULTIPLIER_HIGH() {
|
|
572
|
+
return .1 * this.BASE_1;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
519
575
|
}, ATOMIX_GLASS = {
|
|
520
576
|
BASE_CLASS: "c-atomix-glass",
|
|
521
577
|
CONTAINER_CLASS: "c-atomix-glass__container",
|
|
@@ -527,6 +583,22 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
527
583
|
BORDER_BACKDROP_CLASS: "c-atomix-glass__border-backdrop",
|
|
528
584
|
BORDER_1_CLASS: "c-atomix-glass__border-1",
|
|
529
585
|
BORDER_2_CLASS: "c-atomix-glass__border-2",
|
|
586
|
+
/** Centralized liquid glass rim configuration */
|
|
587
|
+
BORDER: {
|
|
588
|
+
WIDTH_CSS_VAR: "--atomix-glass-border-width",
|
|
589
|
+
DEFAULT_WIDTH: "0.5px",
|
|
590
|
+
GRADIENT_CSS_VARS: {
|
|
591
|
+
GRADIENT_1: "--atomix-glass-border-gradient-1",
|
|
592
|
+
GRADIENT_2: "--atomix-glass-border-gradient-2"
|
|
593
|
+
},
|
|
594
|
+
GRADIENT: GLASS_BORDER_GRADIENT,
|
|
595
|
+
OVER_LIGHT: {
|
|
596
|
+
opacity: .7
|
|
597
|
+
},
|
|
598
|
+
DARK: {
|
|
599
|
+
opacity: .35
|
|
600
|
+
}
|
|
601
|
+
},
|
|
530
602
|
HOVER_1_CLASS: "c-atomix-glass__hover-1",
|
|
531
603
|
HOVER_2_CLASS: "c-atomix-glass__hover-2",
|
|
532
604
|
HOVER_3_CLASS: "c-atomix-glass__hover-3",
|
|
@@ -555,25 +627,22 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
555
627
|
SHADER: "c-atomix-glass--shader"
|
|
556
628
|
},
|
|
557
629
|
DEFAULTS: {
|
|
558
|
-
|
|
630
|
+
/** Subtle refraction — Apple UI chrome avoids heavy liquid distortion */
|
|
631
|
+
DISPLACEMENT_SCALE: 28,
|
|
559
632
|
get BLUR_AMOUNT() {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
// Saturate relative to intensity
|
|
566
|
-
},
|
|
633
|
+
// Apple Music sidebar / player bar: ~20–40px frost (see $glass-backdrop-filter)
|
|
634
|
+
return Math.max(20, .72 * this.DISPLACEMENT_SCALE);
|
|
635
|
+
},
|
|
636
|
+
/** Fixed 180% matches Apple's saturate(180%) backdrop recipe */
|
|
637
|
+
SATURATION: 180,
|
|
567
638
|
get ABERRATION_INTENSITY() {
|
|
568
|
-
return .
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
ELASTICITY: .15,
|
|
639
|
+
return .02 * this.DISPLACEMENT_SCALE;
|
|
640
|
+
},
|
|
641
|
+
ELASTICITY: .05,
|
|
572
642
|
get CORNER_RADIUS() {
|
|
573
643
|
return 16;
|
|
574
644
|
// Use 16 to match SCSS design system (was 20)
|
|
575
645
|
},
|
|
576
|
-
PADDING: "0",
|
|
577
646
|
MODE: "standard",
|
|
578
647
|
OVER_LIGHT: !1,
|
|
579
648
|
ENABLE_OVER_LIGHT_LAYERS: !0,
|
|
@@ -589,19 +658,29 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
589
658
|
},
|
|
590
659
|
CONSTANTS: {
|
|
591
660
|
ACTIVATION_ZONE: 200,
|
|
592
|
-
LERP_FACTOR: .
|
|
661
|
+
LERP_FACTOR: .05,
|
|
662
|
+
// Lower = more viscous, liquid-smooth tracking (Apple feel)
|
|
593
663
|
SMOOTHSTEP_POWER: 2.5,
|
|
594
664
|
MIN_BLUR: .1,
|
|
595
665
|
MOUSE_INFLUENCE_DIVISOR: 100,
|
|
596
666
|
EDGE_FADE_PIXELS: 2,
|
|
597
|
-
//
|
|
598
|
-
|
|
667
|
+
// Interaction intensity multipliers shared by the hook and the imperative style updater
|
|
668
|
+
INTERACTION: {
|
|
669
|
+
HOVER_INTENSITY: 1.4,
|
|
670
|
+
ACTIVE_INTENSITY: 1.6
|
|
671
|
+
},
|
|
672
|
+
// Elasticity physics constants — Apple-tuned: soft springs, fast settling, minimal stretch
|
|
673
|
+
ELASTICITY_TRANSLATION_FACTOR: .06,
|
|
674
|
+
// Subtler elastic shift (was 0.1)
|
|
599
675
|
ELASTICITY_DISTANCE_THRESHOLD: 200,
|
|
600
676
|
ELASTICITY_COMPRESSION_FACTOR: .3,
|
|
601
|
-
ELASTICITY_STIFFNESS: .
|
|
602
|
-
|
|
677
|
+
ELASTICITY_STIFFNESS: .06,
|
|
678
|
+
// Softer springs = gentler motion (was 0.1)
|
|
679
|
+
ELASTICITY_DAMPING: .88,
|
|
680
|
+
// Fast settling, no wobble (was 0.76)
|
|
603
681
|
ELASTICITY_VELOCITY_FACTOR: .65,
|
|
604
|
-
ELASTICITY_STRETCH_RATIO: .
|
|
682
|
+
ELASTICITY_STRETCH_RATIO: .25,
|
|
683
|
+
// Less visible surface tension stretch (was 0.45)
|
|
605
684
|
ELASTICITY_MAGNIFICATION_BASE: 1.02,
|
|
606
685
|
// Note: This default must match the SCSS variable --atomix-radius-md
|
|
607
686
|
// @see src/styles/01-settings/_settings.global.scss
|
|
@@ -615,55 +694,16 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
615
694
|
},
|
|
616
695
|
// Gradient calculation constants
|
|
617
696
|
GRADIENT: {
|
|
618
|
-
BASE_ANGLE:
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
// Minimum percentage for border stop 1
|
|
629
|
-
BASE: 33,
|
|
630
|
-
// Base percentage for border stop 1
|
|
631
|
-
get MULTIPLIER() {
|
|
632
|
-
return .009 * this.BASE;
|
|
633
|
-
}
|
|
634
|
-
},
|
|
635
|
-
BORDER_STOP_2: {
|
|
636
|
-
MAX: 90,
|
|
637
|
-
// Maximum percentage for border stop 2
|
|
638
|
-
BASE: 66,
|
|
639
|
-
// Base percentage for border stop 2
|
|
640
|
-
get MULTIPLIER() {
|
|
641
|
-
return .006 * this.BASE;
|
|
642
|
-
}
|
|
643
|
-
},
|
|
644
|
-
BORDER_OPACITY: {
|
|
645
|
-
BASE_1: .12,
|
|
646
|
-
// Base opacity for border gradient 1
|
|
647
|
-
get BASE_2() {
|
|
648
|
-
return 3.33 * this.BASE_1;
|
|
649
|
-
},
|
|
650
|
-
// Base opacity for border gradient 2
|
|
651
|
-
get BASE_3() {
|
|
652
|
-
return 2.66 * this.BASE_1;
|
|
653
|
-
},
|
|
654
|
-
// Base opacity for border gradient 3
|
|
655
|
-
get BASE_4() {
|
|
656
|
-
return 5 * this.BASE_1;
|
|
657
|
-
},
|
|
658
|
-
// Base opacity for border gradient 4
|
|
659
|
-
get MULTIPLIER_LOW() {
|
|
660
|
-
return .066 * this.BASE_1;
|
|
661
|
-
},
|
|
662
|
-
// Low multiplier for mouse influence on opacity
|
|
663
|
-
get MULTIPLIER_HIGH() {
|
|
664
|
-
return .1 * this.BASE_1;
|
|
665
|
-
}
|
|
666
|
-
},
|
|
697
|
+
BASE_ANGLE: GLASS_BORDER_GRADIENT.BASE_ANGLE,
|
|
698
|
+
ANGLE_MULTIPLIER: GLASS_BORDER_GRADIENT.ANGLE_MULTIPLIER,
|
|
699
|
+
VELOCITY_ANGLE_MULTIPLIER: GLASS_BORDER_GRADIENT.VELOCITY_ANGLE_MULTIPLIER,
|
|
700
|
+
CHROMATIC_OFFSET: GLASS_BORDER_GRADIENT.CHROMATIC_OFFSET,
|
|
701
|
+
/** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.STOP_1 */
|
|
702
|
+
BORDER_STOP_1: GLASS_BORDER_GRADIENT.STOP_1,
|
|
703
|
+
/** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.STOP_2 */
|
|
704
|
+
BORDER_STOP_2: GLASS_BORDER_GRADIENT.STOP_2,
|
|
705
|
+
/** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.OPACITY */
|
|
706
|
+
BORDER_OPACITY: GLASS_BORDER_GRADIENT.OPACITY,
|
|
667
707
|
CENTER_POSITION: 50,
|
|
668
708
|
// Center position percentage (50%)
|
|
669
709
|
HOVER_POSITION: {
|
|
@@ -696,8 +736,8 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
696
736
|
return 2 * this.BLACK_STOP;
|
|
697
737
|
},
|
|
698
738
|
// End percentage for black hover 1
|
|
699
|
-
WHITE_START: .
|
|
700
|
-
//
|
|
739
|
+
WHITE_START: .35,
|
|
740
|
+
// Gentler hover flash — Apple hover is barely visible
|
|
701
741
|
get WHITE_STOP() {
|
|
702
742
|
return this.BLACK_END - 10;
|
|
703
743
|
}
|
|
@@ -715,8 +755,8 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
715
755
|
return 2 * this.BLACK_STOP;
|
|
716
756
|
},
|
|
717
757
|
// End percentage for black hover 2
|
|
718
|
-
WHITE_START:
|
|
719
|
-
//
|
|
758
|
+
WHITE_START: .7,
|
|
759
|
+
// Gentler hover flash
|
|
720
760
|
get WHITE_STOP() {
|
|
721
761
|
return this.BLACK_END;
|
|
722
762
|
}
|
|
@@ -734,8 +774,8 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
734
774
|
return 2 * this.BLACK_STOP;
|
|
735
775
|
},
|
|
736
776
|
// End percentage for black hover 3
|
|
737
|
-
WHITE_START:
|
|
738
|
-
//
|
|
777
|
+
WHITE_START: .7,
|
|
778
|
+
// Gentler hover flash
|
|
739
779
|
get WHITE_STOP() {
|
|
740
780
|
return this.BLACK_END;
|
|
741
781
|
}
|
|
@@ -745,13 +785,13 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
745
785
|
BASE_GRADIENT: {
|
|
746
786
|
ANGLE: 135,
|
|
747
787
|
// Gradient angle in degrees
|
|
748
|
-
BLACK_START_BASE: .
|
|
788
|
+
BLACK_START_BASE: .1,
|
|
749
789
|
// Base start opacity for black
|
|
750
790
|
get BLACK_START_MULTIPLIER() {
|
|
751
791
|
return .02 * this.BLACK_START_BASE;
|
|
752
792
|
},
|
|
753
793
|
// Multiplier for mouse X influence on start
|
|
754
|
-
BLACK_MID_BASE: .
|
|
794
|
+
BLACK_MID_BASE: .07,
|
|
755
795
|
// Base mid opacity for black
|
|
756
796
|
get BLACK_MID_MULTIPLIER() {
|
|
757
797
|
return .02 * this.BLACK_MID_BASE;
|
|
@@ -772,7 +812,7 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
772
812
|
}
|
|
773
813
|
},
|
|
774
814
|
OVERLAY_GRADIENT: {
|
|
775
|
-
BLACK_START_BASE: .
|
|
815
|
+
BLACK_START_BASE: .08,
|
|
776
816
|
// Base start opacity for black overlay
|
|
777
817
|
get BLACK_START_MULTIPLIER() {
|
|
778
818
|
return .025 * this.BLACK_START_BASE;
|
|
@@ -796,14 +836,14 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
796
836
|
return .416 * this.BLACK_START_BASE;
|
|
797
837
|
}
|
|
798
838
|
},
|
|
799
|
-
// Overlay highlight constants
|
|
839
|
+
// Overlay highlight constants — Apple places specular at the top-center
|
|
800
840
|
OVERLAY_HIGHLIGHT: {
|
|
801
|
-
POSITION_X:
|
|
802
|
-
//
|
|
803
|
-
POSITION_Y:
|
|
804
|
-
//
|
|
805
|
-
WHITE_OPACITY: .
|
|
806
|
-
//
|
|
841
|
+
POSITION_X: 50,
|
|
842
|
+
// Centered horizontal — Apple's top-center specular
|
|
843
|
+
POSITION_Y: 5,
|
|
844
|
+
// Very top — catches light like a curved glass surface
|
|
845
|
+
WHITE_OPACITY: .28,
|
|
846
|
+
// Softer specular — visible but not glaring
|
|
807
847
|
get STOP() {
|
|
808
848
|
return 150 * this.WHITE_OPACITY;
|
|
809
849
|
},
|
|
@@ -824,6 +864,10 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
824
864
|
SATURATION: {
|
|
825
865
|
HIGH_CONTRAST: 200
|
|
826
866
|
},
|
|
867
|
+
// Container shadows — hairline inner catch + soft floating lift (Apple player bar)
|
|
868
|
+
CONTAINER_SHADOW: {
|
|
869
|
+
LIGHT: "inset 0 0.5px 0 rgba(255, 255, 255, 0.32), inset 0 1px 2px rgba(255, 255, 255, 0.06), 0 4px 16px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.08)"
|
|
870
|
+
},
|
|
827
871
|
// Phase 1: Animation System Constants
|
|
828
872
|
ANIMATION: {
|
|
829
873
|
// Breathing effect timing (in milliseconds)
|
|
@@ -863,7 +907,44 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
863
907
|
}
|
|
864
908
|
}
|
|
865
909
|
}
|
|
866
|
-
}
|
|
910
|
+
};
|
|
911
|
+
|
|
912
|
+
/**
|
|
913
|
+
* Default theme colors for components
|
|
914
|
+
*/
|
|
915
|
+
/**
|
|
916
|
+
* Button-specific constants
|
|
917
|
+
*/
|
|
918
|
+
/**
|
|
919
|
+
* Component Utilities
|
|
920
|
+
*
|
|
921
|
+
* Helper functions for component development with the new customization system
|
|
922
|
+
*/
|
|
923
|
+
/**
|
|
924
|
+
* Merge multiple class names
|
|
925
|
+
*/
|
|
926
|
+
function mergeClassNames(...classes) {
|
|
927
|
+
return classes.filter(Boolean).join(" ");
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/**
|
|
931
|
+
* Utility to merge multiple React refs into one
|
|
932
|
+
*/ function setRef(ref, value) {
|
|
933
|
+
"function" == typeof ref ? ref(value) : ref && (
|
|
934
|
+
// This is safe because we're checking that ref exists first
|
|
935
|
+
ref.current = value);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* Combines two React refs into a single ref function
|
|
940
|
+
* This is used when you need to use and forward a ref at the same time
|
|
941
|
+
*/ function useForkRef(refA, refB) {
|
|
942
|
+
return React.useMemo((() => null == refA && null == refB ? null : refValue => {
|
|
943
|
+
setRef(refA, refValue), setRef(refB, refValue);
|
|
944
|
+
}), [ refA, refB ]);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
const {CONSTANTS: CONSTANTS$3} = ATOMIX_GLASS, calculateElementCenter = rect => rect ? {
|
|
867
948
|
x: rect.left + rect.width / 2,
|
|
868
949
|
y: rect.top + rect.height / 2
|
|
869
950
|
} : {
|
|
@@ -871,37 +952,37 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
871
952
|
y: 0
|
|
872
953
|
}, calculateMouseInfluence = mouseOffset => {
|
|
873
954
|
if (!mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y) return 0;
|
|
874
|
-
//
|
|
875
|
-
const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$
|
|
955
|
+
// Clamp influence to keep mouse response subtle and stable.
|
|
956
|
+
const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$3.MOUSE_INFLUENCE_DIVISOR;
|
|
876
957
|
return Math.min(.8, influence);
|
|
877
958
|
// Tighter cap to prevent blur/filter blow-out
|
|
878
|
-
}, clampBlur = value => "number" != typeof value || isNaN(value) ? CONSTANTS$
|
|
959
|
+
}, clampBlur = value => "number" != typeof value || isNaN(value) ? CONSTANTS$3.MIN_BLUR : Math.max(CONSTANTS$3.MIN_BLUR, Math.min(50, value)), validateGlassSize = size => size && "number" == typeof size.width && "number" == typeof size.height && size.width > 0 && size.height > 0 && size.width <= CONSTANTS$3.MAX_SIZE && size.height <= CONSTANTS$3.MAX_SIZE, parseBorderRadiusValue = value => {
|
|
879
960
|
if ("number" == typeof value) return Math.max(0, value);
|
|
880
|
-
if ("string" != typeof value || !value.trim()) return CONSTANTS$
|
|
961
|
+
if ("string" != typeof value || !value.trim()) return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
|
|
881
962
|
const trimmedValue = value.trim();
|
|
882
963
|
// Handle px values
|
|
883
964
|
if (trimmedValue.endsWith("px")) {
|
|
884
965
|
const parsed = parseFloat(trimmedValue);
|
|
885
|
-
return isNaN(parsed) ? CONSTANTS$
|
|
966
|
+
return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, parsed);
|
|
886
967
|
}
|
|
887
968
|
// Handle rem values (assume 16px = 1rem)
|
|
888
969
|
if (trimmedValue.endsWith("rem")) {
|
|
889
970
|
const parsed = parseFloat(trimmedValue);
|
|
890
|
-
return isNaN(parsed) ? CONSTANTS$
|
|
971
|
+
return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
|
|
891
972
|
}
|
|
892
973
|
// Handle em values (assume 16px = 1em for simplicity)
|
|
893
974
|
if (trimmedValue.endsWith("em")) {
|
|
894
975
|
const parsed = parseFloat(trimmedValue);
|
|
895
|
-
return isNaN(parsed) ? CONSTANTS$
|
|
976
|
+
return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
|
|
896
977
|
}
|
|
897
978
|
// Handle percentage (convert to approximate px value, assuming 200px container)
|
|
898
979
|
if (trimmedValue.endsWith("%")) {
|
|
899
980
|
const parsed = parseFloat(trimmedValue);
|
|
900
|
-
return isNaN(parsed) ? CONSTANTS$
|
|
981
|
+
return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, parsed / 100 * 200);
|
|
901
982
|
}
|
|
902
983
|
// Handle unitless numbers
|
|
903
984
|
const numValue = parseFloat(trimmedValue);
|
|
904
|
-
return isNaN(numValue) ? CONSTANTS$
|
|
985
|
+
return isNaN(numValue) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, numValue);
|
|
905
986
|
}, extractBorderRadiusFromElement = element => {
|
|
906
987
|
if (!element || !element.props) return null;
|
|
907
988
|
// Check inline styles first (highest priority)
|
|
@@ -917,11 +998,11 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
917
998
|
// If element has children, recursively check them
|
|
918
999
|
if (element.props.children) {
|
|
919
1000
|
const childRadius = extractBorderRadiusFromChildren(element.props.children);
|
|
920
|
-
if (childRadius > 0 && childRadius !== CONSTANTS$
|
|
1001
|
+
if (childRadius > 0 && childRadius !== CONSTANTS$3.DEFAULT_CORNER_RADIUS) return childRadius;
|
|
921
1002
|
}
|
|
922
1003
|
return null;
|
|
923
1004
|
}, extractBorderRadiusFromChildren = children => {
|
|
924
|
-
if (!children) return CONSTANTS$
|
|
1005
|
+
if (!children) return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
|
|
925
1006
|
try {
|
|
926
1007
|
const childArray = React.Children.toArray(children);
|
|
927
1008
|
for (let i = 0; i < childArray.length; i++) {
|
|
@@ -934,17 +1015,78 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
934
1015
|
} catch (error) {
|
|
935
1016
|
// Silently handle errors
|
|
936
1017
|
}
|
|
937
|
-
return CONSTANTS$
|
|
1018
|
+
return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
|
|
938
1019
|
}, smoothstep = t => {
|
|
939
1020
|
const clamped = Math.max(0, Math.min(1, t));
|
|
940
1021
|
return clamped * clamped * (3 - 2 * clamped);
|
|
941
|
-
}, lerp
|
|
1022
|
+
}, lerp = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), clamp = (value, min, max) => "number" != typeof value || isNaN(value) ? min : Math.max(min, Math.min(max, value)), smoothstepEdge = (edge0, edge1, x) => "number" != typeof edge0 || "number" != typeof edge1 || "number" != typeof x ? 0 : smoothstep((x - edge0) / (edge1 - edge0)), easeInOutCubic = t => {
|
|
1023
|
+
if ("number" != typeof t || isNaN(t)) return 0;
|
|
1024
|
+
const clamped = Math.max(0, Math.min(1, t));
|
|
1025
|
+
return clamped < .5 ? 4 * clamped * clamped * clamped : 1 - Math.pow(-2 * clamped + 2, 3) / 2;
|
|
1026
|
+
}, easeOutQuart = t => {
|
|
1027
|
+
if ("number" != typeof t || isNaN(t)) return 0;
|
|
1028
|
+
const clamped = Math.max(0, Math.min(1, t));
|
|
1029
|
+
return 1 - Math.pow(1 - clamped, 4);
|
|
1030
|
+
}, vec2Length = (x, y) => {
|
|
1031
|
+
if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
|
|
1032
|
+
const maxComponent = Math.max(Math.abs(x), Math.abs(y));
|
|
1033
|
+
if (0 === maxComponent) return 0;
|
|
1034
|
+
const scaledX = x / maxComponent, scaledY = y / maxComponent;
|
|
1035
|
+
return maxComponent * Math.sqrt(scaledX * scaledX + scaledY * scaledY);
|
|
1036
|
+
}, getInteractionIntensity = (isHovered, isActive) => ({
|
|
1037
|
+
hoverIntensity: isHovered ? CONSTANTS$3.INTERACTION.HOVER_INTENSITY : 1,
|
|
1038
|
+
activeIntensity: isActive ? CONSTANTS$3.INTERACTION.ACTIVE_INTENSITY : 1
|
|
1039
|
+
})
|
|
1040
|
+
/**
|
|
1041
|
+
* Spring-damper integration helper
|
|
1042
|
+
* Calculates the next value based on velocity, stiffness, and damping.
|
|
1043
|
+
*/ , calculateSpring = (current, target, velocity, stiffness = .1, damping = .8) => {
|
|
942
1044
|
const newVelocity = (velocity + (target - current) * stiffness) * damping;
|
|
943
1045
|
return {
|
|
944
1046
|
value: current + newVelocity,
|
|
945
1047
|
velocity: newVelocity
|
|
946
1048
|
};
|
|
947
|
-
}
|
|
1049
|
+
};
|
|
1050
|
+
|
|
1051
|
+
/**
|
|
1052
|
+
* Calculate element center from bounding rect
|
|
1053
|
+
*/
|
|
1054
|
+
/**
|
|
1055
|
+
* Normalizes a layout inset for use in CSS custom properties.
|
|
1056
|
+
*
|
|
1057
|
+
* @param value - Raw inset from `style` (number, px string, or `auto`).
|
|
1058
|
+
* @param fallback - Value used when `value` is undefined.
|
|
1059
|
+
*/
|
|
1060
|
+
function formatGlassInsetValue(value, fallback = "auto") {
|
|
1061
|
+
return void 0 === value ? "number" == typeof fallback ? `${fallback}px` : String(fallback) : "auto" === value ? "auto" : "number" == typeof value ? `${value}px` : value;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
/**
|
|
1065
|
+
* Determines whether the glass should use fixed/sticky layout semantics.
|
|
1066
|
+
*
|
|
1067
|
+
* @param explicit - Value of the `isFixedOrSticky` prop.
|
|
1068
|
+
* @param position - `position` from the consumer `style` object.
|
|
1069
|
+
*/
|
|
1070
|
+
/** Coerces a value to a finite number, returning `fallback` when invalid. */
|
|
1071
|
+
function toSafeNumber(value, fallback = 0) {
|
|
1072
|
+
return "number" != typeof value || isNaN(value) ? fallback : value;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
/**
|
|
1076
|
+
* Calculates the target frame rate for shader time-animation loops.
|
|
1077
|
+
*
|
|
1078
|
+
* Balances visual quality against distortion complexity and `animationSpeed`.
|
|
1079
|
+
*/
|
|
1080
|
+
/**
|
|
1081
|
+
* Computes per-channel displacement scale for the SVG chromatic-aberration filter.
|
|
1082
|
+
*/
|
|
1083
|
+
function getChromaticDisplacementScale(mode, displacementScale, aberrationIntensity, channelFactor) {
|
|
1084
|
+
return displacementScale * (("shader" === mode ? 1 : -1) - aberrationIntensity * channelFactor);
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
/**
|
|
1088
|
+
* Get displacement map URL based on mode
|
|
1089
|
+
*/ const getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
|
|
948
1090
|
switch (mode) {
|
|
949
1091
|
case "standard":
|
|
950
1092
|
return displacementMap;
|
|
@@ -961,13 +1103,28 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
961
1103
|
default:
|
|
962
1104
|
return console.warn("AtomixGlass: Invalid displacement mode"), displacementMap;
|
|
963
1105
|
}
|
|
964
|
-
}, sharedShaderCache = new Map,
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1106
|
+
}, sharedShaderCache = new Map, CHROMATIC_CHANNELS = [ {
|
|
1107
|
+
result: "RED_DISPLACED",
|
|
1108
|
+
channelResult: "RED_CHANNEL",
|
|
1109
|
+
aberrationFactor: 0,
|
|
1110
|
+
colorMatrix: "1 0 0 0 0\n0 0 0 0 0\n0 0 0 0 0\n0 0 0 1 0"
|
|
1111
|
+
}, {
|
|
1112
|
+
result: "GREEN_DISPLACED",
|
|
1113
|
+
channelResult: "GREEN_CHANNEL",
|
|
1114
|
+
aberrationFactor: .02,
|
|
1115
|
+
colorMatrix: "0 0 0 0 0\n0 1 0 0 0\n0 0 0 0 0\n0 0 0 1 0"
|
|
1116
|
+
}, {
|
|
1117
|
+
result: "BLUE_DISPLACED",
|
|
1118
|
+
channelResult: "BLUE_CHANNEL",
|
|
1119
|
+
aberrationFactor: .03,
|
|
1120
|
+
colorMatrix: "0 0 0 0 0\n0 0 0 0 0\n0 0 1 0 0\n0 0 0 1 0"
|
|
1121
|
+
} ], FILTER_SVG_STYLE = {
|
|
1122
|
+
position: "absolute",
|
|
1123
|
+
width: "100%",
|
|
1124
|
+
height: "100%",
|
|
1125
|
+
inset: 0
|
|
1126
|
+
}, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsx("svg", {
|
|
1127
|
+
style: FILTER_SVG_STYLE,
|
|
971
1128
|
"aria-hidden": "true",
|
|
972
1129
|
children: jsxs("defs", {
|
|
973
1130
|
children: [ jsxs("radialGradient", {
|
|
@@ -1021,43 +1178,21 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
1021
1178
|
dx: "0",
|
|
1022
1179
|
dy: "0",
|
|
1023
1180
|
result: "CENTER_ORIGINAL"
|
|
1024
|
-
}),
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
scale: displacementScale * (("shader" === mode ? 1 : -1) - .02 * aberrationIntensity),
|
|
1040
|
-
xChannelSelector: "R",
|
|
1041
|
-
yChannelSelector: "B",
|
|
1042
|
-
result: "GREEN_DISPLACED"
|
|
1043
|
-
}), jsx("feColorMatrix", {
|
|
1044
|
-
in: "GREEN_DISPLACED",
|
|
1045
|
-
type: "matrix",
|
|
1046
|
-
values: "0 0 0 0 0\n 0 1 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0",
|
|
1047
|
-
result: "GREEN_CHANNEL"
|
|
1048
|
-
}), jsx("feDisplacementMap", {
|
|
1049
|
-
in: "SourceGraphic",
|
|
1050
|
-
in2: "DISPLACEMENT_MAP",
|
|
1051
|
-
scale: displacementScale * (("shader" === mode ? 1 : -1) - .03 * aberrationIntensity),
|
|
1052
|
-
xChannelSelector: "R",
|
|
1053
|
-
yChannelSelector: "B",
|
|
1054
|
-
result: "BLUE_DISPLACED"
|
|
1055
|
-
}), jsx("feColorMatrix", {
|
|
1056
|
-
in: "BLUE_DISPLACED",
|
|
1057
|
-
type: "matrix",
|
|
1058
|
-
values: "0 0 0 0 0\n 0 0 0 0 0\n 0 0 1 0 0\n 0 0 0 1 0",
|
|
1059
|
-
result: "BLUE_CHANNEL"
|
|
1060
|
-
}), jsx("feBlend", {
|
|
1181
|
+
}), CHROMATIC_CHANNELS.map((channel => jsxs(React.Fragment, {
|
|
1182
|
+
children: [ jsx("feDisplacementMap", {
|
|
1183
|
+
in: "SourceGraphic",
|
|
1184
|
+
in2: "DISPLACEMENT_MAP",
|
|
1185
|
+
scale: getChromaticDisplacementScale(mode, displacementScale, aberrationIntensity, channel.aberrationFactor),
|
|
1186
|
+
xChannelSelector: "R",
|
|
1187
|
+
yChannelSelector: "B",
|
|
1188
|
+
result: channel.result
|
|
1189
|
+
}), jsx("feColorMatrix", {
|
|
1190
|
+
in: channel.result,
|
|
1191
|
+
type: "matrix",
|
|
1192
|
+
values: channel.colorMatrix,
|
|
1193
|
+
result: channel.channelResult
|
|
1194
|
+
}) ]
|
|
1195
|
+
}, channel.channelResult))), jsx("feBlend", {
|
|
1061
1196
|
in: "GREEN_CHANNEL",
|
|
1062
1197
|
in2: "BLUE_CHANNEL",
|
|
1063
1198
|
mode: "screen",
|
|
@@ -1098,24 +1233,22 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
1098
1233
|
});
|
|
1099
1234
|
|
|
1100
1235
|
/**
|
|
1101
|
-
*
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
*
|
|
1236
|
+
* Module-level LRU cache for shader displacement maps.
|
|
1237
|
+
*
|
|
1238
|
+
* Shared across all `AtomixGlassContainer` instances so identical size and
|
|
1239
|
+
* variant combinations are generated once.
|
|
1105
1240
|
*/ GlassFilterComponent.displayName = "GlassFilter";
|
|
1106
1241
|
|
|
1107
|
-
|
|
1242
|
+
/** Shallow prop comparison to avoid redundant SVG filter regeneration. */
|
|
1108
1243
|
const GlassFilter = memo(GlassFilterComponent, ((prevProps, nextProps) => prevProps.id === nextProps.id && prevProps.displacementScale === nextProps.displacementScale && prevProps.aberrationIntensity === nextProps.aberrationIntensity && prevProps.mode === nextProps.mode && prevProps.shaderMapUrl === nextProps.shaderMapUrl && prevProps.blurAmount === nextProps.blurAmount)), AtomixGlassContainer = forwardRef((({children: children, className: className = "", style: style, displacementScale: displacementScale = 25, blurAmount: blurAmount = .0625, saturation: saturation = 180, aberrationIntensity: aberrationIntensity = 2, mouseOffset: mouseOffset = {
|
|
1109
1244
|
x: 0,
|
|
1110
1245
|
y: 0
|
|
1111
|
-
}, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0,
|
|
1246
|
+
}, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0, glassSize: glassSize = {
|
|
1112
1247
|
width: 0,
|
|
1113
1248
|
height: 0
|
|
1114
|
-
}, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, isFixedOrSticky: isFixedOrSticky = !1,
|
|
1115
|
-
// Phase 1: Animation System props
|
|
1116
|
-
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) => {
|
|
1249
|
+
}, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, isFixedOrSticky: isFixedOrSticky = !1, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", contentRef: contentRef}, ref) => {
|
|
1117
1250
|
// React 18 useId — stable, unique, and SSR-safe (no module-level counter)
|
|
1118
|
-
const rawId = useId(), filterId = useMemo((() => `atomix-glass-filter-${rawId.replace(/:/g, "")}`), [ rawId ]), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null), shaderUpdateTimeoutRef = useRef(null), animationFrameRef = useRef(null);
|
|
1251
|
+
const rawId = useId(), filterId = useMemo((() => `atomix-glass-filter-${rawId.replace(/:/g, "")}`), [ rawId ]), containerRef = useForkRef(ref, null), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null), shaderUpdateTimeoutRef = useRef(null), animationFrameRef = useRef(null);
|
|
1119
1252
|
// Lazy load shader utilities only when shader mode is needed
|
|
1120
1253
|
useEffect((() => {
|
|
1121
1254
|
"shader" === mode ?
|
|
@@ -1193,15 +1326,23 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
|
|
|
1193
1326
|
shaderGeneratorRef.current = null;
|
|
1194
1327
|
}
|
|
1195
1328
|
};
|
|
1196
|
-
}), [ mode, glassSize, shaderVariant ]),
|
|
1197
|
-
// Phase 1: Time-Based Animation Loop - Continuous shader regeneration
|
|
1198
|
-
useEffect((() => {
|
|
1329
|
+
}), [ mode, glassSize, shaderVariant ]), useEffect((() => {
|
|
1199
1330
|
// Only run animations in shader mode with time animation enabled
|
|
1200
1331
|
if ("shader" !== mode || !withTimeAnimation || effectiveReducedMotion || effectiveWithoutEffects)
|
|
1201
1332
|
// Cancel any existing animation frame
|
|
1202
1333
|
return void (null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
|
|
1203
1334
|
animationFrameRef.current = null));
|
|
1204
|
-
const
|
|
1335
|
+
const targetFps = function(options) {
|
|
1336
|
+
const {distortionQuality: distortionQuality, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5} = options, baseFps = "ultra" === distortionQuality ? 60 : "high" === distortionQuality ? 30 : "medium" === distortionQuality ? 24 : 20, effectiveSpeed = Math.max(.5, Math.min(2, animationSpeed)), complexity = withMultiLayerDistortion ? Math.max(1, distortionOctaves / 3 + .25 * Math.max(0, distortionLacunarity - 2) + Math.max(0, distortionGain - .5)) : 1;
|
|
1337
|
+
return Math.max(12, Math.min(60, Math.round(baseFps * effectiveSpeed / complexity)));
|
|
1338
|
+
}({
|
|
1339
|
+
distortionQuality: distortionQuality,
|
|
1340
|
+
animationSpeed: animationSpeed,
|
|
1341
|
+
withMultiLayerDistortion: withMultiLayerDistortion,
|
|
1342
|
+
distortionOctaves: distortionOctaves,
|
|
1343
|
+
distortionLacunarity: distortionLacunarity,
|
|
1344
|
+
distortionGain: distortionGain
|
|
1345
|
+
}), frameInterval = 1e3 / targetFps;
|
|
1205
1346
|
let lastUpdate = 0, isCancelled = !1;
|
|
1206
1347
|
const animate = currentTime => {
|
|
1207
1348
|
if (!isCancelled) {
|
|
@@ -1225,88 +1366,21 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
|
|
|
1225
1366
|
};
|
|
1226
1367
|
}), [ mode, withTimeAnimation, animationSpeed, displacementScale, withMultiLayerDistortion, distortionOctaves, distortionLacunarity, distortionGain, distortionQuality, effectiveReducedMotion, effectiveWithoutEffects, glassSize ]);
|
|
1227
1368
|
// Removed forced reflow to avoid layout thrash and potential feedback sizing loops
|
|
1228
|
-
const
|
|
1229
|
-
useEffect((() => {
|
|
1230
|
-
if (!ref || "function" == typeof ref) return;
|
|
1231
|
-
const element = ref.current;
|
|
1232
|
-
if (element) try {
|
|
1233
|
-
setRectCache(element.getBoundingClientRect());
|
|
1234
|
-
} catch (error) {
|
|
1235
|
-
console.warn("AtomixGlassContainer: Error getting element bounds", error), setRectCache(null);
|
|
1236
|
-
}
|
|
1237
|
-
}), [ ref, glassSize ]);
|
|
1238
|
-
const liquidBlur = useMemo((() => {
|
|
1239
|
-
const defaultBlur = {
|
|
1240
|
-
baseBlur: blurAmount,
|
|
1241
|
-
edgeBlur: 1.25 * blurAmount,
|
|
1242
|
-
centerBlur: 1.1 * blurAmount,
|
|
1243
|
-
flowBlur: 1.2 * blurAmount
|
|
1244
|
-
};
|
|
1245
|
-
// Enhanced validation for liquid blur
|
|
1246
|
-
if (!withLiquidBlur || !rectCache || !mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y || isNaN(mouseOffset.x) || isNaN(mouseOffset.y)) return defaultBlur;
|
|
1247
|
-
try {
|
|
1248
|
-
const mouseInfluence = calculateMouseInfluence(mouseOffset), maxBlur = 2 * blurAmount, baseBlur = Math.min(maxBlur, blurAmount + mouseInfluence * blurAmount * .15), edgeIntensity = .15 * mouseInfluence, edgeBlur = Math.min(maxBlur, baseBlur * (.8 + .4 * edgeIntensity)), centerIntensity = .1 * mouseInfluence, centerBlur = Math.min(maxBlur, baseBlur * (.3 + .3 * centerIntensity)), flowBlur = Math.min(maxBlur, 1.2 * baseBlur);
|
|
1249
|
-
// NOTE: hover/active multipliers intentionally omitted here —
|
|
1250
|
-
// they belong on opacity layers, not the blur filter itself.
|
|
1251
|
-
return {
|
|
1252
|
-
baseBlur: clampBlur(baseBlur),
|
|
1253
|
-
edgeBlur: clampBlur(edgeBlur),
|
|
1254
|
-
centerBlur: clampBlur(centerBlur),
|
|
1255
|
-
flowBlur: clampBlur(flowBlur)
|
|
1256
|
-
};
|
|
1257
|
-
} catch (error) {
|
|
1258
|
-
return console.warn("AtomixGlassContainer: Error calculating liquid blur", error),
|
|
1259
|
-
defaultBlur;
|
|
1260
|
-
}
|
|
1261
|
-
}), [ withLiquidBlur, blurAmount, mouseOffset, rectCache ]), backdropStyle = useMemo((() => {
|
|
1262
|
-
try {
|
|
1263
|
-
const dynamicSaturation = saturation + 20 * (liquidBlur.baseBlur || 0), validatedBaseBlur = "number" != typeof liquidBlur.baseBlur || isNaN(liquidBlur.baseBlur) ? 0 : liquidBlur.baseBlur, validatedEdgeBlur = "number" != typeof liquidBlur.edgeBlur || isNaN(liquidBlur.edgeBlur) ? 0 : liquidBlur.edgeBlur, validatedCenterBlur = "number" != typeof liquidBlur.centerBlur || isNaN(liquidBlur.centerBlur) ? 0 : liquidBlur.centerBlur, validatedFlowBlur = "number" != typeof liquidBlur.flowBlur || isNaN(liquidBlur.flowBlur) ? 0 : liquidBlur.flowBlur, area = rectCache ? rectCache.width * rectCache.height : 0;
|
|
1264
|
-
// Validate blur values before using them
|
|
1265
|
-
return !withLiquidBlur || effectiveReducedMotion || effectiveWithoutEffects || area > 18e4 ? {
|
|
1266
|
-
backdropFilter: `blur(${clampBlur(Math.max(validatedBaseBlur, .8 * validatedEdgeBlur, 1.1 * validatedCenterBlur, .9 * validatedFlowBlur))}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig?.contrast || 1.05}) brightness(${overLightConfig?.brightness || 1.05})`
|
|
1267
|
-
} : {
|
|
1268
|
-
backdropFilter: `blur(${clampBlur(.4 * validatedBaseBlur + .25 * validatedEdgeBlur + .15 * validatedCenterBlur + .2 * validatedFlowBlur)}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig?.contrast || 1}) brightness(${overLightConfig?.brightness || 1})`
|
|
1269
|
-
};
|
|
1270
|
-
// Single-pass fallback: stronger radius to match perceived blur of multi-pass
|
|
1271
|
-
} catch (error) {
|
|
1272
|
-
return console.warn("AtomixGlassContainer: Error calculating backdrop style", error),
|
|
1273
|
-
{
|
|
1274
|
-
backdropFilter: `blur(${blurAmount}px) saturate(${saturation}%) contrast(1.05) brightness(1.05)`
|
|
1275
|
-
};
|
|
1276
|
-
}
|
|
1277
|
-
}), [ liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion, effectiveWithoutEffects, withLiquidBlur, overLightConfig ]), containerVars = useMemo((() => {
|
|
1369
|
+
const containerVars = useMemo((() => {
|
|
1278
1370
|
try {
|
|
1279
|
-
// Safe extraction of mouse offset values
|
|
1280
|
-
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;
|
|
1281
1371
|
return {
|
|
1282
|
-
"--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px
|
|
1283
|
-
"--atomix-glass-container-backdrop": backdropStyle?.backdropFilter || "none",
|
|
1284
|
-
"--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",
|
|
1285
|
-
"--atomix-glass-container-shadow-opacity": effectiveWithoutEffects ? 0 : 1,
|
|
1286
|
-
// Background and shadow values use design token-aligned RGB values
|
|
1287
|
-
"--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",
|
|
1288
|
-
"--atomix-glass-container-text-shadow": overLight ? "0px 1px 2px rgba(255, 255, 255, 0.15)" : "0px 2px 12px rgba(0, 0, 0, 0.4)",
|
|
1289
|
-
"--atomix-glass-container-box-shadow": overLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)"
|
|
1372
|
+
"--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px`
|
|
1290
1373
|
};
|
|
1291
1374
|
} catch (error) {
|
|
1292
1375
|
return console.warn("AtomixGlassContainer: Error generating container variables", error),
|
|
1293
1376
|
{
|
|
1294
|
-
"--atomix-glass-container-
|
|
1295
|
-
"--atomix-glass-container-radius": "0px",
|
|
1296
|
-
"--atomix-glass-container-backdrop": "none",
|
|
1297
|
-
"--atomix-glass-container-shadow": "none",
|
|
1298
|
-
"--atomix-glass-container-shadow-opacity": 1,
|
|
1299
|
-
"--atomix-glass-container-bg": "none",
|
|
1300
|
-
"--atomix-glass-container-text-shadow": "none"
|
|
1377
|
+
"--atomix-glass-container-radius": "0px"
|
|
1301
1378
|
};
|
|
1302
1379
|
}
|
|
1303
|
-
}), [ borderRadius
|
|
1380
|
+
}), [ borderRadius ]);
|
|
1304
1381
|
return jsx("div", {
|
|
1305
|
-
ref:
|
|
1306
|
-
|
|
1307
|
-
"function" == typeof ref ? ref(el) : ref && (ref.current = el);
|
|
1308
|
-
},
|
|
1309
|
-
className: `${ATOMIX_GLASS.CONTAINER_CLASS} ${className} ${isActive ? ATOMIX_GLASS.CLASSES.ACTIVE : ""} ${overLight ? ATOMIX_GLASS.CLASSES.OVER_LIGHT : ""}`,
|
|
1382
|
+
ref: containerRef,
|
|
1383
|
+
className: mergeClassNames(ATOMIX_GLASS.CONTAINER_CLASS, className, isActive && ATOMIX_GLASS.CLASSES.ACTIVE, overLight && ATOMIX_GLASS.CLASSES.OVER_LIGHT),
|
|
1310
1384
|
style: {
|
|
1311
1385
|
...style,
|
|
1312
1386
|
...containerVars
|
|
@@ -1324,8 +1398,8 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
|
|
|
1324
1398
|
blurAmount: blurAmount,
|
|
1325
1399
|
mode: mode,
|
|
1326
1400
|
id: filterId,
|
|
1327
|
-
displacementScale:
|
|
1328
|
-
aberrationIntensity:
|
|
1401
|
+
displacementScale: toSafeNumber(displacementScale),
|
|
1402
|
+
aberrationIntensity: toSafeNumber(aberrationIntensity),
|
|
1329
1403
|
shaderMapUrl: shaderMapUrl
|
|
1330
1404
|
}), jsx("div", {
|
|
1331
1405
|
className: ATOMIX_GLASS.FILTER_OVERLAY_CLASS,
|
|
@@ -1347,8 +1421,12 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
|
|
|
1347
1421
|
});
|
|
1348
1422
|
}));
|
|
1349
1423
|
|
|
1350
|
-
|
|
1351
|
-
|
|
1424
|
+
/**
|
|
1425
|
+
* Internal glass surface that owns backdrop-filter, SVG distortion, and content.
|
|
1426
|
+
*
|
|
1427
|
+
* Layout and stacking styles are applied via the `style` prop from the parent.
|
|
1428
|
+
* The root wrapper supplies CSS custom properties only.
|
|
1429
|
+
*/ AtomixGlassContainer.displayName = "AtomixGlassContainer";
|
|
1352
1430
|
|
|
1353
1431
|
// Singleton instance
|
|
1354
1432
|
const globalMouseTracker = new
|
|
@@ -1463,28 +1541,32 @@ class {
|
|
|
1463
1541
|
*/ getSubscriberCount() {
|
|
1464
1542
|
return this.listeners.size;
|
|
1465
1543
|
}
|
|
1466
|
-
}, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
|
|
1544
|
+
}, {BORDER: BORDER, CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, BORDER_GRADIENT = BORDER.GRADIENT, WHITE = CONSTANTS$2.PALETTE.WHITE, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
|
|
1467
1545
|
if (!wrapperElement && !containerElement) return;
|
|
1468
1546
|
if (!validateGlassSize(params.glassSize)) return;
|
|
1469
|
-
const {mouseOffset: mouseOffset, globalMousePosition: globalMousePosition, glassSize: glassSize, isHovered: isHovered, isActive: isActive, isOverLight: isOverLight, baseOverLightConfig: baseOverLightConfig, effectiveBorderRadius: effectiveBorderRadius, effectiveWithoutEffects: effectiveWithoutEffects, effectiveReducedMotion: effectiveReducedMotion, elasticity: elasticity, elasticTranslation: elasticTranslation, elasticVelocity: elasticVelocity, mouseVelocity: mouseVelocity, directionalScale: directionalScale, scaleBase: scaleBase, onClick: onClick, withLiquidBlur: withLiquidBlur, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION,
|
|
1547
|
+
const {mouseOffset: mouseOffset, globalMousePosition: globalMousePosition, glassSize: glassSize, isHovered: isHovered, isActive: isActive, isOverLight: isOverLight, baseOverLightConfig: baseOverLightConfig, effectiveBorderRadius: effectiveBorderRadius, effectiveWithoutEffects: effectiveWithoutEffects, effectiveReducedMotion: effectiveReducedMotion, elasticity: elasticity, elasticTranslation: elasticTranslation, elasticVelocity: elasticVelocity, mouseVelocity: mouseVelocity, directionalScale: directionalScale, scaleBase: scaleBase, onClick: onClick, withLiquidBlur: withLiquidBlur, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, isFixedOrSticky: isFixedOrSticky = !1, borderAnimated: borderAnimated = !0, borderOpacityMultiplier: borderOpacityMultiplier = 1} = params, mouseInfluence = calculateMouseInfluence(mouseOffset), {hoverIntensity: hoverIntensity, activeIntensity: activeIntensity} = getInteractionIntensity(isHovered, isActive), overLightConfig = {
|
|
1470
1548
|
opacity: baseOverLightConfig.opacity * hoverIntensity * activeIntensity,
|
|
1471
1549
|
contrast: Math.min(1.6, baseOverLightConfig.contrast + .1 * mouseInfluence),
|
|
1472
1550
|
brightness: Math.min(1.1, baseOverLightConfig.brightness + .05 * mouseInfluence),
|
|
1473
1551
|
shadowIntensity: Math.min(1.2, Math.max(.5, baseOverLightConfig.shadowIntensity + .2 * mouseInfluence)),
|
|
1474
1552
|
borderOpacity: Math.min(1, Math.max(.3, baseOverLightConfig.borderOpacity + .1 * mouseInfluence)),
|
|
1475
1553
|
saturationBoost: baseOverLightConfig.saturationBoost
|
|
1476
|
-
}, scaleX = directionalScale.x * scaleBase, scaleY = directionalScale.y * scaleBase, transformStyle = effectiveWithoutEffects ? `scale(${scaleBase})` : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) scaleX(${scaleX}) scaleY(${scaleY})`,
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
x
|
|
1482
|
-
|
|
1483
|
-
}
|
|
1554
|
+
}, scaleX = directionalScale.x * scaleBase, scaleY = directionalScale.y * scaleBase, transformStyle = effectiveWithoutEffects ? `scale(${scaleBase})` : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) scaleX(${scaleX}) scaleY(${scaleY})`, tensionFactor =
|
|
1555
|
+
/**
|
|
1556
|
+
* Computes tension factor from elastic translation magnitude (0–1).
|
|
1557
|
+
*/
|
|
1558
|
+
function(elasticTranslation) {
|
|
1559
|
+
const magnitude = Math.hypot(elasticTranslation.x, elasticTranslation.y);
|
|
1560
|
+
return smoothstep(magnitude / 80);
|
|
1561
|
+
}
|
|
1562
|
+
/**
|
|
1563
|
+
* Updates the styles of the AtomixGlass wrapper and container elements imperatively
|
|
1564
|
+
* to avoid React re-renders on mouse movement.
|
|
1565
|
+
*/ (elasticTranslation), lightingContrast = Math.min(1.8, overLightConfig.contrast + .2 * tensionFactor), lightingBrightness = Math.min(1.2, overLightConfig.brightness + .1 * tensionFactor);
|
|
1484
1566
|
// Calculate mouse influence
|
|
1485
1567
|
// Update Wrapper Styles (glassVars)
|
|
1486
1568
|
if (wrapperElement) {
|
|
1487
|
-
const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT,
|
|
1569
|
+
const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, hoverPositions = {
|
|
1488
1570
|
hover1: {
|
|
1489
1571
|
x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
|
|
1490
1572
|
y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1
|
|
@@ -1501,28 +1583,55 @@ class {
|
|
|
1501
1583
|
x: GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER,
|
|
1502
1584
|
y: GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER
|
|
1503
1585
|
}, opacityValues = {
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1586
|
+
// hover-1: ambient highlight glow — present on hover and during press
|
|
1587
|
+
hover1: isHovered || isActive ? 1 : 0,
|
|
1588
|
+
// hover-2: press depth shadow — only fires on active (mousedown)
|
|
1589
|
+
hover2: isActive ? 1 : 0,
|
|
1590
|
+
// hover-3: global soft-light surface shift — half-strength on hover, full on press
|
|
1591
|
+
hover3: isActive ? 1 : isHovered ? .55 : 0,
|
|
1592
|
+
// Dark chrome: faint smoky tint; over-light keeps stronger fill
|
|
1593
|
+
base: isOverLight ? overLightConfig.opacity : .14,
|
|
1594
|
+
over: isOverLight ? 1.1 * overLightConfig.opacity : .1
|
|
1509
1595
|
}, style = wrapperElement.style;
|
|
1510
1596
|
style.setProperty("--atomix-glass-transform", transformStyle || "none");
|
|
1511
1597
|
// Parallax for content (liquid refraction feel)
|
|
1512
1598
|
const parallaxFactor = .38 + .12 * tensionFactor;
|
|
1513
1599
|
style.setProperty("--atomix-glass-child-parallax", `translate(${elasticTranslation.x * -parallaxFactor}px, ${elasticTranslation.y * -parallaxFactor}px)`),
|
|
1514
|
-
style.setProperty("--atomix-glass-contrast", lightingContrast.toString()), style.setProperty("--atomix-glass-brightness", lightingBrightness.toString())
|
|
1600
|
+
style.setProperty("--atomix-glass-contrast", lightingContrast.toString()), style.setProperty("--atomix-glass-brightness", lightingBrightness.toString());
|
|
1515
1601
|
// ── Chromatic Rim Lighting ──────────────────────────────────────
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1602
|
+
const borderVars = ATOMIX_GLASS.BORDER.GRADIENT_CSS_VARS;
|
|
1603
|
+
if (borderAnimated && !effectiveWithoutEffects) {
|
|
1604
|
+
const borderCssVars =
|
|
1605
|
+
/**
|
|
1606
|
+
* Builds animated chromatic rim CSS variables for border layers 1 and 2.
|
|
1607
|
+
* When empty, SCSS static conic/linear fallbacks apply.
|
|
1608
|
+
*/
|
|
1609
|
+
function(params) {
|
|
1610
|
+
const {mouseOffset: mouseOffset, mouseVelocity: mouseVelocity, elasticVelocity: elasticVelocity, borderOpacity: borderOpacity, opacityMultiplier: opacityMultiplier = 1, tensionFactor: tensionFactor = 0} = params, mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), velocityRotation = (mouseVelocity.x + elasticVelocity.x) * BORDER_GRADIENT.VELOCITY_ANGLE_MULTIPLIER, borderGradientAngle = BORDER_GRADIENT.BASE_ANGLE + mx * BORDER_GRADIENT.ANGLE_MULTIPLIER + velocityRotation, chromaticOffset = BORDER_GRADIENT.CHROMATIC_OFFSET, angleR = borderGradientAngle - chromaticOffset, angleB = borderGradientAngle + chromaticOffset, borderStop1 = Math.max(BORDER_GRADIENT.STOP_1.MIN, BORDER_GRADIENT.STOP_1.BASE + my * BORDER_GRADIENT.STOP_1.MULTIPLIER), borderStop2 = Math.min(BORDER_GRADIENT.STOP_2.MAX, BORDER_GRADIENT.STOP_2.BASE + my * BORDER_GRADIENT.STOP_2.MULTIPLIER), tensionGlow = 1 + .5 * tensionFactor, opacities = BORDER_GRADIENT.OPACITY, borderOpacities = [ (opacities.BASE_1 + absMx * opacities.MULTIPLIER_LOW) * tensionGlow, (opacities.BASE_2 + absMx * opacities.MULTIPLIER_HIGH) * tensionGlow, (opacities.BASE_3 + absMx * opacities.MULTIPLIER_LOW) * tensionGlow, (opacities.BASE_4 + absMx * opacities.MULTIPLIER_HIGH) * tensionGlow ], configBorderOpacity = borderOpacity * opacityMultiplier, gradient1 = `linear-gradient(${angleB}deg, rgba(${WHITE}, 0) 0%, rgba(${WHITE}, ${(borderOpacities[0] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${WHITE}, ${(borderOpacities[1] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${WHITE}, 0) 100%)`, gradient2 = `linear-gradient(${angleR}deg, rgba(${WHITE}, 0) 0%, rgba(${WHITE}, ${(borderOpacities[2] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${WHITE}, ${(borderOpacities[3] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${WHITE}, 0) 100%)`;
|
|
1611
|
+
return {
|
|
1612
|
+
[BORDER.GRADIENT_CSS_VARS.GRADIENT_1]: gradient1,
|
|
1613
|
+
[BORDER.GRADIENT_CSS_VARS.GRADIENT_2]: gradient2
|
|
1614
|
+
};
|
|
1615
|
+
}({
|
|
1616
|
+
mouseOffset: mouseOffset,
|
|
1617
|
+
mouseVelocity: mouseVelocity,
|
|
1618
|
+
elasticVelocity: elasticVelocity,
|
|
1619
|
+
borderOpacity: overLightConfig.borderOpacity,
|
|
1620
|
+
opacityMultiplier: borderOpacityMultiplier,
|
|
1621
|
+
tensionFactor: tensionFactor
|
|
1622
|
+
});
|
|
1623
|
+
style.setProperty(borderVars.GRADIENT_1, borderCssVars[borderVars.GRADIENT_1] ?? ""),
|
|
1624
|
+
style.setProperty(borderVars.GRADIENT_2, borderCssVars[borderVars.GRADIENT_2] ?? "");
|
|
1625
|
+
} else style.removeProperty(borderVars.GRADIENT_1), style.removeProperty(borderVars.GRADIENT_2);
|
|
1626
|
+
// Hover gradients — cursor-relative radial positions for realistic light tracking.
|
|
1627
|
+
// hover-1: white overlay highlight following cursor (works on both dark + light)
|
|
1628
|
+
style.setProperty("--atomix-glass-hover-1-gradient", `radial-gradient(65% 55% at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${whiteColor}, 0.24) 0%, rgba(${whiteColor}, 0.06) 45%, rgba(${whiteColor}, 0) 72%)`),
|
|
1629
|
+
// hover-2: press depth — darkens at cursor with multiply blend, isOverLight uses stronger black
|
|
1630
|
+
style.setProperty("--atomix-glass-hover-2-gradient", isOverLight ? `radial-gradient(60% 50% at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${blackColor}, 0.22) 0%, rgba(${blackColor}, 0.06) 50%, rgba(${blackColor}, 0) 72%)` : `radial-gradient(60% 50% at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${blackColor}, 0.18) 0%, rgba(${blackColor}, 0.04) 50%, rgba(${blackColor}, 0) 72%)`),
|
|
1631
|
+
// hover-3: full-surface soft-light tint; linear gradient angled with cursor X
|
|
1632
|
+
style.setProperty("--atomix-glass-hover-3-gradient", `linear-gradient(${150 + .3 * mx}deg, rgba(${whiteColor}, ${isOverLight ? .08 : .12}) 0%, rgba(${whiteColor}, 0.04) 55%, rgba(${whiteColor}, 0) 100%)`),
|
|
1633
|
+
style.setProperty("--atomix-glass-base-gradient", isOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + mx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + my * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + absMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `linear-gradient(180deg, rgba(${blackColor}, 0.42) 0%, rgba(${blackColor}, 0.22) 55%, rgba(${blackColor}, 0.12) 100%)`),
|
|
1634
|
+
style.setProperty("--atomix-glass-overlay-gradient", isOverLight ? `radial-gradient(circle at ${basePosition.x}% ${basePosition.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + absMx * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + absMy * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `radial-gradient(120% 80% at 50% 0%, rgba(${whiteColor}, 0.14) 0%, rgba(${whiteColor}, 0) 55%)`),
|
|
1526
1635
|
// Opacities
|
|
1527
1636
|
style.setProperty("--atomix-glass-hover-1-opacity", opacityValues.hover1.toString()),
|
|
1528
1637
|
style.setProperty("--atomix-glass-hover-2-opacity", opacityValues.hover2.toString()),
|
|
@@ -1559,151 +1668,16 @@ class {
|
|
|
1559
1668
|
backdropFilterString = !withLiquidBlur || effectiveReducedMotion || effectiveWithoutEffects || area > 18e4 ? `blur(${clampBlur(Math.max(liquidBlur.baseBlur, .8 * liquidBlur.edgeBlur, 1.1 * liquidBlur.centerBlur, .9 * liquidBlur.flowBlur))}px) saturate(${Math.min(dynamicSaturation, 250)}%) contrast(${lightingContrast}) brightness(${lightingBrightness})` : `blur(${clampBlur(.4 * liquidBlur.baseBlur + .25 * liquidBlur.edgeBlur + .15 * liquidBlur.centerBlur + .2 * liquidBlur.flowBlur)}px) saturate(${Math.min(dynamicSaturation, 250)}%) contrast(${lightingContrast}) brightness(${lightingBrightness})`;
|
|
1560
1669
|
// Container variables
|
|
1561
1670
|
const style = containerElement.style;
|
|
1562
|
-
style.setProperty("--atomix-glass-container-
|
|
1671
|
+
style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
|
|
1563
1672
|
style.setProperty("--atomix-glass-container-backdrop", backdropFilterString),
|
|
1564
1673
|
// Shadows
|
|
1565
|
-
style.setProperty("--atomix-glass-container-shadow", isOverLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${(.
|
|
1674
|
+
style.setProperty("--atomix-glass-container-shadow", isOverLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${(.35 + .002 * mx) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 -1px 0 rgba(0, 0, 0, ${(.15 + .001 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 0 20px rgba(0, 0, 0, ${(.06 + .001 * Math.abs(mx + my)) * (overLightConfig.shadowIntensity || 1)})`, `0 2px 12px rgba(0, 0, 0, ${(.08 + .002 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})` ].join(", ") : ATOMIX_GLASS.CONSTANTS.CONTAINER_SHADOW.LIGHT),
|
|
1566
1675
|
style.setProperty("--atomix-glass-container-shadow-opacity", effectiveWithoutEffects ? "0" : "1"),
|
|
1567
1676
|
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"),
|
|
1568
1677
|
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)"),
|
|
1569
|
-
style.setProperty("--atomix-glass-container-box-shadow", isOverLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "
|
|
1678
|
+
style.setProperty("--atomix-glass-container-box-shadow", isOverLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0 4px 16px rgba(0, 0, 0, 0.14), 0 1px 4px rgba(0, 0, 0, 0.10)");
|
|
1570
1679
|
}
|
|
1571
|
-
};
|
|
1572
|
-
|
|
1573
|
-
/**
|
|
1574
|
-
* Updates the styles of the AtomixGlass wrapper and container elements imperatively
|
|
1575
|
-
* to avoid React re-renders on mouse movement.
|
|
1576
|
-
*/
|
|
1577
|
-
/**
|
|
1578
|
-
* Animation System for AtomixGlass Component
|
|
1579
|
-
*
|
|
1580
|
-
* Implements Phase 1 features from the AtomixGlass Feature Implementation Roadmap:
|
|
1581
|
-
* - Feature 1.1: Time-Based Animation System
|
|
1582
|
-
* - Feature 1.2: Multi-Layer Distortion System (FBM)
|
|
1583
|
-
*
|
|
1584
|
-
* @packageDocumentation
|
|
1585
|
-
*/
|
|
1586
|
-
// ============================================================================
|
|
1587
|
-
// Noise Functions for FBM (Feature 1.2)
|
|
1588
|
-
// ============================================================================
|
|
1589
|
-
/**
|
|
1590
|
-
* Perlin noise implementation for smooth gradient noise
|
|
1591
|
-
*
|
|
1592
|
-
* @param x - X coordinate
|
|
1593
|
-
* @param y - Y coordinate
|
|
1594
|
-
* @returns Noise value in range [0, 1]
|
|
1595
|
-
*/
|
|
1596
|
-
function perlinNoise(x, y) {
|
|
1597
|
-
// Simplified Perlin noise using pseudo-random gradients
|
|
1598
|
-
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);
|
|
1599
|
-
// Scale to [0, 1] range
|
|
1600
|
-
return (lerp(lerpX1, lerpX2, v) + 1) / 2;
|
|
1601
|
-
}
|
|
1602
|
-
|
|
1603
|
-
// ============================================================================
|
|
1604
|
-
// Fractal Brownian Motion (FBM) Engine (Feature 1.2)
|
|
1605
|
-
// ============================================================================
|
|
1606
|
-
/**
|
|
1607
|
-
* Creates an FBM engine with configurable parameters
|
|
1608
|
-
*
|
|
1609
|
-
* @param config - FBM configuration (octaves, lacunarity, gain)
|
|
1610
|
-
* @returns Object with fbm function
|
|
1611
|
-
*
|
|
1612
|
-
* @example
|
|
1613
|
-
* ```typescript
|
|
1614
|
-
* const fbmEngine = createFBMEngine({ octaves: 5, lacunarity: 2, gain: 0.5 });
|
|
1615
|
-
*
|
|
1616
|
-
* // Generate noise at position (0.5, 0.5) with time animation
|
|
1617
|
-
* const noiseValue = fbmEngine.fbm(0.5, 0.5, Date.now());
|
|
1618
|
-
* ```
|
|
1619
|
-
*/ function createFBMEngine(config) {
|
|
1620
|
-
/**
|
|
1621
|
-
* Fractal Brownian Motion function
|
|
1622
|
-
* Combines multiple octaves of noise for complex, natural patterns
|
|
1623
|
-
*
|
|
1624
|
-
* @param x - X coordinate
|
|
1625
|
-
* @param y - Y coordinate
|
|
1626
|
-
* @param time - Optional time value for animation
|
|
1627
|
-
* @returns FBM noise value in range [0, 1]
|
|
1628
|
-
*/
|
|
1629
|
-
const fbm = (x, y, time = 0) => {
|
|
1630
|
-
let value = 0, amplitude = .5, frequency = 1, phase = .001 * time;
|
|
1631
|
-
// Convert to seconds for reasonable animation speed
|
|
1632
|
-
for (let i = 0; i < config.octaves; i++)
|
|
1633
|
-
// Apply time-based phase shift to all octaves
|
|
1634
|
-
value += perlinNoise(x * frequency + phase, y * frequency + phase) * amplitude,
|
|
1635
|
-
frequency *= config.lacunarity, // Increase frequency
|
|
1636
|
-
amplitude *= config.gain;
|
|
1637
|
-
return value;
|
|
1638
|
-
};
|
|
1639
|
-
/**
|
|
1640
|
-
* Get FBM with simple time factor
|
|
1641
|
-
*/ return {
|
|
1642
|
-
fbm: fbm,
|
|
1643
|
-
fbmWithTime: (x, y, time) => fbm(x, y, time)
|
|
1644
|
-
};
|
|
1645
|
-
}
|
|
1646
|
-
|
|
1647
|
-
/**
|
|
1648
|
-
* Gets optimal FBM config based on quality preset
|
|
1649
|
-
*
|
|
1650
|
-
* @param quality - Quality preset level
|
|
1651
|
-
* @returns FBM configuration for the quality level
|
|
1652
|
-
*/ const fbmEngineCache = new Map;
|
|
1653
|
-
|
|
1654
|
-
// ============================================================================
|
|
1655
|
-
// Shader Utility Functions for Time-Based Effects
|
|
1656
|
-
// ============================================================================
|
|
1657
|
-
/**
|
|
1658
|
-
* Liquid glass distortion with time-based animation
|
|
1659
|
-
* Uses FBM to create organic, flowing liquid effects
|
|
1660
|
-
*
|
|
1661
|
-
* @param uv - UV coordinates (normalized 0-1)
|
|
1662
|
-
* @param time - Elapsed time in milliseconds
|
|
1663
|
-
* @param config - FBM configuration
|
|
1664
|
-
* @returns Distorted UV coordinates
|
|
1665
|
-
*/ function liquidGlassWithTime(uv, time, config) {
|
|
1666
|
-
const configKey = `${config.octaves}-${config.lacunarity}-${config.gain}`;
|
|
1667
|
-
let fbmEngine = fbmEngineCache.get(configKey);
|
|
1668
|
-
fbmEngine || (fbmEngine = createFBMEngine(config), fbmEngineCache.set(configKey, fbmEngine));
|
|
1669
|
-
// Animate noise with time
|
|
1670
|
-
const animatedNoise = fbmEngine.fbmWithTime(2 * uv.x + 1e-4 * time, 2 * uv.y + 15e-5 * time, time);
|
|
1671
|
-
return {
|
|
1672
|
-
x: uv.x + .04 * (animatedNoise - .5),
|
|
1673
|
-
y: uv.y + .04 * (animatedNoise - .5)
|
|
1674
|
-
};
|
|
1675
|
-
}
|
|
1676
|
-
|
|
1677
|
-
// ============================================================================
|
|
1678
|
-
// Helper Functions
|
|
1679
|
-
// ============================================================================
|
|
1680
|
-
/**
|
|
1681
|
-
* Fade curve for smooth interpolation (Perlin's fade function)
|
|
1682
|
-
*/ function fade(t) {
|
|
1683
|
-
return t * t * t * (t * (6 * t - 15) + 10);
|
|
1684
|
-
}
|
|
1685
|
-
|
|
1686
|
-
/**
|
|
1687
|
-
* Linear interpolation
|
|
1688
|
-
*/ function lerp(a, b, t) {
|
|
1689
|
-
return a + t * (b - a);
|
|
1690
|
-
}
|
|
1691
|
-
|
|
1692
|
-
/**
|
|
1693
|
-
* Gradient calculation for Perlin noise
|
|
1694
|
-
*/ function grad(hash, x, y) {
|
|
1695
|
-
const h = 15 & hash, u = h < 8 ? x : y, v = h < 4 ? y : 12 === h || 14 === h ? x : 0;
|
|
1696
|
-
return (1 & h ? -u : u) + (2 & h ? -v : v);
|
|
1697
|
-
}
|
|
1698
|
-
|
|
1699
|
-
/**
|
|
1700
|
-
* Permutation table for Perlin noise
|
|
1701
|
-
*/ const p = (() => {
|
|
1702
|
-
const permutation = [];
|
|
1703
|
-
for (let i = 0; i < 256; i++) permutation[i] = Math.floor(256 * Math.random());
|
|
1704
|
-
// Duplicate for overflow handling
|
|
1705
|
-
return [ ...permutation, ...permutation ];
|
|
1706
|
-
})(), {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
|
|
1680
|
+
}, {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
|
|
1707
1681
|
|
|
1708
1682
|
const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new WeakMap, setCachedBackgroundDetection = (parentElement, overLightConfig, result, threshold) => {
|
|
1709
1683
|
parentElement && backgroundDetectionCache.set(parentElement, {
|
|
@@ -1718,12 +1692,35 @@ const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new Weak
|
|
|
1718
1692
|
* Composable hook for AtomixGlass component logic
|
|
1719
1693
|
* Manages all state, calculations, and event handlers
|
|
1720
1694
|
*/
|
|
1721
|
-
function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef: wrapperRef, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, children: children, blurAmount: blurAmount, saturation: saturation,
|
|
1722
|
-
// Default priority
|
|
1723
|
-
// Phase 1: Animation System Props
|
|
1724
|
-
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}) {
|
|
1695
|
+
function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef: wrapperRef, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, border: border, withBorder: withBorder = !0, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, children: children, blurAmount: blurAmount, saturation: saturation, withLiquidBlur: withLiquidBlur, isFixedOrSticky: isFixedOrSticky = !1, priority: priority = 1}) {
|
|
1725
1696
|
// State
|
|
1726
|
-
const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1),
|
|
1697
|
+
const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1), resolvedBorder = useMemo((() =>
|
|
1698
|
+
/**
|
|
1699
|
+
* Resolves `border` and legacy `withBorder` into a single configuration object.
|
|
1700
|
+
*/
|
|
1701
|
+
function(border, withBorder) {
|
|
1702
|
+
const legacyDefault = withBorder ?? !0;
|
|
1703
|
+
return void 0 === border ? {
|
|
1704
|
+
enabled: legacyDefault,
|
|
1705
|
+
width: BORDER.DEFAULT_WIDTH,
|
|
1706
|
+
opacityMultiplier: 1,
|
|
1707
|
+
animated: !0
|
|
1708
|
+
} : "boolean" == typeof border ? {
|
|
1709
|
+
enabled: border,
|
|
1710
|
+
width: BORDER.DEFAULT_WIDTH,
|
|
1711
|
+
opacityMultiplier: 1,
|
|
1712
|
+
animated: !0
|
|
1713
|
+
} : {
|
|
1714
|
+
enabled: border.enabled ?? legacyDefault,
|
|
1715
|
+
width: (value = border.width, void 0 === value ? BORDER.DEFAULT_WIDTH : "number" == typeof value ? `${value}px` : value),
|
|
1716
|
+
opacityMultiplier: border.opacity ?? 1,
|
|
1717
|
+
animated: !1 !== border.animated
|
|
1718
|
+
};
|
|
1719
|
+
/**
|
|
1720
|
+
* Formats border width for CSS custom properties.
|
|
1721
|
+
*/
|
|
1722
|
+
var value;
|
|
1723
|
+
}(border, withBorder)), [ border, withBorder ]), cachedRectRef = useRef(null), internalGlobalMousePositionRef = useRef({
|
|
1727
1724
|
x: 0,
|
|
1728
1725
|
y: 0
|
|
1729
1726
|
}), internalMouseOffsetRef = useRef({
|
|
@@ -1747,52 +1744,10 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
1747
1744
|
}), scaleVelocityRef = useRef({
|
|
1748
1745
|
x: 0,
|
|
1749
1746
|
y: 0
|
|
1750
|
-
})
|
|
1751
|
-
useRef(0);
|
|
1752
|
-
const mouseVelocityRef = useRef({
|
|
1747
|
+
}), mouseVelocityRef = useRef({
|
|
1753
1748
|
x: 0,
|
|
1754
1749
|
y: 0
|
|
1755
|
-
}), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1),
|
|
1756
|
-
// If quality preset is provided, use it as base
|
|
1757
|
-
const preset = (quality = distortionQuality, ATOMIX_GLASS.CONSTANTS.DISTORTION_QUALITY_PRESETS[quality]);
|
|
1758
|
-
// Override with custom values if provided
|
|
1759
|
-
var quality;
|
|
1760
|
-
return {
|
|
1761
|
-
octaves: distortionOctaves ?? preset.octaves,
|
|
1762
|
-
lacunarity: distortionLacunarity ?? preset.lacunarity,
|
|
1763
|
-
gain: distortionGain ?? preset.gain
|
|
1764
|
-
};
|
|
1765
|
-
}), [ distortionQuality, distortionOctaves, distortionLacunarity, distortionGain ]), fbmEngine = useMemo((() => withMultiLayerDistortion ? createFBMEngine(fbmConfig) : null), [ withMultiLayerDistortion, fbmConfig ]), effectiveReducedMotion = useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveWithTimeAnimation = useMemo((() => withTimeAnimation && !effectiveReducedMotion), [ withTimeAnimation, effectiveReducedMotion ]);
|
|
1766
|
-
/**
|
|
1767
|
-
* Animation loop for time-based effects
|
|
1768
|
-
*/
|
|
1769
|
-
useEffect((() => {
|
|
1770
|
-
if (!effectiveWithTimeAnimation || "undefined" == typeof window) return;
|
|
1771
|
-
let lastFrameTime = performance.now();
|
|
1772
|
-
/**
|
|
1773
|
-
* Animation frame handler
|
|
1774
|
-
*/ const animate = currentTime => {
|
|
1775
|
-
// Calculate delta time
|
|
1776
|
-
const deltaTime = currentTime - lastFrameTime;
|
|
1777
|
-
lastFrameTime = currentTime;
|
|
1778
|
-
// Apply animation speed multiplier
|
|
1779
|
-
const scaledDelta = deltaTime * animationSpeed;
|
|
1780
|
-
elapsedTimeRef.current += scaledDelta, shaderTimeRef.current = elapsedTimeRef.current,
|
|
1781
|
-
// Continue animation loop
|
|
1782
|
-
animationFrameIdRef.current = requestAnimationFrame(animate);
|
|
1783
|
-
};
|
|
1784
|
-
// Start animation
|
|
1785
|
-
// Cleanup
|
|
1786
|
-
return animationStartTimeRef.current = performance.now(), animationFrameIdRef.current = requestAnimationFrame(animate),
|
|
1787
|
-
() => {
|
|
1788
|
-
null !== animationFrameIdRef.current && (cancelAnimationFrame(animationFrameIdRef.current),
|
|
1789
|
-
animationFrameIdRef.current = null);
|
|
1790
|
-
};
|
|
1791
|
-
}), [ effectiveWithTimeAnimation, animationSpeed ]);
|
|
1792
|
-
/**
|
|
1793
|
-
* Get current shader time for animations
|
|
1794
|
-
*/
|
|
1795
|
-
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}) {
|
|
1750
|
+
}), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1), effectiveReducedMotion = useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveBorderRadius = useMemo((() => void 0 !== borderRadius ? Math.max(0, borderRadius) : Math.max(0, dynamicBorderRadius)), [ borderRadius, dynamicBorderRadius ]), {glassSize: glassSize} = function({glassRef: glassRef, effectiveBorderRadius: effectiveBorderRadius, cachedRectRef: cachedRectRef}) {
|
|
1796
1751
|
const [glassSize, setGlassSize] = useState({
|
|
1797
1752
|
width: 270,
|
|
1798
1753
|
height: 69
|
|
@@ -1852,9 +1807,6 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
1852
1807
|
effectiveBorderRadius: effectiveBorderRadius,
|
|
1853
1808
|
cachedRectRef: cachedRectRef
|
|
1854
1809
|
}), effectiveHighContrast = useMemo((() => highContrast || userPrefersHighContrast), [ highContrast, userPrefersHighContrast ]), effectiveWithoutEffects = useMemo((() => withoutEffects || effectiveReducedMotion), [ withoutEffects, effectiveReducedMotion ]), globalMousePosition = externalGlobalMousePosition || internalGlobalMousePositionRef.current, mouseOffset = externalMouseOffset || internalMouseOffsetRef.current;
|
|
1855
|
-
/**
|
|
1856
|
-
* Apply time-based distortion to UV coordinates
|
|
1857
|
-
*/
|
|
1858
1810
|
// Extract border-radius from children
|
|
1859
1811
|
useEffect((() => {
|
|
1860
1812
|
const extractRadius = () => {
|
|
@@ -2014,25 +1966,26 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
2014
1966
|
* Get effective overLight value based on configuration
|
|
2015
1967
|
*/
|
|
2016
1968
|
const getEffectiveOverLight = useCallback((() => "boolean" == typeof overLight ? overLight : ("auto" === overLight || "object" == typeof overLight && null !== overLight) && detectedOverLight), [ overLight, detectedOverLight ]), validateConfigValue = useCallback(((value, min, max, defaultValue) => "number" != typeof value || isNaN(value) || !isFinite(value) ? defaultValue : Math.min(max, Math.max(min, value))), []), overLightConfig = useMemo((() => {
|
|
2017
|
-
const isOverLight = getEffectiveOverLight(), hoverIntensity
|
|
1969
|
+
const isOverLight = getEffectiveOverLight(), {hoverIntensity: hoverIntensity, activeIntensity: activeIntensity} = getInteractionIntensity(isHovered, isActive), baseConfig = {
|
|
2018
1970
|
isOverLight: isOverLight,
|
|
2019
1971
|
threshold: .7,
|
|
2020
1972
|
opacity: isOverLight ? Math.min(.6, Math.max(.2, .5 * hoverIntensity * activeIntensity)) : 0,
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
shadowIntensity: .9,
|
|
2026
|
-
borderOpacity: .
|
|
1973
|
+
// Dark UI (Apple Music): neutral contrast + slight brightness lift
|
|
1974
|
+
contrast: isOverLight ? 1.4 : 1.02,
|
|
1975
|
+
brightness: isOverLight ? .9 : 1.02,
|
|
1976
|
+
saturationBoost: isOverLight ? 1.3 : 1,
|
|
1977
|
+
shadowIntensity: isOverLight ? .9 : 1,
|
|
1978
|
+
borderOpacity: isOverLight ? ATOMIX_GLASS.BORDER.OVER_LIGHT.opacity : ATOMIX_GLASS.BORDER.DARK.opacity
|
|
2027
1979
|
};
|
|
2028
1980
|
if ("object" == typeof overLight && null !== overLight) {
|
|
2029
|
-
const objConfig = overLight, validatedThreshold = validateConfigValue(objConfig.threshold, .1, 1, baseConfig.threshold), validatedOpacity = validateConfigValue(objConfig.opacity, .1, 1, baseConfig.opacity), validatedContrast = validateConfigValue(objConfig.contrast, .5, 2.5, baseConfig.contrast), validatedBrightness = validateConfigValue(objConfig.brightness, .5, 2, baseConfig.brightness), validatedSaturationBoost = validateConfigValue(objConfig.saturationBoost, .5, 3, baseConfig.saturationBoost), finalConfig = {
|
|
1981
|
+
const objConfig = overLight, validatedThreshold = validateConfigValue(objConfig.threshold, .1, 1, baseConfig.threshold), validatedOpacity = validateConfigValue(objConfig.opacity, .1, 1, baseConfig.opacity), validatedContrast = validateConfigValue(objConfig.contrast, .5, 2.5, baseConfig.contrast), validatedBrightness = validateConfigValue(objConfig.brightness, .5, 2, baseConfig.brightness), validatedSaturationBoost = validateConfigValue(objConfig.saturationBoost, .5, 3, baseConfig.saturationBoost), validatedBorderOpacity = validateConfigValue(objConfig.borderOpacity, .1, 1, baseConfig.borderOpacity), finalConfig = {
|
|
2030
1982
|
...baseConfig,
|
|
2031
1983
|
threshold: validatedThreshold,
|
|
2032
1984
|
opacity: validatedOpacity * hoverIntensity * activeIntensity,
|
|
2033
1985
|
contrast: validatedContrast,
|
|
2034
1986
|
brightness: validatedBrightness,
|
|
2035
|
-
saturationBoost: validatedSaturationBoost
|
|
1987
|
+
saturationBoost: validatedSaturationBoost,
|
|
1988
|
+
borderOpacity: validatedBorderOpacity
|
|
2036
1989
|
};
|
|
2037
1990
|
return "undefined" == typeof process || process.env, finalConfig;
|
|
2038
1991
|
}
|
|
@@ -2057,8 +2010,8 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
2057
2010
|
};
|
|
2058
2011
|
const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
|
|
2059
2012
|
internalGlobalMousePositionRef.current = {
|
|
2060
|
-
x: lerp
|
|
2061
|
-
y: lerp
|
|
2013
|
+
x: lerp(curG.x, tgtG.x, CONSTANTS.LERP_FACTOR),
|
|
2014
|
+
y: lerp(curG.y, tgtG.y, CONSTANTS.LERP_FACTOR)
|
|
2062
2015
|
};
|
|
2063
2016
|
// ── Calculate Elastic Physics ─────────────────────────────────────
|
|
2064
2017
|
let targetElasticTranslation = {
|
|
@@ -2130,12 +2083,13 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
2130
2083
|
withLiquidBlur: withLiquidBlur,
|
|
2131
2084
|
blurAmount: blurAmount,
|
|
2132
2085
|
saturation: saturation,
|
|
2133
|
-
|
|
2134
|
-
|
|
2086
|
+
isFixedOrSticky: isFixedOrSticky,
|
|
2087
|
+
borderAnimated: resolvedBorder.animated,
|
|
2088
|
+
borderOpacityMultiplier: resolvedBorder.opacityMultiplier
|
|
2135
2089
|
}), Math.abs(mouseVelocityRef.current.x) < .001 && Math.abs(mouseVelocityRef.current.y) < .001 && Math.abs(elasticVelocityRef.current.x) < .001 && Math.abs(elasticVelocityRef.current.y) < .001 && Math.abs(scaleVelocityRef.current.x) < .001 && Math.abs(scaleVelocityRef.current.y) < .001 && Math.abs(internalMouseOffsetRef.current.x - targetMouseOffsetRef.current.x) < .001 && Math.abs(internalMouseOffsetRef.current.y - targetMouseOffsetRef.current.y) < .001 ? stopLerpLoop() : lerpRafRef.current = requestAnimationFrame(tick);
|
|
2136
2090
|
};
|
|
2137
2091
|
lerpRafRef.current = requestAnimationFrame(tick);
|
|
2138
|
-
}), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation,
|
|
2092
|
+
}), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, isFixedOrSticky, resolvedBorder.animated, resolvedBorder.opacityMultiplier, stopLerpLoop ]), handleGlobalMousePosition = useCallback((globalPos => {
|
|
2139
2093
|
if (externalGlobalMousePosition && externalMouseOffset) return;
|
|
2140
2094
|
if (effectiveWithoutEffects) return;
|
|
2141
2095
|
const container = mouseContainer?.current || glassRef.current;
|
|
@@ -2199,9 +2153,10 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
2199
2153
|
withLiquidBlur: withLiquidBlur,
|
|
2200
2154
|
blurAmount: blurAmount,
|
|
2201
2155
|
saturation: saturation,
|
|
2202
|
-
|
|
2156
|
+
borderAnimated: resolvedBorder.animated,
|
|
2157
|
+
borderOpacityMultiplier: resolvedBorder.opacityMultiplier
|
|
2203
2158
|
});
|
|
2204
|
-
}), [ isHovered, isActive, glassSize, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation,
|
|
2159
|
+
}), [ isHovered, isActive, glassSize, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation, resolvedBorder.animated, resolvedBorder.opacityMultiplier, onClick ]);
|
|
2205
2160
|
// Event handlers
|
|
2206
2161
|
const handleMouseEnter = useCallback((() => setIsHovered(!0)), []), handleMouseLeave = useCallback((() => setIsHovered(!1)), []), handleMouseDown = useCallback((() => setIsActive(!0)), []), handleMouseUp = useCallback((() => setIsActive(!1)), []), handleKeyDown = useCallback((e => {
|
|
2207
2162
|
!onClick || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), onClick());
|
|
@@ -2221,9 +2176,8 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
2221
2176
|
mouseOffset: mouseOffset,
|
|
2222
2177
|
// This is now static (refs or props) unless prop changes
|
|
2223
2178
|
overLightConfig: overLightConfig,
|
|
2179
|
+
resolvedBorder: resolvedBorder,
|
|
2224
2180
|
transformStyle: transformStyle,
|
|
2225
|
-
getShaderTime: getShaderTime,
|
|
2226
|
-
applyTimeBasedDistortion: applyTimeBasedDistortion,
|
|
2227
2181
|
handleMouseEnter: handleMouseEnter,
|
|
2228
2182
|
handleMouseLeave: handleMouseLeave,
|
|
2229
2183
|
handleMouseDown: handleMouseDown,
|
|
@@ -2281,148 +2235,6 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
2281
2235
|
*
|
|
2282
2236
|
* @returns Performance tier classification
|
|
2283
2237
|
*/
|
|
2284
|
-
/** Map an FPS value to a semantic color token string. */
|
|
2285
|
-
const getQualityColor = quality => {
|
|
2286
|
-
switch (quality) {
|
|
2287
|
-
case "high":
|
|
2288
|
-
return "var(--atomix-color-success, #4ade80)";
|
|
2289
|
-
|
|
2290
|
-
case "medium":
|
|
2291
|
-
return "var(--atomix-color-warning, #fbbf24)";
|
|
2292
|
-
|
|
2293
|
-
case "low":
|
|
2294
|
-
return "var(--atomix-color-danger, #ef4444)";
|
|
2295
|
-
|
|
2296
|
-
default:
|
|
2297
|
-
return "#9ca3af";
|
|
2298
|
-
}
|
|
2299
|
-
}, getFpsLabel = fps => fps >= 58 ? "Optimal" : fps >= 45 ? "Warning" : "Critical";
|
|
2300
|
-
|
|
2301
|
-
/** Map a quality level string to a semantic color token string. */
|
|
2302
|
-
// Inject keyframes once
|
|
2303
|
-
if ("undefined" != typeof document) {
|
|
2304
|
-
const styleId = "perf-dashboard-keyframes";
|
|
2305
|
-
if (!document.getElementById(styleId)) {
|
|
2306
|
-
const styleEl = document.createElement("style");
|
|
2307
|
-
styleEl.id = styleId, styleEl.textContent = "\n@keyframes perf-dashboard-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n",
|
|
2308
|
-
document.head.appendChild(styleEl);
|
|
2309
|
-
}
|
|
2310
|
-
}
|
|
2311
|
-
|
|
2312
|
-
/**
|
|
2313
|
-
* PerformanceDashboard - Real-time performance monitoring overlay.
|
|
2314
|
-
*
|
|
2315
|
-
* Displays FPS, frame time, quality level, GPU memory, and auto-scaling status.
|
|
2316
|
-
* Rendered only when `debugPerformance={true}` on the parent `AtomixGlass`.
|
|
2317
|
-
*/ const PerformanceDashboard = memo((({metrics: metrics, isVisible: isVisible = !0, onClose: onClose}) => {
|
|
2318
|
-
if (!isVisible) return null;
|
|
2319
|
-
const fpsColor = (fps = metrics.fps) >= 58 ? "var(--atomix-color-success, #4ade80)" : fps >= 45 ? "var(--atomix-color-warning, #fbbf24)" : "var(--atomix-color-danger, #ef4444)";
|
|
2320
|
-
var fps;
|
|
2321
|
-
const isCritical = metrics.fps < 45;
|
|
2322
|
-
return jsxs("div", {
|
|
2323
|
-
className: "c-perf-dashboard u-position-fixed u-top-4 u-end-4 u-p-3 u-px-4 u-text-xs u-font-mono u-text-white u-rounded-md u-border u-border-white-alpha-10 u-shadow-lg",
|
|
2324
|
-
style: {
|
|
2325
|
-
zIndex: 9999,
|
|
2326
|
-
minWidth: "12.5rem",
|
|
2327
|
-
// 200px
|
|
2328
|
-
backgroundColor: "rgba(17, 24, 39, 0.95)",
|
|
2329
|
-
backdropFilter: "blur(8px)",
|
|
2330
|
-
transition: "opacity 0.3s ease"
|
|
2331
|
-
},
|
|
2332
|
-
children: [ jsxs("div", {
|
|
2333
|
-
className: "u-flex u-items-center u-justify-between u-mb-2 u-pb-2 u-border-b u-border-white-alpha-10",
|
|
2334
|
-
children: [ jsx("span", {
|
|
2335
|
-
className: "u-text-sm u-font-bold u-text-white",
|
|
2336
|
-
children: "Performance Monitor"
|
|
2337
|
-
}), onClose && jsx("button", {
|
|
2338
|
-
className: "u-bg-transparent u-border-none u-p-0 u-line-height-1 u-text-base u-text-gray-400 u-cursor-pointer hover:u-text-white",
|
|
2339
|
-
onClick: onClose,
|
|
2340
|
-
"aria-label": "Close performance dashboard",
|
|
2341
|
-
style: {
|
|
2342
|
-
transition: "color 0.2s ease"
|
|
2343
|
-
},
|
|
2344
|
-
children: "×"
|
|
2345
|
-
}) ]
|
|
2346
|
-
}), jsxs("div", {
|
|
2347
|
-
className: "u-flex u-items-center u-justify-between u-mb-1-5",
|
|
2348
|
-
children: [ jsx("span", {
|
|
2349
|
-
className: "u-text-gray-400 u-me-3",
|
|
2350
|
-
children: "FPS"
|
|
2351
|
-
}), jsx("span", {
|
|
2352
|
-
className: "u-font-bold",
|
|
2353
|
-
style: {
|
|
2354
|
-
color: fpsColor
|
|
2355
|
-
},
|
|
2356
|
-
children: Math.round(metrics.fps)
|
|
2357
|
-
}) ]
|
|
2358
|
-
}), jsxs("div", {
|
|
2359
|
-
className: "u-flex u-items-center u-justify-between u-mb-1-5",
|
|
2360
|
-
children: [ jsx("span", {
|
|
2361
|
-
className: "u-text-gray-400 u-me-3",
|
|
2362
|
-
children: "Frame Time"
|
|
2363
|
-
}), jsxs("span", {
|
|
2364
|
-
className: "u-font-bold",
|
|
2365
|
-
children: [ metrics.frameTime.toFixed(2), "ms" ]
|
|
2366
|
-
}) ]
|
|
2367
|
-
}), jsxs("div", {
|
|
2368
|
-
className: "u-flex u-items-center u-justify-between u-mb-1-5",
|
|
2369
|
-
children: [ jsx("span", {
|
|
2370
|
-
className: "u-text-gray-400 u-me-3",
|
|
2371
|
-
children: "Quality"
|
|
2372
|
-
}), jsx("span", {
|
|
2373
|
-
className: "u-font-bold u-text-uppercase",
|
|
2374
|
-
style: {
|
|
2375
|
-
fontSize: "0.6875rem",
|
|
2376
|
-
// 11px
|
|
2377
|
-
color: getQualityColor(metrics.qualityLevel)
|
|
2378
|
-
},
|
|
2379
|
-
children: metrics.qualityLevel
|
|
2380
|
-
}) ]
|
|
2381
|
-
}), metrics.gpuMemory && jsxs("div", {
|
|
2382
|
-
className: "u-flex u-items-center u-justify-between u-mb-1-5",
|
|
2383
|
-
children: [ jsx("span", {
|
|
2384
|
-
className: "u-text-gray-400 u-me-3",
|
|
2385
|
-
children: "GPU Memory"
|
|
2386
|
-
}), jsxs("span", {
|
|
2387
|
-
className: "u-font-bold",
|
|
2388
|
-
children: [ "~", Math.round(metrics.gpuMemory / 1024), "MB" ]
|
|
2389
|
-
}) ]
|
|
2390
|
-
}), metrics.isAutoScaling && jsx("div", {
|
|
2391
|
-
className: "u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10 u-text-center",
|
|
2392
|
-
style: {
|
|
2393
|
-
fontSize: "0.625rem",
|
|
2394
|
-
// 10px
|
|
2395
|
-
color: "#6b7280"
|
|
2396
|
-
},
|
|
2397
|
-
children: "Auto-scaling active"
|
|
2398
|
-
}), jsxs("div", {
|
|
2399
|
-
className: "u-flex u-items-center u-gap-2 u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10",
|
|
2400
|
-
children: [ jsx("div", {
|
|
2401
|
-
className: "u-rounded-full",
|
|
2402
|
-
style: {
|
|
2403
|
-
width: "0.5rem",
|
|
2404
|
-
height: "0.5rem",
|
|
2405
|
-
flexShrink: 0,
|
|
2406
|
-
backgroundColor: fpsColor,
|
|
2407
|
-
...isCritical && {
|
|
2408
|
-
animation: "perf-dashboard-pulse 1s infinite"
|
|
2409
|
-
}
|
|
2410
|
-
}
|
|
2411
|
-
}), jsx("span", {
|
|
2412
|
-
className: "u-text-xs",
|
|
2413
|
-
style: {
|
|
2414
|
-
fontSize: "0.625rem",
|
|
2415
|
-
// 10px
|
|
2416
|
-
color: fpsColor
|
|
2417
|
-
},
|
|
2418
|
-
children: getFpsLabel(metrics.fps)
|
|
2419
|
-
}) ]
|
|
2420
|
-
}) ]
|
|
2421
|
-
});
|
|
2422
|
-
}));
|
|
2423
|
-
|
|
2424
|
-
PerformanceDashboard.displayName = "PerformanceDashboard";
|
|
2425
|
-
|
|
2426
2238
|
/**
|
|
2427
2239
|
* Mobile optimization presets
|
|
2428
2240
|
*
|
|
@@ -2542,18 +2354,13 @@ const PERFORMANCE_PRESET = {
|
|
|
2542
2354
|
saturation: 70
|
|
2543
2355
|
}
|
|
2544
2356
|
}
|
|
2545
|
-
}, AtomixGlassInner = forwardRef((function({children: children, displacementScale: displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, aberrationIntensity: aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer = null, className: className = "",
|
|
2546
|
-
const glassRef = useRef(null), contentRef = useRef(null), internalWrapperRef = useRef(null), mergedRef =
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
}));
|
|
2553
|
-
};
|
|
2554
|
-
}
|
|
2555
|
-
// Internal implementation with forwardRef
|
|
2556
|
-
(ref, internalWrapperRef)), [ ref ]), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = propsIsFixedOrSticky || "fixed" === restStyle.position || "sticky" === restStyle.position, {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveBorderRadius: effectiveBorderRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveWithoutEffects: effectiveWithoutEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, getShaderTime: getShaderTime, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
|
|
2357
|
+
}, AtomixGlassInner = forwardRef((function({children: children, displacementScale: displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, aberrationIntensity: aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer = null, className: className = "", overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, style: style = {}, mode: mode = ATOMIX_GLASS.DEFAULTS.MODE, onClick: onClick, shaderVariant: shaderVariant = "liquidGlass", "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, role: role, tabIndex: tabIndex, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, withLiquidBlur: withLiquidBlur = !1, border: border, withBorder: withBorder = !0, debugBorderRadius: debugBorderRadius = !1, withOverLightLayers: withOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS, debugPerformance: debugPerformance = !1, debugOverLight: debugOverLight = !1, height: height, width: width, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", devicePreset: devicePreset = "balanced", disableResponsiveBreakpoints: disableResponsiveBreakpoints = !1, isFixedOrSticky: propsIsFixedOrSticky, ...rest}, ref) {
|
|
2358
|
+
const glassRef = useRef(null), contentRef = useRef(null), internalWrapperRef = useRef(null), mergedRef = useForkRef(ref, internalWrapperRef), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = (explicit = propsIsFixedOrSticky,
|
|
2359
|
+
position = restStyle.position, Boolean(explicit || "fixed" === position || "sticky" === position));
|
|
2360
|
+
var explicit, position;
|
|
2361
|
+
/**
|
|
2362
|
+
* Extracts layout-related properties from a React `CSSProperties` object.
|
|
2363
|
+
*/ const {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveBorderRadius: effectiveBorderRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveWithoutEffects: effectiveWithoutEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown, resolvedBorder: resolvedBorder} = useAtomixGlass({
|
|
2557
2364
|
glassRef: glassRef,
|
|
2558
2365
|
contentRef: contentRef,
|
|
2559
2366
|
wrapperRef: internalWrapperRef,
|
|
@@ -2573,20 +2380,13 @@ const PERFORMANCE_PRESET = {
|
|
|
2573
2380
|
blurAmount: blurAmount,
|
|
2574
2381
|
saturation: saturation,
|
|
2575
2382
|
withLiquidBlur: withLiquidBlur,
|
|
2576
|
-
|
|
2383
|
+
border: border,
|
|
2384
|
+
withBorder: withBorder,
|
|
2385
|
+
debugBorderRadius: debugBorderRadius,
|
|
2577
2386
|
style: style,
|
|
2578
|
-
isFixedOrSticky: isFixedOrSticky
|
|
2579
|
-
// Phase 1: Animation System props
|
|
2580
|
-
withTimeAnimation: withTimeAnimation,
|
|
2581
|
-
animationSpeed: animationSpeed,
|
|
2582
|
-
withMultiLayerDistortion: withMultiLayerDistortion,
|
|
2583
|
-
distortionOctaves: distortionOctaves,
|
|
2584
|
-
distortionLacunarity: distortionLacunarity,
|
|
2585
|
-
distortionGain: distortionGain,
|
|
2586
|
-
distortionQuality: distortionQuality
|
|
2387
|
+
isFixedOrSticky: isFixedOrSticky
|
|
2587
2388
|
});
|
|
2588
|
-
|
|
2589
|
-
!
|
|
2389
|
+
(
|
|
2590
2390
|
/**
|
|
2591
2391
|
* Responsive Glass Parameters Hook
|
|
2592
2392
|
*
|
|
@@ -2744,7 +2544,7 @@ const PERFORMANCE_PRESET = {
|
|
|
2744
2544
|
}
|
|
2745
2545
|
/**
|
|
2746
2546
|
* Get GPU memory info if available (Chrome DevTools only)
|
|
2747
|
-
*/
|
|
2547
|
+
*/)({
|
|
2748
2548
|
baseParams: {
|
|
2749
2549
|
...useMemo((() =>
|
|
2750
2550
|
/**
|
|
@@ -2778,9 +2578,7 @@ const PERFORMANCE_PRESET = {
|
|
|
2778
2578
|
breakpoints: MOBILE_OPTIMIZED_BREAKPOINTS,
|
|
2779
2579
|
enabled: !disableResponsiveBreakpoints && "undefined" != typeof window,
|
|
2780
2580
|
debug: !1
|
|
2781
|
-
})
|
|
2782
|
-
// Performance monitoring - tracks FPS, frame time, memory usage
|
|
2783
|
-
const {metrics: performanceMetrics, toggleMonitoring: toggleMonitoring} =
|
|
2581
|
+
}),
|
|
2784
2582
|
/**
|
|
2785
2583
|
* Performance Monitor Hook
|
|
2786
2584
|
*
|
|
@@ -2815,7 +2613,13 @@ const PERFORMANCE_PRESET = {
|
|
|
2815
2613
|
timestamp: 0,
|
|
2816
2614
|
isAutoScaling: !0,
|
|
2817
2615
|
lowFpsCount: 0
|
|
2818
|
-
}), [manualOverride, setManualOverride] = useState(!1), [isEnabled, setIsEnabled] = useState(enabled)
|
|
2616
|
+
}), [manualOverride, setManualOverride] = useState(!1), [isEnabled, setIsEnabled] = useState(enabled);
|
|
2617
|
+
// Sync external `enabled` prop changes into internal state
|
|
2618
|
+
useEffect((() => {
|
|
2619
|
+
setIsEnabled(enabled ?? !0);
|
|
2620
|
+
}), [ enabled ]);
|
|
2621
|
+
// Refs for frame tracking
|
|
2622
|
+
const frameCountRef = useRef(0), lastFpsUpdateRef = useRef(0), lastFrameTimeRef = useRef(0), animationFrameRef = useRef(null), lowFpsCountRef = useRef(0), highFpsCountRef = useRef(0), qualityLevelRef = useRef("medium"), updateMetrics = useCallback((newMetrics => {
|
|
2819
2623
|
setMetrics((prev => ({
|
|
2820
2624
|
...prev,
|
|
2821
2625
|
...newMetrics,
|
|
@@ -2935,191 +2739,214 @@ const PERFORMANCE_PRESET = {
|
|
|
2935
2739
|
/**
|
|
2936
2740
|
* Reset to auto-scaling mode
|
|
2937
2741
|
*/ var fps, currentQuality;
|
|
2938
|
-
|
|
2939
|
-
metrics: metrics,
|
|
2940
|
-
recommendedQuality: (fps = metrics.fps, currentQuality = metrics.qualityLevel, fps >= 58 ? "high" : fps >= 45 ? "high" === currentQuality ? "high" : "medium" : "low"),
|
|
2941
|
-
isUnderperforming: metrics.fps < minFps,
|
|
2942
|
-
setQualityLevel: setQualityLevel,
|
|
2943
|
-
resetAutoScaling: resetAutoScaling,
|
|
2944
|
-
toggleMonitoring: toggleMonitoring
|
|
2945
|
-
};
|
|
2742
|
+
fps = metrics.fps, currentQuality = metrics.qualityLevel, metrics.fps;
|
|
2946
2743
|
}({
|
|
2947
2744
|
enabled: debugPerformance,
|
|
2948
|
-
// Enable when debugPerformance is true
|
|
2949
2745
|
debug: !1,
|
|
2950
2746
|
showOverlay: !1
|
|
2951
2747
|
});
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
}), [ debugPerformance ]);
|
|
2957
|
-
// Re-run when debugPerformance changes
|
|
2958
|
-
const isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, rootLayoutStyle = useMemo((() => {
|
|
2959
|
-
if (!isFixedOrSticky) return {};
|
|
2960
|
-
const {position: p, top: t, left: l, right: r, bottom: b} = restStyle;
|
|
2961
|
-
return {
|
|
2962
|
-
...p && {
|
|
2963
|
-
position: p
|
|
2964
|
-
},
|
|
2965
|
-
...void 0 !== t && {
|
|
2966
|
-
top: t
|
|
2967
|
-
},
|
|
2968
|
-
...void 0 !== l && {
|
|
2969
|
-
left: l
|
|
2970
|
-
},
|
|
2971
|
-
...void 0 !== r && {
|
|
2972
|
-
right: r
|
|
2973
|
-
},
|
|
2974
|
-
...void 0 !== b && {
|
|
2975
|
-
bottom: b
|
|
2976
|
-
}
|
|
2977
|
-
};
|
|
2978
|
-
}), [ isFixedOrSticky, restStyle ]);
|
|
2979
|
-
// Calculate base style with transforms
|
|
2980
|
-
// When layout is hoisted to the root, strip those props from the container
|
|
2981
|
-
useMemo((() => {
|
|
2982
|
-
if (isFixedOrSticky) {
|
|
2983
|
-
const {position: _p, top: _t, left: _l, right: _r, bottom: _b, ...visualStyle} = restStyle;
|
|
2984
|
-
return {
|
|
2985
|
-
...visualStyle
|
|
2986
|
-
};
|
|
2748
|
+
const isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, containerStyle = useMemo((() => ({
|
|
2749
|
+
...restStyle,
|
|
2750
|
+
...void 0 !== customZIndex && {
|
|
2751
|
+
zIndex: customZIndex
|
|
2987
2752
|
}
|
|
2753
|
+
})), [ restStyle, customZIndex ]), componentClassName = mergeClassNames(ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`, effectiveWithoutEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`, className), positionStyles = useMemo((() =>
|
|
2754
|
+
/**
|
|
2755
|
+
* Returns the internal positioning context for effect layers relative to the root.
|
|
2756
|
+
*/
|
|
2757
|
+
function(isFixedOrSticky, restStyle) {
|
|
2988
2758
|
return {
|
|
2989
|
-
|
|
2759
|
+
position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
|
|
2760
|
+
top: 0,
|
|
2761
|
+
left: 0,
|
|
2762
|
+
right: "auto",
|
|
2763
|
+
bottom: "auto"
|
|
2990
2764
|
};
|
|
2991
|
-
}
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
})), [ isFixedOrSticky, restStyle.position, restStyle.top, restStyle.left, restStyle.right, restStyle.bottom ]), adjustedSize = useMemo((() => {
|
|
3000
|
-
// Keep a reference to positionStyles to avoid unused-variable lint,
|
|
3001
|
-
// but sizing is driven by explicit width/height or measured size.
|
|
3002
|
-
positionStyles.position;
|
|
3003
|
-
const resolveLength = (value, measured) => void 0 !== value && isFixedOrSticky ? "number" == typeof value ? `${value}px` : value : measured > 0 && isFixedOrSticky ? `${measured}px` : "100%", effectiveWidth = width ?? restStyle.width, effectiveHeight = height ?? restStyle.height;
|
|
2765
|
+
}
|
|
2766
|
+
/**
|
|
2767
|
+
* Computes `--atomix-glass-width` and `--atomix-glass-height` values.
|
|
2768
|
+
*
|
|
2769
|
+
* Fixed/sticky elements prefer explicit dimensions or measured size; in-flow
|
|
2770
|
+
* elements default to `100%`.
|
|
2771
|
+
*/ (isFixedOrSticky, restStyle)), [ isFixedOrSticky, restStyle ]), adjustedSize = useMemo((() => function(options) {
|
|
2772
|
+
const {width: width, height: height, restStyle: restStyle, glassSize: glassSize, isFixedOrSticky: isFixedOrSticky} = options, resolveLength = (value, measured) => void 0 !== value && isFixedOrSticky ? "number" == typeof value ? `${value}px` : value : measured > 0 && isFixedOrSticky ? `${measured}px` : "100%", effectiveWidth = width ?? restStyle.width, effectiveHeight = height ?? restStyle.height;
|
|
3004
2773
|
return {
|
|
3005
2774
|
width: resolveLength(effectiveWidth, glassSize.width),
|
|
3006
2775
|
height: resolveLength(effectiveHeight, glassSize.height)
|
|
3007
2776
|
};
|
|
3008
|
-
}
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
2777
|
+
}
|
|
2778
|
+
/**
|
|
2779
|
+
* Builds the CSS custom properties applied to the root `.c-atomix-glass` element.
|
|
2780
|
+
*
|
|
2781
|
+
* These variables drive layer geometry, transforms, and stacking offsets. They
|
|
2782
|
+
* must not include layout properties that would interfere with backdrop-filter.
|
|
2783
|
+
*/ ({
|
|
2784
|
+
width: width,
|
|
2785
|
+
height: height,
|
|
2786
|
+
restStyle: restStyle,
|
|
2787
|
+
glassSize: glassSize,
|
|
2788
|
+
isFixedOrSticky: isFixedOrSticky
|
|
2789
|
+
})), [ width, height, restStyle, glassSize, isFixedOrSticky ]), glassVars = useMemo((() => function(input) {
|
|
2790
|
+
const {effectiveBorderRadius: effectiveBorderRadius, transformStyle: transformStyle, adjustedSize: adjustedSize, isOverLight: isOverLight, customZIndex: customZIndex, isFixedOrSticky: isFixedOrSticky, positionStyles: positionStyles, restStyle: restStyle, borderWidth: borderWidth = ATOMIX_GLASS.BORDER.DEFAULT_WIDTH} = input, layerPosition =
|
|
2791
|
+
/**
|
|
2792
|
+
* Resolves the `--atomix-glass-position` value for decorative layers.
|
|
2793
|
+
*
|
|
2794
|
+
* Fixed/sticky layers use the same positioning mode as the container; in-flow
|
|
2795
|
+
* layers default to the internal absolute positioning context.
|
|
2796
|
+
*/
|
|
2797
|
+
function(isFixedOrSticky, positionStyles, restStyle) {
|
|
2798
|
+
return isFixedOrSticky ? `${function(style) {
|
|
2799
|
+
const {position: position, top: top, left: left, right: right, bottom: bottom, inset: inset} = style;
|
|
2800
|
+
return {
|
|
2801
|
+
...null != position && {
|
|
2802
|
+
position: position
|
|
2803
|
+
},
|
|
2804
|
+
...void 0 !== top && {
|
|
2805
|
+
top: top
|
|
2806
|
+
},
|
|
2807
|
+
...void 0 !== left && {
|
|
2808
|
+
left: left
|
|
2809
|
+
},
|
|
2810
|
+
...void 0 !== right && {
|
|
2811
|
+
right: right
|
|
2812
|
+
},
|
|
2813
|
+
...void 0 !== bottom && {
|
|
2814
|
+
bottom: bottom
|
|
2815
|
+
},
|
|
2816
|
+
...void 0 !== inset && {
|
|
2817
|
+
inset: inset
|
|
2818
|
+
}
|
|
2819
|
+
};
|
|
2820
|
+
}
|
|
2821
|
+
/**
|
|
2822
|
+
* Resolves inset custom properties for decorative layers (hover, borders, backgrounds).
|
|
2823
|
+
*
|
|
2824
|
+
* For fixed and sticky modes, insets mirror the container so sibling layers remain
|
|
2825
|
+
* aligned. In-flow modes, insets follow the consumer `style` when a non-default
|
|
2826
|
+
* `position` is provided.
|
|
2827
|
+
*/ (restStyle).position ?? restStyle.position ?? "fixed"}` : `${positionStyles.position}`;
|
|
2828
|
+
}(isFixedOrSticky, positionStyles, restStyle), layerInsets = function(isFixedOrSticky, restStyle) {
|
|
2829
|
+
if (isFixedOrSticky) return {
|
|
2830
|
+
top: formatGlassInsetValue(restStyle.top, 0),
|
|
2831
|
+
left: formatGlassInsetValue(restStyle.left, 0),
|
|
2832
|
+
right: formatGlassInsetValue(restStyle.right, "auto"),
|
|
2833
|
+
bottom: formatGlassInsetValue(restStyle.bottom, "auto")
|
|
2834
|
+
};
|
|
2835
|
+
const position = restStyle.position;
|
|
2836
|
+
return null != position && "static" !== position && "relative" !== position ? {
|
|
2837
|
+
top: formatGlassInsetValue(restStyle.top, 0),
|
|
2838
|
+
left: formatGlassInsetValue(restStyle.left, 0),
|
|
2839
|
+
right: formatGlassInsetValue(restStyle.right, "auto"),
|
|
2840
|
+
bottom: formatGlassInsetValue(restStyle.bottom, "auto")
|
|
2841
|
+
} : {
|
|
2842
|
+
top: "0px",
|
|
2843
|
+
left: "0px",
|
|
2844
|
+
right: "auto",
|
|
2845
|
+
bottom: "auto"
|
|
2846
|
+
};
|
|
2847
|
+
}(isFixedOrSticky, restStyle);
|
|
3046
2848
|
return {
|
|
3047
2849
|
...void 0 !== customZIndex && {
|
|
3048
2850
|
"--atomix-glass-base-z-index": customZIndex
|
|
3049
2851
|
},
|
|
3050
2852
|
"--atomix-glass-radius": `${effectiveBorderRadius}px`,
|
|
3051
2853
|
"--atomix-glass-transform": transformStyle || "none",
|
|
3052
|
-
"--atomix-glass-container-position":
|
|
3053
|
-
"--atomix-glass-position":
|
|
3054
|
-
"--atomix-glass-top":
|
|
3055
|
-
"--atomix-glass-left":
|
|
3056
|
-
"--atomix-glass-right":
|
|
3057
|
-
"--atomix-glass-bottom":
|
|
2854
|
+
"--atomix-glass-container-position": layerPosition,
|
|
2855
|
+
"--atomix-glass-position": layerPosition,
|
|
2856
|
+
"--atomix-glass-top": layerInsets.top,
|
|
2857
|
+
"--atomix-glass-left": layerInsets.left,
|
|
2858
|
+
"--atomix-glass-right": layerInsets.right,
|
|
2859
|
+
"--atomix-glass-bottom": layerInsets.bottom,
|
|
3058
2860
|
"--atomix-glass-width": adjustedSize.width,
|
|
3059
2861
|
"--atomix-glass-height": adjustedSize.height,
|
|
3060
|
-
|
|
3061
|
-
"--atomix-glass-
|
|
3062
|
-
"--atomix-glass-
|
|
3063
|
-
|
|
3064
|
-
"--atomix-glass-
|
|
3065
|
-
"--atomix-glass-hover-1-gradient": isOverLight ? `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_STOP}%)`,
|
|
3066
|
-
"--atomix-glass-hover-2-opacity": opacityValues.hover2,
|
|
3067
|
-
"--atomix-glass-hover-2-gradient": isOverLight ? `radial-gradient(circle at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_STOP}%)`,
|
|
3068
|
-
"--atomix-glass-hover-3-opacity": opacityValues.hover3,
|
|
3069
|
-
"--atomix-glass-hover-3-gradient": isOverLight ? `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_STOP}%)`,
|
|
3070
|
-
"--atomix-glass-base-opacity": opacityValues.base,
|
|
3071
|
-
"--atomix-glass-base-gradient": isOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + mx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + my * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + absMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`,
|
|
3072
|
-
"--atomix-glass-overlay-opacity": opacityValues.over,
|
|
3073
|
-
"--atomix-glass-overlay-gradient": isOverLight ? `radial-gradient(circle at ${basePosition.x}% ${basePosition.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + absMx * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + absMy * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`,
|
|
3074
|
-
"--atomix-glass-overlay-highlight-opacity": opacityValues.over * ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER,
|
|
3075
|
-
"--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}%)`
|
|
2862
|
+
// Aliases maintained for backward compatibility and consumer overrides.
|
|
2863
|
+
"--atomix-glass-container-width": adjustedSize.width,
|
|
2864
|
+
"--atomix-glass-container-height": adjustedSize.height,
|
|
2865
|
+
[ATOMIX_GLASS.BORDER.WIDTH_CSS_VAR]: borderWidth,
|
|
2866
|
+
"--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay"
|
|
3076
2867
|
};
|
|
3077
|
-
}
|
|
3078
|
-
|
|
2868
|
+
}
|
|
2869
|
+
/**
|
|
2870
|
+
* Applies mode-specific multipliers and accessibility overrides to container effects.
|
|
2871
|
+
*/ ({
|
|
2872
|
+
effectiveBorderRadius: effectiveBorderRadius,
|
|
2873
|
+
transformStyle: transformStyle,
|
|
2874
|
+
adjustedSize: adjustedSize,
|
|
2875
|
+
isOverLight: isOverLight,
|
|
2876
|
+
customZIndex: customZIndex,
|
|
2877
|
+
isFixedOrSticky: isFixedOrSticky,
|
|
2878
|
+
positionStyles: positionStyles,
|
|
2879
|
+
restStyle: restStyle,
|
|
2880
|
+
borderWidth: resolvedBorder.width
|
|
2881
|
+
})), [ effectiveBorderRadius, transformStyle, adjustedSize, isOverLight, customZIndex, isFixedOrSticky, positionStyles, restStyle, resolvedBorder.width ]), containerEffects = useMemo((() => function(options) {
|
|
2882
|
+
const {MULTIPLIERS: MULTIPLIERS, SATURATION: SATURATION} = ATOMIX_GLASS.CONSTANTS, zeroMouse = {
|
|
2883
|
+
x: 0,
|
|
2884
|
+
y: 0
|
|
2885
|
+
}, resolveSaturation = () => options.effectiveHighContrast ? SATURATION.HIGH_CONTRAST : options.isOverLight ? options.saturation * options.saturationBoost : options.saturation;
|
|
2886
|
+
if (options.effectiveWithoutEffects) return {
|
|
2887
|
+
displacementScale: 0,
|
|
2888
|
+
blurAmount: 0,
|
|
2889
|
+
saturation: resolveSaturation(),
|
|
2890
|
+
aberrationIntensity: 0,
|
|
2891
|
+
mouseOffset: zeroMouse,
|
|
2892
|
+
globalMousePosition: zeroMouse
|
|
2893
|
+
};
|
|
2894
|
+
let resolvedDisplacement = options.displacementScale;
|
|
2895
|
+
"shader" === options.mode ? resolvedDisplacement *= MULTIPLIERS.SHADER_DISPLACEMENT : options.isOverLight && (resolvedDisplacement *= MULTIPLIERS.OVER_LIGHT_DISPLACEMENT);
|
|
2896
|
+
let resolvedAberration = options.aberrationIntensity;
|
|
2897
|
+
return "shader" === options.mode && (resolvedAberration *= MULTIPLIERS.SHADER_ABERRATION),
|
|
2898
|
+
{
|
|
2899
|
+
displacementScale: resolvedDisplacement,
|
|
2900
|
+
blurAmount: options.blurAmount,
|
|
2901
|
+
saturation: resolveSaturation(),
|
|
2902
|
+
aberrationIntensity: resolvedAberration,
|
|
2903
|
+
mouseOffset: options.mouseOffset,
|
|
2904
|
+
globalMousePosition: options.globalMousePosition
|
|
2905
|
+
};
|
|
2906
|
+
}({
|
|
2907
|
+
displacementScale: displacementScale,
|
|
2908
|
+
blurAmount: blurAmount,
|
|
2909
|
+
saturation: saturation,
|
|
2910
|
+
aberrationIntensity: aberrationIntensity,
|
|
2911
|
+
mode: mode,
|
|
2912
|
+
effectiveWithoutEffects: effectiveWithoutEffects,
|
|
2913
|
+
effectiveHighContrast: effectiveHighContrast,
|
|
2914
|
+
isOverLight: isOverLight,
|
|
2915
|
+
saturationBoost: overLightConfig.saturationBoost,
|
|
2916
|
+
mouseOffset: mouseOffset,
|
|
2917
|
+
globalMousePosition: globalMousePosition
|
|
2918
|
+
})), [ displacementScale, blurAmount, saturation, aberrationIntensity, mode, effectiveWithoutEffects, effectiveHighContrast, isOverLight, overLightConfig.saturationBoost, mouseOffset, globalMousePosition ]), renderBackgroundLayer = layerType => jsx("div", {
|
|
2919
|
+
"aria-hidden": "true",
|
|
2920
|
+
className: mergeClassNames(ATOMIX_GLASS.BACKGROUND_LAYER_CLASS, "dark" === layerType ? ATOMIX_GLASS.BACKGROUND_LAYER_DARK_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_BLACK_CLASS, isOverLight ? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS)
|
|
3079
2921
|
});
|
|
3080
|
-
|
|
3081
|
-
// When root is fixed/sticky, internal layers use absolute (relative to root)
|
|
3082
|
-
return jsxs("div", {
|
|
2922
|
+
return jsxs("div", {
|
|
3083
2923
|
...rest,
|
|
3084
2924
|
ref: mergedRef,
|
|
3085
2925
|
className: componentClassName,
|
|
3086
|
-
style:
|
|
3087
|
-
...glassVars
|
|
3088
|
-
},
|
|
2926
|
+
style: glassVars,
|
|
3089
2927
|
role: role || (onClick ? "button" : void 0),
|
|
3090
2928
|
tabIndex: onClick ? tabIndex ?? 0 : tabIndex,
|
|
3091
2929
|
"aria-label": ariaLabel,
|
|
3092
2930
|
"aria-describedby": ariaDescribedBy,
|
|
3093
2931
|
"aria-disabled": !(!onClick || !effectiveWithoutEffects) || !onClick && void 0,
|
|
3094
|
-
"aria-pressed": onClick ? isActive : void 0,
|
|
3095
2932
|
onKeyDown: onClick ? handleKeyDown : void 0,
|
|
3096
2933
|
children: [ jsx(AtomixGlassContainer, {
|
|
3097
2934
|
ref: glassRef,
|
|
3098
2935
|
contentRef: contentRef,
|
|
3099
2936
|
className: className,
|
|
3100
|
-
style:
|
|
3101
|
-
...restStyle
|
|
3102
|
-
},
|
|
2937
|
+
style: containerStyle,
|
|
3103
2938
|
borderRadius: effectiveBorderRadius,
|
|
3104
|
-
displacementScale:
|
|
3105
|
-
blurAmount:
|
|
3106
|
-
saturation:
|
|
3107
|
-
aberrationIntensity:
|
|
2939
|
+
displacementScale: containerEffects.displacementScale,
|
|
2940
|
+
blurAmount: containerEffects.blurAmount,
|
|
2941
|
+
saturation: containerEffects.saturation,
|
|
2942
|
+
aberrationIntensity: containerEffects.aberrationIntensity,
|
|
3108
2943
|
glassSize: glassSize,
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
x: 0,
|
|
3112
|
-
y: 0
|
|
3113
|
-
} : mouseOffset,
|
|
3114
|
-
globalMousePosition: effectiveWithoutEffects ? {
|
|
3115
|
-
x: 0,
|
|
3116
|
-
y: 0
|
|
3117
|
-
} : globalMousePosition,
|
|
2944
|
+
mouseOffset: containerEffects.mouseOffset,
|
|
2945
|
+
globalMousePosition: containerEffects.globalMousePosition,
|
|
3118
2946
|
onMouseEnter: handleMouseEnter,
|
|
3119
2947
|
onMouseLeave: handleMouseLeave,
|
|
3120
2948
|
onMouseDown: handleMouseDown,
|
|
3121
2949
|
onMouseUp: handleMouseUp,
|
|
3122
|
-
isHovered: isHovered,
|
|
3123
2950
|
isActive: isActive,
|
|
3124
2951
|
overLight: isOverLight,
|
|
3125
2952
|
overLightConfig: {
|
|
@@ -3135,8 +2962,6 @@ const PERFORMANCE_PRESET = {
|
|
|
3135
2962
|
shaderVariant: shaderVariant,
|
|
3136
2963
|
withLiquidBlur: withLiquidBlur,
|
|
3137
2964
|
isFixedOrSticky: isFixedOrSticky,
|
|
3138
|
-
// Phase 1: Animation System props
|
|
3139
|
-
shaderTime: getShaderTime(),
|
|
3140
2965
|
withTimeAnimation: withTimeAnimation,
|
|
3141
2966
|
animationSpeed: animationSpeed,
|
|
3142
2967
|
withMultiLayerDistortion: withMultiLayerDistortion,
|
|
@@ -3147,32 +2972,39 @@ const PERFORMANCE_PRESET = {
|
|
|
3147
2972
|
children: children
|
|
3148
2973
|
}), Boolean(onClick) && jsxs(Fragment, {
|
|
3149
2974
|
children: [ jsx("div", {
|
|
2975
|
+
"aria-hidden": "true",
|
|
3150
2976
|
className: ATOMIX_GLASS.HOVER_1_CLASS
|
|
3151
2977
|
}), jsx("div", {
|
|
2978
|
+
"aria-hidden": "true",
|
|
3152
2979
|
className: ATOMIX_GLASS.HOVER_2_CLASS
|
|
3153
2980
|
}), jsx("div", {
|
|
2981
|
+
"aria-hidden": "true",
|
|
3154
2982
|
className: ATOMIX_GLASS.HOVER_3_CLASS
|
|
3155
2983
|
}) ]
|
|
3156
|
-
}),
|
|
2984
|
+
}), [ "dark", "black" ].map((layerType => jsx(React.Fragment, {
|
|
2985
|
+
children: renderBackgroundLayer(layerType)
|
|
2986
|
+
}, layerType))), shouldRenderOverLightLayers && jsxs(Fragment, {
|
|
3157
2987
|
children: [ jsx("div", {
|
|
2988
|
+
"aria-hidden": "true",
|
|
3158
2989
|
className: ATOMIX_GLASS.BASE_LAYER_CLASS
|
|
3159
2990
|
}), jsx("div", {
|
|
2991
|
+
"aria-hidden": "true",
|
|
3160
2992
|
className: ATOMIX_GLASS.OVERLAY_LAYER_CLASS
|
|
3161
2993
|
}), jsx("div", {
|
|
2994
|
+
"aria-hidden": "true",
|
|
3162
2995
|
className: ATOMIX_GLASS.OVERLAY_HIGHLIGHT_CLASS
|
|
3163
2996
|
}) ]
|
|
3164
|
-
}),
|
|
2997
|
+
}), resolvedBorder.enabled && jsxs(Fragment, {
|
|
3165
2998
|
children: [ jsx("span", {
|
|
2999
|
+
"aria-hidden": "true",
|
|
3166
3000
|
className: ATOMIX_GLASS.BORDER_BACKDROP_CLASS
|
|
3167
3001
|
}), jsx("span", {
|
|
3002
|
+
"aria-hidden": "true",
|
|
3168
3003
|
className: ATOMIX_GLASS.BORDER_1_CLASS
|
|
3169
3004
|
}), jsx("span", {
|
|
3005
|
+
"aria-hidden": "true",
|
|
3170
3006
|
className: ATOMIX_GLASS.BORDER_2_CLASS
|
|
3171
3007
|
}) ]
|
|
3172
|
-
}), debugPerformance && performanceMetrics && jsx(PerformanceDashboard, {
|
|
3173
|
-
metrics: performanceMetrics,
|
|
3174
|
-
isVisible: !0,
|
|
3175
|
-
onClose: () => {}
|
|
3176
3008
|
}) ]
|
|
3177
3009
|
});
|
|
3178
3010
|
}));
|
|
@@ -3182,10 +3014,7 @@ const PERFORMANCE_PRESET = {
|
|
|
3182
3014
|
* Default preset for most mobile devices
|
|
3183
3015
|
*/ AtomixGlassInner.displayName = "AtomixGlass";
|
|
3184
3016
|
|
|
3185
|
-
/**
|
|
3186
|
-
* AtomixGlass - wrapped with React.memo to prevent unnecessary re-renders.
|
|
3187
|
-
* Ref is forwarded to the root `<div>` element.
|
|
3188
|
-
*/
|
|
3017
|
+
/** Memoized public export. Ref targets the root `.c-atomix-glass` wrapper. */
|
|
3189
3018
|
const AtomixGlass = memo(AtomixGlassInner), DefaultIcon = () => jsx("i", {
|
|
3190
3019
|
className: "c-accordion__icon",
|
|
3191
3020
|
"aria-hidden": "true",
|
|
@@ -3364,10 +3193,7 @@ const AccordionImpl = memo((({title: title, children: children, defaultOpen: de
|
|
|
3364
3193
|
});
|
|
3365
3194
|
if (glass) {
|
|
3366
3195
|
// Default glass settings for accordions
|
|
3367
|
-
const defaultGlassProps = {
|
|
3368
|
-
displacementScale: 20,
|
|
3369
|
-
elasticity: 0
|
|
3370
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
3196
|
+
const defaultGlassProps = GLASS_DEFAULTS_ACCORDION, glassProps = !0 === glass ? defaultGlassProps : {
|
|
3371
3197
|
...defaultGlassProps,
|
|
3372
3198
|
...glass
|
|
3373
3199
|
};
|
|
@@ -3444,10 +3270,10 @@ const Accordion = AccordionWithSubcomponents, Badge = memo((({label: label, var
|
|
|
3444
3270
|
if (glass) {
|
|
3445
3271
|
// Default glass settings for badges
|
|
3446
3272
|
const defaultGlassProps = {
|
|
3447
|
-
|
|
3448
|
-
borderRadius
|
|
3449
|
-
|
|
3450
|
-
|
|
3273
|
+
...GLASS_DEFAULTS_BADGE,
|
|
3274
|
+
// Override borderRadius dynamically if the ref is available
|
|
3275
|
+
borderRadius: ref.current?.getBoundingClientRect().width ? ref.current?.getBoundingClientRect().width / 2 : GLASS_DEFAULTS_BADGE.borderRadius,
|
|
3276
|
+
className: "c-badge--glass"
|
|
3451
3277
|
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
3452
3278
|
...defaultGlassProps,
|
|
3453
3279
|
...glass
|
|
@@ -3697,12 +3523,7 @@ const Spinner = memo( forwardRef((({size: size = "md", variant: variant = "prim
|
|
|
3697
3523
|
})
|
|
3698
3524
|
});
|
|
3699
3525
|
if (glass) {
|
|
3700
|
-
const defaultGlassProps = {
|
|
3701
|
-
displacementScale: 20,
|
|
3702
|
-
blurAmount: 1,
|
|
3703
|
-
borderRadius: 999,
|
|
3704
|
-
mode: "shader"
|
|
3705
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
3526
|
+
const defaultGlassProps = GLASS_DEFAULTS_SPINNER, glassProps = !0 === glass ? defaultGlassProps : {
|
|
3706
3527
|
...defaultGlassProps,
|
|
3707
3528
|
...glass
|
|
3708
3529
|
};
|
|
@@ -3982,11 +3803,7 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
|
|
|
3982
3803
|
// This is a safe fallback for disabled links.
|
|
3983
3804
|
if (glass) {
|
|
3984
3805
|
// Default glass props
|
|
3985
|
-
const defaultGlassProps = {
|
|
3986
|
-
displacementScale: 20,
|
|
3987
|
-
blurAmount: 0,
|
|
3988
|
-
saturation: 200
|
|
3989
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
3806
|
+
const defaultGlassProps = GLASS_DEFAULTS_BUTTON, glassProps = !0 === glass ? defaultGlassProps : {
|
|
3990
3807
|
...defaultGlassProps,
|
|
3991
3808
|
...glass
|
|
3992
3809
|
};
|
|
@@ -4426,11 +4243,7 @@ const Callout = memo((({title: title, children: children, icon: icon, variant:
|
|
|
4426
4243
|
// Determine appropriate ARIA attributes based on variant
|
|
4427
4244
|
if (glass) {
|
|
4428
4245
|
// Default glass settings for callouts
|
|
4429
|
-
const defaultGlassProps = {
|
|
4430
|
-
displacementScale: 30,
|
|
4431
|
-
borderRadius: 8,
|
|
4432
|
-
elasticity: 0
|
|
4433
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
4246
|
+
const defaultGlassProps = GLASS_DEFAULTS_CALLOUT, glassProps = !0 === glass ? defaultGlassProps : {
|
|
4434
4247
|
...defaultGlassProps,
|
|
4435
4248
|
...glass
|
|
4436
4249
|
};
|
|
@@ -4527,40 +4340,15 @@ ListGroup.displayName = "ListGroup";
|
|
|
4527
4340
|
|
|
4528
4341
|
// Adapted from https://github.com/shuding/liquid-glass
|
|
4529
4342
|
// Constants
|
|
4530
|
-
const
|
|
4531
|
-
// Add input validation
|
|
4532
|
-
if ("number" != typeof a || "number" != typeof b || "number" != typeof t) return 0;
|
|
4533
|
-
const clamped = Math.max(0, Math.min(1, (t - a) / (b - a)));
|
|
4534
|
-
return clamped * clamped * (3 - 2 * clamped);
|
|
4535
|
-
}, calculateLength = (x, y) => {
|
|
4536
|
-
// Add input validation and error handling
|
|
4537
|
-
if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
|
|
4538
|
-
// Prevent potential overflow
|
|
4539
|
-
const maxX = Math.max(Math.abs(x), Math.abs(y));
|
|
4540
|
-
if (0 === maxX) return 0;
|
|
4541
|
-
const scaledX = x / maxX, scaledY = y / maxX;
|
|
4542
|
-
return maxX * Math.sqrt(scaledX * scaledX + scaledY * scaledY);
|
|
4543
|
-
}, roundedRectSDF = (x, y, width, height, radius) => {
|
|
4343
|
+
const roundedRectSDF = (x, y, width, height, radius) => {
|
|
4544
4344
|
// Add input validation
|
|
4545
4345
|
if ("number" != typeof x || "number" != typeof y || "number" != typeof width || "number" != typeof height || "number" != typeof radius) return 0;
|
|
4546
4346
|
const qx = Math.abs(x) - width + radius, qy = Math.abs(y) - height + radius;
|
|
4547
|
-
return Math.min(Math.max(qx, qy), 0) +
|
|
4347
|
+
return Math.min(Math.max(qx, qy), 0) + vec2Length(Math.max(qx, 0), Math.max(qy, 0)) - radius;
|
|
4548
4348
|
}, createTexture = (x, y) => ({
|
|
4549
4349
|
x: "number" != typeof x || isNaN(x) ? .5 : Math.max(0, Math.min(1, x)),
|
|
4550
4350
|
y: "number" != typeof y || isNaN(y) ? .5 : Math.max(0, Math.min(1, y))
|
|
4551
|
-
}), validateVec2 = vec => vec && "number" == typeof vec.x && "number" == typeof vec.y && !isNaN(vec.x) && !isNaN(vec.y),
|
|
4552
|
-
// Add input validation
|
|
4553
|
-
"number" != typeof value || "number" != typeof min || "number" != typeof max || isNaN(value) ? min : isNaN(min) ? 0 : isNaN(max) ? 1 : Math.max(min, Math.min(max, value)), easeInOutCubic = t => {
|
|
4554
|
-
// Add input validation
|
|
4555
|
-
if ("number" != typeof t || isNaN(t)) return 0;
|
|
4556
|
-
const clampedT = Math.max(0, Math.min(1, t));
|
|
4557
|
-
return clampedT < .5 ? 4 * clampedT * clampedT * clampedT : 1 - Math.pow(-2 * clampedT + 2, 3) / 2;
|
|
4558
|
-
}, easeOutQuart = t => {
|
|
4559
|
-
// Add input validation
|
|
4560
|
-
if ("number" != typeof t || isNaN(t)) return 0;
|
|
4561
|
-
const clampedT = Math.max(0, Math.min(1, t));
|
|
4562
|
-
return 1 - Math.pow(1 - clampedT, 4);
|
|
4563
|
-
}, noise2D = (x, y) => {
|
|
4351
|
+
}), validateVec2 = vec => vec && "number" == typeof vec.x && "number" == typeof vec.y && !isNaN(vec.x) && !isNaN(vec.y), noise2D = (x, y) => {
|
|
4564
4352
|
// Add input validation
|
|
4565
4353
|
if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
|
|
4566
4354
|
const X = 255 & Math.floor(x), Y = 255 & Math.floor(y), xf = x - Math.floor(x), yf = y - Math.floor(y), u = easeInOutCubic(xf), v = easeInOutCubic(yf), hash = (i, j) => {
|
|
@@ -4599,13 +4387,13 @@ const smoothStep = (a, b, t) => {
|
|
|
4599
4387
|
x: .5,
|
|
4600
4388
|
y: .5
|
|
4601
4389
|
};
|
|
4602
|
-
const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now(), mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance =
|
|
4390
|
+
const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now(), mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = vec2Length(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(2 * mouseDistance, 1)), organicFlow = fbm(12 * (ix + .5 * mouseX) + time, 12 * (iy + .5 * mouseY) + .7 * time, 3) - .5, distanceToEdge = roundedRectSDF(ix, iy, .4, .3, .35), baseDisplacement = smoothstepEdge(.8, 0, distanceToEdge - .05), radialDist = ((x, y, strength) => {
|
|
4603
4391
|
// Add input validation
|
|
4604
4392
|
if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y) || isNaN(strength)) return {
|
|
4605
4393
|
x: 0,
|
|
4606
4394
|
y: 0
|
|
4607
4395
|
};
|
|
4608
|
-
const distance =
|
|
4396
|
+
const distance = vec2Length(x, y), distortion = Math.pow(Math.min(distance, 10), 2) * strength;
|
|
4609
4397
|
// Limit distance to prevent extreme values
|
|
4610
4398
|
return {
|
|
4611
4399
|
x: x * (1 + distortion),
|
|
@@ -4617,7 +4405,7 @@ const smoothStep = (a, b, t) => {
|
|
|
4617
4405
|
x: 0,
|
|
4618
4406
|
y: 0
|
|
4619
4407
|
};
|
|
4620
|
-
const distance =
|
|
4408
|
+
const distance = vec2Length(x, y);
|
|
4621
4409
|
// Prevent division by zero and extreme values
|
|
4622
4410
|
if (0 === distance) return {
|
|
4623
4411
|
x: 0,
|
|
@@ -4628,8 +4416,8 @@ const smoothStep = (a, b, t) => {
|
|
|
4628
4416
|
x: Math.cos(angle) * distance * intensity,
|
|
4629
4417
|
y: Math.sin(angle) * distance * intensity
|
|
4630
4418
|
};
|
|
4631
|
-
})(ix, iy, .015 * baseDisplacement), scaled =
|
|
4632
|
-
return createTexture(
|
|
4419
|
+
})(ix, iy, .015 * baseDisplacement), scaled = smoothstepEdge(0, 1, 1.15 * baseDisplacement), finalX = ix + totalDistortionX + .5 * chromaticOffset.x, finalY = iy + totalDistortionY + .5 * chromaticOffset.y;
|
|
4420
|
+
return createTexture(clamp(finalX * scaled + .5, 0, 1), clamp(finalY * scaled + .5, 0, 1));
|
|
4633
4421
|
},
|
|
4634
4422
|
// Premium Apple-style fluid glass with enhanced organic flow
|
|
4635
4423
|
appleFluid: (uv, mousePosition) => {
|
|
@@ -4637,8 +4425,8 @@ const smoothStep = (a, b, t) => {
|
|
|
4637
4425
|
x: .5,
|
|
4638
4426
|
y: .5
|
|
4639
4427
|
};
|
|
4640
|
-
const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .6, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance =
|
|
4641
|
-
return createTexture(
|
|
4428
|
+
const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .6, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = vec2Length(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(1.5 * mouseDistance, 1)), organicX = fbm(10 * (ix + .3 * mouseX) + time, 10 * (iy + .3 * mouseY), 5) - .5, organicY = fbm(10 * (ix - .3 * mouseX), 10 * (iy - .3 * mouseY) + .8 * time, 5) - .5, distanceToEdge = roundedRectSDF(ix, iy, .42, .32, .38), mask = smoothstepEdge(.85, -.1, distanceToEdge), fluidVelocityX = Math.sin(6 * ix + 2 * time) * Math.cos(4 * iy - time) * .025, fluidVelocityY = Math.cos(4 * ix - time) * Math.sin(6 * iy + 2 * time) * .025, vortexAngle = Math.atan2(iy - mouseY, ix - mouseX), vortexStrength = mouseFalloff * mouseDistance * .08, vortexX = Math.cos(vortexAngle + time) * vortexStrength, totalY = iy + (.035 * organicY + fluidVelocityY + Math.sin(vortexAngle + time) * vortexStrength) * mask;
|
|
4429
|
+
return createTexture(clamp(ix + (.035 * organicX + fluidVelocityX + vortexX) * mask + .5, 0, 1), clamp(totalY + .5, 0, 1));
|
|
4642
4430
|
},
|
|
4643
4431
|
// High-end glass with advanced refraction and depth
|
|
4644
4432
|
premiumGlass: (uv, mousePosition) => {
|
|
@@ -4646,7 +4434,7 @@ const smoothStep = (a, b, t) => {
|
|
|
4646
4434
|
x: .5,
|
|
4647
4435
|
y: .5
|
|
4648
4436
|
};
|
|
4649
|
-
const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .4, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance =
|
|
4437
|
+
const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .4, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = vec2Length(mouseX, mouseY), centerDistance = vec2Length(ix, iy), refractionStrength = .3 * Math.pow(Math.min(centerDistance, 1), 1.5), refractionAngle = Math.atan2(iy, ix);
|
|
4650
4438
|
// Multi-layer depth effect
|
|
4651
4439
|
let depthX = 0, depthY = 0;
|
|
4652
4440
|
for (let layer = 0; layer < 3; layer++) {
|
|
@@ -4654,8 +4442,8 @@ const smoothStep = (a, b, t) => {
|
|
|
4654
4442
|
depthX += Math.sin(ix * layerScale + layerTime) * layerStrength, depthY += Math.cos(iy * layerScale - layerTime) * layerStrength;
|
|
4655
4443
|
}
|
|
4656
4444
|
// Glass refraction with mouse influence
|
|
4657
|
-
const refractionX = Math.cos(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), refractionY = Math.sin(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), organicNoise = fbm(8 * ix + time, 8 * iy - time, 2) - .5, distanceToEdge = roundedRectSDF(ix, iy, .43, .33, .36), edgeMask =
|
|
4658
|
-
return createTexture(
|
|
4445
|
+
const refractionX = Math.cos(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), refractionY = Math.sin(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), organicNoise = fbm(8 * ix + time, 8 * iy - time, 2) - .5, distanceToEdge = roundedRectSDF(ix, iy, .43, .33, .36), edgeMask = smoothstepEdge(.9, -.05, distanceToEdge), finalY = iy + (refractionY + depthY + .015 * organicNoise) * edgeMask;
|
|
4446
|
+
return createTexture(clamp(ix + (refractionX + depthX + .015 * organicNoise) * edgeMask + .5, 0, 1), clamp(finalY + .5, 0, 1));
|
|
4659
4447
|
},
|
|
4660
4448
|
// Metallic liquid effect with shimmer
|
|
4661
4449
|
liquidMetal: (uv, mousePosition) => {
|
|
@@ -4663,8 +4451,8 @@ const smoothStep = (a, b, t) => {
|
|
|
4663
4451
|
x: .5,
|
|
4664
4452
|
y: .5
|
|
4665
4453
|
};
|
|
4666
|
-
const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * 1.2, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, wave1 = Math.sin(20 * ix + 4 * time) * Math.cos(15 * iy - 3 * time) * .02, wave2 = Math.cos(15 * ix - 2 * time) * Math.sin(20 * iy + 5 * time) * .015, shimmer = .025 * fbm(25 * ix + 2 * time, 25 * iy - 2 * time, 4), flowAngle = Math.atan2(iy - mouseY, ix - mouseX), flowDistance =
|
|
4667
|
-
return createTexture(
|
|
4454
|
+
const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * 1.2, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, wave1 = Math.sin(20 * ix + 4 * time) * Math.cos(15 * iy - 3 * time) * .02, wave2 = Math.cos(15 * ix - 2 * time) * Math.sin(20 * iy + 5 * time) * .015, shimmer = .025 * fbm(25 * ix + 2 * time, 25 * iy - 2 * time, 4), flowAngle = Math.atan2(iy - mouseY, ix - mouseX), flowDistance = vec2Length(ix - mouseX, iy - mouseY), flowEffect = .02 * Math.sin(15 * flowDistance - 6 * time) * easeOutQuart(1 - Math.min(2 * flowDistance, 1)), distanceToEdge = roundedRectSDF(ix, iy, .41, .31, .37), mask = smoothstepEdge(.88, -.08, distanceToEdge), totalX = ix + (wave1 + shimmer + Math.cos(flowAngle) * flowEffect) * mask, totalY = iy + (wave2 + .8 * shimmer + Math.sin(flowAngle) * flowEffect) * mask;
|
|
4455
|
+
return createTexture(clamp(totalX + .5, 0, 1), clamp(totalY + .5, 0, 1));
|
|
4668
4456
|
},
|
|
4669
4457
|
// basiBasi - Expert Premium Glass Shader
|
|
4670
4458
|
// The most advanced shader with caustics, spectral dispersion, parallax depth, and volumetric effects
|
|
@@ -4673,7 +4461,7 @@ const smoothStep = (a, b, t) => {
|
|
|
4673
4461
|
x: .5,
|
|
4674
4462
|
y: .5
|
|
4675
4463
|
};
|
|
4676
|
-
const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .5, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance =
|
|
4464
|
+
const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .5, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = vec2Length(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(1.2 * mouseDistance, 1)), causticIntensity = ((x, y, time, intensity = 1) =>
|
|
4677
4465
|
// Add input validation
|
|
4678
4466
|
"number" != typeof x || "number" != typeof y || "number" != typeof time || "number" != typeof intensity || isNaN(x) || isNaN(y) || isNaN(time) || isNaN(intensity) ? .5 : .5 * (Math.sin(8 * x + 2 * time) * Math.cos(8 * y - 2 * time) * .5 + Math.sin(8 * (x + .5) * 1.3 - 2 * time * .8) * Math.cos(8 * (y - .3) * 1.3 + 2 * time * .8) * .3 + Math.sin(8 * (x - .3) * .7 + 2 * time * 1.2) * Math.cos(8 * (y + .4) * .7 - 2 * time * 1.2) * .2 + 1) * intensity)(ix, iy, time, .8), causticDistortion = .02 * (causticIntensity - .5), refractionAngle = Math.atan2(iy, ix), spectralDispersion = ((x, y, angle) => {
|
|
4679
4467
|
// Add input validation
|
|
@@ -4691,7 +4479,7 @@ const smoothStep = (a, b, t) => {
|
|
|
4691
4479
|
y: 0
|
|
4692
4480
|
}
|
|
4693
4481
|
};
|
|
4694
|
-
const distance =
|
|
4482
|
+
const distance = vec2Length(x, y), dispersionStrength = Math.min(.025 * distance, 1), redOffset = .8 * dispersionStrength, greenOffset = 1 * dispersionStrength, blueOffset = 1.2 * dispersionStrength;
|
|
4695
4483
|
return {
|
|
4696
4484
|
r: {
|
|
4697
4485
|
x: Math.cos(angle) * redOffset,
|
|
@@ -4731,8 +4519,8 @@ const smoothStep = (a, b, t) => {
|
|
|
4731
4519
|
return turbulence;
|
|
4732
4520
|
})(6 * ix, 6 * iy, time, 6), turbulenceX = .012 * Math.cos(turbulence * Math.PI * 2), turbulenceY = .012 * Math.sin(turbulence * Math.PI * 2), microSurface = ((x, y, time) =>
|
|
4733
4521
|
// Add input validation
|
|
4734
|
-
"number" != typeof x || "number" != typeof y || "number" != typeof time || isNaN(x) || isNaN(y) || isNaN(time) ? .5 : .5 * (.7 * fbm(40 * x + .3 * time, 40 * y - .3 * time, 6) + .3 * fbm(80 * x, 80 * y, 4)))(ix, iy, time), microDetailX = .008 * (microSurface - .5), microDetailY = .008 * (microSurface - .5), centerDistance =
|
|
4735
|
-
return createTexture(
|
|
4522
|
+
"number" != typeof x || "number" != typeof y || "number" != typeof time || isNaN(x) || isNaN(y) || isNaN(time) ? .5 : .5 * (.7 * fbm(40 * x + .3 * time, 40 * y - .3 * time, 6) + .3 * fbm(80 * x, 80 * y, 4)))(ix, iy, time), microDetailX = .008 * (microSurface - .5), microDetailY = .008 * (microSurface - .5), centerDistance = vec2Length(ix, iy), dynamicRefraction = .35 * Math.pow(Math.min(centerDistance, 1), 1.8) * (1 + mouseFalloff * mouseDistance * .8), refractionX = Math.cos(refractionAngle) * dynamicRefraction, refractionY = Math.sin(refractionAngle) * dynamicRefraction, vortexAngle = Math.atan2(iy - mouseY, ix - mouseX), vortexDistance = vec2Length(ix - mouseX, iy - mouseY), vortexStrength = mouseFalloff * Math.sin(10 * vortexDistance - 3 * time) * .025, vortexX = Math.cos(vortexAngle + 2 * time) * vortexStrength, vortexY = Math.sin(vortexAngle + 2 * time) * vortexStrength, fluidX = Math.sin(10 * ix + 5 * mouseX + 2.5 * time) * Math.cos(8 * iy - 2 * time) * .018, fluidY = Math.cos(8 * ix - 2 * time) * Math.sin(10 * iy + 5 * mouseY + 2.5 * time) * .018, rippleEffect = (.012 * Math.sin(15 * Math.min(centerDistance, 10) - 4 * time) + .008 * Math.cos(20 * Math.min(centerDistance, 10) + 3 * time)) * mouseFalloff, rippleX = Math.cos(refractionAngle) * rippleEffect, rippleY = Math.sin(refractionAngle) * rippleEffect, distanceToEdge = roundedRectSDF(ix, iy, .44, .34, .39), edgeMask = smoothstepEdge(.92, -.12, distanceToEdge), edgeSoftness = smoothstepEdge(.85, .1, distanceToEdge), finalY = iy + (1.2 * refractionY + .8 * spectralY + 1.5 * parallaxY + .9 * scatteringY + 1 * turbulenceY + .6 * microDetailY + 1.3 * vortexY + 1.1 * fluidY + .7 * rippleY + .8 * causticDistortion) * edgeMask * edgeSoftness * .85;
|
|
4523
|
+
return createTexture(clamp(ix + (1.2 * refractionX + .8 * spectralX + 1.5 * parallaxX + .9 * scatteringX + 1 * turbulenceX + .6 * microDetailX + 1.3 * vortexX + 1.1 * fluidX + .7 * rippleX + causticDistortion) * edgeMask * edgeSoftness * .85 + .5, 0, 1), clamp(finalY + .5, 0, 1));
|
|
4736
4524
|
},
|
|
4737
4525
|
// Aliases for compatibility
|
|
4738
4526
|
plasma: (uv, mousePosition) => fragmentShaders.premiumGlass(uv, mousePosition),
|
|
@@ -4774,8 +4562,8 @@ const smoothStep = (a, b, t) => {
|
|
|
4774
4562
|
let dx = pos.x * w - x, dy = pos.y * h - y;
|
|
4775
4563
|
// Apply edge smoothing for Apple-like effect
|
|
4776
4564
|
const edgeX = 2 * Math.min(x / w, (w - x) / w), edgeY = 2 * Math.min(y / h, (h - y) / h), edgeFactor = Math.min(edgeX, edgeY);
|
|
4777
|
-
dx *=
|
|
4778
|
-
rawValues.push(dx, dy);
|
|
4565
|
+
dx *= smoothstepEdge(0, .2, edgeFactor), dy *= smoothstepEdge(0, .2, edgeFactor),
|
|
4566
|
+
maxScale = Math.max(maxScale, Math.abs(dx), Math.abs(dy)), rawValues.push(dx, dy);
|
|
4779
4567
|
}
|
|
4780
4568
|
// Improved normalization to prevent artifacts while maintaining intensity
|
|
4781
4569
|
maxScale = Math.max(maxScale, 1);
|
|
@@ -4785,9 +4573,9 @@ const smoothStep = (a, b, t) => {
|
|
|
4785
4573
|
let rawIndex = 0;
|
|
4786
4574
|
for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) {
|
|
4787
4575
|
const dx = rawValues[rawIndex++] || 0, dy = rawValues[rawIndex++] || 0, edgeDistance = Math.min(x, y, w - x - 1, h - y - 1), edgeFactor = Math.min(1, edgeDistance / 2), r = dx * edgeFactor / maxScale + .5, g = dy * edgeFactor / maxScale + .5, pixelIndex = 4 * (y * w + x);
|
|
4788
|
-
data[pixelIndex] =
|
|
4789
|
-
data[pixelIndex + 1] =
|
|
4790
|
-
data[pixelIndex + 2] =
|
|
4576
|
+
data[pixelIndex] = clamp(255 * r, 0, 255), // Red channel (X displacement)
|
|
4577
|
+
data[pixelIndex + 1] = clamp(255 * g, 0, 255), // Green channel (Y displacement)
|
|
4578
|
+
data[pixelIndex + 2] = clamp(255 * g, 0, 255), // Blue channel (Y displacement for SVG filter compatibility)
|
|
4791
4579
|
data[pixelIndex + 3] = 255;
|
|
4792
4580
|
}
|
|
4793
4581
|
return this.context.putImageData(imageData, 0, 0), this.canvas.toDataURL();
|
|
@@ -4815,9 +4603,7 @@ const smoothStep = (a, b, t) => {
|
|
|
4815
4603
|
return this.canvasDPI;
|
|
4816
4604
|
}
|
|
4817
4605
|
},
|
|
4818
|
-
|
|
4819
|
-
fragmentShaders: fragmentShaders,
|
|
4820
|
-
liquidGlassWithTime: liquidGlassWithTime
|
|
4606
|
+
fragmentShaders: fragmentShaders
|
|
4821
4607
|
}, Symbol.toStringTag, {
|
|
4822
4608
|
value: "Module"
|
|
4823
4609
|
}));
|