Files
shadcn-ui/apps/v4/components/component-source.tsx
shadcn 3d8837bddb Merge branch 'main' into shadcn/v4
# Conflicts:
#	apps/v4/app/(create)/components/customizer.tsx
#	apps/v4/app/(create)/components/item-picker.tsx
#	apps/v4/app/(create)/components/lock-button.tsx
#	apps/v4/app/(create)/components/picker.tsx
#	apps/v4/app/(create)/components/preview-controls.tsx
#	apps/v4/app/(create)/components/preview.tsx
#	apps/v4/app/(create)/components/random-button.tsx
#	apps/v4/app/(create)/components/reset-button.tsx
#	apps/v4/app/(create)/components/toolbar-controls.tsx
#	apps/v4/app/(create)/create/page.tsx
#	apps/v4/components/docs-sidebar.tsx
#	apps/v4/components/site-header.tsx
#	apps/v4/examples/base/ui-rtl/tooltip.tsx
#	apps/v4/examples/base/ui/tooltip.tsx
#	apps/v4/examples/radix/ui-rtl/tooltip.tsx
#	apps/v4/examples/radix/ui/tooltip.tsx
#	apps/v4/package.json
#	apps/v4/public/r/styles/base-lyra/chatgpt.json
#	apps/v4/public/r/styles/base-lyra/elevenlabs.json
#	apps/v4/public/r/styles/base-lyra/github.json
#	apps/v4/public/r/styles/base-lyra/input-group.json
#	apps/v4/public/r/styles/base-lyra/preview.json
#	apps/v4/public/r/styles/base-lyra/tooltip-example.json
#	apps/v4/public/r/styles/base-lyra/tooltip.json
#	apps/v4/public/r/styles/base-lyra/vercel.json
#	apps/v4/public/r/styles/base-maia/chatgpt.json
#	apps/v4/public/r/styles/base-maia/elevenlabs.json
#	apps/v4/public/r/styles/base-maia/github.json
#	apps/v4/public/r/styles/base-maia/preview.json
#	apps/v4/public/r/styles/base-maia/tooltip-example.json
#	apps/v4/public/r/styles/base-maia/tooltip.json
#	apps/v4/public/r/styles/base-maia/vercel.json
#	apps/v4/public/r/styles/base-mira/chatgpt.json
#	apps/v4/public/r/styles/base-mira/elevenlabs.json
#	apps/v4/public/r/styles/base-mira/github.json
#	apps/v4/public/r/styles/base-mira/input-group.json
#	apps/v4/public/r/styles/base-mira/preview.json
#	apps/v4/public/r/styles/base-mira/tooltip-example.json
#	apps/v4/public/r/styles/base-mira/tooltip.json
#	apps/v4/public/r/styles/base-mira/vercel.json
#	apps/v4/public/r/styles/base-nova/chatgpt.json
#	apps/v4/public/r/styles/base-nova/elevenlabs.json
#	apps/v4/public/r/styles/base-nova/github.json
#	apps/v4/public/r/styles/base-nova/preview.json
#	apps/v4/public/r/styles/base-nova/tooltip-example.json
#	apps/v4/public/r/styles/base-nova/tooltip.json
#	apps/v4/public/r/styles/base-nova/vercel.json
#	apps/v4/public/r/styles/base-vega/chatgpt.json
#	apps/v4/public/r/styles/base-vega/elevenlabs.json
#	apps/v4/public/r/styles/base-vega/github.json
#	apps/v4/public/r/styles/base-vega/preview.json
#	apps/v4/public/r/styles/base-vega/tooltip-example.json
#	apps/v4/public/r/styles/base-vega/tooltip.json
#	apps/v4/public/r/styles/base-vega/vercel.json
#	apps/v4/public/r/styles/radix-lyra/chatgpt.json
#	apps/v4/public/r/styles/radix-lyra/elevenlabs.json
#	apps/v4/public/r/styles/radix-lyra/github.json
#	apps/v4/public/r/styles/radix-lyra/input-group.json
#	apps/v4/public/r/styles/radix-lyra/preview.json
#	apps/v4/public/r/styles/radix-lyra/tooltip-example.json
#	apps/v4/public/r/styles/radix-lyra/tooltip.json
#	apps/v4/public/r/styles/radix-lyra/vercel.json
#	apps/v4/public/r/styles/radix-maia/chatgpt.json
#	apps/v4/public/r/styles/radix-maia/elevenlabs.json
#	apps/v4/public/r/styles/radix-maia/github.json
#	apps/v4/public/r/styles/radix-maia/preview.json
#	apps/v4/public/r/styles/radix-maia/tooltip-example.json
#	apps/v4/public/r/styles/radix-maia/tooltip.json
#	apps/v4/public/r/styles/radix-maia/vercel.json
#	apps/v4/public/r/styles/radix-mira/chatgpt.json
#	apps/v4/public/r/styles/radix-mira/elevenlabs.json
#	apps/v4/public/r/styles/radix-mira/github.json
#	apps/v4/public/r/styles/radix-mira/input-group.json
#	apps/v4/public/r/styles/radix-mira/preview.json
#	apps/v4/public/r/styles/radix-mira/tooltip-example.json
#	apps/v4/public/r/styles/radix-mira/tooltip.json
#	apps/v4/public/r/styles/radix-mira/vercel.json
#	apps/v4/public/r/styles/radix-nova/chatgpt.json
#	apps/v4/public/r/styles/radix-nova/elevenlabs.json
#	apps/v4/public/r/styles/radix-nova/github.json
#	apps/v4/public/r/styles/radix-nova/preview.json
#	apps/v4/public/r/styles/radix-nova/tooltip-example.json
#	apps/v4/public/r/styles/radix-nova/tooltip.json
#	apps/v4/public/r/styles/radix-nova/vercel.json
#	apps/v4/public/r/styles/radix-vega/chatgpt.json
#	apps/v4/public/r/styles/radix-vega/elevenlabs.json
#	apps/v4/public/r/styles/radix-vega/github.json
#	apps/v4/public/r/styles/radix-vega/preview.json
#	apps/v4/public/r/styles/radix-vega/tooltip-example.json
#	apps/v4/public/r/styles/radix-vega/tooltip.json
#	apps/v4/public/r/styles/radix-vega/vercel.json
#	apps/v4/registry/bases/base/blocks/chatgpt.tsx
#	apps/v4/registry/bases/base/blocks/elevenlabs.tsx
#	apps/v4/registry/bases/base/blocks/github.tsx
#	apps/v4/registry/bases/base/blocks/preview.tsx
#	apps/v4/registry/bases/base/blocks/vercel.tsx
#	apps/v4/registry/bases/radix/blocks/chatgpt.tsx
#	apps/v4/registry/bases/radix/blocks/elevenlabs.tsx
#	apps/v4/registry/bases/radix/blocks/github.tsx
#	apps/v4/registry/bases/radix/blocks/preview.tsx
#	apps/v4/registry/bases/radix/blocks/vercel.tsx
2026-03-02 14:00:50 +04:00

