diff --git a/app/docs/navigation.ts b/app/docs/navigation.ts index d9793f54..f1431118 100644 --- a/app/docs/navigation.ts +++ b/app/docs/navigation.ts @@ -104,6 +104,10 @@ export const NAVIGATION: NavigationGroup[] = [ name: 'Text Shimmer Wave', href: '/docs/text-shimmer-wave', }, + { + name: 'Text Highlight', + href: '/docs/text-highlight', + }, ], }, { diff --git a/app/docs/text-highlight/page.mdx b/app/docs/text-highlight/page.mdx new file mode 100644 index 00000000..42eefb51 --- /dev/null +++ b/app/docs/text-highlight/page.mdx @@ -0,0 +1,111 @@ +export const metadata = { + title: 'Text Highlight - Motion-Primitives', + description: + 'Animate a highlight effect on text with a background color. Built for React, Next.js, and Tailwind CSS.', +}; + +import { TextHighlightBasic } from './text-highlight-basic'; +import { TextHighlightDirection } from './text-highlight-direction'; +import { TextHighlightColor } from './text-highlight-color'; +import { TextHighlightSpeed } from './text-highlight-speed'; +import { TextHighlightAnimateOn } from './text-highlight-animate-on'; +import ComponentCodePreview from '@/components/website/component-code-preview'; + +# Text Highlight + +Animate a highlight effect on text with a background color. Customize the direction, color, speed, and trigger behavior. + +## Examples + +### Text Highlight Basic + +} + filePath='app/docs/text-highlight/text-highlight-basic.tsx' + hasReTrigger +/> + +### Direction + +Control the direction of the highlight animation. + +} + filePath='app/docs/text-highlight/text-highlight-direction.tsx' + hasReTrigger +/> + +### Custom Colors + +Customize the highlight color using Tailwind CSS classes. + +} + filePath='app/docs/text-highlight/text-highlight-color.tsx' + hasReTrigger +/> + +### Speed + +Control the animation speed. Higher values make the animation faster. + +} + filePath='app/docs/text-highlight/text-highlight-speed.tsx' + hasReTrigger +/> + +### Animate On + +Control when the highlight animation triggers: on mount, hover, or click. + +} + filePath='app/docs/text-highlight/text-highlight-animate-on.tsx' +/> + +## Installation + + + + + CLI + Manual + + + + + + + + + + + + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Component API + +### TextHighlight + +| Prop | Type | Default | Description | +| :------------- | :---------------------------- | :-------- | :--------------------------------------------------------------------------------------------------- | +| children | string | | The text content. | +| as | keyof JSX.IntrinsicElements | 'p' | The HTML tag to render, defaults to paragraph. | +| className | string | undefined | Optional CSS class for styling the component. | +| duration | number | undefined | The duration of the highlight animation in seconds. If not provided, speed is used. | +| speed | number | 1 | Animation speed multiplier. Higher values = faster animation. Used when duration is not provided. | +| highlightColor | string | undefined | Optional Tailwind CSS class for highlight color (e.g., 'bg-blue-300'). | +| direction | 'left' \| 'right' | 'right' | Direction of the highlight animation. 'right' = left to right, 'left' = right to left. | +| animateOn | 'click' \| 'hover' \| 'mount' | 'mount' | When to trigger the animation. 'mount' = on component mount, 'hover' = on hover, 'click' = on click. | diff --git a/app/docs/text-highlight/text-highlight-animate-on.tsx b/app/docs/text-highlight/text-highlight-animate-on.tsx new file mode 100644 index 00000000..046b2014 --- /dev/null +++ b/app/docs/text-highlight/text-highlight-animate-on.tsx @@ -0,0 +1,28 @@ +import { TextHighlight } from '@/components/core/text-highlight'; + +export function TextHighlightAnimateOn() { + return ( +
+
+

+ Hover to highlight: +

+ Hover over this text +
+
+

+ Click to toggle highlight: +

+ Click this text +
+
+

+ Auto highlight on mount: +

+ + This highlights automatically + +
+
+ ); +} diff --git a/app/docs/text-highlight/text-highlight-basic.tsx b/app/docs/text-highlight/text-highlight-basic.tsx new file mode 100644 index 00000000..02bf96b4 --- /dev/null +++ b/app/docs/text-highlight/text-highlight-basic.tsx @@ -0,0 +1,9 @@ +import { TextHighlight } from '@/components/core/text-highlight'; + +export function TextHighlightBasic() { + return ( + + Highlight this text with an animated background + + ); +} diff --git a/app/docs/text-highlight/text-highlight-color.tsx b/app/docs/text-highlight/text-highlight-color.tsx new file mode 100644 index 00000000..1acbf045 --- /dev/null +++ b/app/docs/text-highlight/text-highlight-color.tsx @@ -0,0 +1,23 @@ +import { TextHighlight } from '@/components/core/text-highlight'; + +export function TextHighlightColor() { + return ( +
+
+ + Blue highlight + +
+
+ + Green highlight + +
+
+ + Pink highlight + +
+
+ ); +} diff --git a/app/docs/text-highlight/text-highlight-direction.tsx b/app/docs/text-highlight/text-highlight-direction.tsx new file mode 100644 index 00000000..283ab70d --- /dev/null +++ b/app/docs/text-highlight/text-highlight-direction.tsx @@ -0,0 +1,18 @@ +import { TextHighlight } from '@/components/core/text-highlight'; + +export function TextHighlightDirection() { + return ( +
+
+ + Highlight from left to right + +
+
+ + Highlight from right to left + +
+
+ ); +} diff --git a/app/docs/text-highlight/text-highlight-speed.tsx b/app/docs/text-highlight/text-highlight-speed.tsx new file mode 100644 index 00000000..a3335cbd --- /dev/null +++ b/app/docs/text-highlight/text-highlight-speed.tsx @@ -0,0 +1,17 @@ +import { TextHighlight } from '@/components/core/text-highlight'; + +export function TextHighlightSpeed() { + return ( +
+
+ Slow highlight (speed: 0.5) +
+
+ Normal highlight (speed: 1) +
+
+ Fast highlight (speed: 2) +
+
+ ); +} diff --git a/components/core/text-highlight.tsx b/components/core/text-highlight.tsx new file mode 100644 index 00000000..39401e5c --- /dev/null +++ b/components/core/text-highlight.tsx @@ -0,0 +1,89 @@ +'use client'; +import React, { useState, type JSX } from 'react'; +import { motion } from 'motion/react'; +import { cn } from '@/lib/utils'; + +export type TextHighlightProps = { + children: string; + as?: React.ElementType; + className?: string; + duration?: number; + speed?: number; + highlightColor?: string; + direction?: 'left' | 'right'; + animateOn?: 'click' | 'hover' | 'mount'; +}; + +function TextHighlightComponent({ + children, + as: Component = 'p', + className, + duration, + speed = 1, + highlightColor, + direction = 'right', + animateOn = 'mount', +}: TextHighlightProps) { + const MotionComponent = motion.create( + Component as keyof JSX.IntrinsicElements + ) as typeof motion.div; + + const [isHighlighted, setIsHighlighted] = useState(animateOn === 'mount'); + + const defaultHighlightColor = 'bg-yellow-300 dark:bg-yellow-500'; + + // Calculate duration: if speed is provided, use it as a multiplier; otherwise use duration directly + const animationDuration = duration !== undefined ? duration : 1 / speed; + + const transformOrigin = direction === 'right' ? 'left' : 'right'; + const initialScaleX = direction === 'right' ? 0 : 0; + const animateScaleX = isHighlighted ? 1 : 0; + + const handleClick = () => { + if (animateOn === 'click') { + setIsHighlighted(!isHighlighted); + } + }; + + const handleMouseEnter = () => { + if (animateOn === 'hover') { + setIsHighlighted(true); + } + }; + + const handleMouseLeave = () => { + if (animateOn === 'hover') { + setIsHighlighted(false); + } + }; + + const cursorStyle = animateOn === 'click' ? 'cursor-pointer' : ''; + + return ( + + {children} + + + ); +} + +export const TextHighlight = React.memo(TextHighlightComponent); diff --git a/scripts/registry-components.ts b/scripts/registry-components.ts index feca7302..df01fd7f 100644 --- a/scripts/registry-components.ts +++ b/scripts/registry-components.ts @@ -177,6 +177,13 @@ export const components: ComponentDefinition[] = [ dependencies: ['motion'], description: 'A component that creates a wave-like shimmer effect on text.', }, + { + name: 'text-highlight', + path: path.join(__dirname, '../components/core/text-highlight.tsx'), + registryDependencies: [], + dependencies: ['motion'], + description: 'A component that animates a highlight effect on text with a background color.', + }, { name: 'magnetic', path: path.join(__dirname, '../components/core/magnetic.tsx'),