fancy-ui-react 0.3.0 → 0.4.0
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/README.md +52 -19
- package/dist/components/animated-beam/AnimatedBeam.d.ts +47 -11
- package/dist/components/animated-beam/AnimatedBeam.js +293 -118
- package/dist/components/animated-tooltip/AnimatedTooltip.d.ts +10 -1
- package/dist/components/animated-tooltip/AnimatedTooltip.js +170 -101
- package/dist/components/bento-grid/BentoFrame.d.ts +16 -0
- package/dist/components/bento-grid/BentoFrame.js +28 -0
- package/dist/components/bento-grid/BentoGrid.d.ts +5 -1
- package/dist/components/bento-grid/BentoGrid.js +71 -2
- package/dist/components/bento-grid/BentoGridCard.js +34 -26
- package/dist/components/bento-grid/BentoGridItem.js +10 -10
- package/dist/components/border-beam/BorderBeam.d.ts +55 -10
- package/dist/components/border-beam/BorderBeam.js +93 -16
- package/dist/components/compare/Compare.d.ts +32 -8
- package/dist/components/compare/Compare.js +213 -95
- package/dist/components/container-scroll/ContainerScroll.d.ts +26 -4
- package/dist/components/container-scroll/ContainerScroll.js +88 -49
- package/dist/components/dock/Dock.d.ts +10 -7
- package/dist/components/dock/Dock.js +76 -31
- package/dist/components/dock/DockIcon.d.ts +14 -3
- package/dist/components/dock/DockIcon.js +23 -19
- package/dist/components/dock/DockSeparator.d.ts +4 -1
- package/dist/components/dock/DockSeparator.js +5 -2
- package/dist/components/dock/types.d.ts +13 -6
- package/dist/components/dropdown-menu/menu-shared.d.ts +11 -8
- package/dist/components/editorial-engine/engine.js +1 -14
- package/dist/components/fireworks-hdr/webgl2-renderer.js +0 -19
- package/dist/components/fireworks-hdr/webgpu-renderer.js +3 -22
- package/dist/components/flip-card/FlipCard.d.ts +42 -1
- package/dist/components/flip-card/FlipCard.js +178 -25
- package/dist/components/flip-card/index.d.ts +1 -1
- package/dist/components/fluid-cursor/FluidCursor.js +5 -4
- package/dist/components/fluid-cursor/dev.d.ts +1 -0
- package/dist/components/fluid-cursor/dev.js +8 -0
- package/dist/components/fluid-cursor/fluid-shared.d.ts +0 -2
- package/dist/components/fluid-cursor/fluid-shared.js +0 -2
- package/dist/components/fluid-cursor/webgpu-engine.js +10 -24
- package/dist/components/glow-border/GlowBorder.d.ts +41 -1
- package/dist/components/glow-border/GlowBorder.js +96 -16
- package/dist/components/glow-border/index.d.ts +2 -2
- package/dist/components/gradient-button/GradientButton.d.ts +10 -5
- package/dist/components/gradient-button/GradientButton.js +25 -18
- package/dist/components/image-trail-cursor/ImageTrailCursor.js +1 -0
- package/dist/components/image-trail-cursor/trail-variants.d.ts +37 -1
- package/dist/components/image-trail-cursor/trail-variants.js +331 -8
- package/dist/components/interactive-hover-button/InteractiveHoverButton.js +30 -35
- package/dist/components/marquee/Marquee.d.ts +7 -3
- package/dist/components/marquee/Marquee.js +134 -2
- package/dist/components/marquee/ReviewCard.d.ts +2 -1
- package/dist/components/marquee/ReviewCard.js +20 -9
- package/dist/components/meteors/Meteors.d.ts +32 -10
- package/dist/components/meteors/Meteors.js +53 -20
- package/dist/components/mosaic-glow/mosaic-glow-core.d.ts +98 -10
- package/dist/components/neon-border/NeonBorder.d.ts +24 -5
- package/dist/components/neon-border/NeonBorder.js +37 -7
- package/dist/components/pagination/Pagination.js +220 -82
- package/dist/components/rainbow-button/RainbowButton.js +13 -5
- package/dist/components/ripple-button/RippleButton.d.ts +20 -1
- package/dist/components/ripple-button/RippleButton.js +44 -21
- package/dist/components/shimmer-button/ShimmerButton.d.ts +5 -5
- package/dist/components/shimmer-button/ShimmerButton.js +17 -19
- package/dist/components/smooth-cursor/SmoothCursor.d.ts +13 -9
- package/dist/components/smooth-cursor/SmoothCursor.js +114 -163
- package/dist/components/smooth-cursor/smooth-cursor-core.d.ts +85 -0
- package/dist/components/smooth-cursor/smooth-cursor-core.js +327 -0
- package/dist/components/stepper/Step.js +32 -19
- package/dist/components/stepper/Stepper.js +18 -2
- package/dist/components/stepper/types.d.ts +13 -0
- package/dist/components/timeline/Timeline.d.ts +8 -1
- package/dist/components/timeline/Timeline.js +165 -76
- package/dist/index.js +2 -1
- package/dist/internals/markdown.d.ts +5 -0
- package/dist/internals/motion/haptics.d.ts +0 -4
- package/dist/internals/motion/presence-core.d.ts +59 -0
- package/dist/internals/motion/presence-core.js +162 -0
- package/dist/internals/motion/presence.d.ts +2 -4
- package/dist/internals/motion/presence.js +1 -156
- package/dist/internals/motion/raf.d.ts +1 -1
- package/dist/internals/motion/stagger.d.ts +3 -4
- package/dist/internals/motion/tokens.js +4 -0
- package/dist/internals/motion/transitions.d.ts +17 -17
- package/dist/internals/motion/types.d.ts +6 -7
- package/dist/internals/relative-time.d.ts +1 -1
- package/dist/styles.css +3470 -203
- package/package.json +18 -2
- package/dist/components/fireworks-hdr/webgpu-types.d.ts +0 -159
|
@@ -37,12 +37,12 @@ class ImageItem {
|
|
|
37
37
|
el: null,
|
|
38
38
|
inner: null
|
|
39
39
|
};
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
40
|
+
// `private`, not `public`: the animation library declares `TweenVars` inside a
|
|
41
|
+
// GLOBAL namespace with no module-level export, so a public `gsap.TweenVars`
|
|
42
|
+
// member emits a bare `gsap.` reference into the shipped .d.ts while tsc drops
|
|
43
|
+
// the value-only `import { gsap }` — deep-importing consumers then hit TS2503
|
|
44
|
+
// "Cannot find namespace 'gsap'". A private member emits no type at all, and it
|
|
45
|
+
// is read only by initEvents() below, so nothing outside this class loses access.
|
|
46
46
|
defaultStyle = { scale: 1, x: 0, y: 0, opacity: 0 };
|
|
47
47
|
rect = null;
|
|
48
48
|
resizeHandler = null;
|
|
@@ -164,7 +164,8 @@ class BaseVariant {
|
|
|
164
164
|
const now = performance.now();
|
|
165
165
|
this.positionHistory.push({ x, y, t: now });
|
|
166
166
|
const cutoff = now - BaseVariant.HISTORY_MAX_AGE;
|
|
167
|
-
while (this.positionHistory.length > BaseVariant.HISTORY_MAX_LEN ||
|
|
167
|
+
while (this.positionHistory.length > BaseVariant.HISTORY_MAX_LEN || // Non-null: `length > 1` on this same clause proves index 0 exists.
|
|
168
|
+
this.positionHistory.length > 1 && this.positionHistory[0].t < cutoff) {
|
|
168
169
|
this.positionHistory.shift();
|
|
169
170
|
}
|
|
170
171
|
}
|
|
@@ -203,6 +204,11 @@ class BaseVariant {
|
|
|
203
204
|
this.cacheMousePos.x = lerp(this.cacheMousePos.x, this.mousePos.x, 0.1);
|
|
204
205
|
this.cacheMousePos.y = lerp(this.cacheMousePos.y, this.mousePos.y, 0.1);
|
|
205
206
|
}
|
|
207
|
+
/** Advance to the next image in the ring. */
|
|
208
|
+
nextImage() {
|
|
209
|
+
this.imgPosition = this.imgPosition < this.imagesTotal - 1 ? this.imgPosition + 1 : 0;
|
|
210
|
+
return this.images[this.imgPosition];
|
|
211
|
+
}
|
|
206
212
|
onImageActivated() {
|
|
207
213
|
this.activeImagesCount++;
|
|
208
214
|
this.isIdle = false;
|
|
@@ -761,6 +767,308 @@ class ImageTrailVariantPixelated extends BaseVariant {
|
|
|
761
767
|
).set(img.DOM.el, { opacity: 0, scale: 0.2 }, ImageTrailVariantPixelated.HOLD);
|
|
762
768
|
}
|
|
763
769
|
}
|
|
770
|
+
function randomBetween(min, max) {
|
|
771
|
+
return min + Math.random() * (max - min);
|
|
772
|
+
}
|
|
773
|
+
class ImageTrailVariantScale extends BaseVariant {
|
|
774
|
+
showNextImage() {
|
|
775
|
+
++this.zIndexVal;
|
|
776
|
+
const img = this.nextImage();
|
|
777
|
+
if (!img) return;
|
|
778
|
+
const w = img.rect?.width ?? 0;
|
|
779
|
+
const h = img.rect?.height ?? 0;
|
|
780
|
+
gsap.killTweensOf(img.DOM.el);
|
|
781
|
+
gsap.timeline({
|
|
782
|
+
onStart: () => this.onImageActivated(),
|
|
783
|
+
onComplete: () => this.onImageDeactivated()
|
|
784
|
+
}).set(img.DOM.el, {
|
|
785
|
+
opacity: 1,
|
|
786
|
+
scale: 0,
|
|
787
|
+
rotation: randomBetween(-20, 20),
|
|
788
|
+
zIndex: this.zIndexVal,
|
|
789
|
+
x: this.mousePos.x - w / 2,
|
|
790
|
+
y: this.mousePos.y - h / 2
|
|
791
|
+
}).to(img.DOM.el, { scale: 1, duration: 0.6, ease: "back.out(2)" }, 0).to(img.DOM.el, { scale: 0, duration: 0.6, ease: "power2.in" }, 0.75).set(img.DOM.el, { opacity: 0 });
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
class ImageTrailVariantFall extends BaseVariant {
|
|
795
|
+
showNextImage() {
|
|
796
|
+
++this.zIndexVal;
|
|
797
|
+
const img = this.nextImage();
|
|
798
|
+
if (!img) return;
|
|
799
|
+
const w = img.rect?.width ?? 0;
|
|
800
|
+
const h = img.rect?.height ?? 0;
|
|
801
|
+
const floor = this.container.getBoundingClientRect().height;
|
|
802
|
+
gsap.killTweensOf(img.DOM.el);
|
|
803
|
+
gsap.timeline({
|
|
804
|
+
onStart: () => this.onImageActivated(),
|
|
805
|
+
onComplete: () => this.onImageDeactivated()
|
|
806
|
+
}).set(img.DOM.el, {
|
|
807
|
+
opacity: 1,
|
|
808
|
+
scale: 0,
|
|
809
|
+
rotation: 0,
|
|
810
|
+
zIndex: this.zIndexVal,
|
|
811
|
+
x: this.mousePos.x - w / 2,
|
|
812
|
+
y: this.mousePos.y - h / 2
|
|
813
|
+
}).to(img.DOM.el, { scale: 1, duration: 0.8, ease: "elastic.out(1, 0.3)" }, 0).to(img.DOM.el, { rotation: randomBetween(-360, 360), duration: 1.1, ease: "power1.out" }, 0).to(img.DOM.el, { y: floor * 1.2 + h, duration: 1, ease: "back.in(0.4)" }, 0).set(img.DOM.el, { opacity: 0 });
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
class ImageTrailVariantGravity extends BaseVariant {
|
|
817
|
+
showNextImage() {
|
|
818
|
+
++this.zIndexVal;
|
|
819
|
+
const img = this.nextImage();
|
|
820
|
+
if (!img) return;
|
|
821
|
+
const w = img.rect?.width ?? 0;
|
|
822
|
+
const h = img.rect?.height ?? 0;
|
|
823
|
+
const height = this.container.getBoundingClientRect().height;
|
|
824
|
+
const startY = this.mousePos.y - h / 2;
|
|
825
|
+
const floorY = Math.max(startY, height - h);
|
|
826
|
+
const drop = floorY - startY;
|
|
827
|
+
const push = Math.max(-140, Math.min(140, (this.mousePos.x - this.lastMousePos.x) * 1.4));
|
|
828
|
+
const fall = 0.3 + 0.35 * Math.sqrt(drop / Math.max(1, height));
|
|
829
|
+
const bounce = drop * 0.32;
|
|
830
|
+
gsap.killTweensOf(img.DOM.el);
|
|
831
|
+
const el = img.DOM.el;
|
|
832
|
+
gsap.timeline({
|
|
833
|
+
onStart: () => this.onImageActivated(),
|
|
834
|
+
onComplete: () => this.onImageDeactivated()
|
|
835
|
+
}).set(el, {
|
|
836
|
+
opacity: 1,
|
|
837
|
+
scale: 0,
|
|
838
|
+
rotation: randomBetween(-10, 10),
|
|
839
|
+
zIndex: this.zIndexVal,
|
|
840
|
+
x: this.mousePos.x - w / 2,
|
|
841
|
+
y: startY
|
|
842
|
+
}).to(el, { scale: 1, duration: 0.4, ease: "elastic.out(2, 0.6)" }, 0).to(
|
|
843
|
+
el,
|
|
844
|
+
{
|
|
845
|
+
x: `+=${push}`,
|
|
846
|
+
rotation: randomBetween(-30, 30),
|
|
847
|
+
duration: fall + 0.9,
|
|
848
|
+
ease: "power1.out"
|
|
849
|
+
},
|
|
850
|
+
0.1
|
|
851
|
+
).to(el, { y: floorY, duration: fall, ease: "power2.in" }, 0.15).to(el, { y: floorY - bounce, duration: 0.28, ease: "power2.out" }).to(el, { y: floorY, duration: 0.28, ease: "power2.in" }).to(el, { y: floorY - bounce * 0.3, duration: 0.16, ease: "power2.out" }).to(el, { y: floorY, duration: 0.16, ease: "power2.in" }).to(el, { opacity: 0, scale: 0.7, duration: 0.3, ease: "power2.in" }, "+=0.15");
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
class ImageTrailVariantFlame extends BaseVariant {
|
|
855
|
+
showNextImage() {
|
|
856
|
+
++this.zIndexVal;
|
|
857
|
+
const img = this.nextImage();
|
|
858
|
+
if (!img) return;
|
|
859
|
+
const w = img.rect?.width ?? 0;
|
|
860
|
+
const h = img.rect?.height ?? 0;
|
|
861
|
+
const { dx, dy } = this.getTouchVelocity();
|
|
862
|
+
const speed = Math.min(1, Math.hypot(dx, dy) / 160);
|
|
863
|
+
const rotation = (Math.random() - 0.5) * 30 * (1 + speed * 2);
|
|
864
|
+
gsap.killTweensOf(img.DOM.el);
|
|
865
|
+
gsap.timeline({
|
|
866
|
+
onStart: () => this.onImageActivated(),
|
|
867
|
+
onComplete: () => this.onImageDeactivated()
|
|
868
|
+
}).set(img.DOM.el, {
|
|
869
|
+
opacity: 1,
|
|
870
|
+
scale: 0,
|
|
871
|
+
rotation,
|
|
872
|
+
zIndex: this.zIndexVal,
|
|
873
|
+
x: this.mousePos.x - w / 2,
|
|
874
|
+
y: this.mousePos.y - h / 2
|
|
875
|
+
}).to(img.DOM.el, { scale: 1, duration: 0.35, ease: "back.out(1.6)" }, 0).to(
|
|
876
|
+
img.DOM.el,
|
|
877
|
+
{
|
|
878
|
+
y: `-=${40 + speed * 40}`,
|
|
879
|
+
scale: 0,
|
|
880
|
+
opacity: 0,
|
|
881
|
+
rotation: rotation * 1.6,
|
|
882
|
+
duration: 0.55,
|
|
883
|
+
ease: "power2.in"
|
|
884
|
+
},
|
|
885
|
+
0.55
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
const SEAM = 0.6;
|
|
890
|
+
const lo = (n) => Math.max(0, n - SEAM);
|
|
891
|
+
const hi = (n) => Math.min(100, n + SEAM);
|
|
892
|
+
const pc = (n) => `${Math.round(n * 100) / 100}%`;
|
|
893
|
+
const poly = (pts) => `polygon(${pts.map(([x, y]) => `${pc(x)} ${pc(y)}`).join(", ")})`;
|
|
894
|
+
function revealFragments(pattern) {
|
|
895
|
+
switch (pattern) {
|
|
896
|
+
case "venetian": {
|
|
897
|
+
const n = 6;
|
|
898
|
+
return Array.from({ length: n }, (_, i) => {
|
|
899
|
+
const y0 = lo(i * 100 / n);
|
|
900
|
+
const y1 = hi((i + 1) * 100 / n);
|
|
901
|
+
return {
|
|
902
|
+
closed: poly([
|
|
903
|
+
[0, y0],
|
|
904
|
+
[100, y0],
|
|
905
|
+
[100, y0],
|
|
906
|
+
[0, y0]
|
|
907
|
+
]),
|
|
908
|
+
open: poly([
|
|
909
|
+
[0, y0],
|
|
910
|
+
[100, y0],
|
|
911
|
+
[100, y1],
|
|
912
|
+
[0, y1]
|
|
913
|
+
]),
|
|
914
|
+
order: i / (n - 1)
|
|
915
|
+
};
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
case "curtain": {
|
|
919
|
+
const n = 6;
|
|
920
|
+
const mid = (n - 1) / 2;
|
|
921
|
+
return Array.from({ length: n }, (_, i) => {
|
|
922
|
+
const x0 = lo(i * 100 / n);
|
|
923
|
+
const x1 = hi((i + 1) * 100 / n);
|
|
924
|
+
const cx = (x0 + x1) / 2;
|
|
925
|
+
return {
|
|
926
|
+
closed: poly([
|
|
927
|
+
[cx, 0],
|
|
928
|
+
[cx, 0],
|
|
929
|
+
[cx, 100],
|
|
930
|
+
[cx, 100]
|
|
931
|
+
]),
|
|
932
|
+
open: poly([
|
|
933
|
+
[x0, 0],
|
|
934
|
+
[x1, 0],
|
|
935
|
+
[x1, 100],
|
|
936
|
+
[x0, 100]
|
|
937
|
+
]),
|
|
938
|
+
order: Math.abs(i - mid) / mid
|
|
939
|
+
};
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
case "hexagon": {
|
|
943
|
+
const centres = [16.67, 50, 83.33];
|
|
944
|
+
const r = 31;
|
|
945
|
+
const cells = [];
|
|
946
|
+
for (const cy of centres) {
|
|
947
|
+
for (const cx of centres) {
|
|
948
|
+
const hex = Array.from({ length: 6 }, (_, k) => {
|
|
949
|
+
const a = Math.PI / 3 * k + Math.PI / 6;
|
|
950
|
+
return [cx + r * Math.cos(a), cy + r * Math.sin(a)];
|
|
951
|
+
});
|
|
952
|
+
cells.push({
|
|
953
|
+
closed: poly(hex.map(() => [cx, cy])),
|
|
954
|
+
open: poly(hex),
|
|
955
|
+
order: Math.hypot(cx - 50, cy - 50) / Math.hypot(33.33, 33.33)
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
return cells;
|
|
960
|
+
}
|
|
961
|
+
case "liquid": {
|
|
962
|
+
const blobs = [
|
|
963
|
+
[50, 50, 48],
|
|
964
|
+
[22, 26, 36],
|
|
965
|
+
[80, 24, 36],
|
|
966
|
+
[26, 80, 36],
|
|
967
|
+
[78, 78, 38]
|
|
968
|
+
];
|
|
969
|
+
return blobs.map(([x, y, r], i) => ({
|
|
970
|
+
closed: `circle(0% at ${pc(x)} ${pc(y)})`,
|
|
971
|
+
open: `circle(${pc(r)} at ${pc(x)} ${pc(y)})`,
|
|
972
|
+
order: i / (blobs.length - 1)
|
|
973
|
+
}));
|
|
974
|
+
}
|
|
975
|
+
case "zoom-split": {
|
|
976
|
+
const quads = [
|
|
977
|
+
[0, 0],
|
|
978
|
+
[50, 0],
|
|
979
|
+
[0, 50],
|
|
980
|
+
[50, 50]
|
|
981
|
+
];
|
|
982
|
+
return quads.map(([x, y], i) => ({
|
|
983
|
+
closed: poly([
|
|
984
|
+
[50, 50],
|
|
985
|
+
[50, 50],
|
|
986
|
+
[50, 50],
|
|
987
|
+
[50, 50]
|
|
988
|
+
]),
|
|
989
|
+
open: poly([
|
|
990
|
+
[lo(x), lo(y)],
|
|
991
|
+
[hi(x + 50), lo(y)],
|
|
992
|
+
[hi(x + 50), hi(y + 50)],
|
|
993
|
+
[lo(x), hi(y + 50)]
|
|
994
|
+
]),
|
|
995
|
+
order: i / 3
|
|
996
|
+
}));
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
const FRAG_CLASS = "content__img-frag";
|
|
1001
|
+
class ImageTrailVariantReveal extends BaseVariant {
|
|
1002
|
+
static STAGGER = 0.22;
|
|
1003
|
+
// seconds from first to last fragment
|
|
1004
|
+
fragments;
|
|
1005
|
+
constructor(container, pattern) {
|
|
1006
|
+
super(container);
|
|
1007
|
+
this.fragments = revealFragments(pattern);
|
|
1008
|
+
for (const img of this.images) {
|
|
1009
|
+
const bg = img.DOM.inner?.style.backgroundImage ?? "";
|
|
1010
|
+
for (const f of this.fragments) {
|
|
1011
|
+
const frag = document.createElement("div");
|
|
1012
|
+
frag.className = FRAG_CLASS;
|
|
1013
|
+
frag.style.cssText = `position:absolute;inset:0;background-image:${bg};background-size:cover;background-position:center;clip-path:${f.closed};`;
|
|
1014
|
+
img.DOM.el.appendChild(frag);
|
|
1015
|
+
}
|
|
1016
|
+
if (img.DOM.inner) img.DOM.inner.style.opacity = "0";
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
showNextImage() {
|
|
1020
|
+
++this.zIndexVal;
|
|
1021
|
+
const img = this.nextImage();
|
|
1022
|
+
if (!img) return;
|
|
1023
|
+
const w = img.rect?.width ?? 0;
|
|
1024
|
+
const h = img.rect?.height ?? 0;
|
|
1025
|
+
const frags = [...img.DOM.el.querySelectorAll(`.${FRAG_CLASS}`)];
|
|
1026
|
+
const stagger = ImageTrailVariantReveal.STAGGER;
|
|
1027
|
+
gsap.killTweensOf([img.DOM.el, ...frags]);
|
|
1028
|
+
const tl = gsap.timeline({
|
|
1029
|
+
onStart: () => this.onImageActivated(),
|
|
1030
|
+
onComplete: () => this.onImageDeactivated()
|
|
1031
|
+
}).set(img.DOM.el, {
|
|
1032
|
+
opacity: 1,
|
|
1033
|
+
scale: 0.85,
|
|
1034
|
+
rotation: 0,
|
|
1035
|
+
zIndex: this.zIndexVal,
|
|
1036
|
+
x: this.mousePos.x - w / 2,
|
|
1037
|
+
y: this.mousePos.y - h / 2
|
|
1038
|
+
}).to(img.DOM.el, { scale: 1, duration: 0.5, ease: "power3.out" }, 0);
|
|
1039
|
+
frags.forEach((frag, i) => {
|
|
1040
|
+
const f = this.fragments[i];
|
|
1041
|
+
tl.fromTo(
|
|
1042
|
+
frag,
|
|
1043
|
+
{ clipPath: f.closed },
|
|
1044
|
+
{ clipPath: f.open, duration: 0.45, ease: "power3.out" },
|
|
1045
|
+
f.order * stagger
|
|
1046
|
+
);
|
|
1047
|
+
tl.to(
|
|
1048
|
+
frag,
|
|
1049
|
+
{ clipPath: f.closed, duration: 0.35, ease: "power3.in" },
|
|
1050
|
+
0.95 + (1 - f.order) * stagger
|
|
1051
|
+
);
|
|
1052
|
+
});
|
|
1053
|
+
tl.set(img.DOM.el, { opacity: 0 });
|
|
1054
|
+
}
|
|
1055
|
+
destroy() {
|
|
1056
|
+
for (const img of this.images) {
|
|
1057
|
+
const frags = img.DOM.el.querySelectorAll(`.${FRAG_CLASS}`);
|
|
1058
|
+
gsap.killTweensOf([...frags]);
|
|
1059
|
+
frags.forEach((f) => f.remove());
|
|
1060
|
+
if (img.DOM.inner) img.DOM.inner.style.opacity = "";
|
|
1061
|
+
}
|
|
1062
|
+
super.destroy();
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
function revealVariant(pattern) {
|
|
1066
|
+
return class extends ImageTrailVariantReveal {
|
|
1067
|
+
constructor(container) {
|
|
1068
|
+
super(container, pattern);
|
|
1069
|
+
}
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
764
1072
|
const variantMap = {
|
|
765
1073
|
type1: ImageTrailVariant1,
|
|
766
1074
|
type2: ImageTrailVariant2,
|
|
@@ -770,7 +1078,16 @@ const variantMap = {
|
|
|
770
1078
|
type6: ImageTrailVariant6,
|
|
771
1079
|
type7: ImageTrailVariant7,
|
|
772
1080
|
type8: ImageTrailVariant8,
|
|
773
|
-
pixelated: ImageTrailVariantPixelated
|
|
1081
|
+
pixelated: ImageTrailVariantPixelated,
|
|
1082
|
+
scale: ImageTrailVariantScale,
|
|
1083
|
+
fall: ImageTrailVariantFall,
|
|
1084
|
+
gravity: ImageTrailVariantGravity,
|
|
1085
|
+
flame: ImageTrailVariantFlame,
|
|
1086
|
+
venetian: revealVariant("venetian"),
|
|
1087
|
+
curtain: revealVariant("curtain"),
|
|
1088
|
+
hexagon: revealVariant("hexagon"),
|
|
1089
|
+
liquid: revealVariant("liquid"),
|
|
1090
|
+
"zoom-split": revealVariant("zoom-split")
|
|
774
1091
|
};
|
|
775
1092
|
export {
|
|
776
1093
|
ImageItem,
|
|
@@ -782,6 +1099,12 @@ export {
|
|
|
782
1099
|
ImageTrailVariant6,
|
|
783
1100
|
ImageTrailVariant7,
|
|
784
1101
|
ImageTrailVariant8,
|
|
1102
|
+
ImageTrailVariantFall,
|
|
1103
|
+
ImageTrailVariantFlame,
|
|
1104
|
+
ImageTrailVariantGravity,
|
|
785
1105
|
ImageTrailVariantPixelated,
|
|
1106
|
+
ImageTrailVariantReveal,
|
|
1107
|
+
ImageTrailVariantScale,
|
|
1108
|
+
revealFragments,
|
|
786
1109
|
variantMap
|
|
787
1110
|
};
|
|
@@ -3,12 +3,13 @@ import { jsxs, jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { forwardRef } from "react";
|
|
4
4
|
import { cn } from "../../utils.js";
|
|
5
5
|
import { useSoundCue } from "../../sound/use-sound.js";
|
|
6
|
+
/* empty css */
|
|
6
7
|
const InteractiveHoverButton = forwardRef(
|
|
7
|
-
({ text = "Button", className, children, sound = false,
|
|
8
|
+
({ text = "Button", className, children, onClick, sound = false, ...restProps }, ref) => {
|
|
8
9
|
const label = children ?? text;
|
|
9
10
|
const playCue = useSoundCue(sound);
|
|
10
11
|
function handleClick(event) {
|
|
11
|
-
if (sound && !disabled) playCue("press");
|
|
12
|
+
if (sound && !restProps.disabled) playCue("press");
|
|
12
13
|
onClick?.(event);
|
|
13
14
|
}
|
|
14
15
|
return /* @__PURE__ */ jsxs(
|
|
@@ -16,45 +17,39 @@ const InteractiveHoverButton = forwardRef(
|
|
|
16
17
|
{
|
|
17
18
|
ref,
|
|
18
19
|
className: cn(
|
|
19
|
-
"group bg-background relative w-auto cursor-pointer overflow-hidden rounded-full border
|
|
20
|
+
"ihb group bg-background relative isolate w-auto cursor-pointer overflow-hidden rounded-full border px-6 py-2.5 text-center font-semibold",
|
|
20
21
|
className
|
|
21
22
|
),
|
|
22
23
|
onClick: handleClick,
|
|
23
|
-
disabled,
|
|
24
24
|
...restProps,
|
|
25
25
|
children: [
|
|
26
|
-
/* @__PURE__ */
|
|
27
|
-
|
|
28
|
-
/* @__PURE__ */ jsx("span", { className: "
|
|
26
|
+
/* @__PURE__ */ jsx("span", { className: "ihb-fill", "aria-hidden": "true" }),
|
|
27
|
+
/* @__PURE__ */ jsxs("span", { className: "ihb-rest", children: [
|
|
28
|
+
/* @__PURE__ */ jsx("span", { className: "ihb-dot-space", "aria-hidden": "true" }),
|
|
29
|
+
/* @__PURE__ */ jsx("span", { className: "ihb-label", children: label })
|
|
29
30
|
] }),
|
|
30
|
-
/* @__PURE__ */ jsxs(
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
]
|
|
53
|
-
}
|
|
54
|
-
)
|
|
55
|
-
]
|
|
56
|
-
}
|
|
57
|
-
)
|
|
31
|
+
/* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "ihb-hover", children: [
|
|
32
|
+
/* @__PURE__ */ jsx("span", { className: "ihb-hover-label", children: label }),
|
|
33
|
+
/* @__PURE__ */ jsxs(
|
|
34
|
+
"svg",
|
|
35
|
+
{
|
|
36
|
+
className: "ihb-arrow",
|
|
37
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
38
|
+
width: "18",
|
|
39
|
+
height: "18",
|
|
40
|
+
viewBox: "0 0 24 24",
|
|
41
|
+
fill: "none",
|
|
42
|
+
stroke: "currentColor",
|
|
43
|
+
strokeWidth: "2",
|
|
44
|
+
strokeLinecap: "round",
|
|
45
|
+
strokeLinejoin: "round",
|
|
46
|
+
children: [
|
|
47
|
+
/* @__PURE__ */ jsx("path", { d: "M5 12h14" }),
|
|
48
|
+
/* @__PURE__ */ jsx("path", { d: "m12 5 7 7-7 7" })
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
] })
|
|
58
53
|
]
|
|
59
54
|
}
|
|
60
55
|
);
|
|
@@ -4,13 +4,17 @@ export interface MarqueeProps {
|
|
|
4
4
|
className?: string;
|
|
5
5
|
/** Reverse the scroll direction */
|
|
6
6
|
reverse?: boolean;
|
|
7
|
-
/**
|
|
7
|
+
/** Ease the conveyor to a stop while the pointer (or focus) is inside */
|
|
8
8
|
pauseOnHover?: boolean;
|
|
9
9
|
/** Scroll vertically instead of horizontally */
|
|
10
10
|
vertical?: boolean;
|
|
11
|
-
/** Number of
|
|
11
|
+
/** Number of copies of the children rendered on the track */
|
|
12
12
|
repeat?: number;
|
|
13
|
+
/** Dissolve items at both edges with a gradient mask */
|
|
14
|
+
fade?: boolean;
|
|
15
|
+
/** Speed multiplier applied on top of `--duration` (2 = twice as fast) */
|
|
16
|
+
speed?: number;
|
|
13
17
|
/** Content to repeat and scroll */
|
|
14
18
|
children?: ReactNode;
|
|
15
19
|
}
|
|
16
|
-
export declare function Marquee({ className, reverse, pauseOnHover, vertical, repeat, children, }: MarqueeProps): import("react").JSX.Element;
|
|
20
|
+
export declare function Marquee({ className, reverse, pauseOnHover, vertical, repeat, fade, speed, children, }: MarqueeProps): import("react").JSX.Element;
|
|
@@ -1,26 +1,158 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useRef, useState, useEffect } from "react";
|
|
3
4
|
import { cn } from "../../utils.js";
|
|
5
|
+
import { useReducedMotion } from "../../internals/motion/media-query.js";
|
|
4
6
|
/* empty css */
|
|
7
|
+
const EASE_TAU = 140;
|
|
8
|
+
const SETTLE_EPSILON = 2e-3;
|
|
9
|
+
const DEFAULT_DURATION_MS = 4e4;
|
|
10
|
+
function parseDuration(raw) {
|
|
11
|
+
const match = /^\s*([\d.]+)\s*(ms|s)\s*$/i.exec(raw);
|
|
12
|
+
if (!match) return DEFAULT_DURATION_MS;
|
|
13
|
+
const value = Number.parseFloat(match[1] ?? "");
|
|
14
|
+
if (!Number.isFinite(value) || value <= 0) return DEFAULT_DURATION_MS;
|
|
15
|
+
return (match[2] ?? "s").toLowerCase() === "ms" ? value : value * 1e3;
|
|
16
|
+
}
|
|
17
|
+
function createConveyor() {
|
|
18
|
+
const c = {
|
|
19
|
+
speed: 1,
|
|
20
|
+
pauseOnHover: false,
|
|
21
|
+
engaged: false,
|
|
22
|
+
factor: 1,
|
|
23
|
+
animations: [],
|
|
24
|
+
rafId: 0,
|
|
25
|
+
lastTs: 0,
|
|
26
|
+
resumeAt: null,
|
|
27
|
+
applyRate() {
|
|
28
|
+
const rate = c.speed * c.factor;
|
|
29
|
+
for (const animation of c.animations) animation.playbackRate = rate;
|
|
30
|
+
},
|
|
31
|
+
wake() {
|
|
32
|
+
if (!c.animations.length || c.rafId) return;
|
|
33
|
+
c.lastTs = 0;
|
|
34
|
+
c.rafId = requestAnimationFrame(tick);
|
|
35
|
+
},
|
|
36
|
+
setEngaged(next) {
|
|
37
|
+
c.engaged = next && c.pauseOnHover;
|
|
38
|
+
c.wake();
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
function tick(ts) {
|
|
42
|
+
const dt = c.lastTs ? Math.min(ts - c.lastTs, 64) : 16;
|
|
43
|
+
c.lastTs = ts;
|
|
44
|
+
const target = c.engaged ? 0 : 1;
|
|
45
|
+
c.factor += (target - c.factor) * (1 - Math.exp(-dt / EASE_TAU));
|
|
46
|
+
if (Math.abs(target - c.factor) < SETTLE_EPSILON) c.factor = target;
|
|
47
|
+
c.applyRate();
|
|
48
|
+
if (c.factor === target) {
|
|
49
|
+
c.rafId = 0;
|
|
50
|
+
c.lastTs = 0;
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
c.rafId = requestAnimationFrame(tick);
|
|
54
|
+
}
|
|
55
|
+
return c;
|
|
56
|
+
}
|
|
5
57
|
function Marquee({
|
|
6
58
|
className,
|
|
7
59
|
reverse = false,
|
|
8
60
|
pauseOnHover = false,
|
|
9
61
|
vertical = false,
|
|
10
62
|
repeat = 4,
|
|
63
|
+
fade = true,
|
|
64
|
+
speed = 1,
|
|
11
65
|
children
|
|
12
66
|
}) {
|
|
67
|
+
const reduced = useReducedMotion();
|
|
68
|
+
const rootRef = useRef(null);
|
|
69
|
+
const [upgraded, setUpgraded] = useState(false);
|
|
70
|
+
const safeSpeed = Number.isFinite(speed) && speed > 0 ? speed : 1;
|
|
71
|
+
const conveyorRef = useRef(null);
|
|
72
|
+
if (!conveyorRef.current) conveyorRef.current = createConveyor();
|
|
73
|
+
const conveyor = conveyorRef.current;
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
conveyor.speed = safeSpeed;
|
|
76
|
+
conveyor.applyRate();
|
|
77
|
+
}, [conveyor, safeSpeed]);
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
conveyor.pauseOnHover = pauseOnHover;
|
|
80
|
+
if (!pauseOnHover && conveyor.engaged) conveyor.setEngaged(false);
|
|
81
|
+
}, [conveyor, pauseOnHover]);
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
const el = rootRef.current;
|
|
84
|
+
if (!el || reduced) return;
|
|
85
|
+
if (typeof Element === "undefined" || typeof Element.prototype.animate !== "function") return;
|
|
86
|
+
const styles = getComputedStyle(el);
|
|
87
|
+
const duration = parseDuration(styles.getPropertyValue("--duration"));
|
|
88
|
+
const gapPx = Number.parseFloat(vertical ? styles.rowGap : styles.columnGap) || 0;
|
|
89
|
+
const axis = vertical ? "translateY" : "translateX";
|
|
90
|
+
const keyframes = [
|
|
91
|
+
{ transform: `${axis}(0)` },
|
|
92
|
+
{ transform: `${axis}(calc(-100% - ${gapPx}px))` }
|
|
93
|
+
];
|
|
94
|
+
const tracks = Array.from(el.querySelectorAll(":scope > [data-marquee-track]"));
|
|
95
|
+
let startTime = 0;
|
|
96
|
+
if (conveyor.resumeAt !== null) {
|
|
97
|
+
startTime = (reverse ? 1 - conveyor.resumeAt : conveyor.resumeAt) * duration;
|
|
98
|
+
} else {
|
|
99
|
+
const running = tracks[0]?.getAnimations?.()[0];
|
|
100
|
+
if (running && typeof running.currentTime === "number") {
|
|
101
|
+
startTime = running.currentTime * conveyor.speed;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
conveyor.animations = tracks.map(
|
|
105
|
+
(track) => track.animate(keyframes, {
|
|
106
|
+
duration,
|
|
107
|
+
iterations: Infinity,
|
|
108
|
+
easing: "linear",
|
|
109
|
+
direction: reverse ? "reverse" : "normal"
|
|
110
|
+
})
|
|
111
|
+
).filter(Boolean);
|
|
112
|
+
for (const animation of conveyor.animations) animation.currentTime = startTime % duration;
|
|
113
|
+
conveyor.applyRate();
|
|
114
|
+
setUpgraded(true);
|
|
115
|
+
if (conveyor.factor !== (conveyor.engaged ? 0 : 1)) conveyor.wake();
|
|
116
|
+
return () => {
|
|
117
|
+
if (conveyor.rafId) cancelAnimationFrame(conveyor.rafId);
|
|
118
|
+
conveyor.rafId = 0;
|
|
119
|
+
const t = conveyor.animations[0]?.currentTime;
|
|
120
|
+
if (typeof t === "number") {
|
|
121
|
+
const progress = t % duration / duration;
|
|
122
|
+
conveyor.resumeAt = reverse ? 1 - progress : progress;
|
|
123
|
+
} else {
|
|
124
|
+
conveyor.resumeAt = null;
|
|
125
|
+
}
|
|
126
|
+
for (const animation of conveyor.animations) animation.cancel?.();
|
|
127
|
+
conveyor.animations = [];
|
|
128
|
+
setUpgraded(false);
|
|
129
|
+
};
|
|
130
|
+
}, [conveyor, vertical, reverse, repeat, className, reduced]);
|
|
131
|
+
function onFocusOut(event) {
|
|
132
|
+
if (!rootRef.current?.contains(event.relatedTarget)) conveyor.setEngaged(false);
|
|
133
|
+
}
|
|
13
134
|
return /* @__PURE__ */ jsx(
|
|
14
135
|
"div",
|
|
15
136
|
{
|
|
137
|
+
ref: rootRef,
|
|
16
138
|
className: cn(
|
|
17
|
-
"
|
|
18
|
-
vertical ? "flex-col" : "flex-row",
|
|
139
|
+
"marquee group flex [gap:var(--gap)] overflow-hidden p-2 [--duration:40s] [--gap:1rem]",
|
|
140
|
+
vertical ? "marquee-vertical flex-col" : "flex-row",
|
|
141
|
+
fade && "marquee-fade",
|
|
142
|
+
upgraded && "marquee-upgraded",
|
|
19
143
|
className
|
|
20
144
|
),
|
|
145
|
+
style: { "--marquee-speed": safeSpeed },
|
|
146
|
+
"data-paused-on-hover": pauseOnHover ? "" : void 0,
|
|
147
|
+
onPointerEnter: () => conveyor.setEngaged(true),
|
|
148
|
+
onPointerLeave: () => conveyor.setEngaged(false),
|
|
149
|
+
onFocus: () => conveyor.setEngaged(true),
|
|
150
|
+
onBlur: onFocusOut,
|
|
21
151
|
children: Array.from({ length: repeat }, (_, index) => /* @__PURE__ */ jsx(
|
|
22
152
|
"div",
|
|
23
153
|
{
|
|
154
|
+
"data-marquee-track": "",
|
|
155
|
+
"aria-hidden": index > 0 ? "true" : void 0,
|
|
24
156
|
className: cn(
|
|
25
157
|
"flex shrink-0 justify-around [gap:var(--gap)]",
|
|
26
158
|
vertical ? "animate-marquee-vertical flex-col" : "animate-marquee flex-row",
|
|
@@ -4,5 +4,6 @@ export interface ReviewCardProps {
|
|
|
4
4
|
username: string;
|
|
5
5
|
body: string;
|
|
6
6
|
}
|
|
7
|
-
/** A ready-made card for testimonial-style marquees
|
|
7
|
+
/** A ready-made card for testimonial-style marquees: a nested double frame,
|
|
8
|
+
* a hairline shell holding a hairline inner panel. */
|
|
8
9
|
export declare function ReviewCard({ img, name, username, body }: ReviewCardProps): import("react").JSX.Element;
|