spiral-loader
agent-elements/spiral-loaderFreeComponent
agent-elements publishes no description for this item.
Live preview
live · rendered by the registry
Rendered by agent-elements on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://agent-elements.21st.dev/r/spiral-loader.jsonSource
1"use client";23import dynamic from "next/dynamic";4import type { ComponentType } from "react";5import { useCallback, useEffect, useRef, useState } from "react";6import type { LottieRefCurrentProps } from "lottie-react";7import { cn } from "./utils/cn";8import { spiralFastData, spiralSlowData } from "./spiral-loader-data";9import { useTheme } from "next-themes";1011const Lottie = dynamic(() => import("lottie-react"), {12 ssr: false,13}) as ComponentType<any>;1415const FAST_REPEATS = 4;16const SLOW_REPEATS = 2;1718export type SpiralLoaderProps = {19 size?: number;20 className?: string;21};2223export function SpiralLoader({ size = 16, className }: SpiralLoaderProps) {24 const [isMounted, setIsMounted] = useState(false);25 const [phase, setPhase] = useState<"fast" | "slow">("fast");26 const repeatCountRef = useRef(0);27 const fastRef = useRef<LottieRefCurrentProps | null>(null);28 const slowRef = useRef<LottieRefCurrentProps | null>(null);29 const { resolvedTheme } = useTheme();3031 useEffect(() => {32 setIsMounted(true);33 }, []);3435 const startFastPhase = useCallback(() => {36 repeatCountRef.current = 0;37 setPhase("fast");38 slowRef.current?.stop();39 fastRef.current?.goToAndPlay(0, true);40 }, []);4142 const startSlowPhase = useCallback(() => {43 repeatCountRef.current = 0;44 setPhase("slow");45 fastRef.current?.stop();46 slowRef.current?.goToAndPlay(0, true);47 }, []);4849 const handleFastComplete = useCallback(() => {50 repeatCountRef.current += 1;51 if (repeatCountRef.current < FAST_REPEATS) {52 fastRef.current?.goToAndPlay(0, true);53 } else {54 startSlowPhase();55 }56 }, [startSlowPhase]);5758 const handleSlowComplete = useCallback(() => {59 repeatCountRef.current += 1;60 if (repeatCountRef.current < SLOW_REPEATS) {61 slowRef.current?.goToAndPlay(0, true);62 } else {63 startFastPhase();64 }65 }, [startFastPhase]);6667 if (!isMounted) return null;68 const needsInvert = resolvedTheme !== "dark";6970 return (71 <div72 className={cn("relative shrink-0", className)}73 style={{ width: size, height: size }}74 >75 <div76 className={cn(77 "absolute inset-0 transition-opacity duration-75",78 needsInvert && "invert",79 phase === "fast" ? "opacity-100" : "opacity-0",80 )}81 >82 <Lottie83 lottieRef={fastRef}84 animationData={spiralFastData}85 loop={false}86 autoplay={true}87 onComplete={handleFastComplete}88// … truncated
More from agent-elements
All 25 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| agent-chatagent-chat | agent-elements | Components | Free | no deps | |
| attachment-buttonattachment-button | agent-elements | Components | Free | no deps | |
| bash-toolbash-tool | agent-elements | Components | Free | no deps | |
| edit-tooledit-tool | agent-elements | Components | Free | no deps | |
| error-messageerror-message | agent-elements | Components | Free | no deps | |
| file-attachmentfile-attachment | agent-elements | Components | Free | no deps | |
| generic-toolgeneric-tool | agent-elements | Components | Free | no deps | |
| input-barinput-bar | agent-elements | Components | Free | no deps |
