CodeBlock
Một khối mã để đọc và sao chép: phần đầu tùy chọn với tên tệp và ngôn ngữ, nút sao chép báo khi đã chép, số dòng, dòng được đánh dấu, và dòng dài cuộn ngang hoặc xuống dòng. Bộ tô màu nhỏ có sẵn tô TS, JS, JSON, CSS, HTML và shell bằng token màu chữ; truyền highlight để cắm bộ khác.
Xem trước
import { CodeBlock } from "@/components/ui/code-block"
const codeSampleTsx = "import { Button } from \"@/components/ui/button\"\n\nexport default function Page() {\n // Save the draft before leaving.\n return <Button variant=\"solid\" onClick={() => save(42)}>Save</Button>\n}"
<CodeBlock language="tsx" filename="app/page.tsx" showLineNumbers code={codeSampleTsx} />Cách dùng
Khi nào dùng
- Hiện mã để đọc hoặc chép trong tài liệu, hướng dẫn cài đặt hoặc changelog.
- Chỉ ra những dòng quan trọng của một tệp, với số dòng và dòng được đánh dấu.
Khi nào không dùng
- Một từ hoặc tên ngắn trong câu. Dùng thẻ code trong văn bản.
- Mã người đọc sửa. Dùng trình soạn mã hoặc Textarea.
- Một log dài đang chạy. Dùng khung log cuộn.
Biến thể
variant
default nằm lõm trong trang hoặc card, surface nổi trên vùng lõm, plain không nền không viền, cho mã trong một panel khác.
import { CodeBlock } from "@/components/ui/code-block"
const codeSampleTsx = "import { Button } from \"@/components/ui/button\"\n\nexport default function Page() {\n // Save the draft before leaving.\n return <Button variant=\"solid\" onClick={() => save(42)}>Save</Button>\n}"
<CodeBlock language="tsx" filename="app/page.tsx" showLineNumbers code={codeSampleTsx} />
<CodeBlock language="tsx" filename="app/page.tsx" variant="surface" showLineNumbers code={codeSampleTsx} />
<CodeBlock language="tsx" filename="app/page.tsx" variant="plain" showLineNumbers code={codeSampleTsx} />size
Cỡ chữ mã, chiều cao dòng và padding: chữ 12, 14 hoặc 16px.
import { CodeBlock } from "@/components/ui/code-block"
const codeSampleTsx = "import { Button } from \"@/components/ui/button\"\n\nexport default function Page() {\n // Save the draft before leaving.\n return <Button variant=\"solid\" onClick={() => save(42)}>Save</Button>\n}"
<CodeBlock language="tsx" filename="app/page.tsx" size="sm" showLineNumbers code={codeSampleTsx} />
<CodeBlock language="tsx" filename="app/page.tsx" showLineNumbers code={codeSampleTsx} />
<CodeBlock language="tsx" filename="app/page.tsx" size="lg" showLineNumbers code={codeSampleTsx} />Ví dụ
Tệp
Tên tệp và ngôn ngữ ở phần đầu, nút sao chép ở cuối.
import { CodeBlock } from "@/components/ui/code-block"
const codeSampleTsx = "import { Button } from \"@/components/ui/button\"\n\nexport default function Page() {\n // Save the draft before leaving.\n return <Button variant=\"solid\" onClick={() => save(42)}>Save</Button>\n}"
<CodeBlock filename="app/page.tsx" language="tsx" code={codeSampleTsx} />Số dòng và dòng được đánh dấu
highlightLines đánh dấu dòng bằng nền info và một vạch info; đếm từ startLine.
import { CodeBlock } from "@/components/ui/code-block"
const codeSampleTsx = "import { Button } from \"@/components/ui/button\"\n\nexport default function Page() {\n // Save the draft before leaving.\n return <Button variant=\"solid\" onClick={() => save(42)}>Save</Button>\n}"
<CodeBlock filename="app/page.tsx" language="tsx" code={codeSampleTsx} showLineNumbers highlightLines={[4, 5]} />Đoạn trích
startLine đánh số đoạn trích theo vị trí của nó trong tệp.
import { CodeBlock } from "@/components/ui/code-block"
const codeSampleCss = ":root {\n --radius-container: 12px;\n --spacing-lg: 16px;\n}"
<CodeBlock filename="tokens.css" language="css" code={codeSampleCss} showLineNumbers startLine={42} highlightLines={[43]} />Xuống dòng
Dòng dài mặc định cuộn ngang. showWrapButton thêm nút bật tắt; defaultWrap bắt đầu ở chế độ xuống dòng.
import { CodeBlock } from "@/components/ui/code-block"
const codeSampleLong = "npx shadcn@latest add https://ui.example.com/r/code-block.json https://ui.example.com/r/button.json --overwrite --yes"
<CodeBlock language="bash" code={codeSampleLong} showWrapButton />Không có phần đầu
Không có tên tệp hoặc ngôn ngữ thì nút sao chép nổi ở góc trên cuối.
import { CodeBlock } from "@/components/ui/code-block"
<CodeBlock language="bash" showLanguage={false} code="npx shadcn@latest add @werewolf/code-block" />Văn bản thuần
highlight={false} tắt màu; ngôn ngữ không có ngữ pháp sẵn cũng hiện thuần.
import { CodeBlock } from "@/components/ui/code-block"
const codeSampleText = "Werewolf UI\nTokens first, components second.\nEvery color comes from a token."
<CodeBlock filename="notes.txt" highlight={false} code={codeSampleText} />Bộ tô màu của bạn
Truyền một hàm trả về token cho từng dòng, như hàm dựng từ kết quả của một bộ tô màu phía server.
import { CodeBlock } from "@/components/ui/code-block"
const codeSampleSql = "SELECT name, email\nFROM users\nWHERE active = true\nORDER BY name;"
const SQL_KEYWORDS = /\b(SELECT|FROM|WHERE|ORDER|BY|AND|OR|true|false)\b/
const highlightSql: CodeBlockHighlighter = (code) =>
code.split("\n").map((line) =>
line
.split(/(\b(?:SELECT|FROM|WHERE|ORDER|BY|AND|OR|true|false)\b)/)
.filter(Boolean)
.map((text) => ({ text, className: SQL_KEYWORDS.test(text) ? "text-text-purple" : undefined }))
)
<CodeBlock language="sql" code={codeSampleSql} highlight={highlightSql} />Mã dài
maxHeight giới hạn chiều cao; mã cuộn cả hai chiều và nhận focus cho bàn phím.
import { CodeBlock } from "@/components/ui/code-block"
const codeSampleJson = "{\n \"name\": \"@werewolf/code-block\",\n \"type\": \"registry:ui\",\n \"private\": false,\n \"version\": 1,\n \"dependencies\": [\"@tabler/icons-react\"],\n \"registryDependencies\": [\"@werewolf/utils\", \"@werewolf/button\"]\n}"
<CodeBlock filename="package.json" language="json" code={codeSampleJson} showLineNumbers maxHeight="160px" />Nên và không nên
Nên
- Ghi tên tệp khi mã thuộc về một tệp, để người đọc biết dán vào đâu.
- Đánh dấu các dòng đã đổi hoặc được nhắc tới, và nói điều đó trong phần chữ.
- Để dòng dài cuộn ngang cho mã cần chép; thêm nút xuống dòng để đọc trên màn hình hẹp.
Không nên
- Đừng đặt CodeBlock giữa câu; dùng thẻ code cho một tên hoặc lệnh ngắn.
- Đừng chỉ dựa vào màu để phân biệt dòng; dòng được đánh dấu cần chữ đi kèm.
- Đừng thêm bộ tô màu nặng chỉ để có màu; bộ có sẵn đủ cho các ngôn ngữ thường gặp, và highlight cắm bộ khác khi thật cần.
Props
| Tên | Kiểu | Giá trị | Mặc định | Mô tả |
|---|---|---|---|---|
| code bắt buộc | string | - | - | Mã, dạng văn bản thuần. Đây là thứ nút sao chép chép đi. |
| language | string | - | - | Ngôn ngữ, như tsx, json, css, html hoặc bash. Hiện ở phần đầu và chọn ngữ pháp có sẵn. |
| filename | string | - | - | Tên tệp ở đầu phần đầu, như app/page.tsx. Nó cũng đặt tên cho vùng code. |
| showLanguage | boolean | - | true | Hiện ngôn ngữ ở phần đầu. |
| variant | enum | default | surface | plain | default | default nằm lõm trong trang hoặc card, surface nổi trên vùng lõm, plain không nền không viền, cho mã trong một panel khác. |
| size | enum | sm | md | lg | md | Cỡ chữ mã, chiều cao dòng và padding: chữ 12, 14 hoặc 16px. |
| showLineNumbers | boolean | - | false | Đánh số từng dòng. |
| startLine | number | - | 1 | Số của dòng đầu tiên, cho một đoạn trích từ giữa tệp. |
| highlightLines | number[] | - | - | Các số dòng được đánh dấu bằng nền info, đếm từ startLine. |
| wrap | boolean | - | - | Dòng dài xuống dòng thay vì cuộn ngang, khi được điều khiển. |
| defaultWrap | boolean | - | false | Trạng thái xuống dòng ban đầu khi không được điều khiển. |
| onWrapChange | (wrap: boolean) => void | - | - | Được gọi khi nút xuống dòng được nhấn. |
| showWrapButton | boolean | - | false | Hiện nút bật tắt xuống dòng. |
| showCopyButton | boolean | - | true | Hiện nút sao chép. |
| onCopy | (code: string) => void | - | - | Được gọi với mã sau khi chép xong. |
| highlight | boolean | CodeBlockHighlighter | - | true | true dùng bộ tô màu có sẵn, false tắt màu, hoặc một hàm trả về token cho từng dòng. |
| maxHeight | string | - | - | Chiều cao tối đa của phần mã, như 320px; phần thừa cuộn dọc. |
| labels | { copy?: string; copied?: string; copyFailed?: string; wrap?: string; highlighted?: string; region?: string } | - | - | Tên các nút, thông báo và chữ đọc cho dòng được đánh dấu và vùng mã. Mặc định: Copy code, Copied, Couldn't copy, Wrap lines, (highlighted), Code. Tiếng Việt: Sao chép mã, Đã sao chép, Không sao chép được, Xuống dòng, (đánh dấu), Mã. |
Cấu tạo
| Phần | Mô tả |
|---|---|
| root | figure: một panel lõm, surface hoặc plain chứa phần đầu và mã. |
| header | figcaption: tên tệp và ngôn ngữ ở đầu, các nút ở cuối, trên một đường kẻ nhạt. |
| name | Tên tệp, chữ monospace, cắt bằng dấu ba chấm. |
| label | Ngôn ngữ, như tsx, bằng chữ secondary. |
| actions | Nút xuống dòng và nút sao chép, Button icon ghost cỡ sm. Không có phần đầu thì chúng nổi ở góc trên cuối. |
| content | Thẻ pre cuộn ngang khi dòng dài. Nó nhận focus để bàn phím cuộn được. |
| line | Một dòng mã. Dòng được đánh dấu có nền info suốt chiều rộng cuộn. |
| lineNumber | Số dòng, chữ secondary, căn phải. Chuyển sang chữ info trên dòng được đánh dấu. |
Khả năng truy cập
Role: figure
| Phím | Hành động |
|---|---|
| Tab | Chuyển tới nút xuống dòng và nút sao chép, rồi tới phần mã, cuộn được bằng phím mũi tên khi dòng dài tràn ra. |
| Enter / Space | Trên nút sao chép, chép mã. Trên nút xuống dòng, bật hoặc tắt xuống dòng. |
- Có tên tệp hoặc ngôn ngữ thì figure được đặt tên bằng phần đầu, nên mã được đọc là EN `app/page.tsx tsx`.
- Nút sao chép tên EN `Copy code`. Sau khi chép, tên chuyển thành EN `Copied` trong hai giây và một vùng status thông báo.
- Nút xuống dòng là nút nhấn giữ (aria-pressed), tên EN `Wrap lines`.
- Số dòng bị ẩn khỏi trình đọc màn hình và khỏi vùng chọn, nên khi chép chỉ có mã.
- Dòng được đánh dấu hiện bằng nền info. Hãy nói ý nghĩa của nó trong phần chữ; màu không tới được mọi người đọc.
Cài đặt
npx werewolf-ui add code-blockChạy npx werewolf-ui init một lần trong app trước khi thêm component. Init cài token, thêm CSS import và luật cho agent. Add cài component này cùng các dependency và giữ nguyên theme của bạn. Xem Cài đặt để biết yêu cầu và cách cài qua registry.