@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/charts.js
CHANGED
|
@@ -462,6 +462,44 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
462
462
|
POSITIONS: [ "top", "bottom", "left", "right" ],
|
|
463
463
|
ACTION_VARIANTS: [ "primary", "secondary", "success", "info", "warning", "error" ]
|
|
464
464
|
}
|
|
465
|
+
}, GLASS_BORDER_GRADIENT = {
|
|
466
|
+
BASE_ANGLE: 135,
|
|
467
|
+
ANGLE_MULTIPLIER: .5,
|
|
468
|
+
VELOCITY_ANGLE_MULTIPLIER: .5,
|
|
469
|
+
CHROMATIC_OFFSET: 1.5,
|
|
470
|
+
STOP_1: {
|
|
471
|
+
MIN: 10,
|
|
472
|
+
BASE: 33,
|
|
473
|
+
get MULTIPLIER() {
|
|
474
|
+
return .009 * this.BASE;
|
|
475
|
+
}
|
|
476
|
+
},
|
|
477
|
+
STOP_2: {
|
|
478
|
+
MAX: 90,
|
|
479
|
+
BASE: 66,
|
|
480
|
+
get MULTIPLIER() {
|
|
481
|
+
return .006 * this.BASE;
|
|
482
|
+
}
|
|
483
|
+
},
|
|
484
|
+
OPACITY: {
|
|
485
|
+
/** Matches $glass-border-1-opacity (0.08) */
|
|
486
|
+
BASE_1: .08,
|
|
487
|
+
get BASE_2() {
|
|
488
|
+
return 3.33 * this.BASE_1;
|
|
489
|
+
},
|
|
490
|
+
get BASE_3() {
|
|
491
|
+
return 2.66 * this.BASE_1;
|
|
492
|
+
},
|
|
493
|
+
get BASE_4() {
|
|
494
|
+
return 5 * this.BASE_1;
|
|
495
|
+
},
|
|
496
|
+
get MULTIPLIER_LOW() {
|
|
497
|
+
return .066 * this.BASE_1;
|
|
498
|
+
},
|
|
499
|
+
get MULTIPLIER_HIGH() {
|
|
500
|
+
return .1 * this.BASE_1;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
465
503
|
}, ATOMIX_GLASS = {
|
|
466
504
|
BASE_CLASS: "c-atomix-glass",
|
|
467
505
|
CONTAINER_CLASS: "c-atomix-glass__container",
|
|
@@ -473,6 +511,22 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
473
511
|
BORDER_BACKDROP_CLASS: "c-atomix-glass__border-backdrop",
|
|
474
512
|
BORDER_1_CLASS: "c-atomix-glass__border-1",
|
|
475
513
|
BORDER_2_CLASS: "c-atomix-glass__border-2",
|
|
514
|
+
/** Centralized liquid glass rim configuration */
|
|
515
|
+
BORDER: {
|
|
516
|
+
WIDTH_CSS_VAR: "--atomix-glass-border-width",
|
|
517
|
+
DEFAULT_WIDTH: "0.5px",
|
|
518
|
+
GRADIENT_CSS_VARS: {
|
|
519
|
+
GRADIENT_1: "--atomix-glass-border-gradient-1",
|
|
520
|
+
GRADIENT_2: "--atomix-glass-border-gradient-2"
|
|
521
|
+
},
|
|
522
|
+
GRADIENT: GLASS_BORDER_GRADIENT,
|
|
523
|
+
OVER_LIGHT: {
|
|
524
|
+
opacity: .7
|
|
525
|
+
},
|
|
526
|
+
DARK: {
|
|
527
|
+
opacity: .35
|
|
528
|
+
}
|
|
529
|
+
},
|
|
476
530
|
HOVER_1_CLASS: "c-atomix-glass__hover-1",
|
|
477
531
|
HOVER_2_CLASS: "c-atomix-glass__hover-2",
|
|
478
532
|
HOVER_3_CLASS: "c-atomix-glass__hover-3",
|
|
@@ -501,25 +555,22 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
501
555
|
SHADER: "c-atomix-glass--shader"
|
|
502
556
|
},
|
|
503
557
|
DEFAULTS: {
|
|
504
|
-
|
|
558
|
+
/** Subtle refraction — Apple UI chrome avoids heavy liquid distortion */
|
|
559
|
+
DISPLACEMENT_SCALE: 28,
|
|
505
560
|
get BLUR_AMOUNT() {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
// Saturate relative to intensity
|
|
512
|
-
},
|
|
561
|
+
// Apple Music sidebar / player bar: ~20–40px frost (see $glass-backdrop-filter)
|
|
562
|
+
return Math.max(20, .72 * this.DISPLACEMENT_SCALE);
|
|
563
|
+
},
|
|
564
|
+
/** Fixed 180% matches Apple's saturate(180%) backdrop recipe */
|
|
565
|
+
SATURATION: 180,
|
|
513
566
|
get ABERRATION_INTENSITY() {
|
|
514
|
-
return .
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
ELASTICITY: .15,
|
|
567
|
+
return .02 * this.DISPLACEMENT_SCALE;
|
|
568
|
+
},
|
|
569
|
+
ELASTICITY: .05,
|
|
518
570
|
get CORNER_RADIUS() {
|
|
519
571
|
return 16;
|
|
520
572
|
// Use 16 to match SCSS design system (was 20)
|
|
521
573
|
},
|
|
522
|
-
PADDING: "0",
|
|
523
574
|
MODE: "standard",
|
|
524
575
|
OVER_LIGHT: !1,
|
|
525
576
|
ENABLE_OVER_LIGHT_LAYERS: !0,
|
|
@@ -535,19 +586,29 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
535
586
|
},
|
|
536
587
|
CONSTANTS: {
|
|
537
588
|
ACTIVATION_ZONE: 200,
|
|
538
|
-
LERP_FACTOR: .
|
|
589
|
+
LERP_FACTOR: .05,
|
|
590
|
+
// Lower = more viscous, liquid-smooth tracking (Apple feel)
|
|
539
591
|
SMOOTHSTEP_POWER: 2.5,
|
|
540
592
|
MIN_BLUR: .1,
|
|
541
593
|
MOUSE_INFLUENCE_DIVISOR: 100,
|
|
542
594
|
EDGE_FADE_PIXELS: 2,
|
|
543
|
-
//
|
|
544
|
-
|
|
595
|
+
// Interaction intensity multipliers shared by the hook and the imperative style updater
|
|
596
|
+
INTERACTION: {
|
|
597
|
+
HOVER_INTENSITY: 1.4,
|
|
598
|
+
ACTIVE_INTENSITY: 1.6
|
|
599
|
+
},
|
|
600
|
+
// Elasticity physics constants — Apple-tuned: soft springs, fast settling, minimal stretch
|
|
601
|
+
ELASTICITY_TRANSLATION_FACTOR: .06,
|
|
602
|
+
// Subtler elastic shift (was 0.1)
|
|
545
603
|
ELASTICITY_DISTANCE_THRESHOLD: 200,
|
|
546
604
|
ELASTICITY_COMPRESSION_FACTOR: .3,
|
|
547
|
-
ELASTICITY_STIFFNESS: .
|
|
548
|
-
|
|
605
|
+
ELASTICITY_STIFFNESS: .06,
|
|
606
|
+
// Softer springs = gentler motion (was 0.1)
|
|
607
|
+
ELASTICITY_DAMPING: .88,
|
|
608
|
+
// Fast settling, no wobble (was 0.76)
|
|
549
609
|
ELASTICITY_VELOCITY_FACTOR: .65,
|
|
550
|
-
ELASTICITY_STRETCH_RATIO: .
|
|
610
|
+
ELASTICITY_STRETCH_RATIO: .25,
|
|
611
|
+
// Less visible surface tension stretch (was 0.45)
|
|
551
612
|
ELASTICITY_MAGNIFICATION_BASE: 1.02,
|
|
552
613
|
// Note: This default must match the SCSS variable --atomix-radius-md
|
|
553
614
|
// @see src/styles/01-settings/_settings.global.scss
|
|
@@ -561,55 +622,16 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
561
622
|
},
|
|
562
623
|
// Gradient calculation constants
|
|
563
624
|
GRADIENT: {
|
|
564
|
-
BASE_ANGLE:
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
// Minimum percentage for border stop 1
|
|
575
|
-
BASE: 33,
|
|
576
|
-
// Base percentage for border stop 1
|
|
577
|
-
get MULTIPLIER() {
|
|
578
|
-
return .009 * this.BASE;
|
|
579
|
-
}
|
|
580
|
-
},
|
|
581
|
-
BORDER_STOP_2: {
|
|
582
|
-
MAX: 90,
|
|
583
|
-
// Maximum percentage for border stop 2
|
|
584
|
-
BASE: 66,
|
|
585
|
-
// Base percentage for border stop 2
|
|
586
|
-
get MULTIPLIER() {
|
|
587
|
-
return .006 * this.BASE;
|
|
588
|
-
}
|
|
589
|
-
},
|
|
590
|
-
BORDER_OPACITY: {
|
|
591
|
-
BASE_1: .12,
|
|
592
|
-
// Base opacity for border gradient 1
|
|
593
|
-
get BASE_2() {
|
|
594
|
-
return 3.33 * this.BASE_1;
|
|
595
|
-
},
|
|
596
|
-
// Base opacity for border gradient 2
|
|
597
|
-
get BASE_3() {
|
|
598
|
-
return 2.66 * this.BASE_1;
|
|
599
|
-
},
|
|
600
|
-
// Base opacity for border gradient 3
|
|
601
|
-
get BASE_4() {
|
|
602
|
-
return 5 * this.BASE_1;
|
|
603
|
-
},
|
|
604
|
-
// Base opacity for border gradient 4
|
|
605
|
-
get MULTIPLIER_LOW() {
|
|
606
|
-
return .066 * this.BASE_1;
|
|
607
|
-
},
|
|
608
|
-
// Low multiplier for mouse influence on opacity
|
|
609
|
-
get MULTIPLIER_HIGH() {
|
|
610
|
-
return .1 * this.BASE_1;
|
|
611
|
-
}
|
|
612
|
-
},
|
|
625
|
+
BASE_ANGLE: GLASS_BORDER_GRADIENT.BASE_ANGLE,
|
|
626
|
+
ANGLE_MULTIPLIER: GLASS_BORDER_GRADIENT.ANGLE_MULTIPLIER,
|
|
627
|
+
VELOCITY_ANGLE_MULTIPLIER: GLASS_BORDER_GRADIENT.VELOCITY_ANGLE_MULTIPLIER,
|
|
628
|
+
CHROMATIC_OFFSET: GLASS_BORDER_GRADIENT.CHROMATIC_OFFSET,
|
|
629
|
+
/** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.STOP_1 */
|
|
630
|
+
BORDER_STOP_1: GLASS_BORDER_GRADIENT.STOP_1,
|
|
631
|
+
/** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.STOP_2 */
|
|
632
|
+
BORDER_STOP_2: GLASS_BORDER_GRADIENT.STOP_2,
|
|
633
|
+
/** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.OPACITY */
|
|
634
|
+
BORDER_OPACITY: GLASS_BORDER_GRADIENT.OPACITY,
|
|
613
635
|
CENTER_POSITION: 50,
|
|
614
636
|
// Center position percentage (50%)
|
|
615
637
|
HOVER_POSITION: {
|
|
@@ -642,8 +664,8 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
642
664
|
return 2 * this.BLACK_STOP;
|
|
643
665
|
},
|
|
644
666
|
// End percentage for black hover 1
|
|
645
|
-
WHITE_START: .
|
|
646
|
-
//
|
|
667
|
+
WHITE_START: .35,
|
|
668
|
+
// Gentler hover flash — Apple hover is barely visible
|
|
647
669
|
get WHITE_STOP() {
|
|
648
670
|
return this.BLACK_END - 10;
|
|
649
671
|
}
|
|
@@ -661,8 +683,8 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
661
683
|
return 2 * this.BLACK_STOP;
|
|
662
684
|
},
|
|
663
685
|
// End percentage for black hover 2
|
|
664
|
-
WHITE_START:
|
|
665
|
-
//
|
|
686
|
+
WHITE_START: .7,
|
|
687
|
+
// Gentler hover flash
|
|
666
688
|
get WHITE_STOP() {
|
|
667
689
|
return this.BLACK_END;
|
|
668
690
|
}
|
|
@@ -680,8 +702,8 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
680
702
|
return 2 * this.BLACK_STOP;
|
|
681
703
|
},
|
|
682
704
|
// End percentage for black hover 3
|
|
683
|
-
WHITE_START:
|
|
684
|
-
//
|
|
705
|
+
WHITE_START: .7,
|
|
706
|
+
// Gentler hover flash
|
|
685
707
|
get WHITE_STOP() {
|
|
686
708
|
return this.BLACK_END;
|
|
687
709
|
}
|
|
@@ -691,13 +713,13 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
691
713
|
BASE_GRADIENT: {
|
|
692
714
|
ANGLE: 135,
|
|
693
715
|
// Gradient angle in degrees
|
|
694
|
-
BLACK_START_BASE: .
|
|
716
|
+
BLACK_START_BASE: .1,
|
|
695
717
|
// Base start opacity for black
|
|
696
718
|
get BLACK_START_MULTIPLIER() {
|
|
697
719
|
return .02 * this.BLACK_START_BASE;
|
|
698
720
|
},
|
|
699
721
|
// Multiplier for mouse X influence on start
|
|
700
|
-
BLACK_MID_BASE: .
|
|
722
|
+
BLACK_MID_BASE: .07,
|
|
701
723
|
// Base mid opacity for black
|
|
702
724
|
get BLACK_MID_MULTIPLIER() {
|
|
703
725
|
return .02 * this.BLACK_MID_BASE;
|
|
@@ -718,7 +740,7 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
718
740
|
}
|
|
719
741
|
},
|
|
720
742
|
OVERLAY_GRADIENT: {
|
|
721
|
-
BLACK_START_BASE: .
|
|
743
|
+
BLACK_START_BASE: .08,
|
|
722
744
|
// Base start opacity for black overlay
|
|
723
745
|
get BLACK_START_MULTIPLIER() {
|
|
724
746
|
return .025 * this.BLACK_START_BASE;
|
|
@@ -742,14 +764,14 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
742
764
|
return .416 * this.BLACK_START_BASE;
|
|
743
765
|
}
|
|
744
766
|
},
|
|
745
|
-
// Overlay highlight constants
|
|
767
|
+
// Overlay highlight constants — Apple places specular at the top-center
|
|
746
768
|
OVERLAY_HIGHLIGHT: {
|
|
747
|
-
POSITION_X:
|
|
748
|
-
//
|
|
749
|
-
POSITION_Y:
|
|
750
|
-
//
|
|
751
|
-
WHITE_OPACITY: .
|
|
752
|
-
//
|
|
769
|
+
POSITION_X: 50,
|
|
770
|
+
// Centered horizontal — Apple's top-center specular
|
|
771
|
+
POSITION_Y: 5,
|
|
772
|
+
// Very top — catches light like a curved glass surface
|
|
773
|
+
WHITE_OPACITY: .28,
|
|
774
|
+
// Softer specular — visible but not glaring
|
|
753
775
|
get STOP() {
|
|
754
776
|
return 150 * this.WHITE_OPACITY;
|
|
755
777
|
},
|
|
@@ -770,6 +792,10 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
770
792
|
SATURATION: {
|
|
771
793
|
HIGH_CONTRAST: 200
|
|
772
794
|
},
|
|
795
|
+
// Container shadows — hairline inner catch + soft floating lift (Apple player bar)
|
|
796
|
+
CONTAINER_SHADOW: {
|
|
797
|
+
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)"
|
|
798
|
+
},
|
|
773
799
|
// Phase 1: Animation System Constants
|
|
774
800
|
ANIMATION: {
|
|
775
801
|
// Breathing effect timing (in milliseconds)
|
|
@@ -1664,9 +1690,38 @@ const ChartToolbar = memo( forwardRef((({chartType: chartType = "line", groups:
|
|
|
1664
1690
|
});
|
|
1665
1691
|
})));
|
|
1666
1692
|
|
|
1693
|
+
/**
|
|
1694
|
+
* Component Utilities
|
|
1695
|
+
*
|
|
1696
|
+
* Helper functions for component development with the new customization system
|
|
1697
|
+
*/
|
|
1698
|
+
/**
|
|
1699
|
+
* Merge multiple class names
|
|
1700
|
+
*/
|
|
1701
|
+
function mergeClassNames(...classes) {
|
|
1702
|
+
return classes.filter(Boolean).join(" ");
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
/**
|
|
1706
|
+
* Utility to merge multiple React refs into one
|
|
1707
|
+
*/ function setRef(ref, value) {
|
|
1708
|
+
"function" == typeof ref ? ref(value) : ref && (
|
|
1709
|
+
// This is safe because we're checking that ref exists first
|
|
1710
|
+
ref.current = value);
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
/**
|
|
1714
|
+
* Combines two React refs into a single ref function
|
|
1715
|
+
* This is used when you need to use and forward a ref at the same time
|
|
1716
|
+
*/ function useForkRef(refA, refB) {
|
|
1717
|
+
return React.useMemo((() => null == refA && null == refB ? null : refValue => {
|
|
1718
|
+
setRef(refA, refValue), setRef(refB, refValue);
|
|
1719
|
+
}), [ refA, refB ]);
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1667
1722
|
ChartToolbar.displayName = "ChartToolbar";
|
|
1668
1723
|
|
|
1669
|
-
const {CONSTANTS: CONSTANTS$
|
|
1724
|
+
const {CONSTANTS: CONSTANTS$3} = ATOMIX_GLASS, calculateElementCenter = rect => rect ? {
|
|
1670
1725
|
x: rect.left + rect.width / 2,
|
|
1671
1726
|
y: rect.top + rect.height / 2
|
|
1672
1727
|
} : {
|
|
@@ -1674,37 +1729,37 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect =>
|
|
|
1674
1729
|
y: 0
|
|
1675
1730
|
}, calculateMouseInfluence = mouseOffset => {
|
|
1676
1731
|
if (!mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y) return 0;
|
|
1677
|
-
//
|
|
1678
|
-
const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$
|
|
1732
|
+
// Clamp influence to keep mouse response subtle and stable.
|
|
1733
|
+
const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$3.MOUSE_INFLUENCE_DIVISOR;
|
|
1679
1734
|
return Math.min(.8, influence);
|
|
1680
1735
|
// Tighter cap to prevent blur/filter blow-out
|
|
1681
|
-
}, clampBlur = value => "number" != typeof value || isNaN(value) ? CONSTANTS$
|
|
1736
|
+
}, 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 => {
|
|
1682
1737
|
if ("number" == typeof value) return Math.max(0, value);
|
|
1683
|
-
if ("string" != typeof value || !value.trim()) return CONSTANTS$
|
|
1738
|
+
if ("string" != typeof value || !value.trim()) return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
|
|
1684
1739
|
const trimmedValue = value.trim();
|
|
1685
1740
|
// Handle px values
|
|
1686
1741
|
if (trimmedValue.endsWith("px")) {
|
|
1687
1742
|
const parsed = parseFloat(trimmedValue);
|
|
1688
|
-
return isNaN(parsed) ? CONSTANTS$
|
|
1743
|
+
return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, parsed);
|
|
1689
1744
|
}
|
|
1690
1745
|
// Handle rem values (assume 16px = 1rem)
|
|
1691
1746
|
if (trimmedValue.endsWith("rem")) {
|
|
1692
1747
|
const parsed = parseFloat(trimmedValue);
|
|
1693
|
-
return isNaN(parsed) ? CONSTANTS$
|
|
1748
|
+
return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
|
|
1694
1749
|
}
|
|
1695
1750
|
// Handle em values (assume 16px = 1em for simplicity)
|
|
1696
1751
|
if (trimmedValue.endsWith("em")) {
|
|
1697
1752
|
const parsed = parseFloat(trimmedValue);
|
|
1698
|
-
return isNaN(parsed) ? CONSTANTS$
|
|
1753
|
+
return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
|
|
1699
1754
|
}
|
|
1700
1755
|
// Handle percentage (convert to approximate px value, assuming 200px container)
|
|
1701
1756
|
if (trimmedValue.endsWith("%")) {
|
|
1702
1757
|
const parsed = parseFloat(trimmedValue);
|
|
1703
|
-
return isNaN(parsed) ? CONSTANTS$
|
|
1758
|
+
return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, parsed / 100 * 200);
|
|
1704
1759
|
}
|
|
1705
1760
|
// Handle unitless numbers
|
|
1706
1761
|
const numValue = parseFloat(trimmedValue);
|
|
1707
|
-
return isNaN(numValue) ? CONSTANTS$
|
|
1762
|
+
return isNaN(numValue) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, numValue);
|
|
1708
1763
|
}, extractBorderRadiusFromElement = element => {
|
|
1709
1764
|
if (!element || !element.props) return null;
|
|
1710
1765
|
// Check inline styles first (highest priority)
|
|
@@ -1720,11 +1775,11 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect =>
|
|
|
1720
1775
|
// If element has children, recursively check them
|
|
1721
1776
|
if (element.props.children) {
|
|
1722
1777
|
const childRadius = extractBorderRadiusFromChildren(element.props.children);
|
|
1723
|
-
if (childRadius > 0 && childRadius !== CONSTANTS$
|
|
1778
|
+
if (childRadius > 0 && childRadius !== CONSTANTS$3.DEFAULT_CORNER_RADIUS) return childRadius;
|
|
1724
1779
|
}
|
|
1725
1780
|
return null;
|
|
1726
1781
|
}, extractBorderRadiusFromChildren = children => {
|
|
1727
|
-
if (!children) return CONSTANTS$
|
|
1782
|
+
if (!children) return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
|
|
1728
1783
|
try {
|
|
1729
1784
|
const childArray = React.Children.toArray(children);
|
|
1730
1785
|
for (let i = 0; i < childArray.length; i++) {
|
|
@@ -1737,17 +1792,78 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect =>
|
|
|
1737
1792
|
} catch (error) {
|
|
1738
1793
|
// Silently handle errors
|
|
1739
1794
|
}
|
|
1740
|
-
return CONSTANTS$
|
|
1795
|
+
return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
|
|
1741
1796
|
}, smoothstep = t => {
|
|
1742
1797
|
const clamped = Math.max(0, Math.min(1, t));
|
|
1743
1798
|
return clamped * clamped * (3 - 2 * clamped);
|
|
1744
|
-
}, lerp
|
|
1799
|
+
}, 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 => {
|
|
1800
|
+
if ("number" != typeof t || isNaN(t)) return 0;
|
|
1801
|
+
const clamped = Math.max(0, Math.min(1, t));
|
|
1802
|
+
return clamped < .5 ? 4 * clamped * clamped * clamped : 1 - Math.pow(-2 * clamped + 2, 3) / 2;
|
|
1803
|
+
}, easeOutQuart = t => {
|
|
1804
|
+
if ("number" != typeof t || isNaN(t)) return 0;
|
|
1805
|
+
const clamped = Math.max(0, Math.min(1, t));
|
|
1806
|
+
return 1 - Math.pow(1 - clamped, 4);
|
|
1807
|
+
}, vec2Length = (x, y) => {
|
|
1808
|
+
if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
|
|
1809
|
+
const maxComponent = Math.max(Math.abs(x), Math.abs(y));
|
|
1810
|
+
if (0 === maxComponent) return 0;
|
|
1811
|
+
const scaledX = x / maxComponent, scaledY = y / maxComponent;
|
|
1812
|
+
return maxComponent * Math.sqrt(scaledX * scaledX + scaledY * scaledY);
|
|
1813
|
+
}, getInteractionIntensity = (isHovered, isActive) => ({
|
|
1814
|
+
hoverIntensity: isHovered ? CONSTANTS$3.INTERACTION.HOVER_INTENSITY : 1,
|
|
1815
|
+
activeIntensity: isActive ? CONSTANTS$3.INTERACTION.ACTIVE_INTENSITY : 1
|
|
1816
|
+
})
|
|
1817
|
+
/**
|
|
1818
|
+
* Spring-damper integration helper
|
|
1819
|
+
* Calculates the next value based on velocity, stiffness, and damping.
|
|
1820
|
+
*/ , calculateSpring = (current, target, velocity, stiffness = .1, damping = .8) => {
|
|
1745
1821
|
const newVelocity = (velocity + (target - current) * stiffness) * damping;
|
|
1746
1822
|
return {
|
|
1747
1823
|
value: current + newVelocity,
|
|
1748
1824
|
velocity: newVelocity
|
|
1749
1825
|
};
|
|
1750
|
-
}
|
|
1826
|
+
};
|
|
1827
|
+
|
|
1828
|
+
/**
|
|
1829
|
+
* Calculate element center from bounding rect
|
|
1830
|
+
*/
|
|
1831
|
+
/**
|
|
1832
|
+
* Normalizes a layout inset for use in CSS custom properties.
|
|
1833
|
+
*
|
|
1834
|
+
* @param value - Raw inset from `style` (number, px string, or `auto`).
|
|
1835
|
+
* @param fallback - Value used when `value` is undefined.
|
|
1836
|
+
*/
|
|
1837
|
+
function formatGlassInsetValue(value, fallback = "auto") {
|
|
1838
|
+
return void 0 === value ? "number" == typeof fallback ? `${fallback}px` : String(fallback) : "auto" === value ? "auto" : "number" == typeof value ? `${value}px` : value;
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
/**
|
|
1842
|
+
* Determines whether the glass should use fixed/sticky layout semantics.
|
|
1843
|
+
*
|
|
1844
|
+
* @param explicit - Value of the `isFixedOrSticky` prop.
|
|
1845
|
+
* @param position - `position` from the consumer `style` object.
|
|
1846
|
+
*/
|
|
1847
|
+
/** Coerces a value to a finite number, returning `fallback` when invalid. */
|
|
1848
|
+
function toSafeNumber(value, fallback = 0) {
|
|
1849
|
+
return "number" != typeof value || isNaN(value) ? fallback : value;
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
/**
|
|
1853
|
+
* Calculates the target frame rate for shader time-animation loops.
|
|
1854
|
+
*
|
|
1855
|
+
* Balances visual quality against distortion complexity and `animationSpeed`.
|
|
1856
|
+
*/
|
|
1857
|
+
/**
|
|
1858
|
+
* Computes per-channel displacement scale for the SVG chromatic-aberration filter.
|
|
1859
|
+
*/
|
|
1860
|
+
function getChromaticDisplacementScale(mode, displacementScale, aberrationIntensity, channelFactor) {
|
|
1861
|
+
return displacementScale * (("shader" === mode ? 1 : -1) - aberrationIntensity * channelFactor);
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
/**
|
|
1865
|
+
* Get displacement map URL based on mode
|
|
1866
|
+
*/ const getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
|
|
1751
1867
|
switch (mode) {
|
|
1752
1868
|
case "standard":
|
|
1753
1869
|
return displacementMap;
|
|
@@ -1764,13 +1880,28 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect =>
|
|
|
1764
1880
|
default:
|
|
1765
1881
|
return console.warn("AtomixGlass: Invalid displacement mode"), displacementMap;
|
|
1766
1882
|
}
|
|
1767
|
-
}, sharedShaderCache = new Map,
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1883
|
+
}, sharedShaderCache = new Map, CHROMATIC_CHANNELS = [ {
|
|
1884
|
+
result: "RED_DISPLACED",
|
|
1885
|
+
channelResult: "RED_CHANNEL",
|
|
1886
|
+
aberrationFactor: 0,
|
|
1887
|
+
colorMatrix: "1 0 0 0 0\n0 0 0 0 0\n0 0 0 0 0\n0 0 0 1 0"
|
|
1888
|
+
}, {
|
|
1889
|
+
result: "GREEN_DISPLACED",
|
|
1890
|
+
channelResult: "GREEN_CHANNEL",
|
|
1891
|
+
aberrationFactor: .02,
|
|
1892
|
+
colorMatrix: "0 0 0 0 0\n0 1 0 0 0\n0 0 0 0 0\n0 0 0 1 0"
|
|
1893
|
+
}, {
|
|
1894
|
+
result: "BLUE_DISPLACED",
|
|
1895
|
+
channelResult: "BLUE_CHANNEL",
|
|
1896
|
+
aberrationFactor: .03,
|
|
1897
|
+
colorMatrix: "0 0 0 0 0\n0 0 0 0 0\n0 0 1 0 0\n0 0 0 1 0"
|
|
1898
|
+
} ], FILTER_SVG_STYLE = {
|
|
1899
|
+
position: "absolute",
|
|
1900
|
+
width: "100%",
|
|
1901
|
+
height: "100%",
|
|
1902
|
+
inset: 0
|
|
1903
|
+
}, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsx("svg", {
|
|
1904
|
+
style: FILTER_SVG_STYLE,
|
|
1774
1905
|
"aria-hidden": "true",
|
|
1775
1906
|
children: jsxs("defs", {
|
|
1776
1907
|
children: [ jsxs("radialGradient", {
|
|
@@ -1824,43 +1955,21 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect =>
|
|
|
1824
1955
|
dx: "0",
|
|
1825
1956
|
dy: "0",
|
|
1826
1957
|
result: "CENTER_ORIGINAL"
|
|
1827
|
-
}),
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
scale: displacementScale * (("shader" === mode ? 1 : -1) - .02 * aberrationIntensity),
|
|
1843
|
-
xChannelSelector: "R",
|
|
1844
|
-
yChannelSelector: "B",
|
|
1845
|
-
result: "GREEN_DISPLACED"
|
|
1846
|
-
}), jsx("feColorMatrix", {
|
|
1847
|
-
in: "GREEN_DISPLACED",
|
|
1848
|
-
type: "matrix",
|
|
1849
|
-
values: "0 0 0 0 0\n 0 1 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0",
|
|
1850
|
-
result: "GREEN_CHANNEL"
|
|
1851
|
-
}), jsx("feDisplacementMap", {
|
|
1852
|
-
in: "SourceGraphic",
|
|
1853
|
-
in2: "DISPLACEMENT_MAP",
|
|
1854
|
-
scale: displacementScale * (("shader" === mode ? 1 : -1) - .03 * aberrationIntensity),
|
|
1855
|
-
xChannelSelector: "R",
|
|
1856
|
-
yChannelSelector: "B",
|
|
1857
|
-
result: "BLUE_DISPLACED"
|
|
1858
|
-
}), jsx("feColorMatrix", {
|
|
1859
|
-
in: "BLUE_DISPLACED",
|
|
1860
|
-
type: "matrix",
|
|
1861
|
-
values: "0 0 0 0 0\n 0 0 0 0 0\n 0 0 1 0 0\n 0 0 0 1 0",
|
|
1862
|
-
result: "BLUE_CHANNEL"
|
|
1863
|
-
}), jsx("feBlend", {
|
|
1958
|
+
}), CHROMATIC_CHANNELS.map((channel => jsxs(React.Fragment, {
|
|
1959
|
+
children: [ jsx("feDisplacementMap", {
|
|
1960
|
+
in: "SourceGraphic",
|
|
1961
|
+
in2: "DISPLACEMENT_MAP",
|
|
1962
|
+
scale: getChromaticDisplacementScale(mode, displacementScale, aberrationIntensity, channel.aberrationFactor),
|
|
1963
|
+
xChannelSelector: "R",
|
|
1964
|
+
yChannelSelector: "B",
|
|
1965
|
+
result: channel.result
|
|
1966
|
+
}), jsx("feColorMatrix", {
|
|
1967
|
+
in: channel.result,
|
|
1968
|
+
type: "matrix",
|
|
1969
|
+
values: channel.colorMatrix,
|
|
1970
|
+
result: channel.channelResult
|
|
1971
|
+
}) ]
|
|
1972
|
+
}, channel.channelResult))), jsx("feBlend", {
|
|
1864
1973
|
in: "GREEN_CHANNEL",
|
|
1865
1974
|
in2: "BLUE_CHANNEL",
|
|
1866
1975
|
mode: "screen",
|
|
@@ -1901,21 +2010,22 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect =>
|
|
|
1901
2010
|
});
|
|
1902
2011
|
|
|
1903
2012
|
/**
|
|
1904
|
-
*
|
|
2013
|
+
* Module-level LRU cache for shader displacement maps.
|
|
2014
|
+
*
|
|
2015
|
+
* Shared across all `AtomixGlassContainer` instances so identical size and
|
|
2016
|
+
* variant combinations are generated once.
|
|
1905
2017
|
*/ GlassFilterComponent.displayName = "GlassFilter";
|
|
1906
2018
|
|
|
1907
|
-
|
|
2019
|
+
/** Shallow prop comparison to avoid redundant SVG filter regeneration. */
|
|
1908
2020
|
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 = {
|
|
1909
2021
|
x: 0,
|
|
1910
2022
|
y: 0
|
|
1911
|
-
}, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0,
|
|
2023
|
+
}, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0, glassSize: glassSize = {
|
|
1912
2024
|
width: 0,
|
|
1913
2025
|
height: 0
|
|
1914
|
-
}, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, isFixedOrSticky: isFixedOrSticky = !1,
|
|
1915
|
-
// Phase 1: Animation System props
|
|
1916
|
-
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) => {
|
|
2026
|
+
}, 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) => {
|
|
1917
2027
|
// React 18 useId — stable, unique, and SSR-safe (no module-level counter)
|
|
1918
|
-
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);
|
|
2028
|
+
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);
|
|
1919
2029
|
// Lazy load shader utilities only when shader mode is needed
|
|
1920
2030
|
useEffect((() => {
|
|
1921
2031
|
"shader" === mode ?
|
|
@@ -1993,15 +2103,23 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
|
|
|
1993
2103
|
shaderGeneratorRef.current = null;
|
|
1994
2104
|
}
|
|
1995
2105
|
};
|
|
1996
|
-
}), [ mode, glassSize, shaderVariant ]),
|
|
1997
|
-
// Phase 1: Time-Based Animation Loop - Continuous shader regeneration
|
|
1998
|
-
useEffect((() => {
|
|
2106
|
+
}), [ mode, glassSize, shaderVariant ]), useEffect((() => {
|
|
1999
2107
|
// Only run animations in shader mode with time animation enabled
|
|
2000
2108
|
if ("shader" !== mode || !withTimeAnimation || effectiveReducedMotion || effectiveWithoutEffects)
|
|
2001
2109
|
// Cancel any existing animation frame
|
|
2002
2110
|
return void (null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
|
|
2003
2111
|
animationFrameRef.current = null));
|
|
2004
|
-
const
|
|
2112
|
+
const targetFps = function(options) {
|
|
2113
|
+
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;
|
|
2114
|
+
return Math.max(12, Math.min(60, Math.round(baseFps * effectiveSpeed / complexity)));
|
|
2115
|
+
}({
|
|
2116
|
+
distortionQuality: distortionQuality,
|
|
2117
|
+
animationSpeed: animationSpeed,
|
|
2118
|
+
withMultiLayerDistortion: withMultiLayerDistortion,
|
|
2119
|
+
distortionOctaves: distortionOctaves,
|
|
2120
|
+
distortionLacunarity: distortionLacunarity,
|
|
2121
|
+
distortionGain: distortionGain
|
|
2122
|
+
}), frameInterval = 1e3 / targetFps;
|
|
2005
2123
|
let lastUpdate = 0, isCancelled = !1;
|
|
2006
2124
|
const animate = currentTime => {
|
|
2007
2125
|
if (!isCancelled) {
|
|
@@ -2025,88 +2143,21 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
|
|
|
2025
2143
|
};
|
|
2026
2144
|
}), [ mode, withTimeAnimation, animationSpeed, displacementScale, withMultiLayerDistortion, distortionOctaves, distortionLacunarity, distortionGain, distortionQuality, effectiveReducedMotion, effectiveWithoutEffects, glassSize ]);
|
|
2027
2145
|
// Removed forced reflow to avoid layout thrash and potential feedback sizing loops
|
|
2028
|
-
const
|
|
2029
|
-
useEffect((() => {
|
|
2030
|
-
if (!ref || "function" == typeof ref) return;
|
|
2031
|
-
const element = ref.current;
|
|
2032
|
-
if (element) try {
|
|
2033
|
-
setRectCache(element.getBoundingClientRect());
|
|
2034
|
-
} catch (error) {
|
|
2035
|
-
console.warn("AtomixGlassContainer: Error getting element bounds", error), setRectCache(null);
|
|
2036
|
-
}
|
|
2037
|
-
}), [ ref, glassSize ]);
|
|
2038
|
-
const liquidBlur = useMemo((() => {
|
|
2039
|
-
const defaultBlur = {
|
|
2040
|
-
baseBlur: blurAmount,
|
|
2041
|
-
edgeBlur: 1.25 * blurAmount,
|
|
2042
|
-
centerBlur: 1.1 * blurAmount,
|
|
2043
|
-
flowBlur: 1.2 * blurAmount
|
|
2044
|
-
};
|
|
2045
|
-
// Enhanced validation for liquid blur
|
|
2046
|
-
if (!withLiquidBlur || !rectCache || !mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y || isNaN(mouseOffset.x) || isNaN(mouseOffset.y)) return defaultBlur;
|
|
2146
|
+
const containerVars = useMemo((() => {
|
|
2047
2147
|
try {
|
|
2048
|
-
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);
|
|
2049
|
-
// NOTE: hover/active multipliers intentionally omitted here —
|
|
2050
|
-
// they belong on opacity layers, not the blur filter itself.
|
|
2051
2148
|
return {
|
|
2052
|
-
|
|
2053
|
-
edgeBlur: clampBlur(edgeBlur),
|
|
2054
|
-
centerBlur: clampBlur(centerBlur),
|
|
2055
|
-
flowBlur: clampBlur(flowBlur)
|
|
2056
|
-
};
|
|
2057
|
-
} catch (error) {
|
|
2058
|
-
return console.warn("AtomixGlassContainer: Error calculating liquid blur", error),
|
|
2059
|
-
defaultBlur;
|
|
2060
|
-
}
|
|
2061
|
-
}), [ withLiquidBlur, blurAmount, mouseOffset, rectCache ]), backdropStyle = useMemo((() => {
|
|
2062
|
-
try {
|
|
2063
|
-
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;
|
|
2064
|
-
// Validate blur values before using them
|
|
2065
|
-
return !withLiquidBlur || effectiveReducedMotion || effectiveWithoutEffects || area > 18e4 ? {
|
|
2066
|
-
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})`
|
|
2067
|
-
} : {
|
|
2068
|
-
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})`
|
|
2069
|
-
};
|
|
2070
|
-
// Single-pass fallback: stronger radius to match perceived blur of multi-pass
|
|
2071
|
-
} catch (error) {
|
|
2072
|
-
return console.warn("AtomixGlassContainer: Error calculating backdrop style", error),
|
|
2073
|
-
{
|
|
2074
|
-
backdropFilter: `blur(${blurAmount}px) saturate(${saturation}%) contrast(1.05) brightness(1.05)`
|
|
2075
|
-
};
|
|
2076
|
-
}
|
|
2077
|
-
}), [ liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion, effectiveWithoutEffects, withLiquidBlur, overLightConfig ]), containerVars = useMemo((() => {
|
|
2078
|
-
try {
|
|
2079
|
-
// Safe extraction of mouse offset values
|
|
2080
|
-
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;
|
|
2081
|
-
return {
|
|
2082
|
-
"--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px`,
|
|
2083
|
-
"--atomix-glass-container-backdrop": backdropStyle?.backdropFilter || "none",
|
|
2084
|
-
"--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",
|
|
2085
|
-
"--atomix-glass-container-shadow-opacity": effectiveWithoutEffects ? 0 : 1,
|
|
2086
|
-
// Background and shadow values use design token-aligned RGB values
|
|
2087
|
-
"--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",
|
|
2088
|
-
"--atomix-glass-container-text-shadow": overLight ? "0px 1px 2px rgba(255, 255, 255, 0.15)" : "0px 2px 12px rgba(0, 0, 0, 0.4)",
|
|
2089
|
-
"--atomix-glass-container-box-shadow": overLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)"
|
|
2149
|
+
"--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px`
|
|
2090
2150
|
};
|
|
2091
2151
|
} catch (error) {
|
|
2092
2152
|
return console.warn("AtomixGlassContainer: Error generating container variables", error),
|
|
2093
2153
|
{
|
|
2094
|
-
"--atomix-glass-container-
|
|
2095
|
-
"--atomix-glass-container-radius": "0px",
|
|
2096
|
-
"--atomix-glass-container-backdrop": "none",
|
|
2097
|
-
"--atomix-glass-container-shadow": "none",
|
|
2098
|
-
"--atomix-glass-container-shadow-opacity": 1,
|
|
2099
|
-
"--atomix-glass-container-bg": "none",
|
|
2100
|
-
"--atomix-glass-container-text-shadow": "none"
|
|
2154
|
+
"--atomix-glass-container-radius": "0px"
|
|
2101
2155
|
};
|
|
2102
2156
|
}
|
|
2103
|
-
}), [ borderRadius
|
|
2157
|
+
}), [ borderRadius ]);
|
|
2104
2158
|
return jsx("div", {
|
|
2105
|
-
ref:
|
|
2106
|
-
|
|
2107
|
-
"function" == typeof ref ? ref(el) : ref && (ref.current = el);
|
|
2108
|
-
},
|
|
2109
|
-
className: `${ATOMIX_GLASS.CONTAINER_CLASS} ${className} ${isActive ? ATOMIX_GLASS.CLASSES.ACTIVE : ""} ${overLight ? ATOMIX_GLASS.CLASSES.OVER_LIGHT : ""}`,
|
|
2159
|
+
ref: containerRef,
|
|
2160
|
+
className: mergeClassNames(ATOMIX_GLASS.CONTAINER_CLASS, className, isActive && ATOMIX_GLASS.CLASSES.ACTIVE, overLight && ATOMIX_GLASS.CLASSES.OVER_LIGHT),
|
|
2110
2161
|
style: {
|
|
2111
2162
|
...style,
|
|
2112
2163
|
...containerVars
|
|
@@ -2124,8 +2175,8 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
|
|
|
2124
2175
|
blurAmount: blurAmount,
|
|
2125
2176
|
mode: mode,
|
|
2126
2177
|
id: filterId,
|
|
2127
|
-
displacementScale:
|
|
2128
|
-
aberrationIntensity:
|
|
2178
|
+
displacementScale: toSafeNumber(displacementScale),
|
|
2179
|
+
aberrationIntensity: toSafeNumber(aberrationIntensity),
|
|
2129
2180
|
shaderMapUrl: shaderMapUrl
|
|
2130
2181
|
}), jsx("div", {
|
|
2131
2182
|
className: ATOMIX_GLASS.FILTER_OVERLAY_CLASS,
|
|
@@ -2147,8 +2198,12 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
|
|
|
2147
2198
|
});
|
|
2148
2199
|
}));
|
|
2149
2200
|
|
|
2150
|
-
|
|
2151
|
-
|
|
2201
|
+
/**
|
|
2202
|
+
* Internal glass surface that owns backdrop-filter, SVG distortion, and content.
|
|
2203
|
+
*
|
|
2204
|
+
* Layout and stacking styles are applied via the `style` prop from the parent.
|
|
2205
|
+
* The root wrapper supplies CSS custom properties only.
|
|
2206
|
+
*/ AtomixGlassContainer.displayName = "AtomixGlassContainer";
|
|
2152
2207
|
|
|
2153
2208
|
// Singleton instance
|
|
2154
2209
|
const globalMouseTracker = new
|
|
@@ -2263,28 +2318,32 @@ class {
|
|
|
2263
2318
|
*/ getSubscriberCount() {
|
|
2264
2319
|
return this.listeners.size;
|
|
2265
2320
|
}
|
|
2266
|
-
}, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
|
|
2321
|
+
}, {BORDER: BORDER, CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, BORDER_GRADIENT = BORDER.GRADIENT, WHITE = CONSTANTS$2.PALETTE.WHITE, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
|
|
2267
2322
|
if (!wrapperElement && !containerElement) return;
|
|
2268
2323
|
if (!validateGlassSize(params.glassSize)) return;
|
|
2269
|
-
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,
|
|
2324
|
+
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 = {
|
|
2270
2325
|
opacity: baseOverLightConfig.opacity * hoverIntensity * activeIntensity,
|
|
2271
2326
|
contrast: Math.min(1.6, baseOverLightConfig.contrast + .1 * mouseInfluence),
|
|
2272
2327
|
brightness: Math.min(1.1, baseOverLightConfig.brightness + .05 * mouseInfluence),
|
|
2273
2328
|
shadowIntensity: Math.min(1.2, Math.max(.5, baseOverLightConfig.shadowIntensity + .2 * mouseInfluence)),
|
|
2274
2329
|
borderOpacity: Math.min(1, Math.max(.3, baseOverLightConfig.borderOpacity + .1 * mouseInfluence)),
|
|
2275
2330
|
saturationBoost: baseOverLightConfig.saturationBoost
|
|
2276
|
-
}, scaleX = directionalScale.x * scaleBase, scaleY = directionalScale.y * scaleBase, transformStyle = effectiveWithoutEffects ? `scale(${scaleBase})` : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) scaleX(${scaleX}) scaleY(${scaleY})`,
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
x
|
|
2282
|
-
|
|
2283
|
-
}
|
|
2331
|
+
}, scaleX = directionalScale.x * scaleBase, scaleY = directionalScale.y * scaleBase, transformStyle = effectiveWithoutEffects ? `scale(${scaleBase})` : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) scaleX(${scaleX}) scaleY(${scaleY})`, tensionFactor =
|
|
2332
|
+
/**
|
|
2333
|
+
* Computes tension factor from elastic translation magnitude (0–1).
|
|
2334
|
+
*/
|
|
2335
|
+
function(elasticTranslation) {
|
|
2336
|
+
const magnitude = Math.hypot(elasticTranslation.x, elasticTranslation.y);
|
|
2337
|
+
return smoothstep(magnitude / 80);
|
|
2338
|
+
}
|
|
2339
|
+
/**
|
|
2340
|
+
* Updates the styles of the AtomixGlass wrapper and container elements imperatively
|
|
2341
|
+
* to avoid React re-renders on mouse movement.
|
|
2342
|
+
*/ (elasticTranslation), lightingContrast = Math.min(1.8, overLightConfig.contrast + .2 * tensionFactor), lightingBrightness = Math.min(1.2, overLightConfig.brightness + .1 * tensionFactor);
|
|
2284
2343
|
// Calculate mouse influence
|
|
2285
2344
|
// Update Wrapper Styles (glassVars)
|
|
2286
2345
|
if (wrapperElement) {
|
|
2287
|
-
const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT,
|
|
2346
|
+
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 = {
|
|
2288
2347
|
hover1: {
|
|
2289
2348
|
x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
|
|
2290
2349
|
y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1
|
|
@@ -2301,28 +2360,55 @@ class {
|
|
|
2301
2360
|
x: GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER,
|
|
2302
2361
|
y: GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER
|
|
2303
2362
|
}, opacityValues = {
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2363
|
+
// hover-1: ambient highlight glow — present on hover and during press
|
|
2364
|
+
hover1: isHovered || isActive ? 1 : 0,
|
|
2365
|
+
// hover-2: press depth shadow — only fires on active (mousedown)
|
|
2366
|
+
hover2: isActive ? 1 : 0,
|
|
2367
|
+
// hover-3: global soft-light surface shift — half-strength on hover, full on press
|
|
2368
|
+
hover3: isActive ? 1 : isHovered ? .55 : 0,
|
|
2369
|
+
// Dark chrome: faint smoky tint; over-light keeps stronger fill
|
|
2370
|
+
base: isOverLight ? overLightConfig.opacity : .14,
|
|
2371
|
+
over: isOverLight ? 1.1 * overLightConfig.opacity : .1
|
|
2309
2372
|
}, style = wrapperElement.style;
|
|
2310
2373
|
style.setProperty("--atomix-glass-transform", transformStyle || "none");
|
|
2311
2374
|
// Parallax for content (liquid refraction feel)
|
|
2312
2375
|
const parallaxFactor = .38 + .12 * tensionFactor;
|
|
2313
2376
|
style.setProperty("--atomix-glass-child-parallax", `translate(${elasticTranslation.x * -parallaxFactor}px, ${elasticTranslation.y * -parallaxFactor}px)`),
|
|
2314
|
-
style.setProperty("--atomix-glass-contrast", lightingContrast.toString()), style.setProperty("--atomix-glass-brightness", lightingBrightness.toString())
|
|
2377
|
+
style.setProperty("--atomix-glass-contrast", lightingContrast.toString()), style.setProperty("--atomix-glass-brightness", lightingBrightness.toString());
|
|
2315
2378
|
// ── Chromatic Rim Lighting ──────────────────────────────────────
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2379
|
+
const borderVars = ATOMIX_GLASS.BORDER.GRADIENT_CSS_VARS;
|
|
2380
|
+
if (borderAnimated && !effectiveWithoutEffects) {
|
|
2381
|
+
const borderCssVars =
|
|
2382
|
+
/**
|
|
2383
|
+
* Builds animated chromatic rim CSS variables for border layers 1 and 2.
|
|
2384
|
+
* When empty, SCSS static conic/linear fallbacks apply.
|
|
2385
|
+
*/
|
|
2386
|
+
function(params) {
|
|
2387
|
+
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%)`;
|
|
2388
|
+
return {
|
|
2389
|
+
[BORDER.GRADIENT_CSS_VARS.GRADIENT_1]: gradient1,
|
|
2390
|
+
[BORDER.GRADIENT_CSS_VARS.GRADIENT_2]: gradient2
|
|
2391
|
+
};
|
|
2392
|
+
}({
|
|
2393
|
+
mouseOffset: mouseOffset,
|
|
2394
|
+
mouseVelocity: mouseVelocity,
|
|
2395
|
+
elasticVelocity: elasticVelocity,
|
|
2396
|
+
borderOpacity: overLightConfig.borderOpacity,
|
|
2397
|
+
opacityMultiplier: borderOpacityMultiplier,
|
|
2398
|
+
tensionFactor: tensionFactor
|
|
2399
|
+
});
|
|
2400
|
+
style.setProperty(borderVars.GRADIENT_1, borderCssVars[borderVars.GRADIENT_1] ?? ""),
|
|
2401
|
+
style.setProperty(borderVars.GRADIENT_2, borderCssVars[borderVars.GRADIENT_2] ?? "");
|
|
2402
|
+
} else style.removeProperty(borderVars.GRADIENT_1), style.removeProperty(borderVars.GRADIENT_2);
|
|
2403
|
+
// Hover gradients — cursor-relative radial positions for realistic light tracking.
|
|
2404
|
+
// hover-1: white overlay highlight following cursor (works on both dark + light)
|
|
2405
|
+
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%)`),
|
|
2406
|
+
// hover-2: press depth — darkens at cursor with multiply blend, isOverLight uses stronger black
|
|
2407
|
+
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%)`),
|
|
2408
|
+
// hover-3: full-surface soft-light tint; linear gradient angled with cursor X
|
|
2409
|
+
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%)`),
|
|
2410
|
+
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%)`),
|
|
2411
|
+
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%)`),
|
|
2326
2412
|
// Opacities
|
|
2327
2413
|
style.setProperty("--atomix-glass-hover-1-opacity", opacityValues.hover1.toString()),
|
|
2328
2414
|
style.setProperty("--atomix-glass-hover-2-opacity", opacityValues.hover2.toString()),
|
|
@@ -2359,151 +2445,16 @@ class {
|
|
|
2359
2445
|
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})`;
|
|
2360
2446
|
// Container variables
|
|
2361
2447
|
const style = containerElement.style;
|
|
2362
|
-
style.setProperty("--atomix-glass-container-
|
|
2448
|
+
style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
|
|
2363
2449
|
style.setProperty("--atomix-glass-container-backdrop", backdropFilterString),
|
|
2364
2450
|
// Shadows
|
|
2365
|
-
style.setProperty("--atomix-glass-container-shadow", isOverLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${(.
|
|
2451
|
+
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),
|
|
2366
2452
|
style.setProperty("--atomix-glass-container-shadow-opacity", effectiveWithoutEffects ? "0" : "1"),
|
|
2367
2453
|
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"),
|
|
2368
2454
|
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)"),
|
|
2369
|
-
style.setProperty("--atomix-glass-container-box-shadow", isOverLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "
|
|
2455
|
+
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)");
|
|
2370
2456
|
}
|
|
2371
|
-
};
|
|
2372
|
-
|
|
2373
|
-
/**
|
|
2374
|
-
* Updates the styles of the AtomixGlass wrapper and container elements imperatively
|
|
2375
|
-
* to avoid React re-renders on mouse movement.
|
|
2376
|
-
*/
|
|
2377
|
-
/**
|
|
2378
|
-
* Animation System for AtomixGlass Component
|
|
2379
|
-
*
|
|
2380
|
-
* Implements Phase 1 features from the AtomixGlass Feature Implementation Roadmap:
|
|
2381
|
-
* - Feature 1.1: Time-Based Animation System
|
|
2382
|
-
* - Feature 1.2: Multi-Layer Distortion System (FBM)
|
|
2383
|
-
*
|
|
2384
|
-
* @packageDocumentation
|
|
2385
|
-
*/
|
|
2386
|
-
// ============================================================================
|
|
2387
|
-
// Noise Functions for FBM (Feature 1.2)
|
|
2388
|
-
// ============================================================================
|
|
2389
|
-
/**
|
|
2390
|
-
* Perlin noise implementation for smooth gradient noise
|
|
2391
|
-
*
|
|
2392
|
-
* @param x - X coordinate
|
|
2393
|
-
* @param y - Y coordinate
|
|
2394
|
-
* @returns Noise value in range [0, 1]
|
|
2395
|
-
*/
|
|
2396
|
-
function perlinNoise(x, y) {
|
|
2397
|
-
// Simplified Perlin noise using pseudo-random gradients
|
|
2398
|
-
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);
|
|
2399
|
-
// Scale to [0, 1] range
|
|
2400
|
-
return (lerp(lerpX1, lerpX2, v) + 1) / 2;
|
|
2401
|
-
}
|
|
2402
|
-
|
|
2403
|
-
// ============================================================================
|
|
2404
|
-
// Fractal Brownian Motion (FBM) Engine (Feature 1.2)
|
|
2405
|
-
// ============================================================================
|
|
2406
|
-
/**
|
|
2407
|
-
* Creates an FBM engine with configurable parameters
|
|
2408
|
-
*
|
|
2409
|
-
* @param config - FBM configuration (octaves, lacunarity, gain)
|
|
2410
|
-
* @returns Object with fbm function
|
|
2411
|
-
*
|
|
2412
|
-
* @example
|
|
2413
|
-
* ```typescript
|
|
2414
|
-
* const fbmEngine = createFBMEngine({ octaves: 5, lacunarity: 2, gain: 0.5 });
|
|
2415
|
-
*
|
|
2416
|
-
* // Generate noise at position (0.5, 0.5) with time animation
|
|
2417
|
-
* const noiseValue = fbmEngine.fbm(0.5, 0.5, Date.now());
|
|
2418
|
-
* ```
|
|
2419
|
-
*/ function createFBMEngine(config) {
|
|
2420
|
-
/**
|
|
2421
|
-
* Fractal Brownian Motion function
|
|
2422
|
-
* Combines multiple octaves of noise for complex, natural patterns
|
|
2423
|
-
*
|
|
2424
|
-
* @param x - X coordinate
|
|
2425
|
-
* @param y - Y coordinate
|
|
2426
|
-
* @param time - Optional time value for animation
|
|
2427
|
-
* @returns FBM noise value in range [0, 1]
|
|
2428
|
-
*/
|
|
2429
|
-
const fbm = (x, y, time = 0) => {
|
|
2430
|
-
let value = 0, amplitude = .5, frequency = 1, phase = .001 * time;
|
|
2431
|
-
// Convert to seconds for reasonable animation speed
|
|
2432
|
-
for (let i = 0; i < config.octaves; i++)
|
|
2433
|
-
// Apply time-based phase shift to all octaves
|
|
2434
|
-
value += perlinNoise(x * frequency + phase, y * frequency + phase) * amplitude,
|
|
2435
|
-
frequency *= config.lacunarity, // Increase frequency
|
|
2436
|
-
amplitude *= config.gain;
|
|
2437
|
-
return value;
|
|
2438
|
-
};
|
|
2439
|
-
/**
|
|
2440
|
-
* Get FBM with simple time factor
|
|
2441
|
-
*/ return {
|
|
2442
|
-
fbm: fbm,
|
|
2443
|
-
fbmWithTime: (x, y, time) => fbm(x, y, time)
|
|
2444
|
-
};
|
|
2445
|
-
}
|
|
2446
|
-
|
|
2447
|
-
/**
|
|
2448
|
-
* Gets optimal FBM config based on quality preset
|
|
2449
|
-
*
|
|
2450
|
-
* @param quality - Quality preset level
|
|
2451
|
-
* @returns FBM configuration for the quality level
|
|
2452
|
-
*/ const fbmEngineCache = new Map;
|
|
2453
|
-
|
|
2454
|
-
// ============================================================================
|
|
2455
|
-
// Shader Utility Functions for Time-Based Effects
|
|
2456
|
-
// ============================================================================
|
|
2457
|
-
/**
|
|
2458
|
-
* Liquid glass distortion with time-based animation
|
|
2459
|
-
* Uses FBM to create organic, flowing liquid effects
|
|
2460
|
-
*
|
|
2461
|
-
* @param uv - UV coordinates (normalized 0-1)
|
|
2462
|
-
* @param time - Elapsed time in milliseconds
|
|
2463
|
-
* @param config - FBM configuration
|
|
2464
|
-
* @returns Distorted UV coordinates
|
|
2465
|
-
*/ function liquidGlassWithTime(uv, time, config) {
|
|
2466
|
-
const configKey = `${config.octaves}-${config.lacunarity}-${config.gain}`;
|
|
2467
|
-
let fbmEngine = fbmEngineCache.get(configKey);
|
|
2468
|
-
fbmEngine || (fbmEngine = createFBMEngine(config), fbmEngineCache.set(configKey, fbmEngine));
|
|
2469
|
-
// Animate noise with time
|
|
2470
|
-
const animatedNoise = fbmEngine.fbmWithTime(2 * uv.x + 1e-4 * time, 2 * uv.y + 15e-5 * time, time);
|
|
2471
|
-
return {
|
|
2472
|
-
x: uv.x + .04 * (animatedNoise - .5),
|
|
2473
|
-
y: uv.y + .04 * (animatedNoise - .5)
|
|
2474
|
-
};
|
|
2475
|
-
}
|
|
2476
|
-
|
|
2477
|
-
// ============================================================================
|
|
2478
|
-
// Helper Functions
|
|
2479
|
-
// ============================================================================
|
|
2480
|
-
/**
|
|
2481
|
-
* Fade curve for smooth interpolation (Perlin's fade function)
|
|
2482
|
-
*/ function fade(t) {
|
|
2483
|
-
return t * t * t * (t * (6 * t - 15) + 10);
|
|
2484
|
-
}
|
|
2485
|
-
|
|
2486
|
-
/**
|
|
2487
|
-
* Linear interpolation
|
|
2488
|
-
*/ function lerp(a, b, t) {
|
|
2489
|
-
return a + t * (b - a);
|
|
2490
|
-
}
|
|
2491
|
-
|
|
2492
|
-
/**
|
|
2493
|
-
* Gradient calculation for Perlin noise
|
|
2494
|
-
*/ function grad(hash, x, y) {
|
|
2495
|
-
const h = 15 & hash, u = h < 8 ? x : y, v = h < 4 ? y : 12 === h || 14 === h ? x : 0;
|
|
2496
|
-
return (1 & h ? -u : u) + (2 & h ? -v : v);
|
|
2497
|
-
}
|
|
2498
|
-
|
|
2499
|
-
/**
|
|
2500
|
-
* Permutation table for Perlin noise
|
|
2501
|
-
*/ const p = (() => {
|
|
2502
|
-
const permutation = [];
|
|
2503
|
-
for (let i = 0; i < 256; i++) permutation[i] = Math.floor(256 * Math.random());
|
|
2504
|
-
// Duplicate for overflow handling
|
|
2505
|
-
return [ ...permutation, ...permutation ];
|
|
2506
|
-
})(), {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
|
|
2457
|
+
}, {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
|
|
2507
2458
|
|
|
2508
2459
|
const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new WeakMap, setCachedBackgroundDetection = (parentElement, overLightConfig, result, threshold) => {
|
|
2509
2460
|
parentElement && backgroundDetectionCache.set(parentElement, {
|
|
@@ -2518,12 +2469,35 @@ const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new Weak
|
|
|
2518
2469
|
* Composable hook for AtomixGlass component logic
|
|
2519
2470
|
* Manages all state, calculations, and event handlers
|
|
2520
2471
|
*/
|
|
2521
|
-
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,
|
|
2522
|
-
// Default priority
|
|
2523
|
-
// Phase 1: Animation System Props
|
|
2524
|
-
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}) {
|
|
2472
|
+
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}) {
|
|
2525
2473
|
// State
|
|
2526
|
-
const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1),
|
|
2474
|
+
const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1), resolvedBorder = useMemo((() =>
|
|
2475
|
+
/**
|
|
2476
|
+
* Resolves `border` and legacy `withBorder` into a single configuration object.
|
|
2477
|
+
*/
|
|
2478
|
+
function(border, withBorder) {
|
|
2479
|
+
const legacyDefault = withBorder ?? !0;
|
|
2480
|
+
return void 0 === border ? {
|
|
2481
|
+
enabled: legacyDefault,
|
|
2482
|
+
width: BORDER.DEFAULT_WIDTH,
|
|
2483
|
+
opacityMultiplier: 1,
|
|
2484
|
+
animated: !0
|
|
2485
|
+
} : "boolean" == typeof border ? {
|
|
2486
|
+
enabled: border,
|
|
2487
|
+
width: BORDER.DEFAULT_WIDTH,
|
|
2488
|
+
opacityMultiplier: 1,
|
|
2489
|
+
animated: !0
|
|
2490
|
+
} : {
|
|
2491
|
+
enabled: border.enabled ?? legacyDefault,
|
|
2492
|
+
width: (value = border.width, void 0 === value ? BORDER.DEFAULT_WIDTH : "number" == typeof value ? `${value}px` : value),
|
|
2493
|
+
opacityMultiplier: border.opacity ?? 1,
|
|
2494
|
+
animated: !1 !== border.animated
|
|
2495
|
+
};
|
|
2496
|
+
/**
|
|
2497
|
+
* Formats border width for CSS custom properties.
|
|
2498
|
+
*/
|
|
2499
|
+
var value;
|
|
2500
|
+
}(border, withBorder)), [ border, withBorder ]), cachedRectRef = useRef(null), internalGlobalMousePositionRef = useRef({
|
|
2527
2501
|
x: 0,
|
|
2528
2502
|
y: 0
|
|
2529
2503
|
}), internalMouseOffsetRef = useRef({
|
|
@@ -2547,52 +2521,10 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
2547
2521
|
}), scaleVelocityRef = useRef({
|
|
2548
2522
|
x: 0,
|
|
2549
2523
|
y: 0
|
|
2550
|
-
})
|
|
2551
|
-
useRef(0);
|
|
2552
|
-
const mouseVelocityRef = useRef({
|
|
2524
|
+
}), mouseVelocityRef = useRef({
|
|
2553
2525
|
x: 0,
|
|
2554
2526
|
y: 0
|
|
2555
|
-
}), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1),
|
|
2556
|
-
// If quality preset is provided, use it as base
|
|
2557
|
-
const preset = (quality = distortionQuality, ATOMIX_GLASS.CONSTANTS.DISTORTION_QUALITY_PRESETS[quality]);
|
|
2558
|
-
// Override with custom values if provided
|
|
2559
|
-
var quality;
|
|
2560
|
-
return {
|
|
2561
|
-
octaves: distortionOctaves ?? preset.octaves,
|
|
2562
|
-
lacunarity: distortionLacunarity ?? preset.lacunarity,
|
|
2563
|
-
gain: distortionGain ?? preset.gain
|
|
2564
|
-
};
|
|
2565
|
-
}), [ distortionQuality, distortionOctaves, distortionLacunarity, distortionGain ]), fbmEngine = useMemo((() => withMultiLayerDistortion ? createFBMEngine(fbmConfig) : null), [ withMultiLayerDistortion, fbmConfig ]), effectiveReducedMotion = useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveWithTimeAnimation = useMemo((() => withTimeAnimation && !effectiveReducedMotion), [ withTimeAnimation, effectiveReducedMotion ]);
|
|
2566
|
-
/**
|
|
2567
|
-
* Animation loop for time-based effects
|
|
2568
|
-
*/
|
|
2569
|
-
useEffect((() => {
|
|
2570
|
-
if (!effectiveWithTimeAnimation || "undefined" == typeof window) return;
|
|
2571
|
-
let lastFrameTime = performance.now();
|
|
2572
|
-
/**
|
|
2573
|
-
* Animation frame handler
|
|
2574
|
-
*/ const animate = currentTime => {
|
|
2575
|
-
// Calculate delta time
|
|
2576
|
-
const deltaTime = currentTime - lastFrameTime;
|
|
2577
|
-
lastFrameTime = currentTime;
|
|
2578
|
-
// Apply animation speed multiplier
|
|
2579
|
-
const scaledDelta = deltaTime * animationSpeed;
|
|
2580
|
-
elapsedTimeRef.current += scaledDelta, shaderTimeRef.current = elapsedTimeRef.current,
|
|
2581
|
-
// Continue animation loop
|
|
2582
|
-
animationFrameIdRef.current = requestAnimationFrame(animate);
|
|
2583
|
-
};
|
|
2584
|
-
// Start animation
|
|
2585
|
-
// Cleanup
|
|
2586
|
-
return animationStartTimeRef.current = performance.now(), animationFrameIdRef.current = requestAnimationFrame(animate),
|
|
2587
|
-
() => {
|
|
2588
|
-
null !== animationFrameIdRef.current && (cancelAnimationFrame(animationFrameIdRef.current),
|
|
2589
|
-
animationFrameIdRef.current = null);
|
|
2590
|
-
};
|
|
2591
|
-
}), [ effectiveWithTimeAnimation, animationSpeed ]);
|
|
2592
|
-
/**
|
|
2593
|
-
* Get current shader time for animations
|
|
2594
|
-
*/
|
|
2595
|
-
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}) {
|
|
2527
|
+
}), [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}) {
|
|
2596
2528
|
const [glassSize, setGlassSize] = useState({
|
|
2597
2529
|
width: 270,
|
|
2598
2530
|
height: 69
|
|
@@ -2652,9 +2584,6 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
2652
2584
|
effectiveBorderRadius: effectiveBorderRadius,
|
|
2653
2585
|
cachedRectRef: cachedRectRef
|
|
2654
2586
|
}), effectiveHighContrast = useMemo((() => highContrast || userPrefersHighContrast), [ highContrast, userPrefersHighContrast ]), effectiveWithoutEffects = useMemo((() => withoutEffects || effectiveReducedMotion), [ withoutEffects, effectiveReducedMotion ]), globalMousePosition = externalGlobalMousePosition || internalGlobalMousePositionRef.current, mouseOffset = externalMouseOffset || internalMouseOffsetRef.current;
|
|
2655
|
-
/**
|
|
2656
|
-
* Apply time-based distortion to UV coordinates
|
|
2657
|
-
*/
|
|
2658
2587
|
// Extract border-radius from children
|
|
2659
2588
|
useEffect((() => {
|
|
2660
2589
|
const extractRadius = () => {
|
|
@@ -2814,25 +2743,26 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
2814
2743
|
* Get effective overLight value based on configuration
|
|
2815
2744
|
*/
|
|
2816
2745
|
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((() => {
|
|
2817
|
-
const isOverLight = getEffectiveOverLight(), hoverIntensity
|
|
2746
|
+
const isOverLight = getEffectiveOverLight(), {hoverIntensity: hoverIntensity, activeIntensity: activeIntensity} = getInteractionIntensity(isHovered, isActive), baseConfig = {
|
|
2818
2747
|
isOverLight: isOverLight,
|
|
2819
2748
|
threshold: .7,
|
|
2820
2749
|
opacity: isOverLight ? Math.min(.6, Math.max(.2, .5 * hoverIntensity * activeIntensity)) : 0,
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
shadowIntensity: .9,
|
|
2826
|
-
borderOpacity: .
|
|
2750
|
+
// Dark UI (Apple Music): neutral contrast + slight brightness lift
|
|
2751
|
+
contrast: isOverLight ? 1.4 : 1.02,
|
|
2752
|
+
brightness: isOverLight ? .9 : 1.02,
|
|
2753
|
+
saturationBoost: isOverLight ? 1.3 : 1,
|
|
2754
|
+
shadowIntensity: isOverLight ? .9 : 1,
|
|
2755
|
+
borderOpacity: isOverLight ? ATOMIX_GLASS.BORDER.OVER_LIGHT.opacity : ATOMIX_GLASS.BORDER.DARK.opacity
|
|
2827
2756
|
};
|
|
2828
2757
|
if ("object" == typeof overLight && null !== overLight) {
|
|
2829
|
-
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 = {
|
|
2758
|
+
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 = {
|
|
2830
2759
|
...baseConfig,
|
|
2831
2760
|
threshold: validatedThreshold,
|
|
2832
2761
|
opacity: validatedOpacity * hoverIntensity * activeIntensity,
|
|
2833
2762
|
contrast: validatedContrast,
|
|
2834
2763
|
brightness: validatedBrightness,
|
|
2835
|
-
saturationBoost: validatedSaturationBoost
|
|
2764
|
+
saturationBoost: validatedSaturationBoost,
|
|
2765
|
+
borderOpacity: validatedBorderOpacity
|
|
2836
2766
|
};
|
|
2837
2767
|
return "undefined" == typeof process || process.env, finalConfig;
|
|
2838
2768
|
}
|
|
@@ -2857,8 +2787,8 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
2857
2787
|
};
|
|
2858
2788
|
const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
|
|
2859
2789
|
internalGlobalMousePositionRef.current = {
|
|
2860
|
-
x: lerp
|
|
2861
|
-
y: lerp
|
|
2790
|
+
x: lerp(curG.x, tgtG.x, CONSTANTS.LERP_FACTOR),
|
|
2791
|
+
y: lerp(curG.y, tgtG.y, CONSTANTS.LERP_FACTOR)
|
|
2862
2792
|
};
|
|
2863
2793
|
// ── Calculate Elastic Physics ─────────────────────────────────────
|
|
2864
2794
|
let targetElasticTranslation = {
|
|
@@ -2930,12 +2860,13 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
2930
2860
|
withLiquidBlur: withLiquidBlur,
|
|
2931
2861
|
blurAmount: blurAmount,
|
|
2932
2862
|
saturation: saturation,
|
|
2933
|
-
|
|
2934
|
-
|
|
2863
|
+
isFixedOrSticky: isFixedOrSticky,
|
|
2864
|
+
borderAnimated: resolvedBorder.animated,
|
|
2865
|
+
borderOpacityMultiplier: resolvedBorder.opacityMultiplier
|
|
2935
2866
|
}), 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);
|
|
2936
2867
|
};
|
|
2937
2868
|
lerpRafRef.current = requestAnimationFrame(tick);
|
|
2938
|
-
}), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation,
|
|
2869
|
+
}), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, isFixedOrSticky, resolvedBorder.animated, resolvedBorder.opacityMultiplier, stopLerpLoop ]), handleGlobalMousePosition = useCallback((globalPos => {
|
|
2939
2870
|
if (externalGlobalMousePosition && externalMouseOffset) return;
|
|
2940
2871
|
if (effectiveWithoutEffects) return;
|
|
2941
2872
|
const container = mouseContainer?.current || glassRef.current;
|
|
@@ -2999,9 +2930,10 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
2999
2930
|
withLiquidBlur: withLiquidBlur,
|
|
3000
2931
|
blurAmount: blurAmount,
|
|
3001
2932
|
saturation: saturation,
|
|
3002
|
-
|
|
2933
|
+
borderAnimated: resolvedBorder.animated,
|
|
2934
|
+
borderOpacityMultiplier: resolvedBorder.opacityMultiplier
|
|
3003
2935
|
});
|
|
3004
|
-
}), [ isHovered, isActive, glassSize, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation,
|
|
2936
|
+
}), [ isHovered, isActive, glassSize, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation, resolvedBorder.animated, resolvedBorder.opacityMultiplier, onClick ]);
|
|
3005
2937
|
// Event handlers
|
|
3006
2938
|
const handleMouseEnter = useCallback((() => setIsHovered(!0)), []), handleMouseLeave = useCallback((() => setIsHovered(!1)), []), handleMouseDown = useCallback((() => setIsActive(!0)), []), handleMouseUp = useCallback((() => setIsActive(!1)), []), handleKeyDown = useCallback((e => {
|
|
3007
2939
|
!onClick || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), onClick());
|
|
@@ -3021,9 +2953,8 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
|
|
|
3021
2953
|
mouseOffset: mouseOffset,
|
|
3022
2954
|
// This is now static (refs or props) unless prop changes
|
|
3023
2955
|
overLightConfig: overLightConfig,
|
|
2956
|
+
resolvedBorder: resolvedBorder,
|
|
3024
2957
|
transformStyle: transformStyle,
|
|
3025
|
-
getShaderTime: getShaderTime,
|
|
3026
|
-
applyTimeBasedDistortion: applyTimeBasedDistortion,
|
|
3027
2958
|
handleMouseEnter: handleMouseEnter,
|
|
3028
2959
|
handleMouseLeave: handleMouseLeave,
|
|
3029
2960
|
handleMouseDown: handleMouseDown,
|
|
@@ -3171,148 +3102,6 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
|
3171
3102
|
/**
|
|
3172
3103
|
* Get GPU memory info if available (Chrome DevTools only)
|
|
3173
3104
|
*/
|
|
3174
|
-
/** Map an FPS value to a semantic color token string. */
|
|
3175
|
-
const getQualityColor = quality => {
|
|
3176
|
-
switch (quality) {
|
|
3177
|
-
case "high":
|
|
3178
|
-
return "var(--atomix-color-success, #4ade80)";
|
|
3179
|
-
|
|
3180
|
-
case "medium":
|
|
3181
|
-
return "var(--atomix-color-warning, #fbbf24)";
|
|
3182
|
-
|
|
3183
|
-
case "low":
|
|
3184
|
-
return "var(--atomix-color-danger, #ef4444)";
|
|
3185
|
-
|
|
3186
|
-
default:
|
|
3187
|
-
return "#9ca3af";
|
|
3188
|
-
}
|
|
3189
|
-
}, getFpsLabel = fps => fps >= 58 ? "Optimal" : fps >= 45 ? "Warning" : "Critical";
|
|
3190
|
-
|
|
3191
|
-
/** Map a quality level string to a semantic color token string. */
|
|
3192
|
-
// Inject keyframes once
|
|
3193
|
-
if ("undefined" != typeof document) {
|
|
3194
|
-
const styleId = "perf-dashboard-keyframes";
|
|
3195
|
-
if (!document.getElementById(styleId)) {
|
|
3196
|
-
const styleEl = document.createElement("style");
|
|
3197
|
-
styleEl.id = styleId, styleEl.textContent = "\n@keyframes perf-dashboard-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n",
|
|
3198
|
-
document.head.appendChild(styleEl);
|
|
3199
|
-
}
|
|
3200
|
-
}
|
|
3201
|
-
|
|
3202
|
-
/**
|
|
3203
|
-
* PerformanceDashboard - Real-time performance monitoring overlay.
|
|
3204
|
-
*
|
|
3205
|
-
* Displays FPS, frame time, quality level, GPU memory, and auto-scaling status.
|
|
3206
|
-
* Rendered only when `debugPerformance={true}` on the parent `AtomixGlass`.
|
|
3207
|
-
*/ const PerformanceDashboard = memo((({metrics: metrics, isVisible: isVisible = !0, onClose: onClose}) => {
|
|
3208
|
-
if (!isVisible) return null;
|
|
3209
|
-
const fpsColor = (fps = metrics.fps) >= 58 ? "var(--atomix-color-success, #4ade80)" : fps >= 45 ? "var(--atomix-color-warning, #fbbf24)" : "var(--atomix-color-danger, #ef4444)";
|
|
3210
|
-
var fps;
|
|
3211
|
-
const isCritical = metrics.fps < 45;
|
|
3212
|
-
return jsxs("div", {
|
|
3213
|
-
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",
|
|
3214
|
-
style: {
|
|
3215
|
-
zIndex: 9999,
|
|
3216
|
-
minWidth: "12.5rem",
|
|
3217
|
-
// 200px
|
|
3218
|
-
backgroundColor: "rgba(17, 24, 39, 0.95)",
|
|
3219
|
-
backdropFilter: "blur(8px)",
|
|
3220
|
-
transition: "opacity 0.3s ease"
|
|
3221
|
-
},
|
|
3222
|
-
children: [ jsxs("div", {
|
|
3223
|
-
className: "u-flex u-items-center u-justify-between u-mb-2 u-pb-2 u-border-b u-border-white-alpha-10",
|
|
3224
|
-
children: [ jsx("span", {
|
|
3225
|
-
className: "u-text-sm u-font-bold u-text-white",
|
|
3226
|
-
children: "Performance Monitor"
|
|
3227
|
-
}), onClose && jsx("button", {
|
|
3228
|
-
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",
|
|
3229
|
-
onClick: onClose,
|
|
3230
|
-
"aria-label": "Close performance dashboard",
|
|
3231
|
-
style: {
|
|
3232
|
-
transition: "color 0.2s ease"
|
|
3233
|
-
},
|
|
3234
|
-
children: "×"
|
|
3235
|
-
}) ]
|
|
3236
|
-
}), jsxs("div", {
|
|
3237
|
-
className: "u-flex u-items-center u-justify-between u-mb-1-5",
|
|
3238
|
-
children: [ jsx("span", {
|
|
3239
|
-
className: "u-text-gray-400 u-me-3",
|
|
3240
|
-
children: "FPS"
|
|
3241
|
-
}), jsx("span", {
|
|
3242
|
-
className: "u-font-bold",
|
|
3243
|
-
style: {
|
|
3244
|
-
color: fpsColor
|
|
3245
|
-
},
|
|
3246
|
-
children: Math.round(metrics.fps)
|
|
3247
|
-
}) ]
|
|
3248
|
-
}), jsxs("div", {
|
|
3249
|
-
className: "u-flex u-items-center u-justify-between u-mb-1-5",
|
|
3250
|
-
children: [ jsx("span", {
|
|
3251
|
-
className: "u-text-gray-400 u-me-3",
|
|
3252
|
-
children: "Frame Time"
|
|
3253
|
-
}), jsxs("span", {
|
|
3254
|
-
className: "u-font-bold",
|
|
3255
|
-
children: [ metrics.frameTime.toFixed(2), "ms" ]
|
|
3256
|
-
}) ]
|
|
3257
|
-
}), jsxs("div", {
|
|
3258
|
-
className: "u-flex u-items-center u-justify-between u-mb-1-5",
|
|
3259
|
-
children: [ jsx("span", {
|
|
3260
|
-
className: "u-text-gray-400 u-me-3",
|
|
3261
|
-
children: "Quality"
|
|
3262
|
-
}), jsx("span", {
|
|
3263
|
-
className: "u-font-bold u-text-uppercase",
|
|
3264
|
-
style: {
|
|
3265
|
-
fontSize: "0.6875rem",
|
|
3266
|
-
// 11px
|
|
3267
|
-
color: getQualityColor(metrics.qualityLevel)
|
|
3268
|
-
},
|
|
3269
|
-
children: metrics.qualityLevel
|
|
3270
|
-
}) ]
|
|
3271
|
-
}), metrics.gpuMemory && jsxs("div", {
|
|
3272
|
-
className: "u-flex u-items-center u-justify-between u-mb-1-5",
|
|
3273
|
-
children: [ jsx("span", {
|
|
3274
|
-
className: "u-text-gray-400 u-me-3",
|
|
3275
|
-
children: "GPU Memory"
|
|
3276
|
-
}), jsxs("span", {
|
|
3277
|
-
className: "u-font-bold",
|
|
3278
|
-
children: [ "~", Math.round(metrics.gpuMemory / 1024), "MB" ]
|
|
3279
|
-
}) ]
|
|
3280
|
-
}), metrics.isAutoScaling && jsx("div", {
|
|
3281
|
-
className: "u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10 u-text-center",
|
|
3282
|
-
style: {
|
|
3283
|
-
fontSize: "0.625rem",
|
|
3284
|
-
// 10px
|
|
3285
|
-
color: "#6b7280"
|
|
3286
|
-
},
|
|
3287
|
-
children: "Auto-scaling active"
|
|
3288
|
-
}), jsxs("div", {
|
|
3289
|
-
className: "u-flex u-items-center u-gap-2 u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10",
|
|
3290
|
-
children: [ jsx("div", {
|
|
3291
|
-
className: "u-rounded-full",
|
|
3292
|
-
style: {
|
|
3293
|
-
width: "0.5rem",
|
|
3294
|
-
height: "0.5rem",
|
|
3295
|
-
flexShrink: 0,
|
|
3296
|
-
backgroundColor: fpsColor,
|
|
3297
|
-
...isCritical && {
|
|
3298
|
-
animation: "perf-dashboard-pulse 1s infinite"
|
|
3299
|
-
}
|
|
3300
|
-
}
|
|
3301
|
-
}), jsx("span", {
|
|
3302
|
-
className: "u-text-xs",
|
|
3303
|
-
style: {
|
|
3304
|
-
fontSize: "0.625rem",
|
|
3305
|
-
// 10px
|
|
3306
|
-
color: fpsColor
|
|
3307
|
-
},
|
|
3308
|
-
children: getFpsLabel(metrics.fps)
|
|
3309
|
-
}) ]
|
|
3310
|
-
}) ]
|
|
3311
|
-
});
|
|
3312
|
-
}));
|
|
3313
|
-
|
|
3314
|
-
PerformanceDashboard.displayName = "PerformanceDashboard";
|
|
3315
|
-
|
|
3316
3105
|
/**
|
|
3317
3106
|
* Mobile optimization presets
|
|
3318
3107
|
*
|
|
@@ -3432,18 +3221,13 @@ const PERFORMANCE_PRESET = {
|
|
|
3432
3221
|
saturation: 70
|
|
3433
3222
|
}
|
|
3434
3223
|
}
|
|
3435
|
-
}, 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 = "",
|
|
3436
|
-
const glassRef = useRef(null), contentRef = useRef(null), internalWrapperRef = useRef(null), mergedRef =
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
}));
|
|
3443
|
-
};
|
|
3444
|
-
}
|
|
3445
|
-
// Internal implementation with forwardRef
|
|
3446
|
-
(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({
|
|
3224
|
+
}, 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) {
|
|
3225
|
+
const glassRef = useRef(null), contentRef = useRef(null), internalWrapperRef = useRef(null), mergedRef = useForkRef(ref, internalWrapperRef), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = (explicit = propsIsFixedOrSticky,
|
|
3226
|
+
position = restStyle.position, Boolean(explicit || "fixed" === position || "sticky" === position));
|
|
3227
|
+
var explicit, position;
|
|
3228
|
+
/**
|
|
3229
|
+
* Extracts layout-related properties from a React `CSSProperties` object.
|
|
3230
|
+
*/ 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({
|
|
3447
3231
|
glassRef: glassRef,
|
|
3448
3232
|
contentRef: contentRef,
|
|
3449
3233
|
wrapperRef: internalWrapperRef,
|
|
@@ -3463,20 +3247,13 @@ const PERFORMANCE_PRESET = {
|
|
|
3463
3247
|
blurAmount: blurAmount,
|
|
3464
3248
|
saturation: saturation,
|
|
3465
3249
|
withLiquidBlur: withLiquidBlur,
|
|
3466
|
-
|
|
3250
|
+
border: border,
|
|
3251
|
+
withBorder: withBorder,
|
|
3252
|
+
debugBorderRadius: debugBorderRadius,
|
|
3467
3253
|
style: style,
|
|
3468
|
-
isFixedOrSticky: isFixedOrSticky
|
|
3469
|
-
// Phase 1: Animation System props
|
|
3470
|
-
withTimeAnimation: withTimeAnimation,
|
|
3471
|
-
animationSpeed: animationSpeed,
|
|
3472
|
-
withMultiLayerDistortion: withMultiLayerDistortion,
|
|
3473
|
-
distortionOctaves: distortionOctaves,
|
|
3474
|
-
distortionLacunarity: distortionLacunarity,
|
|
3475
|
-
distortionGain: distortionGain,
|
|
3476
|
-
distortionQuality: distortionQuality
|
|
3254
|
+
isFixedOrSticky: isFixedOrSticky
|
|
3477
3255
|
});
|
|
3478
|
-
|
|
3479
|
-
!
|
|
3256
|
+
(
|
|
3480
3257
|
/**
|
|
3481
3258
|
* Responsive Glass Parameters Hook
|
|
3482
3259
|
*
|
|
@@ -3631,7 +3408,7 @@ const PERFORMANCE_PRESET = {
|
|
|
3631
3408
|
}), [ enabled ]), useCallback((() => {
|
|
3632
3409
|
calculateParams();
|
|
3633
3410
|
}), [ calculateParams ]);
|
|
3634
|
-
}({
|
|
3411
|
+
})({
|
|
3635
3412
|
baseParams: {
|
|
3636
3413
|
...useMemo((() =>
|
|
3637
3414
|
/**
|
|
@@ -3665,9 +3442,7 @@ const PERFORMANCE_PRESET = {
|
|
|
3665
3442
|
breakpoints: MOBILE_OPTIMIZED_BREAKPOINTS,
|
|
3666
3443
|
enabled: !disableResponsiveBreakpoints && "undefined" != typeof window,
|
|
3667
3444
|
debug: !1
|
|
3668
|
-
})
|
|
3669
|
-
// Performance monitoring - tracks FPS, frame time, memory usage
|
|
3670
|
-
const {metrics: performanceMetrics, toggleMonitoring: toggleMonitoring} =
|
|
3445
|
+
}),
|
|
3671
3446
|
/**
|
|
3672
3447
|
* Performance Monitor Hook
|
|
3673
3448
|
*
|
|
@@ -3702,7 +3477,13 @@ const PERFORMANCE_PRESET = {
|
|
|
3702
3477
|
timestamp: 0,
|
|
3703
3478
|
isAutoScaling: !0,
|
|
3704
3479
|
lowFpsCount: 0
|
|
3705
|
-
}), [manualOverride, setManualOverride] = useState(!1), [isEnabled, setIsEnabled] = useState(enabled)
|
|
3480
|
+
}), [manualOverride, setManualOverride] = useState(!1), [isEnabled, setIsEnabled] = useState(enabled);
|
|
3481
|
+
// Sync external `enabled` prop changes into internal state
|
|
3482
|
+
useEffect((() => {
|
|
3483
|
+
setIsEnabled(enabled ?? !0);
|
|
3484
|
+
}), [ enabled ]);
|
|
3485
|
+
// Refs for frame tracking
|
|
3486
|
+
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 => {
|
|
3706
3487
|
setMetrics((prev => ({
|
|
3707
3488
|
...prev,
|
|
3708
3489
|
...newMetrics,
|
|
@@ -3822,191 +3603,214 @@ const PERFORMANCE_PRESET = {
|
|
|
3822
3603
|
/**
|
|
3823
3604
|
* Reset to auto-scaling mode
|
|
3824
3605
|
*/ var fps, currentQuality;
|
|
3825
|
-
|
|
3826
|
-
metrics: metrics,
|
|
3827
|
-
recommendedQuality: (fps = metrics.fps, currentQuality = metrics.qualityLevel, fps >= 58 ? "high" : fps >= 45 ? "high" === currentQuality ? "high" : "medium" : "low"),
|
|
3828
|
-
isUnderperforming: metrics.fps < minFps,
|
|
3829
|
-
setQualityLevel: setQualityLevel,
|
|
3830
|
-
resetAutoScaling: resetAutoScaling,
|
|
3831
|
-
toggleMonitoring: toggleMonitoring
|
|
3832
|
-
};
|
|
3606
|
+
fps = metrics.fps, currentQuality = metrics.qualityLevel, metrics.fps;
|
|
3833
3607
|
}({
|
|
3834
3608
|
enabled: debugPerformance,
|
|
3835
|
-
// Enable when debugPerformance is true
|
|
3836
3609
|
debug: !1,
|
|
3837
3610
|
showOverlay: !1
|
|
3838
3611
|
});
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
}), [ debugPerformance ]);
|
|
3844
|
-
// Re-run when debugPerformance changes
|
|
3845
|
-
const isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, rootLayoutStyle = useMemo((() => {
|
|
3846
|
-
if (!isFixedOrSticky) return {};
|
|
3847
|
-
const {position: p, top: t, left: l, right: r, bottom: b} = restStyle;
|
|
3848
|
-
return {
|
|
3849
|
-
...p && {
|
|
3850
|
-
position: p
|
|
3851
|
-
},
|
|
3852
|
-
...void 0 !== t && {
|
|
3853
|
-
top: t
|
|
3854
|
-
},
|
|
3855
|
-
...void 0 !== l && {
|
|
3856
|
-
left: l
|
|
3857
|
-
},
|
|
3858
|
-
...void 0 !== r && {
|
|
3859
|
-
right: r
|
|
3860
|
-
},
|
|
3861
|
-
...void 0 !== b && {
|
|
3862
|
-
bottom: b
|
|
3863
|
-
}
|
|
3864
|
-
};
|
|
3865
|
-
}), [ isFixedOrSticky, restStyle ]);
|
|
3866
|
-
// Calculate base style with transforms
|
|
3867
|
-
// When layout is hoisted to the root, strip those props from the container
|
|
3868
|
-
useMemo((() => {
|
|
3869
|
-
if (isFixedOrSticky) {
|
|
3870
|
-
const {position: _p, top: _t, left: _l, right: _r, bottom: _b, ...visualStyle} = restStyle;
|
|
3871
|
-
return {
|
|
3872
|
-
...visualStyle
|
|
3873
|
-
};
|
|
3612
|
+
const isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, containerStyle = useMemo((() => ({
|
|
3613
|
+
...restStyle,
|
|
3614
|
+
...void 0 !== customZIndex && {
|
|
3615
|
+
zIndex: customZIndex
|
|
3874
3616
|
}
|
|
3617
|
+
})), [ 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((() =>
|
|
3618
|
+
/**
|
|
3619
|
+
* Returns the internal positioning context for effect layers relative to the root.
|
|
3620
|
+
*/
|
|
3621
|
+
function(isFixedOrSticky, restStyle) {
|
|
3875
3622
|
return {
|
|
3876
|
-
|
|
3623
|
+
position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
|
|
3624
|
+
top: 0,
|
|
3625
|
+
left: 0,
|
|
3626
|
+
right: "auto",
|
|
3627
|
+
bottom: "auto"
|
|
3877
3628
|
};
|
|
3878
|
-
}
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
})), [ isFixedOrSticky, restStyle.position, restStyle.top, restStyle.left, restStyle.right, restStyle.bottom ]), adjustedSize = useMemo((() => {
|
|
3887
|
-
// Keep a reference to positionStyles to avoid unused-variable lint,
|
|
3888
|
-
// but sizing is driven by explicit width/height or measured size.
|
|
3889
|
-
positionStyles.position;
|
|
3890
|
-
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;
|
|
3629
|
+
}
|
|
3630
|
+
/**
|
|
3631
|
+
* Computes `--atomix-glass-width` and `--atomix-glass-height` values.
|
|
3632
|
+
*
|
|
3633
|
+
* Fixed/sticky elements prefer explicit dimensions or measured size; in-flow
|
|
3634
|
+
* elements default to `100%`.
|
|
3635
|
+
*/ (isFixedOrSticky, restStyle)), [ isFixedOrSticky, restStyle ]), adjustedSize = useMemo((() => function(options) {
|
|
3636
|
+
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;
|
|
3891
3637
|
return {
|
|
3892
3638
|
width: resolveLength(effectiveWidth, glassSize.width),
|
|
3893
3639
|
height: resolveLength(effectiveHeight, glassSize.height)
|
|
3894
3640
|
};
|
|
3895
|
-
}
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3641
|
+
}
|
|
3642
|
+
/**
|
|
3643
|
+
* Builds the CSS custom properties applied to the root `.c-atomix-glass` element.
|
|
3644
|
+
*
|
|
3645
|
+
* These variables drive layer geometry, transforms, and stacking offsets. They
|
|
3646
|
+
* must not include layout properties that would interfere with backdrop-filter.
|
|
3647
|
+
*/ ({
|
|
3648
|
+
width: width,
|
|
3649
|
+
height: height,
|
|
3650
|
+
restStyle: restStyle,
|
|
3651
|
+
glassSize: glassSize,
|
|
3652
|
+
isFixedOrSticky: isFixedOrSticky
|
|
3653
|
+
})), [ width, height, restStyle, glassSize, isFixedOrSticky ]), glassVars = useMemo((() => function(input) {
|
|
3654
|
+
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 =
|
|
3655
|
+
/**
|
|
3656
|
+
* Resolves the `--atomix-glass-position` value for decorative layers.
|
|
3657
|
+
*
|
|
3658
|
+
* Fixed/sticky layers use the same positioning mode as the container; in-flow
|
|
3659
|
+
* layers default to the internal absolute positioning context.
|
|
3660
|
+
*/
|
|
3661
|
+
function(isFixedOrSticky, positionStyles, restStyle) {
|
|
3662
|
+
return isFixedOrSticky ? `${function(style) {
|
|
3663
|
+
const {position: position, top: top, left: left, right: right, bottom: bottom, inset: inset} = style;
|
|
3664
|
+
return {
|
|
3665
|
+
...null != position && {
|
|
3666
|
+
position: position
|
|
3667
|
+
},
|
|
3668
|
+
...void 0 !== top && {
|
|
3669
|
+
top: top
|
|
3670
|
+
},
|
|
3671
|
+
...void 0 !== left && {
|
|
3672
|
+
left: left
|
|
3673
|
+
},
|
|
3674
|
+
...void 0 !== right && {
|
|
3675
|
+
right: right
|
|
3676
|
+
},
|
|
3677
|
+
...void 0 !== bottom && {
|
|
3678
|
+
bottom: bottom
|
|
3679
|
+
},
|
|
3680
|
+
...void 0 !== inset && {
|
|
3681
|
+
inset: inset
|
|
3682
|
+
}
|
|
3683
|
+
};
|
|
3684
|
+
}
|
|
3685
|
+
/**
|
|
3686
|
+
* Resolves inset custom properties for decorative layers (hover, borders, backgrounds).
|
|
3687
|
+
*
|
|
3688
|
+
* For fixed and sticky modes, insets mirror the container so sibling layers remain
|
|
3689
|
+
* aligned. In-flow modes, insets follow the consumer `style` when a non-default
|
|
3690
|
+
* `position` is provided.
|
|
3691
|
+
*/ (restStyle).position ?? restStyle.position ?? "fixed"}` : `${positionStyles.position}`;
|
|
3692
|
+
}(isFixedOrSticky, positionStyles, restStyle), layerInsets = function(isFixedOrSticky, restStyle) {
|
|
3693
|
+
if (isFixedOrSticky) return {
|
|
3694
|
+
top: formatGlassInsetValue(restStyle.top, 0),
|
|
3695
|
+
left: formatGlassInsetValue(restStyle.left, 0),
|
|
3696
|
+
right: formatGlassInsetValue(restStyle.right, "auto"),
|
|
3697
|
+
bottom: formatGlassInsetValue(restStyle.bottom, "auto")
|
|
3698
|
+
};
|
|
3699
|
+
const position = restStyle.position;
|
|
3700
|
+
return null != position && "static" !== position && "relative" !== position ? {
|
|
3701
|
+
top: formatGlassInsetValue(restStyle.top, 0),
|
|
3702
|
+
left: formatGlassInsetValue(restStyle.left, 0),
|
|
3703
|
+
right: formatGlassInsetValue(restStyle.right, "auto"),
|
|
3704
|
+
bottom: formatGlassInsetValue(restStyle.bottom, "auto")
|
|
3705
|
+
} : {
|
|
3706
|
+
top: "0px",
|
|
3707
|
+
left: "0px",
|
|
3708
|
+
right: "auto",
|
|
3709
|
+
bottom: "auto"
|
|
3710
|
+
};
|
|
3711
|
+
}(isFixedOrSticky, restStyle);
|
|
3933
3712
|
return {
|
|
3934
3713
|
...void 0 !== customZIndex && {
|
|
3935
3714
|
"--atomix-glass-base-z-index": customZIndex
|
|
3936
3715
|
},
|
|
3937
3716
|
"--atomix-glass-radius": `${effectiveBorderRadius}px`,
|
|
3938
3717
|
"--atomix-glass-transform": transformStyle || "none",
|
|
3939
|
-
"--atomix-glass-container-position":
|
|
3940
|
-
"--atomix-glass-position":
|
|
3941
|
-
"--atomix-glass-top":
|
|
3942
|
-
"--atomix-glass-left":
|
|
3943
|
-
"--atomix-glass-right":
|
|
3944
|
-
"--atomix-glass-bottom":
|
|
3718
|
+
"--atomix-glass-container-position": layerPosition,
|
|
3719
|
+
"--atomix-glass-position": layerPosition,
|
|
3720
|
+
"--atomix-glass-top": layerInsets.top,
|
|
3721
|
+
"--atomix-glass-left": layerInsets.left,
|
|
3722
|
+
"--atomix-glass-right": layerInsets.right,
|
|
3723
|
+
"--atomix-glass-bottom": layerInsets.bottom,
|
|
3945
3724
|
"--atomix-glass-width": adjustedSize.width,
|
|
3946
3725
|
"--atomix-glass-height": adjustedSize.height,
|
|
3947
|
-
|
|
3948
|
-
"--atomix-glass-
|
|
3949
|
-
"--atomix-glass-
|
|
3950
|
-
|
|
3951
|
-
"--atomix-glass-
|
|
3952
|
-
"--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}%)`,
|
|
3953
|
-
"--atomix-glass-hover-2-opacity": opacityValues.hover2,
|
|
3954
|
-
"--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}%)`,
|
|
3955
|
-
"--atomix-glass-hover-3-opacity": opacityValues.hover3,
|
|
3956
|
-
"--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}%)`,
|
|
3957
|
-
"--atomix-glass-base-opacity": opacityValues.base,
|
|
3958
|
-
"--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})`,
|
|
3959
|
-
"--atomix-glass-overlay-opacity": opacityValues.over,
|
|
3960
|
-
"--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})`,
|
|
3961
|
-
"--atomix-glass-overlay-highlight-opacity": opacityValues.over * ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER,
|
|
3962
|
-
"--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}%)`
|
|
3726
|
+
// Aliases maintained for backward compatibility and consumer overrides.
|
|
3727
|
+
"--atomix-glass-container-width": adjustedSize.width,
|
|
3728
|
+
"--atomix-glass-container-height": adjustedSize.height,
|
|
3729
|
+
[ATOMIX_GLASS.BORDER.WIDTH_CSS_VAR]: borderWidth,
|
|
3730
|
+
"--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay"
|
|
3963
3731
|
};
|
|
3964
|
-
}
|
|
3965
|
-
|
|
3732
|
+
}
|
|
3733
|
+
/**
|
|
3734
|
+
* Applies mode-specific multipliers and accessibility overrides to container effects.
|
|
3735
|
+
*/ ({
|
|
3736
|
+
effectiveBorderRadius: effectiveBorderRadius,
|
|
3737
|
+
transformStyle: transformStyle,
|
|
3738
|
+
adjustedSize: adjustedSize,
|
|
3739
|
+
isOverLight: isOverLight,
|
|
3740
|
+
customZIndex: customZIndex,
|
|
3741
|
+
isFixedOrSticky: isFixedOrSticky,
|
|
3742
|
+
positionStyles: positionStyles,
|
|
3743
|
+
restStyle: restStyle,
|
|
3744
|
+
borderWidth: resolvedBorder.width
|
|
3745
|
+
})), [ effectiveBorderRadius, transformStyle, adjustedSize, isOverLight, customZIndex, isFixedOrSticky, positionStyles, restStyle, resolvedBorder.width ]), containerEffects = useMemo((() => function(options) {
|
|
3746
|
+
const {MULTIPLIERS: MULTIPLIERS, SATURATION: SATURATION} = ATOMIX_GLASS.CONSTANTS, zeroMouse = {
|
|
3747
|
+
x: 0,
|
|
3748
|
+
y: 0
|
|
3749
|
+
}, resolveSaturation = () => options.effectiveHighContrast ? SATURATION.HIGH_CONTRAST : options.isOverLight ? options.saturation * options.saturationBoost : options.saturation;
|
|
3750
|
+
if (options.effectiveWithoutEffects) return {
|
|
3751
|
+
displacementScale: 0,
|
|
3752
|
+
blurAmount: 0,
|
|
3753
|
+
saturation: resolveSaturation(),
|
|
3754
|
+
aberrationIntensity: 0,
|
|
3755
|
+
mouseOffset: zeroMouse,
|
|
3756
|
+
globalMousePosition: zeroMouse
|
|
3757
|
+
};
|
|
3758
|
+
let resolvedDisplacement = options.displacementScale;
|
|
3759
|
+
"shader" === options.mode ? resolvedDisplacement *= MULTIPLIERS.SHADER_DISPLACEMENT : options.isOverLight && (resolvedDisplacement *= MULTIPLIERS.OVER_LIGHT_DISPLACEMENT);
|
|
3760
|
+
let resolvedAberration = options.aberrationIntensity;
|
|
3761
|
+
return "shader" === options.mode && (resolvedAberration *= MULTIPLIERS.SHADER_ABERRATION),
|
|
3762
|
+
{
|
|
3763
|
+
displacementScale: resolvedDisplacement,
|
|
3764
|
+
blurAmount: options.blurAmount,
|
|
3765
|
+
saturation: resolveSaturation(),
|
|
3766
|
+
aberrationIntensity: resolvedAberration,
|
|
3767
|
+
mouseOffset: options.mouseOffset,
|
|
3768
|
+
globalMousePosition: options.globalMousePosition
|
|
3769
|
+
};
|
|
3770
|
+
}({
|
|
3771
|
+
displacementScale: displacementScale,
|
|
3772
|
+
blurAmount: blurAmount,
|
|
3773
|
+
saturation: saturation,
|
|
3774
|
+
aberrationIntensity: aberrationIntensity,
|
|
3775
|
+
mode: mode,
|
|
3776
|
+
effectiveWithoutEffects: effectiveWithoutEffects,
|
|
3777
|
+
effectiveHighContrast: effectiveHighContrast,
|
|
3778
|
+
isOverLight: isOverLight,
|
|
3779
|
+
saturationBoost: overLightConfig.saturationBoost,
|
|
3780
|
+
mouseOffset: mouseOffset,
|
|
3781
|
+
globalMousePosition: globalMousePosition
|
|
3782
|
+
})), [ displacementScale, blurAmount, saturation, aberrationIntensity, mode, effectiveWithoutEffects, effectiveHighContrast, isOverLight, overLightConfig.saturationBoost, mouseOffset, globalMousePosition ]), renderBackgroundLayer = layerType => jsx("div", {
|
|
3783
|
+
"aria-hidden": "true",
|
|
3784
|
+
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)
|
|
3966
3785
|
});
|
|
3967
|
-
|
|
3968
|
-
// When root is fixed/sticky, internal layers use absolute (relative to root)
|
|
3969
|
-
return jsxs("div", {
|
|
3786
|
+
return jsxs("div", {
|
|
3970
3787
|
...rest,
|
|
3971
3788
|
ref: mergedRef,
|
|
3972
3789
|
className: componentClassName,
|
|
3973
|
-
style:
|
|
3974
|
-
...glassVars
|
|
3975
|
-
},
|
|
3790
|
+
style: glassVars,
|
|
3976
3791
|
role: role || (onClick ? "button" : void 0),
|
|
3977
3792
|
tabIndex: onClick ? tabIndex ?? 0 : tabIndex,
|
|
3978
3793
|
"aria-label": ariaLabel,
|
|
3979
3794
|
"aria-describedby": ariaDescribedBy,
|
|
3980
3795
|
"aria-disabled": !(!onClick || !effectiveWithoutEffects) || !onClick && void 0,
|
|
3981
|
-
"aria-pressed": onClick ? isActive : void 0,
|
|
3982
3796
|
onKeyDown: onClick ? handleKeyDown : void 0,
|
|
3983
3797
|
children: [ jsx(AtomixGlassContainer, {
|
|
3984
3798
|
ref: glassRef,
|
|
3985
3799
|
contentRef: contentRef,
|
|
3986
3800
|
className: className,
|
|
3987
|
-
style:
|
|
3988
|
-
...restStyle
|
|
3989
|
-
},
|
|
3801
|
+
style: containerStyle,
|
|
3990
3802
|
borderRadius: effectiveBorderRadius,
|
|
3991
|
-
displacementScale:
|
|
3992
|
-
blurAmount:
|
|
3993
|
-
saturation:
|
|
3994
|
-
aberrationIntensity:
|
|
3803
|
+
displacementScale: containerEffects.displacementScale,
|
|
3804
|
+
blurAmount: containerEffects.blurAmount,
|
|
3805
|
+
saturation: containerEffects.saturation,
|
|
3806
|
+
aberrationIntensity: containerEffects.aberrationIntensity,
|
|
3995
3807
|
glassSize: glassSize,
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
x: 0,
|
|
3999
|
-
y: 0
|
|
4000
|
-
} : mouseOffset,
|
|
4001
|
-
globalMousePosition: effectiveWithoutEffects ? {
|
|
4002
|
-
x: 0,
|
|
4003
|
-
y: 0
|
|
4004
|
-
} : globalMousePosition,
|
|
3808
|
+
mouseOffset: containerEffects.mouseOffset,
|
|
3809
|
+
globalMousePosition: containerEffects.globalMousePosition,
|
|
4005
3810
|
onMouseEnter: handleMouseEnter,
|
|
4006
3811
|
onMouseLeave: handleMouseLeave,
|
|
4007
3812
|
onMouseDown: handleMouseDown,
|
|
4008
3813
|
onMouseUp: handleMouseUp,
|
|
4009
|
-
isHovered: isHovered,
|
|
4010
3814
|
isActive: isActive,
|
|
4011
3815
|
overLight: isOverLight,
|
|
4012
3816
|
overLightConfig: {
|
|
@@ -4022,8 +3826,6 @@ const PERFORMANCE_PRESET = {
|
|
|
4022
3826
|
shaderVariant: shaderVariant,
|
|
4023
3827
|
withLiquidBlur: withLiquidBlur,
|
|
4024
3828
|
isFixedOrSticky: isFixedOrSticky,
|
|
4025
|
-
// Phase 1: Animation System props
|
|
4026
|
-
shaderTime: getShaderTime(),
|
|
4027
3829
|
withTimeAnimation: withTimeAnimation,
|
|
4028
3830
|
animationSpeed: animationSpeed,
|
|
4029
3831
|
withMultiLayerDistortion: withMultiLayerDistortion,
|
|
@@ -4034,32 +3836,39 @@ const PERFORMANCE_PRESET = {
|
|
|
4034
3836
|
children: children
|
|
4035
3837
|
}), Boolean(onClick) && jsxs(Fragment, {
|
|
4036
3838
|
children: [ jsx("div", {
|
|
3839
|
+
"aria-hidden": "true",
|
|
4037
3840
|
className: ATOMIX_GLASS.HOVER_1_CLASS
|
|
4038
3841
|
}), jsx("div", {
|
|
3842
|
+
"aria-hidden": "true",
|
|
4039
3843
|
className: ATOMIX_GLASS.HOVER_2_CLASS
|
|
4040
3844
|
}), jsx("div", {
|
|
3845
|
+
"aria-hidden": "true",
|
|
4041
3846
|
className: ATOMIX_GLASS.HOVER_3_CLASS
|
|
4042
3847
|
}) ]
|
|
4043
|
-
}),
|
|
3848
|
+
}), [ "dark", "black" ].map((layerType => jsx(React.Fragment, {
|
|
3849
|
+
children: renderBackgroundLayer(layerType)
|
|
3850
|
+
}, layerType))), shouldRenderOverLightLayers && jsxs(Fragment, {
|
|
4044
3851
|
children: [ jsx("div", {
|
|
3852
|
+
"aria-hidden": "true",
|
|
4045
3853
|
className: ATOMIX_GLASS.BASE_LAYER_CLASS
|
|
4046
3854
|
}), jsx("div", {
|
|
3855
|
+
"aria-hidden": "true",
|
|
4047
3856
|
className: ATOMIX_GLASS.OVERLAY_LAYER_CLASS
|
|
4048
3857
|
}), jsx("div", {
|
|
3858
|
+
"aria-hidden": "true",
|
|
4049
3859
|
className: ATOMIX_GLASS.OVERLAY_HIGHLIGHT_CLASS
|
|
4050
3860
|
}) ]
|
|
4051
|
-
}),
|
|
3861
|
+
}), resolvedBorder.enabled && jsxs(Fragment, {
|
|
4052
3862
|
children: [ jsx("span", {
|
|
3863
|
+
"aria-hidden": "true",
|
|
4053
3864
|
className: ATOMIX_GLASS.BORDER_BACKDROP_CLASS
|
|
4054
3865
|
}), jsx("span", {
|
|
3866
|
+
"aria-hidden": "true",
|
|
4055
3867
|
className: ATOMIX_GLASS.BORDER_1_CLASS
|
|
4056
3868
|
}), jsx("span", {
|
|
3869
|
+
"aria-hidden": "true",
|
|
4057
3870
|
className: ATOMIX_GLASS.BORDER_2_CLASS
|
|
4058
3871
|
}) ]
|
|
4059
|
-
}), debugPerformance && performanceMetrics && jsx(PerformanceDashboard, {
|
|
4060
|
-
metrics: performanceMetrics,
|
|
4061
|
-
isVisible: !0,
|
|
4062
|
-
onClose: () => {}
|
|
4063
3872
|
}) ]
|
|
4064
3873
|
});
|
|
4065
3874
|
}));
|
|
@@ -4069,10 +3878,7 @@ const PERFORMANCE_PRESET = {
|
|
|
4069
3878
|
* Default preset for most mobile devices
|
|
4070
3879
|
*/ AtomixGlassInner.displayName = "AtomixGlass";
|
|
4071
3880
|
|
|
4072
|
-
/**
|
|
4073
|
-
* AtomixGlass - wrapped with React.memo to prevent unnecessary re-renders.
|
|
4074
|
-
* Ref is forwarded to the root `<div>` element.
|
|
4075
|
-
*/
|
|
3881
|
+
/** Memoized public export. Ref targets the root `.c-atomix-glass` wrapper. */
|
|
4076
3882
|
const AtomixGlass = memo(AtomixGlassInner), ChartContext = createContext(null), Chart = memo( forwardRef((({children: children, type: type = "line", size: size = "md", variant: variant = "primary", title: title, subtitle: subtitle, loading: loading = !1, error: error, className: className = "", "aria-label": ariaLabel, onFullscreen: onFullscreen, onExport: onExport, onRefresh: onRefresh, showToolbar: showToolbar = !1, enableFullscreen: enableFullscreen = !1, enableExport: enableExport = !1, enableRefresh: enableRefresh = !1, exportFormats: exportFormats = [ "png", "svg", "csv" ], datasets: datasets, config: config,
|
|
4077
3883
|
// Destructure non-DOM props to prevent passing to DOM element
|
|
4078
3884
|
toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, customToolbarGroups: customToolbarGroups, data: data, showLegend: showLegend, interactive: interactive, fullscreen: fullscreen, onDataPointClick: onDataPointClick, onLegendItemClick: onLegendItemClick, glass: glass, ...props}, ref) => {
|
|
@@ -7388,40 +7194,15 @@ WaterfallChart.displayName = "WaterfallChart";
|
|
|
7388
7194
|
|
|
7389
7195
|
// Adapted from https://github.com/shuding/liquid-glass
|
|
7390
7196
|
// Constants
|
|
7391
|
-
const
|
|
7392
|
-
// Add input validation
|
|
7393
|
-
if ("number" != typeof a || "number" != typeof b || "number" != typeof t) return 0;
|
|
7394
|
-
const clamped = Math.max(0, Math.min(1, (t - a) / (b - a)));
|
|
7395
|
-
return clamped * clamped * (3 - 2 * clamped);
|
|
7396
|
-
}, calculateLength = (x, y) => {
|
|
7397
|
-
// Add input validation and error handling
|
|
7398
|
-
if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
|
|
7399
|
-
// Prevent potential overflow
|
|
7400
|
-
const maxX = Math.max(Math.abs(x), Math.abs(y));
|
|
7401
|
-
if (0 === maxX) return 0;
|
|
7402
|
-
const scaledX = x / maxX, scaledY = y / maxX;
|
|
7403
|
-
return maxX * Math.sqrt(scaledX * scaledX + scaledY * scaledY);
|
|
7404
|
-
}, roundedRectSDF = (x, y, width, height, radius) => {
|
|
7197
|
+
const roundedRectSDF = (x, y, width, height, radius) => {
|
|
7405
7198
|
// Add input validation
|
|
7406
7199
|
if ("number" != typeof x || "number" != typeof y || "number" != typeof width || "number" != typeof height || "number" != typeof radius) return 0;
|
|
7407
7200
|
const qx = Math.abs(x) - width + radius, qy = Math.abs(y) - height + radius;
|
|
7408
|
-
return Math.min(Math.max(qx, qy), 0) +
|
|
7201
|
+
return Math.min(Math.max(qx, qy), 0) + vec2Length(Math.max(qx, 0), Math.max(qy, 0)) - radius;
|
|
7409
7202
|
}, createTexture = (x, y) => ({
|
|
7410
7203
|
x: "number" != typeof x || isNaN(x) ? .5 : Math.max(0, Math.min(1, x)),
|
|
7411
7204
|
y: "number" != typeof y || isNaN(y) ? .5 : Math.max(0, Math.min(1, y))
|
|
7412
|
-
}), validateVec2 = vec => vec && "number" == typeof vec.x && "number" == typeof vec.y && !isNaN(vec.x) && !isNaN(vec.y),
|
|
7413
|
-
// Add input validation
|
|
7414
|
-
"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 => {
|
|
7415
|
-
// Add input validation
|
|
7416
|
-
if ("number" != typeof t || isNaN(t)) return 0;
|
|
7417
|
-
const clampedT = Math.max(0, Math.min(1, t));
|
|
7418
|
-
return clampedT < .5 ? 4 * clampedT * clampedT * clampedT : 1 - Math.pow(-2 * clampedT + 2, 3) / 2;
|
|
7419
|
-
}, easeOutQuart = t => {
|
|
7420
|
-
// Add input validation
|
|
7421
|
-
if ("number" != typeof t || isNaN(t)) return 0;
|
|
7422
|
-
const clampedT = Math.max(0, Math.min(1, t));
|
|
7423
|
-
return 1 - Math.pow(1 - clampedT, 4);
|
|
7424
|
-
}, noise2D = (x, y) => {
|
|
7205
|
+
}), validateVec2 = vec => vec && "number" == typeof vec.x && "number" == typeof vec.y && !isNaN(vec.x) && !isNaN(vec.y), noise2D = (x, y) => {
|
|
7425
7206
|
// Add input validation
|
|
7426
7207
|
if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
|
|
7427
7208
|
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) => {
|
|
@@ -7460,13 +7241,13 @@ const smoothStep = (a, b, t) => {
|
|
|
7460
7241
|
x: .5,
|
|
7461
7242
|
y: .5
|
|
7462
7243
|
};
|
|
7463
|
-
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 =
|
|
7244
|
+
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) => {
|
|
7464
7245
|
// Add input validation
|
|
7465
7246
|
if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y) || isNaN(strength)) return {
|
|
7466
7247
|
x: 0,
|
|
7467
7248
|
y: 0
|
|
7468
7249
|
};
|
|
7469
|
-
const distance =
|
|
7250
|
+
const distance = vec2Length(x, y), distortion = Math.pow(Math.min(distance, 10), 2) * strength;
|
|
7470
7251
|
// Limit distance to prevent extreme values
|
|
7471
7252
|
return {
|
|
7472
7253
|
x: x * (1 + distortion),
|
|
@@ -7478,7 +7259,7 @@ const smoothStep = (a, b, t) => {
|
|
|
7478
7259
|
x: 0,
|
|
7479
7260
|
y: 0
|
|
7480
7261
|
};
|
|
7481
|
-
const distance =
|
|
7262
|
+
const distance = vec2Length(x, y);
|
|
7482
7263
|
// Prevent division by zero and extreme values
|
|
7483
7264
|
if (0 === distance) return {
|
|
7484
7265
|
x: 0,
|
|
@@ -7489,8 +7270,8 @@ const smoothStep = (a, b, t) => {
|
|
|
7489
7270
|
x: Math.cos(angle) * distance * intensity,
|
|
7490
7271
|
y: Math.sin(angle) * distance * intensity
|
|
7491
7272
|
};
|
|
7492
|
-
})(ix, iy, .015 * baseDisplacement), scaled =
|
|
7493
|
-
return createTexture(
|
|
7273
|
+
})(ix, iy, .015 * baseDisplacement), scaled = smoothstepEdge(0, 1, 1.15 * baseDisplacement), finalX = ix + totalDistortionX + .5 * chromaticOffset.x, finalY = iy + totalDistortionY + .5 * chromaticOffset.y;
|
|
7274
|
+
return createTexture(clamp(finalX * scaled + .5, 0, 1), clamp(finalY * scaled + .5, 0, 1));
|
|
7494
7275
|
},
|
|
7495
7276
|
// Premium Apple-style fluid glass with enhanced organic flow
|
|
7496
7277
|
appleFluid: (uv, mousePosition) => {
|
|
@@ -7498,8 +7279,8 @@ const smoothStep = (a, b, t) => {
|
|
|
7498
7279
|
x: .5,
|
|
7499
7280
|
y: .5
|
|
7500
7281
|
};
|
|
7501
|
-
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 =
|
|
7502
|
-
return createTexture(
|
|
7282
|
+
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;
|
|
7283
|
+
return createTexture(clamp(ix + (.035 * organicX + fluidVelocityX + vortexX) * mask + .5, 0, 1), clamp(totalY + .5, 0, 1));
|
|
7503
7284
|
},
|
|
7504
7285
|
// High-end glass with advanced refraction and depth
|
|
7505
7286
|
premiumGlass: (uv, mousePosition) => {
|
|
@@ -7507,7 +7288,7 @@ const smoothStep = (a, b, t) => {
|
|
|
7507
7288
|
x: .5,
|
|
7508
7289
|
y: .5
|
|
7509
7290
|
};
|
|
7510
|
-
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 =
|
|
7291
|
+
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);
|
|
7511
7292
|
// Multi-layer depth effect
|
|
7512
7293
|
let depthX = 0, depthY = 0;
|
|
7513
7294
|
for (let layer = 0; layer < 3; layer++) {
|
|
@@ -7515,8 +7296,8 @@ const smoothStep = (a, b, t) => {
|
|
|
7515
7296
|
depthX += Math.sin(ix * layerScale + layerTime) * layerStrength, depthY += Math.cos(iy * layerScale - layerTime) * layerStrength;
|
|
7516
7297
|
}
|
|
7517
7298
|
// Glass refraction with mouse influence
|
|
7518
|
-
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 =
|
|
7519
|
-
return createTexture(
|
|
7299
|
+
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;
|
|
7300
|
+
return createTexture(clamp(ix + (refractionX + depthX + .015 * organicNoise) * edgeMask + .5, 0, 1), clamp(finalY + .5, 0, 1));
|
|
7520
7301
|
},
|
|
7521
7302
|
// Metallic liquid effect with shimmer
|
|
7522
7303
|
liquidMetal: (uv, mousePosition) => {
|
|
@@ -7524,8 +7305,8 @@ const smoothStep = (a, b, t) => {
|
|
|
7524
7305
|
x: .5,
|
|
7525
7306
|
y: .5
|
|
7526
7307
|
};
|
|
7527
|
-
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 =
|
|
7528
|
-
return createTexture(
|
|
7308
|
+
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;
|
|
7309
|
+
return createTexture(clamp(totalX + .5, 0, 1), clamp(totalY + .5, 0, 1));
|
|
7529
7310
|
},
|
|
7530
7311
|
// basiBasi - Expert Premium Glass Shader
|
|
7531
7312
|
// The most advanced shader with caustics, spectral dispersion, parallax depth, and volumetric effects
|
|
@@ -7534,7 +7315,7 @@ const smoothStep = (a, b, t) => {
|
|
|
7534
7315
|
x: .5,
|
|
7535
7316
|
y: .5
|
|
7536
7317
|
};
|
|
7537
|
-
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 =
|
|
7318
|
+
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) =>
|
|
7538
7319
|
// Add input validation
|
|
7539
7320
|
"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) => {
|
|
7540
7321
|
// Add input validation
|
|
@@ -7552,7 +7333,7 @@ const smoothStep = (a, b, t) => {
|
|
|
7552
7333
|
y: 0
|
|
7553
7334
|
}
|
|
7554
7335
|
};
|
|
7555
|
-
const distance =
|
|
7336
|
+
const distance = vec2Length(x, y), dispersionStrength = Math.min(.025 * distance, 1), redOffset = .8 * dispersionStrength, greenOffset = 1 * dispersionStrength, blueOffset = 1.2 * dispersionStrength;
|
|
7556
7337
|
return {
|
|
7557
7338
|
r: {
|
|
7558
7339
|
x: Math.cos(angle) * redOffset,
|
|
@@ -7592,8 +7373,8 @@ const smoothStep = (a, b, t) => {
|
|
|
7592
7373
|
return turbulence;
|
|
7593
7374
|
})(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) =>
|
|
7594
7375
|
// Add input validation
|
|
7595
|
-
"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 =
|
|
7596
|
-
return createTexture(
|
|
7376
|
+
"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;
|
|
7377
|
+
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));
|
|
7597
7378
|
},
|
|
7598
7379
|
// Aliases for compatibility
|
|
7599
7380
|
plasma: (uv, mousePosition) => fragmentShaders.premiumGlass(uv, mousePosition),
|
|
@@ -7635,8 +7416,8 @@ const smoothStep = (a, b, t) => {
|
|
|
7635
7416
|
let dx = pos.x * w - x, dy = pos.y * h - y;
|
|
7636
7417
|
// Apply edge smoothing for Apple-like effect
|
|
7637
7418
|
const edgeX = 2 * Math.min(x / w, (w - x) / w), edgeY = 2 * Math.min(y / h, (h - y) / h), edgeFactor = Math.min(edgeX, edgeY);
|
|
7638
|
-
dx *=
|
|
7639
|
-
rawValues.push(dx, dy);
|
|
7419
|
+
dx *= smoothstepEdge(0, .2, edgeFactor), dy *= smoothstepEdge(0, .2, edgeFactor),
|
|
7420
|
+
maxScale = Math.max(maxScale, Math.abs(dx), Math.abs(dy)), rawValues.push(dx, dy);
|
|
7640
7421
|
}
|
|
7641
7422
|
// Improved normalization to prevent artifacts while maintaining intensity
|
|
7642
7423
|
maxScale = Math.max(maxScale, 1);
|
|
@@ -7646,9 +7427,9 @@ const smoothStep = (a, b, t) => {
|
|
|
7646
7427
|
let rawIndex = 0;
|
|
7647
7428
|
for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) {
|
|
7648
7429
|
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);
|
|
7649
|
-
data[pixelIndex] =
|
|
7650
|
-
data[pixelIndex + 1] =
|
|
7651
|
-
data[pixelIndex + 2] =
|
|
7430
|
+
data[pixelIndex] = clamp(255 * r, 0, 255), // Red channel (X displacement)
|
|
7431
|
+
data[pixelIndex + 1] = clamp(255 * g, 0, 255), // Green channel (Y displacement)
|
|
7432
|
+
data[pixelIndex + 2] = clamp(255 * g, 0, 255), // Blue channel (Y displacement for SVG filter compatibility)
|
|
7652
7433
|
data[pixelIndex + 3] = 255;
|
|
7653
7434
|
}
|
|
7654
7435
|
return this.context.putImageData(imageData, 0, 0), this.canvas.toDataURL();
|
|
@@ -7676,9 +7457,7 @@ const smoothStep = (a, b, t) => {
|
|
|
7676
7457
|
return this.canvasDPI;
|
|
7677
7458
|
}
|
|
7678
7459
|
},
|
|
7679
|
-
|
|
7680
|
-
fragmentShaders: fragmentShaders,
|
|
7681
|
-
liquidGlassWithTime: liquidGlassWithTime
|
|
7460
|
+
fragmentShaders: fragmentShaders
|
|
7682
7461
|
}, Symbol.toStringTag, {
|
|
7683
7462
|
value: "Module"
|
|
7684
7463
|
}));
|