115 lines
2.7 KiB
TypeScript

import * as React from "react"
import { formatCode } from "@/lib/format-code"
import { highlightCode } from "@/lib/highlight-code"
import { readFileFromRoot } from "@/lib/read-file"
import { getDemoItem, getRegistryItem } from "@/lib/registry"
import { cn } from "@/lib/utils"
import { CodeCollapsibleWrapper } from "@/components/code-collapsible-wrapper"
import { CopyButton } from "@/components/copy-button"
import { getIconForLanguageExtension } from "@/components/icons"
export async function ComponentSource({
name,
src,
title,
language,
collapsible = true,
className,
styleName = "new-york-v4",
maxLines,
}: React.ComponentProps<"div"> & {
name?: string
src?: string
title?: string
language?: string
collapsible?: boolean
styleName?: string
maxLines?: number
}) {
if (!name && !src) {
return null
}
let code: string | undefined
if (name) {
const item =
(await getDemoItem(name, styleName)) ??
(await getRegistryItem(name, styleName))
code = item?.files?.[0]?.content
}
if (src) {
code = await readFileFromRoot(src)
}
if (!code) {
return null
}
code = await formatCode(code, styleName)
code = code.replaceAll("/* eslint-disable react/no-children-prop */\n", "")
// Truncate code if maxLines is set.
if (maxLines) {
code = code.split("\n").slice(0, maxLines).join("\n")
}
const lang = language ?? title?.split(".").pop() ?? "tsx"
const highlightedCode = await highlightCode(code, lang)
if (!collapsible) {
return (
<div className={cn("relative", className)}>
<ComponentCode
code={code}
highlightedCode={highlightedCode}
language={lang}
title={title}
/>
</div>
)
}
return (
<CodeCollapsibleWrapper className={className}>
<ComponentCode
code={code}
highlightedCode={highlightedCode}
language={lang}
title={title}
/>
</CodeCollapsibleWrapper>
)
}
function ComponentCode({
code,
highlightedCode,
language,
title,
}: {
code: string
highlightedCode: string
language: string
title: string | undefined
}) {
return (
<figure data-rehype-pretty-code-figure="" className="[&>pre]:max-h-96">
{title && (
<figcaption
data-rehype-pretty-code-title=""
className="flex items-center gap-2 text-code-foreground [&_svg]:size-4 [&_svg]:text-code-foreground [&_svg]:opacity-70"
data-language={language}
>
{getIconForLanguageExtension(language)}
{title}
</figcaption>
)}
<CopyButton value={code} />
<div dangerouslySetInnerHTML={{ __html: highlightedCode }} />
</figure>
)
}