# Format elapsed

A measured span of time in the locale: "4.2s" under ten seconds, "42s" under a minute, then "2m 5s". Rounded down, so it never reads longer than what was measured. In a component, pass `useFormat()` from LocaleProvider. This module has no `"use client"`, so a server component or a server-side replay can call it too, with a format of its own: `formatElapsed(ms, { tag: "en-GB", number: (n, o) => new Intl.NumberFormat("en-GB", o).format(n) })`.

- Registry name: `format-elapsed` (`@candor/format-elapsed`)
- Tier: Free (MIT). No licence key needed.
- Docs: https://candor.themethodic.com/docs/format-elapsed

## Install

```bash
npx candor-ui add format-elapsed
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/format-elapsed`.
It brings in: tokens.

## Example

```tsx
"use client"

import { useFormat } from "@/components/candor/locale"
import { formatElapsed } from "@/lib/candor/format-elapsed"

// Measured spans, as a run's timings report them. On the server, pass a format of your own instead of useFormat().
const spans = [
  { label: "Read the ticket", ms: 4_290 },
  { label: "Searched the help centre", ms: 42_900 },
  { label: "Drafted the reply", ms: 125_000 },
]

export default function Example() {
  const format = useFormat()
  return (
    <dl className="grid max-w-sm grid-cols-[1fr_auto] gap-x-6 gap-y-1 text-sm">
      {spans.map((s) => (
        <div key={s.label} className="contents">
          <dt className="text-muted-foreground">{s.label}</dt>
          <dd className="text-end tabular-nums">{formatElapsed(s.ms, format)}</dd>
        </div>
      ))}
    </dl>
  )
}
```

## Functions

### formatElapsed

```ts
formatElapsed(ms: number, format: ElapsedFormat)
```

## Types

### ElapsedFormat

How a measured span reads: the locale it's in and its number format, as LocaleProvider's `useFormat()` gives them.

```ts
{
  /** The BCP 47 tag the list of units is joined in; undefined is the runtime's own locale. */
  tag: string | undefined;
  /** A number in the locale, with Intl.NumberFormat's options. */
  number: (n: number, options?: Intl.NumberFormatOptions) => string;
}
```

## Types from other items

The props above take these. Each is defined by another item; import it from the path shown.

### NumberFormat

Import: `import type { NumberFormat } from "@/components/candor/scale"` (item `scale`, https://candor.themethodic.com/docs/scale.md)

Writes a number in full, in the locale; charts pass `useFormat().number` so server and browser agree.

```ts
(n: number, options?: Intl.NumberFormatOptions) => string
```

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