+ }
transition={{ type: "tween", ease: "backOut", duration: 0.5 }}
>
;
export default meta;
@@ -17,5 +22,6 @@ type Story = StoryObj;
export const Primary: Story = {
args: {
text: "ANIMATA",
+ direction: "up",
},
};
diff --git a/animata/text/mirror-text.tsx b/animata/text/mirror-text.tsx
index 68708e38..9bdeba2c 100644
--- a/animata/text/mirror-text.tsx
+++ b/animata/text/mirror-text.tsx
@@ -16,11 +16,11 @@ export default function MirrorText({
containerClassName?: string;
}) {
- const animation = cn("transition-all duration-500 ease-slow", {
- "group-hover:-translate-y-4": direction === "up",
- "group-hover:translate-y-4": direction === "down",
- "group-hover:-translate-x-4": direction === "left",
- "group-hover:translate-x-4": direction === "right",
+ const animation = cn("transition duration-500 ease-slow", {
+ "group-hover/mirror:-translate-y-4": direction === "up",
+ "group-hover/mirror:translate-y-4": direction === "down",
+ "group-hover/mirror:-translate-x-4": direction === "left",
+ "group-hover/mirror:translate-x-4": direction === "right",
});
const content = (
@@ -32,7 +32,7 @@ export default function MirrorText({
return (
diff --git a/animata/text/scroll-reveal.stories.tsx b/animata/text/scroll-reveal.stories.tsx
index c67300ba..a70517cc 100644
--- a/animata/text/scroll-reveal.stories.tsx
+++ b/animata/text/scroll-reveal.stories.tsx
@@ -1,7 +1,6 @@
+import type { Meta, StoryObj } from "@storybook/react";
import { Baby, File } from "lucide-react";
-
import ScrollReveal from "@/animata/text/scroll-reveal";
-import { Meta, StoryObj } from "@storybook/react";
const meta = {
title: "Text/Scroll Reveal",
@@ -22,9 +21,9 @@ export const Primary: Story = {
children: (
<>
This component reveals its children{" "}
-
as
- you scroll down the page{" "}
-
+
as you
+ scroll down the page{" "}
+
.
It uses a sticky container with a fixed height and a large space at the bottom. Finally, it
diff --git a/animata/text/scroll-reveal.tsx b/animata/text/scroll-reveal.tsx
index 94106577..f07d5a57 100644
--- a/animata/text/scroll-reveal.tsx
+++ b/animata/text/scroll-reveal.tsx
@@ -1,5 +1,5 @@
-import React, { useRef } from "react";
-import { motion, MotionValue, useScroll, useTransform } from "framer-motion";
+import { type MotionValue, motion, useMotionValue, useTransform } from "motion/react";
+import React, { useCallback, useEffect, useRef } from "react";
import { cn } from "@/lib/utils";
@@ -15,9 +15,10 @@ const flatten = (children: React.ReactNode): React.ReactNode[] => {
React.Children.forEach(children, (child) => {
if (React.isValidElement(child)) {
+ const childProps = child.props as Record
;
if (child.type === React.Fragment) {
- result.push(...flatten(child.props.children));
- } else if (child.props.children) {
+ result.push(...flatten(childProps.children as React.ReactNode));
+ } else if (childProps.children) {
result.push(React.cloneElement(child, {}));
} else {
result.push(child);
@@ -48,7 +49,7 @@ function OpacityChild({
let className = "";
if (React.isValidElement(children)) {
- className = Reflect.get(children, "props")?.className;
+ className = (Reflect.get(children, "props") as Record)?.className as string;
}
return (
@@ -62,10 +63,22 @@ export default function ScrollReveal({ children, className, ...props }: ScrollRe
const flat = flatten(children);
const count = flat.length;
const containerRef = useRef(null);
+ const scrollYProgress = useMotionValue(0);
- const { scrollYProgress } = useScroll({
- container: containerRef,
- });
+ const handleScroll = useCallback(() => {
+ const el = containerRef.current;
+ if (!el) return;
+ const { scrollTop, scrollHeight, clientHeight } = el;
+ const maxScroll = scrollHeight - clientHeight;
+ scrollYProgress.set(maxScroll > 0 ? scrollTop / maxScroll : 0);
+ }, [scrollYProgress]);
+
+ useEffect(() => {
+ const el = containerRef.current;
+ if (!el) return;
+ el.addEventListener("scroll", handleScroll, { passive: true });
+ return () => el.removeEventListener("scroll", handleScroll);
+ }, [handleScroll]);
return (
diff --git a/animata/text/split-text.stories.tsx b/animata/text/split-text.stories.tsx
index f9fa0f60..5a8f4ffc 100644
--- a/animata/text/split-text.stories.tsx
+++ b/animata/text/split-text.stories.tsx
@@ -1,5 +1,5 @@
+import type { Meta, StoryObj } from "@storybook/react";
import SplitText from "@/animata/text/split-text";
-import { Meta, StoryObj } from "@storybook/react";
const meta = {
title: "Text/Split Text",
diff --git a/animata/text/split-text.tsx b/animata/text/split-text.tsx
index 03aa4723..d8707766 100644
--- a/animata/text/split-text.tsx
+++ b/animata/text/split-text.tsx
@@ -10,10 +10,10 @@ export default function SplitText({
className?: string;
}) {
const [activeIndex, setIndex] = useState
();
- const timer = useRef();
+ const timer = useRef(undefined);
const letterClassName =
- "inline h-1/2 select-none overflow-y-hidden leading-none transition-all duration-300 ease-out whitespace-pre";
+ "inline h-1/2 select-none overflow-y-hidden leading-none transition duration-300 ease-out whitespace-pre";
return (
;
export default meta;
type Story = StoryObj
;
export const Primary: Story = {
- args: {},
+ args: {
+ text: "Animata",
+ delay: 0.09,
+ applyMask: true,
+ direction: "drop",
+ },
};
diff --git a/animata/text/staggered-letter.tsx b/animata/text/staggered-letter.tsx
index 29fc2c04..b6dcf4b9 100644
--- a/animata/text/staggered-letter.tsx
+++ b/animata/text/staggered-letter.tsx
@@ -1,5 +1,5 @@
-import { HTMLAttributes } from "react";
-import { motion } from "framer-motion";
+import { motion } from "motion/react";
+import type { HTMLAttributes } from "react";
import { cn } from "@/lib/utils";
diff --git a/animata/text/swap-text.stories.tsx b/animata/text/swap-text.stories.tsx
index 7381ef94..1b1caf00 100644
--- a/animata/text/swap-text.stories.tsx
+++ b/animata/text/swap-text.stories.tsx
@@ -1,5 +1,5 @@
+import type { Meta, StoryObj } from "@storybook/react";
import SwapText from "@/animata/text/swap-text";
-import { Meta, StoryObj } from "@storybook/react";
const meta = {
title: "Text/Swap Text",
@@ -19,6 +19,7 @@ export const Primary: Story = {
initialText: "Open",
finalText: "Close",
supportsHover: true,
+ disableClick: false,
},
};
diff --git a/animata/text/swap-text.tsx b/animata/text/swap-text.tsx
index 404c7343..dd5decf9 100644
--- a/animata/text/swap-text.tsx
+++ b/animata/text/swap-text.tsx
@@ -52,21 +52,21 @@ export default function SwapText({
...props
}: SwapTextProps) {
const [active, setActive] = useState(false);
- const common = "block transition-all duration-1000 ease-slow";
+ const common = "block transition duration-1000 ease-slow";
const longWord = finalText.length > initialText.length ? finalText : null;
return (
!disableClick && setActive((current) => !current)}
>
{initialText}
@@ -78,7 +78,7 @@ export default function SwapText({
{finalText}
diff --git a/animata/text/text-border-animation.stories.tsx b/animata/text/text-border-animation.stories.tsx
index 6960d14c..3d0062fa 100644
--- a/animata/text/text-border-animation.stories.tsx
+++ b/animata/text/text-border-animation.stories.tsx
@@ -1,5 +1,5 @@
+import type { Meta, StoryObj } from "@storybook/react";
import TextBorderAnimation from "@/animata/text/text-border-animation";
-import { Meta, StoryObj } from "@storybook/react";
const meta = {
title: "Text/Text Border Animation",
diff --git a/animata/text/text-border-animation.tsx b/animata/text/text-border-animation.tsx
index 33a8a675..50d530e8 100644
--- a/animata/text/text-border-animation.tsx
+++ b/animata/text/text-border-animation.tsx
@@ -12,7 +12,7 @@ interface TextProps {
className?: string;
}
-
+
export default function TextBorderAnimation({ text = "Programming", className }: TextProps) {
const [isHoveredIn, setIsHoveredIn] = useState(false);
const [isHoveredOut, setIsHoveredOut] = useState(false);
diff --git a/animata/text/text-explode-imessage.stories.tsx b/animata/text/text-explode-imessage.stories.tsx
index dd8a8417..73b8a5f1 100644
--- a/animata/text/text-explode-imessage.stories.tsx
+++ b/animata/text/text-explode-imessage.stories.tsx
@@ -1,5 +1,5 @@
+import type { Meta, StoryObj } from "@storybook/react";
import TextExplodeIMessage from "@/animata/text/text-explode-imessage";
-import { Meta, StoryObj } from "@storybook/react";
const meta = {
title: "Text/Text Explode Imessage",
@@ -8,7 +8,12 @@ const meta = {
layout: "centered",
},
tags: ["autodocs"],
- argTypes: {},
+ argTypes: {
+ mode: {
+ control: { type: "select" },
+ options: ["loop", "hover"],
+ },
+ },
} satisfies Meta;
export default meta;
@@ -17,6 +22,7 @@ type Story = StoryObj;
export const Primary: Story = {
args: {
text: "iMessage text explode effect 🧨 🔥 🎃 🎉 🪅",
+ mode: "loop",
className: "text-red-500",
},
};
diff --git a/animata/text/text-explode-imessage.tsx b/animata/text/text-explode-imessage.tsx
index 45fdfbd4..c3ee448f 100644
--- a/animata/text/text-explode-imessage.tsx
+++ b/animata/text/text-explode-imessage.tsx
@@ -1,5 +1,5 @@
+import { motion, useAnimationControls, type Variants } from "motion/react";
import { useCallback, useEffect, useRef } from "react";
-import { motion, useAnimationControls, Variants } from "framer-motion";
import { cn } from "@/lib/utils";
diff --git a/animata/text/text-flip.stories.tsx b/animata/text/text-flip.stories.tsx
index 43353b30..710a64ca 100644
--- a/animata/text/text-flip.stories.tsx
+++ b/animata/text/text-flip.stories.tsx
@@ -1,5 +1,5 @@
+import type { Meta, StoryObj } from "@storybook/react";
import TextFlip from "@/animata/text/text-flip";
-import { Meta, StoryObj } from "@storybook/react";
const meta = {
title: "Text/Text Flip",
diff --git a/animata/text/ticker.stories.tsx b/animata/text/ticker.stories.tsx
index df614229..5ee4cf98 100644
--- a/animata/text/ticker.stories.tsx
+++ b/animata/text/ticker.stories.tsx
@@ -1,5 +1,5 @@
+import type { Meta, StoryObj } from "@storybook/react";
import Ticker from "@/animata/text/ticker";
-import { Meta, StoryObj } from "@storybook/react";
const meta = {
title: "Text/Ticker",
@@ -17,6 +17,7 @@ type Story = StoryObj;
export const Primary: Story = {
args: {
value: "456.78",
+ delay: 0,
className: "text-4xl md:text-7xl font-black",
},
};
diff --git a/animata/text/ticker.tsx b/animata/text/ticker.tsx
index 9c5025d2..d179bf74 100644
--- a/animata/text/ticker.tsx
+++ b/animata/text/ticker.tsx
@@ -1,7 +1,7 @@
"use client";
+import { motion, useMotionValue, useSpring } from "motion/react";
import { useCallback, useEffect, useRef } from "react";
-import { motion, useMotionValue, useSpring } from "framer-motion";
import { cn } from "@/lib/utils";
diff --git a/animata/text/typing-text.stories.tsx b/animata/text/typing-text.stories.tsx
index 319febf7..0a100f1c 100644
--- a/animata/text/typing-text.stories.tsx
+++ b/animata/text/typing-text.stories.tsx
@@ -1,5 +1,5 @@
+import type { Meta, StoryObj } from "@storybook/react";
import TypingText from "@/animata/text/typing-text";
-import { Meta, StoryObj } from "@storybook/react";
const meta = {
title: "Text/Typing Text",
@@ -17,7 +17,13 @@ type Story = StoryObj;
export const Primary: Story = {
args: {
text: "> yarn add @animata/awesomeness",
+ delay: 32,
+ repeat: true,
grow: false,
+ alwaysVisibleCount: 1,
+ smooth: false,
+ waitTime: 1000,
+ hideCursorOnComplete: false,
},
render: (props) => (
diff --git a/animata/text/typing-text.tsx b/animata/text/typing-text.tsx
index e8ee54d8..40d79571 100644
--- a/animata/text/typing-text.tsx
+++ b/animata/text/typing-text.tsx
@@ -1,4 +1,4 @@
-import { ReactNode, useEffect, useMemo, useState } from "react";
+import { type ReactNode, useEffect, useMemo, useState } from "react";
import { cn } from "@/lib/utils";
diff --git a/animata/text/underline-hover-text.stories.tsx b/animata/text/underline-hover-text.stories.tsx
index 0d163c16..e1ac132a 100644
--- a/animata/text/underline-hover-text.stories.tsx
+++ b/animata/text/underline-hover-text.stories.tsx
@@ -1,5 +1,7 @@
-import UnderlineHoverText, { UnderlineHoverTextProps } from "@/animata/text/underline-hover-text";
-import { Meta, StoryFn } from "@storybook/react";
+import type { Meta, StoryFn } from "@storybook/react";
+import UnderlineHoverText, {
+ type UnderlineHoverTextProps,
+} from "@/animata/text/underline-hover-text";
export default {
title: "text/Underline hover text",
@@ -18,7 +20,12 @@ export default {
const Template: StoryFn
= (args) => ;
-export const Default = Template.bind({});
-Default.args = {
+export const Primary = Template.bind({});
+Primary.args = {
text: "Hover over me",
+ textColor: "text-yellow-600",
+ hoverTextColor: "hover:text-white",
+ hoverColor: "hover:after:bg-indigo-500",
+ fontSize: "text-2xl",
+ fontWeight: "font-medium",
};
diff --git a/animata/text/underline-hover-text.tsx b/animata/text/underline-hover-text.tsx
index e26a6821..586aa28f 100644
--- a/animata/text/underline-hover-text.tsx
+++ b/animata/text/underline-hover-text.tsx
@@ -1,5 +1,5 @@
"use client";
-import React from "react";
+import type React from "react";
import { cn } from "@/lib/utils";
diff --git a/animata/text/wave-reveal.stories.tsx b/animata/text/wave-reveal.stories.tsx
index 3498e24e..7fe71692 100644
--- a/animata/text/wave-reveal.stories.tsx
+++ b/animata/text/wave-reveal.stories.tsx
@@ -1,5 +1,5 @@
+import type { Meta, StoryObj } from "@storybook/react";
import WaveReveal from "@/animata/text/wave-reveal";
-import { Meta, StoryObj } from "@storybook/react";
const meta = {
title: "Text/Wave Reveal",
@@ -8,7 +8,16 @@ const meta = {
layout: "centered",
},
tags: ["autodocs"],
- argTypes: {},
+ argTypes: {
+ direction: {
+ control: { type: "select" },
+ options: ["up", "down"],
+ },
+ mode: {
+ control: { type: "select" },
+ options: ["letter", "word"],
+ },
+ },
} satisfies Meta;
export default meta;
@@ -17,6 +26,11 @@ type Story = StoryObj;
export const Primary: Story = {
args: {
text: "Hello World",
+ direction: "down",
+ mode: "letter",
+ duration: "2000ms",
+ delay: 0,
+ blur: true,
className: "text-foreground",
},
};
diff --git a/animata/text/wave-reveal.tsx b/animata/text/wave-reveal.tsx
index 74030b36..7997572c 100644
--- a/animata/text/wave-reveal.tsx
+++ b/animata/text/wave-reveal.tsx
@@ -1,4 +1,4 @@
-import { ReactNode } from "react";
+import type { ReactNode } from "react";
import { cn } from "@/lib/utils";
@@ -107,7 +107,7 @@ const createDelay = ({
}: Pick & {
index: number;
}) => {
- return delay + (index + offset) * 50 + "ms";
+ return `${delay + (index + offset) * 50}ms`;
};
const createAnimatedNodes = (args: ReducedValue, word: string, index: number): ReducedValue => {
@@ -119,13 +119,13 @@ const createAnimatedNodes = (args: ReducedValue, word: string, index: number): R
const isLast = index === length - 1;
const className = cn(
- "inline-block opacity-0 transition-all ease-in-out fill-mode-forwards",
+ "inline-block opacity-0 transition ease-in-out fill-mode-forwards",
{
// Determine the animation direction
- ["animate-[reveal-down]"]: !isUp && !blur,
- ["animate-[reveal-up]"]: isUp && !blur,
- ["animate-[reveal-down,content-blur]"]: !isUp && blur,
- ["animate-[reveal-up,content-blur]"]: isUp && blur,
+ "animate-[reveal-down]": !isUp && !blur,
+ "animate-[reveal-up]": isUp && !blur,
+ "animate-[reveal-down,content-blur]": !isUp && blur,
+ "animate-[reveal-up,content-blur]": isUp && blur,
},
args.className,
);
diff --git a/animata/widget/alarm-clock.stories.tsx b/animata/widget/alarm-clock.stories.tsx
index 34f4a6cb..04420394 100644
--- a/animata/widget/alarm-clock.stories.tsx
+++ b/animata/widget/alarm-clock.stories.tsx
@@ -1,5 +1,5 @@
+import type { Meta, StoryObj } from "@storybook/react";
import AlarmClock from "@/animata/widget/alarm-clock";
-import { Meta, StoryObj } from "@storybook/react";
const meta = {
title: "Widget/Alarm Clock",
diff --git a/animata/widget/alarm-clock.tsx b/animata/widget/alarm-clock.tsx
index 5e5c68f7..9593bfd8 100644
--- a/animata/widget/alarm-clock.tsx
+++ b/animata/widget/alarm-clock.tsx
@@ -1,7 +1,7 @@
"use client";
-import { useState } from "react";
import { AlarmClockIcon } from "lucide-react";
+import { useState } from "react";
import ToggleSwitch from "@/animata/button/toggle-switch";
import { cn } from "@/lib/utils";
diff --git a/animata/widget/battery-level.stories.tsx b/animata/widget/battery-level.stories.tsx
index 89bacd9b..2f08bc0a 100644
--- a/animata/widget/battery-level.stories.tsx
+++ b/animata/widget/battery-level.stories.tsx
@@ -1,5 +1,5 @@
+import type { Meta, StoryObj } from "@storybook/react";
import BatteryLevel from "@/animata/widget/battery-level";
-import { Meta, StoryObj } from "@storybook/react";
const meta = {
title: "Widget/Battery Level",
diff --git a/animata/widget/battery.stories.tsx b/animata/widget/battery.stories.tsx
index 19d75565..9f5e084b 100644
--- a/animata/widget/battery.stories.tsx
+++ b/animata/widget/battery.stories.tsx
@@ -1,5 +1,5 @@
+import type { Meta, StoryObj } from "@storybook/react";
import Battery from "@/animata/widget/battery";
-import { Meta, StoryObj } from "@storybook/react";
const meta = {
title: "Widget/Battery",
diff --git a/animata/widget/battery.tsx b/animata/widget/battery.tsx
index 0cff3fe5..fae1f70e 100644
--- a/animata/widget/battery.tsx
+++ b/animata/widget/battery.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useEffect, useRef } from "react";
import { BatteryMediumIcon } from "lucide-react";
+import { useEffect, useRef } from "react";
import { cn } from "@/lib/utils";
@@ -19,7 +19,7 @@ const Battery = () => {
}, [gap]);
return (
-
+