"use client"; import { forwardRef, Suspense, useEffect, useMemo, useRef, useState } from "react"; import { Demos } from "@/examples"; import { CodeIcon, EyeIcon, MoonIcon, SunIcon } from "@iconicicons/react"; import { Button, Tabs, type TabsElement, type TabsProps } from "@lemonsqueezy/wedges"; import { cn } from "@/lib/utils"; import { PreviewCode } from "./PreviewCode"; type PreviewComponentType = TabsElement; type PreviewComponentProps = TabsProps & { align?: "start" | "center" | "end"; /** * Name of the demo component defined in `@/examples/index.ts`. */ name: string; }; export const PreviewComponent = forwardRef( ({ align, children, name, ...otherProps }, ref) => { const previewRef = useRef(null); const [theme, setTheme] = useState<"light" | "dark">("light"); const Component = useMemo(() => Demos[name]?.component, [name]); const Preview = !Component ? NotFound : Component; const toggleTheme = () => { if (previewRef.current) { previewRef.current.classList.add("[&_*]:!transition-none"); } theme === "light" ? setTheme("dark") : setTheme("light"); }; useEffect(() => { // This function runs after the render is committed to the screen const removeTransitionClass = () => { if (!previewRef.current) { return; } previewRef.current.classList.remove("[&_*]:!transition-none"); }; setTimeout(removeTransitionClass, 0); }, [theme]); // This effect runs when `theme` changes return ( } value="preview"> Preview } value="code"> Code
}>
{children}
); } ); PreviewComponent.displayName = "PreviewComponent"; function SuspenseFallback() { return (
{/**/} Loading preview
); } function NotFound() { return Unable to display component preview; }