├── .eslintrc.json ├── .gitignore ├── .vercelignore ├── CONTRIBUTING.md ├── LICENCE.md ├── README.md ├── app ├── docs │ ├── accordion │ │ ├── accordion-basic.tsx │ │ ├── accordion-icons.tsx │ │ ├── accordion-variant.tsx │ │ └── page.mdx │ ├── animated-background │ │ ├── animated-card-background-hover.tsx │ │ ├── animated-tabs-hover.tsx │ │ ├── animated-tabs.tsx │ │ ├── page.mdx │ │ └── segmented-control.tsx │ ├── animated-group │ │ ├── animated-group-custom-variants-2.tsx │ │ ├── animated-group-custom-variants.tsx │ │ ├── animated-group-preset.tsx │ │ └── page.mdx │ ├── animated-number │ │ ├── animated-number-basic.tsx │ │ ├── animated-number-counter.tsx │ │ ├── animated-number-in-view.tsx │ │ └── page.mdx │ ├── border-trail │ │ ├── border-trail-card-1.tsx │ │ ├── border-trail-card-2.tsx │ │ ├── border-trail-textarea.tsx │ │ └── page.mdx │ ├── carousel │ │ ├── carousel-basic.tsx │ │ ├── carousel-custom-indicator.tsx │ │ ├── carousel-custom-sizes.tsx │ │ ├── carousel-spacing.tsx │ │ └── page.mdx │ ├── cursor │ │ ├── cursor-1.tsx │ │ ├── cursor-2.tsx │ │ ├── cursor-3.tsx │ │ └── page.mdx │ ├── dialog │ │ ├── dialog-basic.tsx │ │ ├── dialog-controlled.tsx │ │ ├── dialog-custom-backdrop.tsx │ │ ├── dialog-custom-exit.tsx │ │ ├── dialog-custom-variants-transtion.tsx │ │ └── page.mdx │ ├── disclosure │ │ ├── disclosure-basic.tsx │ │ ├── disclosure-card.tsx │ │ └── page.mdx │ ├── dock │ │ ├── apple-style-dock.tsx │ │ └── page.mdx │ ├── glow-effect │ │ ├── glow-effect-button.tsx │ │ ├── glow-effect-card-background.tsx │ │ ├── glow-effect-card-mode.tsx │ │ └── page.mdx │ ├── image-comparison │ │ ├── image-comparison-basic.tsx │ │ ├── image-comparison-custom-slider.tsx │ │ ├── image-comparison-hover.tsx │ │ ├── image-comparison-spring.tsx │ │ └── page.mdx │ ├── in-view │ │ ├── in-view-basic-multiple.tsx │ │ ├── in-view-basic.tsx │ │ ├── in-view-images-grid.tsx │ │ └── page.mdx │ ├── infinite-slider │ │ ├── infinite-slider-basic.tsx │ │ ├── infinite-slider-hover-speed.tsx │ │ ├── infinite-slider-vertical.tsx │ │ └── page.mdx │ ├── installation │ │ └── page.mdx │ ├── layout.tsx │ ├── magnetic │ │ ├── magnetic-basic.tsx │ │ ├── magnetic-nested.tsx │ │ └── page.mdx │ ├── morphing-dialog │ │ ├── morphing-dialog-basic-1.tsx │ │ ├── morphing-dialog-basic-2.tsx │ │ ├── morphing-dialog-image.tsx │ │ └── page.mdx │ ├── morphing-popover │ │ ├── morphing-popover-basic.tsx │ │ ├── morphing-popover-custom-transition-variants.tsx │ │ ├── morphing-popover-textarea.tsx │ │ └── page.mdx │ ├── navigation.ts │ ├── page.mdx │ ├── progressive-blur │ │ ├── page.mdx │ │ ├── progressive-blur-basic.tsx │ │ ├── progressive-blur-hover.tsx │ │ └── progressive-blur-slider.tsx │ ├── scroll-progress │ │ ├── page.mdx │ │ ├── scroll-progress-basic-1.tsx │ │ ├── scroll-progress-basic-2.tsx │ │ └── scroll-progress-basic-3.tsx │ ├── sliding-number │ │ ├── clock.tsx │ │ ├── page.mdx │ │ ├── sliding-basic.tsx │ │ └── sliding-slider.tsx │ ├── spinning-text │ │ ├── page.mdx │ │ ├── spinning-text-basic.tsx │ │ ├── spinning-text-custom-transition.tsx │ │ └── spinning-text-custom-variants.tsx │ ├── spotlight │ │ ├── page.mdx │ │ ├── spotlight-basic.tsx │ │ ├── spotlight-border.tsx │ │ └── spotlight-custom-color.tsx │ ├── text-effect │ │ ├── page.mdx │ │ ├── text-effect-custom-delay.tsx │ │ ├── text-effect-exit.tsx │ │ ├── text-effect-line.tsx │ │ ├── text-effect-per-char.tsx │ │ ├── text-effect-per-word.tsx │ │ ├── text-effect-preset.tsx │ │ ├── text-effect-speed.tsx │ │ └── text-effect-variants.tsx │ ├── text-loop │ │ ├── page.mdx │ │ ├── text-loop-basic.tsx │ │ ├── text-loop-custom-variants-transition.tsx │ │ └── text-loop-on-index.tsx │ ├── text-morph │ │ ├── page.mdx │ │ ├── text-morph-button.tsx │ │ └── text-morph-input.tsx │ ├── text-roll │ │ ├── page.mdx │ │ ├── text-roll-basic.tsx │ │ ├── text-roll-custom-transition-delay.tsx │ │ └── text-roll-custom-variants.tsx │ ├── text-scramble │ │ ├── page.mdx │ │ ├── text-scramble-basic.tsx │ │ ├── text-scramble-custom-char-duration.tsx │ │ └── text-scramble-custom-trigger.tsx │ ├── text-shimmer-wave │ │ ├── page.mdx │ │ ├── text-shimmer-wave-basic.tsx │ │ └── text-shimmer-wave-color.tsx │ ├── text-shimmer │ │ ├── page.mdx │ │ ├── text-shimmer-basic.tsx │ │ └── text-shimmer-color.tsx │ ├── tilt │ │ ├── page.mdx │ │ ├── tilt-card-1.tsx │ │ └── tilt-spotlight.tsx │ ├── toolbar-dynamic │ │ └── page.mdx │ ├── toolbar-expandable │ │ └── page.mdx │ └── transition-panel │ │ ├── page.mdx │ │ ├── transition-panel-card.tsx │ │ └── transition-panel-tabs.tsx ├── globals.css ├── icon.ico ├── layout.tsx ├── opengraph-image.alt ├── opengraph-image.jpg ├── page.tsx ├── showcase │ └── page.tsx ├── twitter-image.alt └── twitter-image.jpg ├── cli ├── README.md ├── package-lock.json ├── package.json ├── src │ └── index.ts └── tsconfig.json ├── components.json ├── components ├── core │ ├── accordion.tsx │ ├── animated-background.tsx │ ├── animated-group.tsx │ ├── animated-number.tsx │ ├── border-trail.tsx │ ├── carousel.tsx │ ├── cursor.tsx │ ├── dialog.tsx │ ├── disclosure.tsx │ ├── dock.tsx │ ├── glow-effect.tsx │ ├── image-comparison.tsx │ ├── in-view.tsx │ ├── infinite-slider.tsx │ ├── magnetic.tsx │ ├── morphing-dialog.tsx │ ├── morphing-popover.tsx │ ├── progressive-blur.tsx │ ├── scroll-progress.tsx │ ├── sliding-number.tsx │ ├── spinning-text.tsx │ ├── spotlight.tsx │ ├── text-effect.tsx │ ├── text-loop.tsx │ ├── text-morph.tsx │ ├── text-roll.tsx │ ├── text-scramble.tsx │ ├── text-shimmer-wave.tsx │ ├── text-shimmer.tsx │ ├── tilt.tsx │ ├── toolbar-dynamic.tsx │ ├── toolbar-expandable.tsx │ └── transition-panel.tsx ├── ui │ ├── button.tsx │ ├── input.tsx │ ├── label.tsx │ └── tooltip.tsx └── website │ ├── card-example-landing.tsx │ ├── code-block.tsx │ ├── code-preview.tsx │ ├── code-renderer.tsx │ ├── component-code-preview.tsx │ ├── component-preview.tsx │ ├── dropdown-menu.tsx │ ├── header.tsx │ ├── icons │ ├── github.tsx │ ├── motion-primitives-logo.tsx │ ├── shadcn-logo.tsx │ └── x.tsx │ ├── installation-cli.tsx │ ├── launch-banner.tsx │ ├── open-in-v0.tsx │ ├── scroll-area.tsx │ ├── table-of-contents.tsx │ ├── tabs.tsx │ ├── theme-provider.tsx │ └── theme-switch.tsx ├── hooks ├── useClickOutside.tsx └── usePreventScroll.tsx ├── lib ├── browser.ts ├── code.ts ├── custom-theme.ts ├── shiki.ts ├── theme-css-variables.ts └── utils.ts ├── mdx-components.tsx ├── next.config.mjs ├── package-lock.json ├── package.json ├── postcss.config.mjs ├── prettier.config.js ├── public ├── apple_music_logo.svg ├── c │ ├── accordion.json │ ├── animated-background.json │ ├── animated-group.json │ ├── animated-number.json │ ├── border-trail.json │ ├── carousel.json │ ├── cursor.json │ ├── dialog.json │ ├── disclosure.json │ ├── dock.json │ ├── glow-effect.json │ ├── image-comparison.json │ ├── in-view.json │ ├── infinite-slider.json │ ├── magnetic.json │ ├── morphing-dialog.json │ ├── morphing-popover.json │ ├── progressive-blur.json │ ├── registry.json │ ├── scroll-progress.json │ ├── sliding-number.json │ ├── spinning-text.json │ ├── spotlight.json │ ├── text-effect.json │ ├── text-loop.json │ ├── text-morph.json │ ├── text-roll.json │ ├── text-scramble.json │ ├── text-shimmer-wave.json │ ├── text-shimmer.json │ ├── tilt.json │ ├── toolbar-dynamic.json │ ├── toolbar-expandable.json │ └── transition-panel.json ├── chrome_logo.svg ├── e │ ├── accordion-basic.json │ ├── accordion-icons.json │ ├── accordion-variant.json │ ├── animated-card-background-hover.json │ ├── animated-group-custom-variants-2.json │ ├── animated-group-custom-variants.json │ ├── animated-group-preset.json │ ├── animated-number-basic.json │ ├── animated-number-counter.json │ ├── animated-number-in-view.json │ ├── animated-tabs-hover.json │ ├── animated-tabs.json │ ├── apple-style-dock.json │ ├── border-trail-card-1.json │ ├── border-trail-card-2.json │ ├── border-trail-textarea.json │ ├── carousel-basic.json │ ├── carousel-custom-indicator.json │ ├── carousel-custom-sizes.json │ ├── carousel-spacing.json │ ├── clock.json │ ├── cursor-1.json │ ├── cursor-2.json │ ├── cursor-3.json │ ├── dialog-basic.json │ ├── dialog-controlled.json │ ├── dialog-custom-backdrop.json │ ├── dialog-custom-exit.json │ ├── dialog-custom-variants-transtion.json │ ├── disclosure-basic.json │ ├── disclosure-card.json │ ├── glow-effect-button.json │ ├── glow-effect-card-background.json │ ├── glow-effect-card-mode.json │ ├── image-comparison-basic.json │ ├── image-comparison-custom-slider.json │ ├── image-comparison-hover.json │ ├── image-comparison-spring.json │ ├── in-view-basic-multiple.json │ ├── in-view-basic.json │ ├── in-view-images-grid.json │ ├── infinite-slider-basic.json │ ├── infinite-slider-hover-speed.json │ ├── infinite-slider-vertical.json │ ├── magnetic-basic.json │ ├── magnetic-nested.json │ ├── morphing-dialog-basic-1.json │ ├── morphing-dialog-basic-2.json │ ├── morphing-dialog-image.json │ ├── morphing-popover-basic.json │ ├── morphing-popover-custom-transition-variants.json │ ├── morphing-popover-textarea.json │ ├── progressive-blur-basic.json │ ├── progressive-blur-hover.json │ ├── progressive-blur-slider.json │ ├── scroll-progress-basic-1.json │ ├── scroll-progress-basic-2.json │ ├── scroll-progress-basic-3.json │ ├── segmented-control.json │ ├── sliding-basic.json │ ├── sliding-slider.json │ ├── spinning-text-basic.json │ ├── spinning-text-custom-transition.json │ ├── spinning-text-custom-variants.json │ ├── spotlight-basic.json │ ├── spotlight-border.json │ ├── spotlight-custom-color.json │ ├── text-effect-custom-delay.json │ ├── text-effect-exit.json │ ├── text-effect-line.json │ ├── text-effect-per-char.json │ ├── text-effect-per-word.json │ ├── text-effect-preset.json │ ├── text-effect-speed.json │ ├── text-effect-variants.json │ ├── text-loop-basic.json │ ├── text-loop-custom-variants-transition.json │ ├── text-loop-on-index.json │ ├── text-morph-button.json │ ├── text-morph-input.json │ ├── text-roll-basic.json │ ├── text-roll-custom-transition-delay.json │ ├── text-roll-custom-variants.json │ ├── text-scramble-basic.json │ ├── text-scramble-custom-char-duration.json │ ├── text-scramble-custom-trigger.json │ ├── text-shimmer-basic.json │ ├── text-shimmer-color.json │ ├── text-shimmer-wave-basic.json │ ├── text-shimmer-wave-color.json │ ├── tilt-card-1.json │ ├── tilt-spotlight.json │ ├── transition-panel-card.json │ └── transition-panel-tabs.json ├── eb-27-lamp-edouard-wilfrid-buquet.jpg ├── gucci_logo.svg ├── h │ ├── useClickOutside.json │ └── usePreventScroll.json ├── jquery_logo.svg ├── mp_dark.png ├── mp_light.png ├── national_geographic_logo.svg ├── nintendo_logo.svg ├── prada_logo.svg ├── sony_logo.svg └── strava_logo.svg ├── scripts ├── registry-build.ts ├── registry-components.ts ├── registry-examples.ts ├── registry-hooks.ts └── registry-schema.ts └── tsconfig.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "next/core-web-vitals", 4 | "prettier", 5 | "plugin:tailwindcss/recommended" 6 | ], 7 | "plugins": ["tailwindcss"] 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | # cli 39 | cli/dist 40 | cli/node_modules 41 | -------------------------------------------------------------------------------- /.vercelignore: -------------------------------------------------------------------------------- 1 | /cli 2 | -------------------------------------------------------------------------------- /LICENCE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 ibelick 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | app/page.tsx 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Motion-Primitives 2 | 3 | Beautifully designed, easy-to-integrate motion components for engineers and designers, built with [motion](https://motion.dev/) and [Tailwind CSS](https://tailwindcss.com/). 4 | 5 | **This project is in beta. Expect new components to be released regularly and significant updates to the code.** 6 | 7 |

