Files
suaveplan/openspec/changes/enterprise-react-docs/tasks.md
2026-05-27 23:29:53 +01:00

5.0 KiB

Tasks: enterprise-react-docs

Change ID: enterprise-react-docs Package: @suaveplan/react-docs Target path: react/platform/react-docs Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/docs, @suaveplan/react-translate


0. Pre-flight (non-negotiable)

  • 0.1 Confirm clean working tree (git status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in each)
  • 0.2 If any worktrees exist under .claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
  • 0.3 Confirm the package set in MANIFEST.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

1. Scaffold

  • Create directory tree. Write package.json at 0.1.0, tsconfig.json, vitest.config.ts, scripts.
  • Dependencies: @suaveplan/error workspace:^, @suaveplan/docs workspace:^, @suaveplan/react-translate workspace:^, react-markdown catalog:docs, rehype-highlight catalog:docs, remark-gfm catalog:docs, lucide-react catalog:ui, tailwind-merge catalog:ui, @opentelemetry/api catalog:observability, tslib catalog:build.

2. Error codes and types

  • Define DocsUiError; codes: DOCS_RENDER_FAILED, DOCS_LINK_UNSAFE.
  • Define all prop types: DocViewerProps, DocNavProps, DocSearchProps, OrphanReportProps, DocStatsProps, DocBreadcrumbProps, CategoryBadgeProps, DocOutlineProps.

3. Utils

  • sanitiseLink(href: string): string | null — strips javascript: URIs and protocols other than http:, https:, relative paths. Returns null for disallowed hrefs.
  • Write link-sanitiser.test.ts (≤500 lines): safe hrefs pass through, javascript URIs return null, external blocked when allowExternal=false. { timeout: 5000 }.
  • Write link-sanitiser.md.

4. Components

CategoryBadge

  • Styled chip for doc category label. Accepts category: string, variant?: 'default' | 'outline'.
  • Write test, stories (default, outline, all-categories, playground), md.

DocBreadcrumb

  • Navigation breadcrumb from DocFile path. useTranslation for "Home" / separator aria.
  • Write test, stories (default, deep-path, single, playground), md.

DocStats

  • Total/package/category/orphan counts display. OTel docs.stats.view counter.
  • Write test, stories (default, with-orphans, empty, playground), md.

OrphanReport

  • Lists orphan docs with suggested parent locations from findOrphans. useTranslation for labels. OTel docs.orphan.click counter.
  • Write test, stories (default, empty, playground), md.

DocOutline

  • TOC panel derived from markdown heading nodes with scroll-spy highlight.
  • Write test, stories (default, long-doc, no-headings, playground), md.

DocSearch

  • Live search input with keyboard-navigable dropdown. role="combobox", aria-activedescendant, aria-expanded. Accepts onSearch(query): Promise<DocFile[]>. OTel docs.search counter on submit.
  • Write doc-search.test.tsx (≤500 lines): renders results, keyboard nav (down/up/enter/escape), empty state, debounce. { timeout: 10000 }.
  • Write stories (default, loading, empty, keyboard, playground), md.

DocNav

  • Collapsible sidebar grouped by category → package. Keyboard expand/collapse (Enter/Space), arrow-key navigation between items. OTel docs.nav.expand counter.
  • Write doc-nav.test.tsx (≤500 lines): renders tree, expand/collapse, keyboard nav, active-item highlight. { timeout: 5000 }.
  • Write stories (default, all-expanded, single-category, playground), md.

DocViewer

  • GFM markdown rendered via react-markdown + rehype-highlight. Breadcrumb, category badge, skip-link, <main> landmark. Intercepts relative links via sanitiseLink → onLinkClick. OTel docs.view counter on mount.
  • Write doc-viewer.test.tsx (≤500 lines): renders markdown, code blocks highlighted, link interception fires onLinkClick, unsafe href blocked, skip-link present. { timeout: 5000 }.
  • Write stories (default, code-blocks, with-outline, empty, playground), md.

5. E2E

  • e2e/docs.spec.ts — Playwright:
    • Search for a term; select from dropdown; verify DocViewer renders the doc.
    • Click expand/collapse in DocNav; verify tree state toggles.
    • Click an orphan in OrphanReport; verify navigation fires.
    • Verify mobile viewport renders nav as collapsible drawer.

6. Verify and publish

  • bunx turbo lint typecheck test --filter=@suaveplan/react-docs — green.
  • bunx turbo test:coverage --filter=@suaveplan/react-docs — 100%.
  • bun scripts/publish.ts --package @suaveplan/react-docs.
  • Archive change folder.