FileTabs

import { FileTabs } from '@hanzo/ui/agents'

Editing

Open files as tabs over the editor; an edit marks its tab until the host saves it.

1 2 3 4
export function Editing() {
const [files, setFiles] = useState<OpenFile[]>([
{ path: 'src/app.tsx', content: 'export function App() {\n return <h1>MEGA Shop</h1>\n}\n' },
{ path: 'README.md', content: '# MEGA Shop\n' },
{ path: 'public/hero.png', error: 'A binary file — open it from the preview.' },
])
const [shown, setShown] = useState<string | null>('src/app.tsx')
return (
<YStack width="100%" maxW={640} height={280} borderWidth={1} borderColor="$borderColor" rounded="$4" overflow="hidden">
<FileTabs files={files} value={shown} onSelect={setShown} onClose={(path) => setFiles((all) => all.filter((f) => f.path !== path))} onChange={(path, content) => setFiles((all) => all.map((f) => (f.path === path ? { ...f, content, dirty: true } : f))) } />
</YStack>
)
}

Read-only

No `onChange`, so the field shows the file and takes no edits.

1 2
export function ReadOnly() {
return (
<YStack width="100%" maxW={640} height={200} borderWidth={1} borderColor="$borderColor" rounded="$4" overflow="hidden">
<FileTabs files={[{ path: 'go.mod', content: 'module widgets\n' }]} value="go.mod" onSelect={() => {}} />
</YStack>
)
}

Types

export interface OpenFile {
path: string
/** The text. Absent while it is being read. */
content?: string
/** Why it cannot be shown — too large, binary, unreadable. */
error?: string
/** Changed since it was opened. */
dirty?: boolean
/** This file may not be edited, whatever the tabs allow. */
readOnly?: boolean
}
export interface FileTabsProps extends Col {
files: readonly OpenFile[]
/** The path of the shown file. */
value: string | null
onSelect: (path: string) => void
/** Omit to make tabs unclosable. */
onClose?: (path: string) => void
/** Omit to make every file read-only. */
onChange?: (path: string, content: string) => void
/** Drawn when nothing is open. */
empty?: ReactNode
}

Exports

FileTabstype FileTabsPropstype OpenFile