{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "primitives-animate-code-block",
  "title": "Code Block",
  "description": "A code block component that animates the code as it is written.",
  "dependencies": [
    "shiki"
  ],
  "registryDependencies": [
    "@odysseyui/hooks-use-is-in-view"
  ],
  "files": [
    {
      "path": "registry/primitives/animate/code-block/index.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\n\nimport {\n  useIsInView,\n  type UseIsInViewOptions,\n} from '@/hooks/use-is-in-view';\n\ntype CodeBlockProps = React.ComponentProps<'div'> & {\n  code: string;\n  lang: string;\n  theme?: 'light' | 'dark';\n  themes?: { light: string; dark: string };\n  writing?: boolean;\n  duration?: number;\n  delay?: number;\n  onDone?: () => void;\n  onWrite?: (info: { index: number; length: number; done: boolean }) => void;\n  scrollContainerRef?: React.RefObject<HTMLElement | null>;\n} & UseIsInViewOptions;\n\nfunction CodeBlock({\n  ref,\n  code,\n  lang,\n  theme = 'light',\n  themes = {\n    light: 'github-light',\n    dark: 'github-dark',\n  },\n  writing = false,\n  duration = 5000,\n  delay = 0,\n  onDone,\n  onWrite,\n  scrollContainerRef,\n  inView = false,\n  inViewOnce = true,\n  inViewMargin = '0px',\n  ...props\n}: CodeBlockProps) {\n  const { ref: localRef, isInView } = useIsInView(\n    ref as React.Ref<HTMLDivElement>,\n    {\n      inView,\n      inViewOnce,\n      inViewMargin,\n    },\n  );\n\n  const [visibleCode, setVisibleCode] = React.useState('');\n  const [highlightedCode, setHighlightedCode] = React.useState('');\n  const [isDone, setIsDone] = React.useState(false);\n\n  React.useEffect(() => {\n    if (!visibleCode.length || !isInView) return;\n\n    const loadHighlightedCode = async () => {\n      try {\n        const { codeToHtml } = await import('shiki');\n\n        const highlighted = await codeToHtml(visibleCode, {\n          lang,\n          themes,\n          defaultColor: theme,\n        });\n\n        setHighlightedCode(highlighted);\n      } catch (e) {\n        console.error(`Language \"${lang}\" could not be loaded.`, e);\n      }\n    };\n\n    loadHighlightedCode();\n  }, [lang, themes, writing, isInView, duration, delay, visibleCode, theme]);\n\n  React.useEffect(() => {\n    if (!writing) {\n      setVisibleCode(code);\n      onDone?.();\n      onWrite?.({ index: code.length, length: code.length, done: true });\n      return;\n    }\n\n    if (!code.length || !isInView) return;\n\n    const characters = Array.from(code);\n    let index = 0;\n    const totalDuration = duration;\n    const interval = totalDuration / characters.length;\n    let intervalId: NodeJS.Timeout;\n\n    const timeout = setTimeout(() => {\n      intervalId = setInterval(() => {\n        if (index < characters.length) {\n          setVisibleCode(() => {\n            const nextChar = characters.slice(0, index + 1).join('');\n            onWrite?.({\n              index: index + 1,\n              length: characters.length,\n              done: false,\n            });\n            index += 1;\n            return nextChar;\n          });\n          localRef.current?.scrollTo({\n            top: localRef.current?.scrollHeight,\n            behavior: 'smooth',\n          });\n        } else {\n          clearInterval(intervalId);\n          setIsDone(true);\n          onDone?.();\n          onWrite?.({\n            index: characters.length,\n            length: characters.length,\n            done: true,\n          });\n        }\n      }, interval);\n    }, delay);\n\n    return () => {\n      clearTimeout(timeout);\n      clearInterval(intervalId);\n    };\n  }, [code, duration, delay, isInView, writing, onDone, onWrite, localRef]);\n\n  React.useEffect(() => {\n    if (!writing || !isInView) return;\n    const el =\n      scrollContainerRef?.current ??\n      (localRef.current?.parentElement as HTMLElement | null) ??\n      (localRef.current as unknown as HTMLElement | null);\n\n    if (!el) return;\n\n    requestAnimationFrame(() => {\n      el.scrollTo({\n        top: el.scrollHeight,\n        behavior: 'smooth',\n      });\n    });\n  }, [highlightedCode, writing, isInView, scrollContainerRef, localRef]);\n\n  return (\n    <div\n      ref={localRef}\n      data-slot=\"code-block\"\n      data-writing={writing}\n      data-done={isDone}\n      dangerouslySetInnerHTML={{ __html: highlightedCode }}\n      {...props}\n    />\n  );\n}\n\nexport { CodeBlock, type CodeBlockProps };\n",
      "type": "registry:ui",
      "target": "components/odysseyui/primitives/animate/code-block.tsx"
    }
  ],
  "type": "registry:ui"
}