# Data

Data, chart and report shapes.

- Registry name: `data` (`@candor/data`)
- 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/data

## Install

```bash
npx candor-ui add data
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/data`.

## Types

### Series

Data, chart and report shapes. A missing value is null, never 0: charts draw it as a gap, tables as a dash, and summaries say how much is missing.

```ts
{ id: string label: string /** One value per category or x position; null where there's no data. */ values: (number | null)[] }
```

### ChartState

```ts
| { kind: "ready" } | { kind: "loading" } /** Nothing to plot, and why. */ | { kind: "empty"; reason: string } /** Some of the range is missing. */ | { kind: "partial"; note: string } | { kind: "error"; reason: string }
```

### ValueFormat

```ts
"number" | "percent" | "currency" | "duration"
```

### Column

```ts
{ id: string label: string /** How to read the cell's value for sorting and display. */ value: (row: Row) => string | number | null /** Custom cell rendering; defaults to the value. */ render?: ((row: Row) => React.ReactNode) | undefined numeric?: boolean | undefined /** Hidden by default; shown via column settings. */ optional?: boolean | undefined width?: string | undefined }
```

### FilterChip

```ts
{ id: string; label: string; value: string }
```

### TreeNode

```ts
{ id: string label: string /** A short descriptor shown muted after the label, e.g. "Object" or "12 fields". */ meta?: string | undefined icon?: React.ComponentType<{ className?: string | undefined }> | undefined children?: TreeNode[] | undefined }
```

### ImportColumn

```ts
{ /** The header as it appeared in the file. */ header: string /** A few values from the column, for the person to recognise it. */ samples: string[] }
```

### TargetField

```ts
{ name: string; label: string; type: "text" | "number" | "date" | "choice" | "email" | "id"; required?: boolean | undefined }
```

### ColumnMapping

```ts
{ header: string /** The field it maps to; null = don't import this column. */ field: string | null /** How the mapping was made. */ by: "match" | "model" | "you" /** For model suggestions: how sure, 0–1. */ confidence?: number | undefined }
```

### ImportIssue

```ts
{ row: number field: string kind: "invalid" | "missing" | "duplicate" | "too-long" | "unknown-value" message: string /** The raw value as read. */ value: string /** A fix the person can accept. */ suggestion?: string | undefined }
```

### Kpi

```ts
{ label: string /** null when it couldn't be computed; `missing` says why. */ value: number | null /** The value as your server wrote it ("about $1,200"), shown instead of formatting `value`. */ valueText?: string | undefined format?: ValueFormat | undefined missing?: string | undefined /** Change vs a named period. */ delta?: { value: number; vs: string; good: "up" | "down" } | undefined trend?: 
```

### Finding

```ts
{ id: string severity: "critical" | "serious" | "warning" | "info" title: string body: string /** The evidence behind it, as short labelled items. */ evidence: { label: string; detail?: string | undefined }[] /** What to do about it, when there's a clear next step. */ action?: string | undefined }
```

### Subscore

```ts
{ label: string /** null = not computed; `needs` says what's required. */ score: number | null max: number weight?: number | undefined needs?: string | undefined }
```

## 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`.
