Getting Started
Components
- Agent Status
- Agent Template Card
- API Key Card
- Audio Player
- Bar Visualizer
- Channel Status Card
- Chat Composer
- Code Editor
- Condition Builder
- Confirm Dialog
- Conversation
- Conversation Bar
- Dataset Card
- Document Status Badge
- Extraction Strategy Select
- File Icon
- File Upload
- Indexing Progress
- Live Waveform
- Matrix
- Message
- Mic Selector
- Model Diff View
- Model Selector
- Model Type Filter
- Node Catalog
- Option Editor
- Orb
- Output Variables View
- Package Card
- Prompt Editor
- Provider Status Card
- Radio Card
- Resource Card
- Resource Sidebar
- Response
- Run Node List
- Scrub Bar
- Segment Card
- Shimmering Text
- Speech Input
- Token Trend Chart
- Tool Call Card
- Transcript Viewer
- Usage Stat Card
- Variable Binding Editor
- Variable Selector
- Voice Button
- Voice Picker
- Waveform
- Workflow Node Card
- Workspace Selector
Workflow transform
12345678910
"use client"
import { useState } from "react"
import {
CodeEditor,
type CodeEditorLanguage,
} from "@/components/ui/code-editor"
const initialCode = `export async function run(input) {
const records = await zgi.dataset.query(input.datasetId)
return records
.filter((record) => record.score > 0.82)
.map((record) => ({
id: record.id,
summary: record.summary,
}))
}`
export function CodeEditorDemo() {
const [value, setValue] = useState(initialCode)
const [language, setLanguage] = useState<CodeEditorLanguage>("typescript")
return (
<CodeEditor
value={value}
onValueChange={setValue}
language={language}
onLanguageChange={setLanguage}
title="Workflow transform"
className="w-full max-w-2xl"
/>
)
}
Installation
pnpm dlx shadcn@latest add https://ui.zgi.ai/r/code-editor.jsonpnpm dlx shadcn@latest add https://ui.zgi.ai/r/code-editor.json
yarn dlx shadcn@latest add https://ui.zgi.ai/r/code-editor.jsonComponent
"use client"
import * as React from "react"
import { CheckIcon, CopyIcon } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
export type CodeEditorLanguage =
| "javascript"
| "typescript"
| "python"
| "json"
| "sql"
export interface CodeEditorProps
extends Omit<
React.ComponentProps<"textarea">,
"onChange" | "title" | "value"
> {
value: string
onValueChange?: (value: string) => void
language?: CodeEditorLanguage
onLanguageChange?: (language: CodeEditorLanguage) => void
languages?: CodeEditorLanguage[]
title?: React.ReactNode
showCopyButton?: boolean
showLanguageSelector?: boolean
editorClassName?: string
}
const languageLabels: Record<CodeEditorLanguage, string> = {
javascript: "JavaScript",
typescript: "TypeScript",
python: "Python",
json: "JSON",
sql: "SQL",
}
export function CodeEditor({
value,
onValueChange,
language = "typescript",
onLanguageChange,
languages = ["typescript", "javascript", "python", "json", "sql"],
title = "Code",
showCopyButton = true,
showLanguageSelector = true,
readOnly,
disabled,
className,
editorClassName,
...props
}: CodeEditorProps) {
const [copied, setCopied] = React.useState(false)
const lines = React.useMemo(() => value.split("\n"), [value])
async function copyCode() {
await navigator.clipboard.writeText(value)
setCopied(true)
window.setTimeout(() => setCopied(false), 1200)
}
return (
<div
className={cn(
"border-border bg-card text-card-foreground overflow-hidden rounded-lg border shadow-sm",
className
)}
>
<div className="border-border bg-muted/30 flex min-h-11 items-center justify-between gap-3 border-b px-3">
<div className="min-w-0 text-sm font-medium">{title}</div>
<div className="flex shrink-0 items-center gap-2">
{showLanguageSelector ? (
<Select
value={language}
onValueChange={(next) =>
onLanguageChange?.(next as CodeEditorLanguage)
}
disabled={disabled || readOnly}
>
<SelectTrigger className="h-8 w-34 rounded-md text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
{languages.map((item) => (
<SelectItem key={item} value={item}>
{languageLabels[item]}
</SelectItem>
))}
</SelectContent>
</Select>
) : null}
{showCopyButton ? (
<Button
type="button"
variant="ghost"
size="icon"
className="size-8 rounded-md"
onClick={copyCode}
aria-label="Copy code"
>
{copied ? (
<CheckIcon className="size-4" />
) : (
<CopyIcon className="size-4" />
)}
</Button>
) : null}
</div>
</div>
<div className="grid grid-cols-[auto_minmax(0,1fr)]">
<pre
aria-hidden="true"
className="text-muted-foreground border-border bg-muted/20 min-w-10 border-r py-3 pr-3 pl-4 text-right font-mono text-xs leading-6 select-none"
>
{lines.map((_, index) => (
<span key={index} className="block">
{index + 1}
</span>
))}
</pre>
<textarea
value={value}
onChange={(event) => onValueChange?.(event.target.value)}
readOnly={readOnly}
disabled={disabled}
spellCheck={false}
className={cn(
"text-foreground min-h-72 w-full resize-y bg-transparent p-3 font-mono text-sm leading-6 outline-none",
"placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
editorClassName
)}
{...props}
/>
</div>
</div>
)
}
Usage
import { CodeEditor } from "@/components/ui/code-editor"
export function Example() {
return (
<CodeEditor
value="const result = input"
language="typescript"
onValueChange={console.log}
/>
)
}Props
| Prop | Type | Default |
|---|---|---|
| value | string | required |
| onValueChange | (value: string) => void | - |
| language | CodeEditorLanguage | "typescript" |
| onLanguageChange | (language) => void | - |
| showCopyButton | boolean | true |
| showLanguageSelector | boolean | true |
Deploy and Scale Agents with ZGI
ZGI delivers the infrastructure and developer experience you need to ship reliable audio & agent applications at scale.
Talk to an expert