# PrettyCode

Syntax-highlighted code block. Prism-powered, dark-by-default surface.

## Why dark by default

PrettyCode renders on a fixed dark surface (`#0d1117` + `vsDark` palette)
regardless of the host theme — the same convention as GitHub, VSCode,
ChatGPT, Slack. Syntax highlighting ships its own contrast model
(keyword / string / number / comment) that flattens to low-contrast
pastels when forced onto a light UI surface.

The surface is intentionally **not** a semantic token. Semantic tokens
(`--primary`, `--accent`, `--card`) describe UI affordances; code
display is data, not UI.

## Structure

```
PrettyCode/
├── PrettyCode.client.tsx       # Main component (Highlight + dark surface)
├── registerPrismLanguages.ts   # Lazy-load extra grammars (bash, ruby, java, php)
├── index.tsx                   # Public re-export
└── lazy.tsx                    # Lazy-loaded export
```

## Usage

```tsx
import { PrettyCode } from '@djangocfg/ui-tools/code';

<PrettyCode data={sourceCode} language="typescript" />

// Inline snippet (used in markdown rendering)
<PrettyCode data={`const x = 1`} language="ts" inline />

// Capped at 50 visible lines, scrolls if longer
<PrettyCode data={longBlob} language="json" maxLines={50} />

// Chrome-less variant — embed inside another scroll container
<PrettyCode data={src} language="bash" variant="plain" />
```

## Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `data` | `string \| object` | — | Code string. Objects are `JSON.stringify`d. |
| `language` | `Language` | — | Prism language id. Unknown → plain text. |
| `mode` | `'dark' \| 'light'` | `'dark'` | Palette override. Default is always dark (see "Why dark"). |
| `inline` | `boolean` | `false` | Render as inline `<code>` (no card / toolbar). |
| `variant` | `'card' \| 'plain'` | `'card'` | `plain` strips border, background, and toolbar. |
| `isCompact` | `boolean` | `false` | 12px font instead of 14px. |
| `maxLines` | `number` | `undefined` | When set, block scrolls past this many lines. |
| `customBg` | `string` | — | Tailwind class to override the dark surface. |
| `scrollIsolation` | `boolean` | `true` | Block scroll capture until clicked (long snippets). |
| `className` | `string` | — | Extra classes on the wrapper. |

## When to override `mode`

Almost never. The dark default is correct for ~all cases. Pass
`mode="light"` only for deliberate light-on-light renders (e.g. PDF
export targeting a printed page). The surface falls back to
`bg-card` semantic token in that mode.

## Supported languages

Out of the box: `javascript`, `typescript`, `python`, `json`, `css`,
`markup` (html/xml), `sql`, `yaml`, `markdown`, `go`.

Lazy-loaded on first use: `bash`/`shell`, `ruby`, `java`, `php`.
Lazy load is tracked through `useEnsurePrismLanguages()` — the
component re-renders once the grammar resolves.

Unknown languages fall back to plain text (no highlighting, no error).

## Storybook

`UI Tools / Code / PrettyCode` — `Playground`, `TypeScript`, `Json`,
`Python`, `Bash`, `Sql`, `Yaml`, `LongFileWithScroll`, `Inline`,
`Compact`, `LightMode`, `PlainVariant`.
