# Metrics

Metric panels, accessible data tables and chart arrangements.

- Group: Website
- Import: `import { MetricsRange } from '@misoto22/folio/website'`
- Page: https://ui.misoto22.com/components/metrics/

## When to reach for it

Arrange measurements and externally rendered charts without importing chart engines.

## Best practices

### Do

- Supply localized labels, descriptive links and meaningful image alternatives.

### Don’t

- Do not put service credentials, routing logic or backend models inside presentation components.

## MetricsRange

A controlled range selector. Selection represents the data the host successfully loaded.

### Props

- `label` (required) — `string`.
- `value` (required) — `string`.
- `options` (required) — `{ value: string; label: string }[]`.
- `onChange` (required) — `(value: string) => void`.

## MetricsSection

A dashboard section without a dependency on a chart engine or a domain response.

### Props

- `title` — `ReactNode`.
- `caption` — `ReactNode`.
- `action` — `ReactNode`.
- `children` (required) — `ReactNode`.

Also accepts: `Omit<HTMLAttributes<HTMLElement>, 'title'>`.

## MetricsPanel

A labeled panel. Children may use the separately imported charts entry.

### Props

- `title` (required) — `string`.
- `caption` — `string`.
- `children` (required) — `ReactNode`.

Also accepts: `Omit<HTMLAttributes<HTMLElement>, 'title'>`.

## MetricsPanelGrid

Responsive grids share their dividers and minimum panel width.

### Props

- `columns` — `2 | 4` default `2`.

Also accepts: `HTMLAttributes<HTMLDivElement>`.

## MetricsEmptyState

An empty time series retains its plot space and tells the reader what will appear once the first observation arrives.

### Props

- `title` (required) — `ReactNode`.
- `description` (required) — `ReactNode`.

## MetricsList

Already-formatted metric rows, with a named value relation and an explicit empty state.

### Props

- `label` (required) — `string`.
- `items` (required) — `{ id: string; label: ReactNode; value: ReactNode; icon?: ReactNode }[]`.
- `empty` (required) — `string`.

## MetricValue

A supplied number with its units on the supporting type step.

### Props

- `segments` (required) — `{ text: string; unit?: boolean }[]`.

## MetricDelta

Neutral direction marks never assume an increase is good or a decrease is an error.

### Props

- `direction` (required) — `'up' | 'down' | 'steady'`.
- `children` (required) — `ReactNode`.

## LiveCount

Unknown live counts remain absent; a measured zero is a real reading.

### Props

- `value` (required) — `number | null`.
- `label` (required) — `string`.

## Example — a controlled range

```tsx
import { MetricsList, MetricsPanel, MetricsPanelGrid, MetricsRange, MetricsSection } from '@misoto22/folio/website'

<MetricsSection title="Library activity" caption="Sample data"
  action={<MetricsRange label="Period" value={range} onChange={setRange} options={[{ value: 'week', label: 'Week' }, { value: 'month', label: 'Month' }]} />}>
  <MetricsPanelGrid>
    <MetricsPanel title="Reading"><MetricsList label="Reading totals" empty="No readings" items={[
      { id: 'articles', label: 'Articles opened', value: range === 'week' ? '24' : '96' },
      { id: 'minutes', label: 'Minutes reading', value: range === 'week' ? '180' : '720' },
    ]} /></MetricsPanel>
    <MetricsPanel title="Collection"><MetricsList label="Collection totals" empty="No records" items={[
      { id: 'saved', label: 'Saved records', value: range === 'week' ? '7' : '28' },
      { id: 'notes', label: 'Notes written', value: range === 'week' ? '3' : '12' },
    ]} /></MetricsPanel>
  </MetricsPanelGrid>
</MetricsSection>
```
