# Artifact chip

A chip in the thread for something that lives in a panel beside it: a diff, an approval, a form, a table or a plan the agent made. Pressing it calls `onOpen`, and the app opens that thing's tab in its panel; `active` marks the chip whose tab is showing. The thing's state is a word and an icon, never colour alone: "Being prepared", "Waiting for you", "Applied", "Rejected" or "Failed". Set "applied" only from the settled outcome, never on the person's press. The title is the model's text, drawn as text. Screen readers hear the kind before the title ("Diff: Raise the refund limit"): Candor's word for a kind it knows, or the app's own with `kindLabel`.

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

## Install

```bash
npx candor-ui add artifact-chip
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/artifact-chip`.
It brings in: badge, bidi, locale, status, tokens, utils.
npm packages: lucide-react@^1.67.0.

## Example

```tsx
"use client"

import * as React from "react"
import { ArtifactChip } from "@/components/candor/artifact-chip"

// A kind Candor has no word for ("chart") is named by the app with kindLabel, so it is read "Chart: …".
const artifacts: { id: string; kind: string; kindLabel?: string; title: string; state: "pending" | "open" | "applied" | "rejected" }[] = [
  { id: "a1", kind: "diff", title: "Raise the refund limit to £500", state: "open" },
  { id: "a2", kind: "approval", title: "Refund three duplicate charges", state: "applied" },
  { id: "a3", kind: "table", title: "Orders charged twice in October", state: "pending" },
  { id: "a4", kind: "plan", title: "Move the team to the new rota", state: "rejected" },
  { id: "a5", kind: "chart", kindLabel: "Chart", title: "Refunds by week", state: "open" },
]

export default function Example() {
  const [showing, setShowing] = React.useState<string>("a1")
  return (
    <div className="flex max-w-lg flex-col items-start gap-2">
      {artifacts.map((a) => (
        <ArtifactChip key={a.id} kind={a.kind} kindLabel={a.kindLabel} title={a.title} state={a.state} active={showing === a.id} onOpen={() => setShowing(a.id)} />
      ))}
      <p className="text-xs text-muted-foreground">The panel would show {artifacts.find((a) => a.id === showing)?.title}.</p>
    </div>
  )
}
```

## <ArtifactChip>

Props:

- `kind: string`: What it is: "diff", "approval", "form", "table" and "plan" have their own icon and word; any other kind a generic icon.
- `title: string`: Its title, often the agent's ("Raise the refund limit").
- `state: ArtifactState`: Where it stands: "pending" while the agent prepares it, "open" when it waits for the person, then "applied", "rejected" or "failed". "applied" only once the outcome has settled. The chip carries it as `data-artifact-state` for your styles (not `data-state`, which a Radix app's `[data-state=open]` styles would match).
- `onOpen: () => void`: Opens its tab in the app's panel.
- `active?: boolean | undefined`: Its tab is the one showing in the panel (`aria-current`).
- `kindLabel?: string | undefined`: The app's word for its kind, read before the title as "{kindLabel}:" for any kind; for one of Candor's kinds it replaces Candor's word. Left out, a kind Candor doesn't know is read with no kind word. The app's word, not the model's; drawn as text either way. The icon doesn't change.
- `className?: string | undefined`: Classes, merged with Candor's.

## Strings (`artifactChip`)

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

- `opens`: Opens in the panel
- `pending`: Being prepared
- `open`: Waiting for you
- `applied`: Applied
- `rejected`: Rejected
- `failed`: Failed
- `kind`: {kind}:
- `diff`: Diff
- `approval`: Approval
- `form`: Form
- `table`: Table
- `plan`: Plan

## Motion

- **tint** (tint): The chip's border darkens when the pointer is over it, and a ring fades in when it takes keyboard focus. Its state badge changes colour with its word when the state changes.

Set with `--cd-motion-artifact-chip-<moment>-*` in your brand file; the families are in the design reference.

## 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`: its fixed strings in `strings`, its nouns in `nouns`; entity kinds and agent roles in `EntityKindsProvider` and `AgentRolesProvider`.
