# tocSpy

> Follows the reader through a page for an "On this page" list: marks every section on screen, slides one marker over them, names the section being read and keeps it in view inside a scrolling rail.

```ts
import { tocSpy } from "@sdxc/ui/docs";
```

Watches the headings that the host's `a[href^="#"]` links point at. On every settled
scroll and resize it sets `data-active` on each link whose section is on screen
(`"lead"` on the first), moves the `[data-toc-marker]` element over them through
`--toc-marker-start` / `--toc-marker-size`, and on the closest `[data-toc]` writes the lead's
text into `[data-toc-reading]` and sets `--toc-progress` (0–1) for a progress ring. The top edge a section must pass is
the first heading's `scroll-margin-top`, so it matches where a jump to that heading lands.
A link followed inside a `<details>` closes it, so the section is not hidden under the list.

## Signature

```ts
tocSpy(): MixinDescriptor<HTMLElement>
```

## Examples

```tsx
<nav><ul mix={[tocSpy()]}><li><a href="#install">Install</a></li></ul></nav>
```

## Used with it

The events, constants and types its module publishes, each imported from `@sdxc/ui/docs` too.

### sectionsInView

The indexes of the sections on screen. A reader scrolled to the bottom of the page is
credited with the last section even when its heading never reached the top edge.

#### Signature

```ts
sectionsInView(starts: number[], viewport: { top: number; bottom: number }, atBottom: boolean): number[]
```

#### Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| `starts` | `number[]` |  |
| `viewport` | `{ top: number; bottom: number }` |  |
| `atBottom` | `boolean` |  |
