# Component Taxonomy & Docs Generation Plan

> Status: **approved**, not yet executed.
> Goal: give `@42-components` a clear separation criterion so consumers
> immediately know *what to use for X*, and make `LLM.md` readable again by
> splitting it per category — driven by **co-located frontmatter** as the source
> of truth, with Storybook handling its own sidebar natively.

## 1. Separation criterion

Components are grouped by **primary user intent** — the problem the consumer is
trying to solve ("I need to capture input", "I need a transient layer", "I need
to show a dataset"). Every component belongs to **exactly one** primary
category. This mirrors how users (and AI agents) search for a component.

## 2. Taxonomy (approved)

| Category | Key | Use it when… | Components |
| --- | --- | --- | --- |
| **Inputs & Forms** | `inputs` | you capture data from the user | form, select, combobox, nested-select, choice, tags-input, slider, color-picker, date-picker, time-picker, textarea-emoji, rich-text-editor, file-dropzone (13) |
| **Overlays** | `overlays` | you need a transient layer above content | modal, drawer, popover, tooltip, dropdown, command-palette (6) |
| **Navigation** | `navigation` | you move around or structure a flow | nav, mega-menu, tabs, pagination, stepper (5) |
| **Data & Collections** | `data` | you display/manipulate sets of data | data-view, sortable-table, kanban, tree, calendar (5) |
| **Media** | `media` | you show images or people | gallery, image-viewer, avatar, avatar-group (4) |
| **Feedback & Status** | `feedback` | you communicate state/progress/an action | alert, toast, progress, skeleton, clipboard (5) |
| **Disclosure & Layout** | `disclosure` | you show/hide regions of content | accordion, carousel (2) |
| **Presentational (CSS-only)** | `presentational` | no controller, just classes | badge, breadcrumb, button, card, divider, input-label (6) |

**Total:** 40 JS controllers + 6 CSS-only = 46.

Resolved ambiguous assignments:

- `clipboard` → **Feedback** (surfaces a "copied" state).
- `calendar` → **Data & Collections** (renders/manipulates a dataset of events).
- `carousel` → **Disclosure & Layout** (shows one region at a time).
- `toast` → **Feedback** (notifications), not Overlays.

Cross-references (a component lives in one category but may be mentioned in
another): `breadcrumb` is presentational but conceptually Navigation; `calendar`
also backs `date-picker` (Inputs).

## 3. Source of truth — co-located frontmatter (no central registry)

The category lives **next to the prose it describes**, as YAML frontmatter in
each component's doc fragment. This is the conventional docs pattern
(Docusaurus/VitePress/Nextra) and avoids a second list to keep in sync with the
filesystem.

```md
---
name: tabs
category: navigation
summary: Switch between panels with one tab visible at a time
subpath: '@42/core/tabs'
deepDoc: docs/llm/tabs.md   # optional, when a detailed doc exists
---

Switch between panels…

```html
<div data-c42-tabs> … </div>
```
```

Frontmatter schema:

| Field | Required | Meaning |
| --- | --- | --- |
| `name` | yes | dir / `data-c42-` prefix (e.g. `tabs`) |
| `category` | yes | one of the taxonomy keys in §2 |
| `summary` | yes | one-line "use when" shown in the index |
| `subpath` | controllers | import path (`@42/core/tabs`); omit for presentational |
| `presentational` | css-only | `true` for CSS-only entries |
| `deepDoc` | optional | path to an existing detailed doc |

### Why not a central `registry.ts`

A central typed registry was considered and rejected for now: it duplicates the
category (also encoded in the Storybook title) and adds another file to update
per component. A registry only pays off if we later generate **all** the
"add a component" steps (package.json `exports`, `vite.config` entries,
`copy-assets.mjs`, the barrel) from one object. That is explicitly out of scope
here (§9); revisit if/when we automate the build wiring.

## 4. Storybook — native categorization

Storybook builds its sidebar from the `title` field using `/` as hierarchy, so
**no tooling is needed** for grouping. Each story sets:

```ts
title: 'Core/Navigation/Tabs'   // Core/<Category label>/<Component>
```

Optionally add CSF3 `tags: ['navigation']` for cross-cutting filtering. The
category in the title is validated against the fragment frontmatter by
`docs:check` (§5) so the two surfaces cannot drift.

## 5. `LLM.md` restructure — Option B (index + per-category files)

`LLM.md` becomes a slim **router** (~150 lines):

1. What is this / Installation
2. Universal pattern
3. Theming (colors, dark mode, token layers)
4. **Choosing a component** — generated category table (category → component →
   one-line `summary` → link to its reference section)

The full per-component reference moves into one file per category:

```
docs/llm/
  reference/
    inputs.md          # generated: index + component bodies for `inputs`
    overlays.md
    navigation.md
    data.md
    media.md
    feedback.md
    disclosure.md
    presentational.md
    _fragments/        # hand-authored bodies WITH frontmatter (source of truth)
      tabs.md
      modal.md
      …
  <name>.md            # existing deep-dives (calendar, form, kanban, …) — kept
```

### What is generated vs authored

- **Authored (human-owned):** each `_fragments/<name>.md` — frontmatter +
  the proven body template (description → HTML → TS → `Options` → `Events`).
  Existing deep dives stay as-is.
- **Generated (from fragment frontmatter):**
  - The `LLM.md` "Choosing a component" table (inside `<!-- GEN -->` markers).
  - Each `docs/llm/reference/<category>.md`: generated header + intra-file index
    + the category's fragment bodies concatenated in a stable order, linking to
    `deepDoc` when present.

## 6. Generation tooling

`scripts/generate-docs.mjs` (node + a tiny YAML/frontmatter parser, e.g.
`gray-matter`):

- `pnpm docs:generate` — (re)write generated regions:
  - `LLM.md` between `<!-- GEN:index start -->` / `<!-- GEN:index end -->`.
  - `docs/llm/reference/<category>.md` files in full.
- `pnpm docs:check` — generate to a buffer and `diff` against committed files;
  non-zero exit if stale. Wire into CI / the `build-storybook` integration check.
- Validations enforced by the generator:
  - Every `packages/core/<dir>` (excluding `shared`, `dist`, `node_modules`)
    has a `_fragments/<name>.md` with valid frontmatter, and vice-versa
    (no orphan components, no orphan fragments).
  - `category` is one of the taxonomy keys.
  - Each Storybook `title`'s category segment matches the fragment `category`.

## 7. Surfaces to update

- `LLM.md` → slim router + generated index.
- `docs/llm/reference/*` → new generated category files + authored fragments
  (migrated from the current flat `## Components` section).
- `stories/*.stories.ts` → titles to `Core/<Category>/<Name>` (+ optional `tags`).
- `README.md` → short category table.
- `AGENTS.md` → point to `docs/component-taxonomy.md`; add to the new-component
  checklist: "add `docs/llm/reference/_fragments/<name>.md` with frontmatter and
  set the story `title` category", and run `pnpm docs:generate`.

## 8. Execution phases

1. **Generator + scripts** — add `scripts/generate-docs.mjs`, the frontmatter
   parser dep, and `docs:generate` / `docs:check`.
2. **Fragments** — split the current `LLM.md` `## Components` section into
   `docs/llm/reference/_fragments/<name>.md`, adding frontmatter to each
   (mechanical move, no content loss).
3. **Generate** — produce `LLM.md` index + `docs/llm/reference/<category>.md`;
   trim `LLM.md` to the router shape.
4. **Storybook** — set story titles to `Core/<Category>/<Name>` (+ optional tags).
5. **README / AGENTS** — update tables, pointers, and the new-component checklist.
6. **Verify** — `pnpm lint`, `pnpm test`, `pnpm build-storybook`, `pnpm docs:check`,
   and a manual link/scan review of `LLM.md` + category files.

## 9. Verification & acceptance

- `pnpm docs:check` passes (generated docs in sync with fragments).
- Storybook sidebar shows `Core/<Category>/<Component>` for all JS components and
  `Presentational/<Component>` for CSS-only.
- `LLM.md` ≤ ~200 lines; each `docs/llm/reference/<category>.md` is small and
  scannable.
- No orphan components (fragments ⇄ filesystem ⇄ story titles all consistent).
- `pnpm lint && pnpm test && pnpm build-storybook` green.

## 10. Out of scope (for now)

- A central code registry, and generating `package.json` exports /
  `vite.config` entries / `copy-assets.mjs` / the barrel from one object.
- Renaming subpath exports or moving component code between packages.
- Changing the per-component doc template itself.
- Pushing to `main` (kept local by request).