8 | hero 9 |

10 | 11 | ## Documentation 12 | 13 | Visit [motion-primitives.com/docs](http://motion-primitives.com/docs) to view the full documentation. 14 | 15 | ## Contributing 16 | 17 | Please read the [contributing guide](/CONTRIBUTING.md). 18 | 19 | ## License 20 | 21 | Licensed under the [MIT license](/LICENSE.md). 22 | -------------------------------------------------------------------------------- /app/docs/animated-background/animated-card-background-hover.tsx: -------------------------------------------------------------------------------- 1 | import { AnimatedBackground } from '@/components/core/animated-background'; 2 | 3 | export function AnimatedCardBackgroundHover() { 4 | const ITEMS = [ 5 | { 6 | id: 1, 7 | title: 'Dialog', 8 | description: 'Enhances modal presentations.', 9 | }, 10 | { 11 | id: 2, 12 | title: 'Popover', 13 | description: 'For small interactive overlays.', 14 | }, 15 | { 16 | id: 3, 17 | title: 'Accordion', 18 | description: 'Collapsible sections for more content.', 19 | }, 20 | { 21 | id: 4, 22 | title: 'Collapsible', 23 | description: 'Collapsible sections for more content.', 24 | }, 25 | { 26 | id: 5, 27 | title: 'Drag to Reorder', 28 | description: 'Reorder items with drag and drop.', 29 | }, 30 | { 31 | id: 6, 32 | title: 'Swipe to Delete', 33 | description: 'Delete items with swipe gestures.', 34 | }, 35 | ]; 36 | 37 | return ( 38 |
39 | 48 | {ITEMS.map((item, index) => ( 49 |
50 |
51 |

52 | {item.title} 53 |

54 |

55 | {item.description} 56 |

57 |
58 |
59 | ))} 60 |
61 |
62 | ); 63 | } 64 | -------------------------------------------------------------------------------- /app/docs/animated-background/animated-tabs-hover.tsx: -------------------------------------------------------------------------------- 1 | import { AnimatedBackground } from '@/components/core/animated-background'; 2 | 3 | export function AnimatedTabsHover() { 4 | const TABS = ['Home', 'About', 'Services', 'Contact']; 5 | 6 | return ( 7 |
8 | 18 | {TABS.map((tab, index) => ( 19 | 27 | ))} 28 | 29 |
30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /app/docs/animated-background/animated-tabs.tsx: -------------------------------------------------------------------------------- 1 | import { Home, PhoneCall, Settings, User } from 'lucide-react'; 2 | import { AnimatedBackground } from '@/components/core/animated-background'; 3 | 4 | export function AnimatedTabs() { 5 | const TABS = [ 6 | { 7 | label: 'Home', 8 | icon: , 9 | }, 10 | { 11 | label: 'About', 12 | icon: , 13 | }, 14 | { 15 | label: 'Services', 16 | icon: , 17 | }, 18 | { 19 | label: 'Contact', 20 | icon: , 21 | }, 22 | ]; 23 | 24 | return ( 25 |
26 |
27 | 36 | {TABS.map((tab) => ( 37 | 45 | ))} 46 | 47 |
48 |
49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /app/docs/animated-background/segmented-control.tsx: -------------------------------------------------------------------------------- 1 | import { AnimatedBackground } from '@/components/core/animated-background'; 2 | 3 | export function SegmentedControl() { 4 | return ( 5 |
6 | 14 | {['Day', 'Week', 'Month', 'Year'].map((label, index) => { 15 | return ( 16 | 25 | ); 26 | })} 27 | 28 |
29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /app/docs/animated-group/animated-group-custom-variants-2.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { AnimatedGroup } from '@/components/core/animated-group'; 3 | 4 | export function AnimatedGroupCustomVariants2() { 5 | return ( 6 | 37 |
38 | Apple Music logo 43 |
44 |
45 | Chrome logo 46 |
47 |
48 | Strava logo 53 |
54 |
55 | Nintendo logo 60 |
61 |
62 | ); 63 | } 64 | -------------------------------------------------------------------------------- /app/docs/animated-group/animated-group-custom-variants.tsx: -------------------------------------------------------------------------------- 1 | import { AnimatedGroup } from '@/components/core/animated-group'; 2 | 3 | export function AnimatedGroupCustomVariants() { 4 | return ( 5 | 32 | impressionist painting, uploaded to Cosmos 37 | impressionist painting, uploaded to Cosmos 42 | impressionist painting, uploaded to Cosmos 47 | impressionist painting, uploaded to Cosmos 52 | 53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /app/docs/animated-group/animated-group-preset.tsx: -------------------------------------------------------------------------------- 1 | import { AnimatedGroup } from '@/components/core/animated-group'; 2 | 3 | export function AnimatedGroupPreset() { 4 | return ( 5 | 9 | impressionist painting, uploaded to Cosmos 14 | impressionist painting, uploaded to Cosmos 19 | impressionist painting, uploaded to Cosmos 24 | impressionist painting, uploaded to Cosmos 29 | 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /app/docs/animated-number/animated-number-basic.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { useEffect, useState } from 'react'; 3 | import { AnimatedNumber } from '@/components/core/animated-number'; 4 | 5 | export function AnimatedNumberBasic() { 6 | const [value, setValue] = useState(0); 7 | 8 | useEffect(() => { 9 | setValue(2082); 10 | }, []); 11 | 12 | return ( 13 |
14 | 21 | 22 | 23 | 31 |
32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /app/docs/animated-number/animated-number-counter.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { useState } from 'react'; 3 | import { AnimatedNumber } from '@/components/core/animated-number'; 4 | import { Minus, Plus } from 'lucide-react'; 5 | 6 | export function AnimatedNumberCounter() { 7 | const [value, setValue] = useState(1000); 8 | 9 | return ( 10 |
11 | 17 | 25 | 31 |
32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /app/docs/animated-number/animated-number-in-view.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { AnimatedNumber } from '@/components/core/animated-number'; 3 | import { useInView } from 'motion/react'; 4 | import { useRef, useState } from 'react'; 5 | 6 | export function AnimatedNumberInView() { 7 | const [value, setValue] = useState(0); 8 | const ref = useRef(null); 9 | const isInView = useInView(ref); 10 | 11 | if (isInView && value === 0) { 12 | setValue(10000); 13 | } 14 | 15 | return ( 16 |
17 | 25 |
26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /app/docs/border-trail/border-trail-card-1.tsx: -------------------------------------------------------------------------------- 1 | import { BorderTrail } from '@/components/core/border-trail'; 2 | 3 | export function BorderTrailCard1() { 4 | return ( 5 |
6 | 13 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /app/docs/border-trail/border-trail-card-2.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { cn } from '@/lib/utils'; 3 | import { BorderTrail } from '@/components/core/border-trail'; 4 | import { useState } from 'react'; 5 | 6 | export function BorderTrailCard2() { 7 | const [isLoading, setIsLoading] = useState(false); 8 | const [isVisible, setIsVisible] = useState(true); 9 | 10 | const handleAnimationComplete = () => { 11 | setIsLoading(false); 12 | setTimeout(() => setIsVisible(false), 300); 13 | }; 14 | 15 | const handleLoad = () => { 16 | setIsLoading(true); 17 | setIsVisible(true); 18 | }; 19 | 20 | return ( 21 |
22 | {isVisible && ( 23 | 36 | )} 37 |
38 | 46 |
47 |
48 | ); 49 | } 50 | -------------------------------------------------------------------------------- /app/docs/border-trail/border-trail-textarea.tsx: -------------------------------------------------------------------------------- 1 | import { BorderTrail } from '@/components/core/border-trail'; 2 | 3 | export function BorderTrailTextarea() { 4 | return ( 5 |
6 |