# File list

The files the work produced: each with its type, size and where it stands ("Checked", "Not yet checked"), Open for the ones the reader can show, and Download, with a menu when it comes in several formats. Files can be grouped ("Result 2", "Sources"). Nothing here is a link: open and download go through your handlers, so a URL from model output never reaches the page.

- Registry name: `file-list` (`@candor/file-list`)
- Tier: Pro. Installing it needs a Pro, Premium or Team licence key: the person runs `npx candor-ui key <key>` themselves; never ask for the key in chat or write it to a file.
- Docs: https://candor.themethodic.com/docs/file-list

## Install

```bash
npx candor-ui add file-list
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/file-list`.
It brings in: attachment-preview, button, dropdown-menu, locale, work, utils.
npm packages: lucide-react@^1.67.0.

## Example

```tsx
"use client"

import * as React from "react"
import { FileList } from "@/components/file-list"
import type { Deliverable } from "@/lib/work"

const files: Deliverable[] = [
  { id: "report", group: "Result 2", name: "Pricing review.docx", size: 48_000, state: "Checked", tone: "success", readable: true, formats: [{ id: "docx", label: "Word" }, { id: "pdf", label: "PDF" }] },
  { id: "record", group: "Result 2", name: "What proves it.pdf", size: 210_000, state: "Checked", tone: "success", formats: [{ id: "pdf", label: "PDF" }] },
  { id: "draft", group: "In progress", name: "Section 3 draft", state: "Not yet checked", tone: "attention" },
  { id: "sheet", group: "Sources", name: "revenue-by-plan.csv", mediaType: "text/csv", size: 184_000 },
]

export default function Example() {
  const [said, setSaid] = React.useState("")
  return (
    <div className="flex max-w-md flex-col gap-2">
      <FileList files={files} onOpen={(id) => setSaid(`open ${id}`)} onDownload={(id, format) => setSaid(`download ${id}${format ? ` as ${format}` : ""}`)} />
      <p className="text-xs text-muted-foreground" aria-live="polite">
        {said && `Your app would ${said}.`}
      </p>
    </div>
  )
}
```

## <FileList>

Props:

- `files: Deliverable[]`: The files, in order; a file's `group` puts it under that heading, groups in the order first seen.
- `onOpen?: ((id: string) => void) | undefined`: Adds Open to readable files; called with the file's id.
- `onDownload?: ((id: string, format?: string) => void) | undefined`: Adds Download; called with the file's id and the chosen format's id (undefined with no formats).
- `label?: string | undefined`: The list's accessible name. Defaults to "Files".
- `empty?: React.ReactNode | undefined`: Shown when there are no files. Defaults to "No files yet."
- `headingLevel?: 2 | 3 | 4 | 5 | 6 | undefined` (default `3`): The level of the group headings, to fit the page's outline. Defaults to 3.
- `className?: string | undefined`

## Strings (`fileList`)

The fixed words, English by default. Override any of them under `fileList` in `<LocaleProvider strings={{ fileList: { … } }}>`; the table is exported as `fileListStrings`.

- `label`: Files
- `none`: No files yet.
- `open`: Open
- `openName`: Open {name}
- `download`: Download
- `downloadName`: Download {name}
- `downloadAs`: Download {format}
- `downloadNameAs`: Download {name} as {format}

## Rules for using Candor UI

- Components take plain typed data. Never pass model output as HTML or render it as a link; messages are typed blocks.
- A control that can't be used says why: wrap it in `<Locked reason="…">`, don't just disable it.
- Don't show a value you don't have: leave it out (it renders as —) rather than guess. An estimate is labelled as one.
- Nothing is pre-selected in a decision a person makes, and the agent is named from your app's data, never from model output.
- Your app's words go in `LocaleProvider` (fixed strings) and `TermsProvider` (nouns); entity kinds and agent roles in `EntityKindsProvider` and `AgentRolesProvider`.
