From 595e094647ee34b3d662be09b3646e452abcb685 Mon Sep 17 00:00:00 2001 From: Nicholas Petrasek Date: Wed, 30 Sep 2026 21:34:38 +0200 Subject: [PATCH] chore: clean release documentation and patch development tooling --- .../v5-stable-promotion-implementation.md | 481 --------------- .../plans/2026-09-03-device-lab.md | 566 ------------------ ...26-09-04-adoption-conversion-foundation.md | 323 ---------- .../plans/2026-09-04-example-workbench.md | 458 -------------- .../specs/2026-09-03-device-lab-design.md | 187 ------ .../2026-09-04-adoption-campaign-design.md | 242 -------- .../2026-09-04-example-workbench-design.md | 203 ------- package-lock.json | 98 +-- package.json | 2 +- 9 files changed, 50 insertions(+), 2510 deletions(-) delete mode 100644 docs/roadmap/v5-stable-promotion-implementation.md delete mode 100644 docs/superpowers/plans/2026-09-03-device-lab.md delete mode 100644 docs/superpowers/plans/2026-09-04-adoption-conversion-foundation.md delete mode 100644 docs/superpowers/plans/2026-09-04-example-workbench.md delete mode 100644 docs/superpowers/specs/2026-09-03-device-lab-design.md delete mode 100644 docs/superpowers/specs/2026-09-04-adoption-campaign-design.md delete mode 100644 docs/superpowers/specs/2026-09-04-example-workbench-design.md diff --git a/docs/roadmap/v5-stable-promotion-implementation.md b/docs/roadmap/v5-stable-promotion-implementation.md deleted file mode 100644 index 447b4093..00000000 --- a/docs/roadmap/v5-stable-promotion-implementation.md +++ /dev/null @@ -1,481 +0,0 @@ -# Version 5 Stable Promotion Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Promote the reviewed version 5 codebase to `main`, publish `5.0.0` on npm's `latest` channel, and expose accurate release status on the production website. - -**Architecture:** Work moves through protected stages: stable preparation on `v5`, code-line promotion to `main`, production sign-off, trusted publication, and a post-publication website update. Release presentation uses the package version plus an explicit set of publicly verified versions, preventing previews from claiming an unpublished package exists. - -**Tech Stack:** Git worktrees, GitHub pull requests and Actions, npm trusted publishing with OIDC, React 19, TypeScript, Vitest, Playwright, Next.js, Vercel. - -**Spec:** `docs/roadmap/v5-stable-promotion-design.md` - -## Global Constraints - -- Never push directly to `v5` or `main`; repository changes land through reviewed pull requests. -- Publish `5.0.0` only from the exact signed-off `main` commit through `.github/workflows/release.yml` with channel `latest`. -- Never overwrite an npm version or Git tag; keep `next` on `5.0.0-alpha.0` unless separately authorized. -- Do not claim `5.0.0` is available before the public npm registry confirms it. -- Keep repository and release text free of automation or assistant attribution. -- Require Node.js 24, React 19, all release gates, every configured browser project, and the protected `npm` environment. - ---- - -### Task 1: Synchronize protected-branch ancestry - -**Files:** - -- Resolve if conflicted: `package-lock.json` -- Verify: version 5 source, package metadata, and workflows - -**Interfaces:** - -- Consumes: current `origin/v5` and `origin/main`. -- Produces: a preparation branch containing both histories and the version 5 dependency graph. - -- [ ] **Step 1: Refresh and inspect branch tips** - -```bash -git fetch origin --prune -git log -1 --oneline origin/v5 -git log -1 --oneline origin/main -git status --short --branch -``` - -Expected: clean `release/v5-stable-preparation`, based on `origin/v5`. - -- [ ] **Step 2: Stage the ancestry merge** - -```bash -git merge --no-ff --no-commit origin/main -``` - -Expected: a clean staged merge or conflicts only in independently changed files. Inspect before committing. - -- [ ] **Step 3: Retain and regenerate the v5 lockfile if conflicted** - -```bash -git checkout --ours package-lock.json -npm install --package-lock-only --ignore-scripts -git add package-lock.json -git diff --name-only --diff-filter=U -git diff --cached --stat -``` - -Expected: no unresolved paths, no restored v4 sources, and v5 dependencies remain authoritative. - -- [ ] **Step 4: Verify and commit the synchronized tree** - -```bash -npm ci -npm test -npm run typecheck -git commit -m "chore: synchronize stable release history" -``` - -Expected: 122 unit tests and TypeScript pass before the merge commit. - ---- - -### Task 2: Represent prepared stable releases truthfully - -**Files:** - -- Modify: `website/content/release.test.ts` -- Modify: `website/content/release.ts` -- Modify: `website/components/QuickStart.tsx` -- Modify: `website/components/LaunchPath.tsx` -- Modify: `website/content/learn/installation.tsx` -- Modify: `e2e/website/docs.spec.ts` - -**Interfaces:** - -- Consumes: `getReleasePresentation(version: string)` and `buildEvidence.version`. -- Produces: exact-version `published` state independent of prerelease status. - -- [ ] **Step 1: Write failing state tests** - -```ts -test('prepared stable releases use latest without claiming publication', () => { - expect(getReleasePresentation('5.0.0')).toEqual({ - channel: 'latest', - installCommand: 'npm install @nipe-solutions/react-spring-bottom-sheet', - prerelease: false, - published: false, - }) -}) - -test('published stable releases remain available', () => { - expect(getReleasePresentation('4.1.0').published).toBe(true) -}) -``` - -- [ ] **Step 2: Verify the test fails for the existing stable default** - -```bash -npm run test:unit -- website/content/release.test.ts -``` - -Expected: FAIL because every stable version currently reports `published: true`. - -- [ ] **Step 3: Implement explicit public-version state** - -Use: - -```ts -const publishedVersions = new Set(['4.1.0', '5.0.0-alpha.0']) -``` - -and return `published: publishedVersions.has(version)`. - -- [ ] **Step 4: Update component branches** - -Use `!release.published` for qualifiers in `QuickStart` and `LaunchPath`. In `InstallationGuide`, render unpublished copy as: - -```tsx -<> - Prepared release: version {buildEvidence.version} is not - published yet. After publication, it will be available from npm's{' '} - {release.channel} tag. - -``` - -Keep published prerelease copy separate, and label every unpublished install command `After publication`. - -- [ ] **Step 5: Extend rendered-state expectations** - -In `e2e/website/docs.spec.ts`, derive `release` with `getReleasePresentation(packageVersion)` and assert: - -```ts -await expect(page.getByText('Prepared release', { exact: true })).toHaveCount( - release.published ? 0 : 1, -) -await expect( - page.getByText('is not published yet', { exact: false }), -).toHaveCount(release.published ? 0 : 1) -``` - -- [ ] **Step 6: Verify and commit** - -```bash -npm run test:unit -- website/content/release.test.ts -npm run test:website -npm run typecheck -npm run lint -git add website e2e/website/docs.spec.ts -git commit -m "fix: distinguish prepared stable releases" -``` - ---- - -### Task 3: Prepare immutable `5.0.0` metadata and evidence - -**Files:** - -- Modify: `package.json`, `package-lock.json`, `CHANGELOG.md` -- Regenerate: `website/content/evidence.ts` -- Create: `docs/releases/v5.0.0-signoff.md` - -**Interfaces:** - -- Consumes: Task 2 release state and `docs/releases/v5-alpha.0-signoff.md`. -- Produces: an unpublished `5.0.0` candidate with explicit remaining gates. - -- [ ] **Step 1: Change metadata without tagging** - -```bash -npm version 5.0.0 --no-git-tag-version -node scripts/write-website-evidence.mjs -``` - -- [ ] **Step 2: Finalize the changelog** - -Use this first heading: - -```markdown -## [5.0.0](https://github.com/NIPE-Solutions/react-spring-bottom-sheet/compare/4.1.0...v5.0.0) (2026-09-03) -``` - -Replace alpha-oriented introductory text with stable React 19 redesign and migration guidance. Preserve Added, Changed, and Removed details. - -- [ ] **Step 3: Create the stable sign-off record** - -Create `docs/releases/v5.0.0-signoff.md` recording the alpha VoiceOver, keyboard, physical iOS, and physical Android evidence as carried forward because post-alpha changes do not alter runtime behavior. Add unchecked entries for complete stable automation, GitHub browser checks, exact packed consumers, production deployment, and external publishing protection. State that publication remains blocked until every item is complete. - -- [ ] **Step 4: Verify metadata and prepared rendering** - -```bash -node -e "const p=require('./package.json'); const l=require('./package-lock.json'); if (p.version !== '5.0.0' || l.version !== p.version || l.packages[''].version !== p.version) process.exit(1)" -npm ci -npm run build:website -npm run test:website:e2e -- e2e/website/docs.spec.ts e2e/website/home.spec.ts --project=chromium -``` - -Expected: `5.0.0` renders with the default install command and unpublished qualifiers. - -- [ ] **Step 5: Commit the candidate** - -```bash -git add package.json package-lock.json CHANGELOG.md website/content/evidence.ts docs/releases/v5.0.0-signoff.md -git commit -m "chore: prepare version 5.0.0" -``` - ---- - -### Task 4: Verify and open the preparation PR into `v5` - -**Files:** - -- Modify after evidence: `docs/releases/v5.0.0-signoff.md` -- Review: `origin/v5...HEAD` - -**Interfaces:** - -- Consumes: prepared candidate. -- Produces: reviewed preparation PR with reproducible evidence. - -- [ ] **Step 1: Run every local gate** - -```bash -npm ci -npm run release:check -npm run test:e2e -npm run test:website:e2e -npm audit --json -``` - -Expected: every browser project passes; production advisories are blocking and development advisories are explicitly triaged. - -- [ ] **Step 2: Record local evidence and commit** - -Mark local readiness and packed-consumer evidence complete, retaining GitHub and post-promotion items unchecked. Then: - -```bash -git add docs/releases/v5.0.0-signoff.md -git commit -m "docs: record version 5 stable candidate evidence" -``` - -- [ ] **Step 3: Obtain independent review** - -Review `origin/v5...HEAD` against the design and plan. Fix every Critical or Important finding test-first and repeat review until approved. - -- [ ] **Step 4: Run final verification on the reviewed commit** - -```bash -npm run release:check -npm run test:e2e -npm run test:website:e2e -actionlint .github/workflows/ci.yml .github/workflows/release.yml -git diff --check origin/v5...HEAD -``` - -- [ ] **Step 5: Push and open the PR** - -```bash -git push -u origin release/v5-stable-preparation -gh pr create --base v5 --head release/v5-stable-preparation --title "chore: prepare version 5 stable release" --body-file /tmp/v5-stable-preparation-pr.md -``` - -The body summarizes ancestry, metadata, release copy, evidence, verification, and advisory triage without claiming publication. Wait for quality, all browser jobs, and Vercel; ask the maintainer to merge. - ---- - -### Task 5: Promote `v5` to protected `main` - -**Files:** None; this task promotes the reviewed tree. - -**Interfaces:** - -- Consumes: merged stable preparation on `v5`. -- Produces: version 5 on `main`. - -- [ ] **Step 1: Confirm merge and ancestry** - -```bash -git fetch origin --prune -PREPARATION_PR=$(gh pr list --state merged --head release/v5-stable-preparation --base v5 --json number --jq '.[0].number') -test -n "$PREPARATION_PR" -gh pr view "$PREPARATION_PR" --json state,mergeCommit -git merge-base --is-ancestor origin/main origin/v5 -``` - -- [ ] **Step 2: Open the promotion PR** - -```bash -gh pr create --base main --head v5 --title "feat: release version 5" --body-file /tmp/v5-promotion-pr.md -``` - -The body identifies the breaking React 19 release, migration path, evidence, prepared npm state, and post-merge release sequence. Wait for required checks and Vercel; ask the maintainer to merge. Do not publish yet. - ---- - -### Task 6: Verify production and land stable sign-off - -**Files:** - -- Modify on a new branch from `main`: `docs/releases/v5.0.0-signoff.md` - -**Interfaces:** - -- Consumes: promoted production deployment and external configuration. -- Produces: exact signed-off `main` commit eligible for publication. - -- [ ] **Step 1: Create an isolated sign-off worktree** - -```bash -git fetch origin --prune -git worktree add .worktrees/release-v5-stable-signoff -b release/v5-stable-signoff origin/main -``` - -- [ ] **Step 2: Verify production** - -Check successful responses and content for `/`, `/docs/installation/`, `/docs/api/`, `/examples/basic/`, `/examples/custom-portal/`, `/robots.txt`, `/sitemap.xml`, and `/opengraph-image`. Confirm rendered `5.0.0`, prepared-not-published wording, and representative sheet interaction. - -- [ ] **Step 3: Verify external protection** - -Confirm npm trusted publishing targets this repository and release workflow. Confirm the GitHub `npm` environment restricts branches to `main` and `v5`, retains the maintainer reviewer, disallows admin bypass, and permits the configured solo-maintainer self-review exception. - -- [ ] **Step 4: Complete and land sign-off** - -Mark GitHub checks, production, and external protection complete with dates and precise outcomes. Then: - -```bash -npm ci -npm run release:check -git add docs/releases/v5.0.0-signoff.md -git commit -m "docs: record version 5 stable sign-off" -git push -u origin release/v5-stable-signoff -gh pr create --base main --head release/v5-stable-signoff --title "docs: record version 5 stable sign-off" --body-file /tmp/v5-stable-signoff-pr.md -``` - -Wait for checks and ask the maintainer to merge. Do not publish from the branch. - ---- - -### Task 7: Publish and verify stable `5.0.0` - -**Files:** None during publication. - -**Interfaces:** - -- Consumes: exact signed-off `origin/main` and explicit maintainer authorization. -- Produces: npm `latest` `5.0.0` and GitHub release `v5.0.0`. - -- [ ] **Step 1: Confirm immutable preconditions** - -```bash -git fetch origin --prune -npm view @nipe-solutions/react-spring-bottom-sheet@5.0.0 version -npm view @nipe-solutions/react-spring-bottom-sheet dist-tags --json -``` - -Expected: exact version is absent, `latest` is `4.1.0`, and `next` is `5.0.0-alpha.0`. - -- [ ] **Step 2: Dispatch the protected workflow** - -```bash -gh workflow run Release --ref main -f version=5.0.0 -f channel=latest -f "confirmation=publish 5.0.0 with latest" -``` - -Resolve its run ID and prove its `headSha` equals `origin/main`. Wait for verification jobs, then approve the protected `npm` deployment without bypassing failures. - -- [ ] **Step 3: Verify registry and GitHub outputs** - -```bash -npm view @nipe-solutions/react-spring-bottom-sheet@latest version -npm view @nipe-solutions/react-spring-bottom-sheet@next version -gh release view v5.0.0 --json tagName,targetCommitish,isPrerelease,isDraft,publishedAt,url -``` - -Expected: `latest` is `5.0.0`, `next` remains the alpha, and `v5.0.0` is a public non-prerelease targeting the workflow commit. Verify npm provenance and a temporary clean React 19 consumer covering ESM, CommonJS, TypeScript, and stylesheet exports. - -- [ ] **Step 4: Recover without republishing if necessary** - -If npm accepted `5.0.0` before a later step failed, never rerun publication. Repair only missing verification or GitHub release state from the immutable commit. - ---- - -### Task 8: Mark `5.0.0` available on the website - -**Files:** - -- Modify on a new branch from `main`: `website/content/release.test.ts` -- Modify: `website/content/release.ts` - -**Interfaces:** - -- Consumes: independently verified npm `latest` `5.0.0`. -- Produces: public stable install presentation without qualifiers. - -- [ ] **Step 1: Create an isolated website worktree** - -```bash -git fetch origin --prune -git worktree add .worktrees/docs-v5-stable-available -b docs/v5-stable-available origin/main -``` - -- [ ] **Step 2: Write and observe the failing test** - -```ts -expect(getReleasePresentation('5.0.0').published).toBe(true) -``` - -```bash -npm run test:unit -- website/content/release.test.ts -``` - -Expected: FAIL because `5.0.0` is not in the public-version set. - -- [ ] **Step 3: Add the verified version and run rendered checks** - -Add `'5.0.0'` to `publishedVersions`, then run: - -```bash -npm run test:unit -- website/content/release.test.ts -npm run test:website -npm run build:website -npm run test:website:e2e -- e2e/website/docs.spec.ts e2e/website/home.spec.ts --project=chromium -``` - -Expected: stable install copy has no prepared-release qualifier. - -- [ ] **Step 4: Commit, review, and open the website PR** - -```bash -git add website/content/release.ts website/content/release.test.ts -git commit -m "docs: mark version 5 as stable" -git push -u origin docs/v5-stable-available -gh pr create --base main --head docs/v5-stable-available --title "docs: mark version 5 as stable" --body-file /tmp/v5-stable-available-pr.md -``` - -Obtain independent review, wait for GitHub and Vercel checks, and ask the maintainer to merge. - ---- - -### Task 9: Close the promotion program - -**Files:** None unless a defect requires its own focused PR. - -**Interfaces:** - -- Consumes: merged website state and verified releases. -- Produces: final evidence and clean owned workspaces. - -- [ ] **Step 1: Verify final external state** - -```bash -git fetch origin --prune -npm view @nipe-solutions/react-spring-bottom-sheet dist-tags --json -gh release view v5.0.0 --json isPrerelease,isDraft,publishedAt,url -gh pr list --state open --limit 20 -``` - -Confirm the production site renders `5.0.0` as available and representative documentation, examples, legal pages, and sheets work. - -- [ ] **Step 2: Clean only owned merged workspaces** - -For each promotion worktree, require clean status and prove its commit is an ancestor of its protected target before removal. Delete its merged local branch. Leave `.worktrees/v5-styling` and unrelated workspaces untouched. - -- [ ] **Step 3: Report exact completion evidence** - -Report npm tags, GitHub release URL, production domain, merged PRs, tested browser projects, clean-consumer result, and any intentionally retained branch. diff --git a/docs/superpowers/plans/2026-09-03-device-lab.md b/docs/superpowers/plans/2026-09-03-device-lab.md deleted file mode 100644 index f9c0fa96..00000000 --- a/docs/superpowers/plans/2026-09-03-device-lab.md +++ /dev/null @@ -1,566 +0,0 @@ -# Interactive Device Lab Implementation Plan - -**Goal:** Present every recipe in a shareable phone or tablet viewport and render build-time highlighted source from the exact runnable component file. - -**Architecture:** Normal pages move under a route group that owns the site chrome, while minimal same-origin embed pages use a separate route group. A client-side device lab changes URL-backed presets and animates a persistent iframe; server-only source loading and Shiki tokenization keep the displayed code accurate without shipping a highlighter. - -**Tech stack:** Next.js 16 App Router/static export, React 19, TypeScript 6, Motion 13, Shiki, Vitest, Node test runner, Playwright, axe-core. - -**Spec:** `docs/superpowers/specs/2026-09-03-device-lab-design.md` - -## Global constraints - -- Preserve the library's public API and package output. -- Support Node.js 24 only. -- Keep `/examples/[slug]/` and add `/examples/[slug]/embed/`, both statically generated. -- Use only `phone`/`tablet` and `portrait`/`landscape`; default to phone portrait. -- Keep the iframe mounted while device configuration changes. -- Honor `prefers-reduced-motion`. -- Read source only from allowlisted recipe files beneath `website/recipes`. -- Load TSX highlighting at build time; do not ship Shiki to the browser. -- Do not imitate a commercial editor or add decorative window controls. -- End every delivery slice with `npm run check` and the relevant browser matrix. - ---- - -## Slice 1: Isolated embeds and canonical source - -### Task 1: Separate site chrome from embedded routes - -**Files:** - -- Modify: `website/app/layout.tsx` -- Create: `website/app/(site)/layout.tsx` -- Move: every current route directory and `page.tsx` from `website/app/` to `website/app/(site)/`, leaving `layout.tsx` and `site.css` at the root -- Create: `website/app/(embed)/examples/[slug]/embed/page.tsx` -- Create: `website/components/RecipeEmbedPage.tsx` -- Modify: `website/components/RecipePreview.tsx` -- Modify: `website/app/(site)/examples/[slug]/page.tsx` -- Modify: `scripts/verify-website.test.mjs` -- Modify: `e2e/website/recipes.spec.ts` - -**Interfaces:** - -- Consumes: `recipes` and `getRecipe(slug)` from `website/recipes/registry.ts`. -- Produces: static `/examples//embed/index.html` pages with `robots: { index: false, follow: false }`. -- Produces: `RecipePreview({ slug, title })`, initially as a persistent same-origin iframe that Task 5 enhances with device controls. - -- [ ] **Step 1: Add failing static-route assertions** - -Extend the website verification test to require the embedded route source and its static-parameter contract: - -```js -const embedPage = readFileSync( - new URL( - '../website/app/(embed)/examples/[slug]/embed/page.tsx', - import.meta.url - ), - 'utf8' -) -assert.match(embedPage, /generateStaticParams/) -assert.match(embedPage, /index:\s*false/) -assert.match(embedPage, /follow:\s*false/) -``` - -- [ ] **Step 2: Run the verifier and confirm the missing-embed failure** - -Run: `npm run test:website` - -Expected: FAIL because no embedded recipe output exists. - -- [ ] **Step 3: Move site routes behind a chrome layout** - -Keep global metadata, ``, ``, stylesheet imports, and the body content slot in `website/app/layout.tsx`. Put the skip link, `SiteHeader`, and `SiteFooter` in `website/app/(site)/layout.tsx`: - -```tsx -export default function SiteLayout({ children }: { children: ReactNode }) { - return ( - <> - - Skip to content - - - {children} - - - ) -} -``` - -Move existing route files without changing their resulting URLs. Keep metadata-only root files such as `sitemap.ts`, `robots.ts`, and `opengraph-image.tsx` at `website/app/`. Update relative imports affected by the additional route-group directory and update source-contract tests that intentionally address the moved legal pages. - -- [ ] **Step 4: Add the embedded recipe page** - -Export `generateStaticParams`, `dynamicParams = false`, and recipe-specific metadata. Render a minimal main element: - -```tsx -export default async function EmbedPage({ params }: PageProps) { - const recipe = getRecipe((await params).slug) - if (!recipe) notFound() - return -} -``` - -`RecipeEmbedPage` renders the component inside `
` with a compact neutral application surface and no site chrome. - -- [ ] **Step 5: Point the recipe preview at the embedded route** - -Change `RecipePreview` to accept `slug` and `title`, then render an iframe with `src={`/examples/${slug}/embed/`}` and `title={`${title} interactive preview`}`. Update the recipe page call site so recipes no longer mount directly in the parent document. - -- [ ] **Step 6: Verify routes and static output** - -Add a `recipeFrame(page)` helper returning `page.frameLocator('[title$="interactive preview"]')`, then migrate every existing recipe interaction in `e2e/website/recipes.spec.ts` to locate triggers, dialogs, state, and custom portal bounds within that frame. Keep documentation-page source and narrow-layout assertions on the parent page. - -Run: `npm run test:website && npm run build:website` - -Expected: PASS, with all recipe and embed HTML files present. - -- [ ] **Step 7: Commit Task 1** - -```bash -git add website/app website/components/RecipeEmbedPage.tsx website/components/RecipePreview.tsx scripts/verify-website.test.mjs e2e/website/recipes.spec.ts -git commit -m "feat(docs): isolate recipe preview routes" -``` - -### Task 2: Make recipe files the canonical displayed source - -**Files:** - -- Modify: `website/recipes/types.ts` -- Modify: `website/recipes/registry.ts` -- Create: `website/recipes/source.ts` -- Create: `website/recipes/source.test.ts` -- Modify: `website/app/(site)/examples/[slug]/page.tsx` -- Delete: `website/recipes/*/source.ts` - -**Interfaces:** - -- Produces: `sourceFile: RecipeSourceFile` on `RecipeDefinition`. -- Produces: `loadRecipeSource(sourceFile: RecipeSourceFile): Promise<{ filename: string; source: string }>` as a server-only function. -- Security invariant: resolved files must remain inside the canonical `website/recipes` directory and end in `.tsx`. - -- [ ] **Step 1: Write failing loader tests** - -Cover a valid registered source, a missing source, a path traversal, and a non-TSX extension: - -```ts -await expect(loadRecipeSource('basic/BasicSheet.tsx')).resolves.toMatchObject({ - filename: 'BasicSheet.tsx', -}) -await expect( - loadRecipeSource('../package.json' as RecipeSourceFile) -).rejects.toThrow('Recipe source must remain inside website/recipes') -``` - -Also assert the returned source equals `readFile` output byte-for-byte. - -- [ ] **Step 2: Confirm the tests fail before implementation** - -Run: `npx vitest run website/recipes/source.test.ts` - -Expected: FAIL because `sourceFile` and `loadRecipeSource` do not exist. - -- [ ] **Step 3: Introduce typed, allowlisted paths** - -Define the union from the registry's known filenames rather than accepting arbitrary strings: - -```ts -export type RecipeSourceFile = - | 'basic/BasicSheet.tsx' - | 'controlled/ControlledSheet.tsx' - | 'snap-points/SnapPointSheet.tsx' - | 'content-height/ContentHeightSheet.tsx' - | 'scrolling/ScrollingSheet.tsx' - | 'form/FormSheet.tsx' - | 'custom-portal/CustomPortalSheet.tsx' - | 'non-modal/NonModalSheet.tsx' - | 'reduced-motion/ReducedMotionSheet.tsx' - | 'custom-theme/CustomThemeSheet.tsx' - | 'dark-theme/DarkThemeSheet.tsx' - | 'confirmation/ConfirmationSheet.tsx' -``` - -Replace each `source` registry field with its matching `sourceFile`. Remove all imports from the duplicated source modules. - -- [ ] **Step 4: Implement server-only source loading** - -Use `fileURLToPath`, `resolve`, `relative`, and `readFile` from Node modules so the loader can only execute during the server build. Reject absolute relatives, `..` prefixes, and non-`.tsx` extensions before reading. Return `basename(absolutePath)` and the unmodified UTF-8 source. - -- [ ] **Step 5: Load source in the recipe server page** - -Resolve the registered file before rendering `RecipeSource`: - -```tsx -const source = await loadRecipeSource(recipe.sourceFile) -return -``` - -- [ ] **Step 6: Remove duplicated source modules and run focused checks** - -Run: `npx vitest run website/recipes/source.test.ts website/recipes/registry.test.ts && npm run typecheck && npm run build:website` - -Expected: PASS and no import or output references to the deleted source modules. - -- [ ] **Step 7: Commit Task 2** - -```bash -git add website/recipes website/app/'(site)'/examples/'[slug]'/page.tsx -git commit -m "refactor(docs): derive recipe source from components" -``` - -### Task 3: Gate Slice 1 - -- [ ] **Step 1: Run the repository gate** - -Run: `npm run check` - -Expected: PASS. - -- [ ] **Step 2: Run recipe pages in Chromium and Firefox** - -Run: `npx playwright test --config playwright.website.config.ts e2e/website/recipes.spec.ts --project=chromium --project=firefox` - -Expected: PASS. - -- [ ] **Step 3: Record the slice checkpoint** - -```bash -git commit --allow-empty -m "test(docs): verify isolated recipe embeds" -``` - ---- - -## Slice 2: URL-backed device lab - -### Task 4: Add typed device presets and URL parsing - -**Files:** - -- Create: `website/components/device-lab/device-config.ts` -- Create: `website/components/device-lab/device-config.test.ts` - -**Interfaces:** - -- Produces: `Device = 'phone' | 'tablet'`. -- Produces: `Orientation = 'portrait' | 'landscape'`. -- Produces: `DeviceSelection`, `DevicePreset`, `DEFAULT_DEVICE_SELECTION`, `getDevicePreset(selection)`, `parseDeviceSelection(searchParams)`, and `toDeviceSearchParams(selection)`. - -- [ ] **Step 1: Write the table-driven failing tests** - -Assert all four logical dimensions, the default, valid query parsing, invalid-value fallback, and stable serialization: - -```ts -expect( - getDevicePreset({ device: 'phone', orientation: 'portrait' }) -).toMatchObject({ - width: 390, - height: 780, -}) -expect( - parseDeviceSelection( - new URLSearchParams('device=watch&orientation=upside-down') - ) -).toEqual(DEFAULT_DEVICE_SELECTION) -expect( - toDeviceSearchParams({ - device: 'tablet', - orientation: 'landscape', - }).toString() -).toBe('device=tablet&orientation=landscape') -``` - -- [ ] **Step 2: Run and confirm failure** - -Run: `npx vitest run website/components/device-lab/device-config.test.ts` - -Expected: FAIL because the module is missing. - -- [ ] **Step 3: Implement immutable preset data and pure helpers** - -Use the exact dimensions from the specification and return new `URLSearchParams` instances. Do not accept numeric dimensions or preserve invalid device keys. - -- [ ] **Step 4: Run and commit** - -Run: `npx vitest run website/components/device-lab/device-config.test.ts` - -Expected: PASS. - -```bash -git add website/components/device-lab -git commit -m "feat(docs): define device preview presets" -``` - -### Task 5: Build the persistent iframe controller - -**Files:** - -- Create: `website/components/device-lab/DeviceLab.tsx` -- Create: `website/components/device-lab/DeviceControls.tsx` -- Create: `website/components/device-lab/DeviceFrame.tsx` -- Create: `website/components/device-lab/RecipeEmbed.tsx` -- Create: `website/components/device-lab/use-scaled-frame.ts` -- Create: `website/components/device-lab/use-scaled-frame.test.tsx` -- Modify: `website/components/RecipePreview.tsx` -- Modify: `website/app/(site)/examples/[slug]/page.tsx` - -**Interfaces:** - -- `DeviceLabProps = { slug: string; title: string }`. -- `RecipeEmbedProps = { slug: string; title: string; onReady(): void; onFailure(): void }`. -- The iframe `src` is always `/examples/${slug}/embed/`; device state never appears in it. - -- [ ] **Step 1: Write failing scale and identity tests** - -For the scaling hook, assert `scale = min(1, availableWidth / outerWidth)` and the scaled stage height. In a component test, change all four control combinations and assert the same iframe DOM node and `src` remain present. - -- [ ] **Step 2: Confirm focused failures** - -Run: `npx vitest run website/components/device-lab/use-scaled-frame.test.tsx` - -Expected: FAIL because the hook and device components do not exist. - -- [ ] **Step 3: Implement semantic controls and URL updates** - -Render two labelled groups of buttons. Each button has visible text and `aria-pressed`. Use `useSearchParams`, `usePathname`, and `useRouter` to update only `device` and `orientation`, preserve unrelated parameters, and avoid navigation when the requested state is already active. Invalid values trigger `router.replace` with the normalized phone-portrait state; user control changes use `router.push` so browser history remains meaningful. - -Wrap `DeviceLab` in a `Suspense` boundary whose fallback renders the phone-portrait frame. This keeps the page compatible with static export while query state is resolved in the client. Reconcile back/forward changes from `useSearchParams` without assigning a changing React `key` to the iframe. - -- [ ] **Step 4: Implement proportional frame scaling** - -Observe the available stage width with `ResizeObserver`. Give the iframe its exact logical pixel width and height, then transform the complete device frame by the computed scale. Set the outer stage height to the scaled frame height so later content remains in normal flow. - -- [ ] **Step 5: Implement loading and failure states** - -Keep the iframe in place while loading. Mark ready on `load`. Start a bounded timeout that reveals a textual fallback and direct `/examples//embed/` link without changing the iframe `src`; clear the timer after load and on unmount. - -- [ ] **Step 6: Replace the direct recipe preview** - -Replace `RecipePreview`'s initial iframe wrapper with `DeviceLab`. Its `slug` and `title` interface remains unchanged, and the embedded route remains the only preview owner. - -- [ ] **Step 7: Run focused checks and commit** - -Run: `npx vitest run website/components/device-lab && npm run typecheck && npm run build:website` - -Expected: PASS. - -```bash -git add website/components/device-lab website/components/RecipePreview.tsx website/app/'(site)'/examples/'[slug]'/page.tsx -git commit -m "feat(docs): add responsive device lab" -``` - -### Task 6: Style and animate the device lab - -**Files:** - -- Modify: `website/app/site.css` -- Modify: `e2e/website/recipes.spec.ts` - -**Interfaces:** - -- CSS custom properties on the frame: `--device-width`, `--device-height`, `--device-scale`, `--device-radius`. -- Test identifiers: `data-device`, `data-orientation`, and `data-preview-ready`; no test-only behavioral branches. - -- [ ] **Step 1: Add failing browser assertions** - -Cover phone portrait defaults, tablet landscape URL restoration, visible pressed states, logical iframe dimensions, browser back/forward, and iframe identity while a basic sheet remains open. Capture the iframe element handle before changing orientation and assert the same embedded document marker remains afterward. - -- [ ] **Step 2: Run the focused Chromium test and confirm failure** - -Run: `npx playwright test --config playwright.website.config.ts e2e/website/recipes.spec.ts --project=chromium --grep "device lab"` - -Expected: FAIL on absent controls or dimensions. - -- [ ] **Step 3: Add restrained frame styling** - -Remove the recipe-stage grid. Add a neutral stage, one-pixel bezel, subtle shadow, responsive control wrapping, readable viewport metadata, and device-specific radii. Keep hardware detail presentational. Ensure the page has no horizontal overflow from 320px through 1440px. - -- [ ] **Step 4: Add motion and reduced-motion behavior** - -Animate only user-triggered changes to dimensions, radius, bezel, and reserved stage height. Use Motion's existing dependency or CSS interpolation where it preserves a stable iframe node. Under `prefers-reduced-motion: reduce`, set transition duration to zero and disable transform interpolation. - -- [ ] **Step 5: Pass browser and accessibility checks** - -Run: - -```bash -npx playwright test --config playwright.website.config.ts e2e/website/recipes.spec.ts --project=chromium --project=firefox -``` - -Expected: PASS, including axe scans and reduced-motion assertions. - -- [ ] **Step 6: Commit Task 6** - -```bash -git add website/app/site.css e2e/website/recipes.spec.ts -git commit -m "style(docs): animate device preview states" -``` - -### Task 7: Gate Slice 2 - -- [ ] **Step 1: Run repository and browser gates** - -Run: - -```bash -npm run check -npm run test:website:e2e -- --project=chromium --project=firefox -``` - -Expected: both commands PASS. - -- [ ] **Step 2: Record the slice checkpoint** - -```bash -git commit --allow-empty -m "test(docs): verify device lab behavior" -``` - ---- - -## Slice 3: Project-specific highlighted source - -### Task 8: Add server-rendered Shiki tokenization - -**Files:** - -- Modify: `package.json` -- Modify: `package-lock.json` -- Create: `website/components/source-code/highlighter.ts` -- Create: `website/components/source-code/highlighter.test.ts` -- Create: `website/components/source-code/HighlightedCode.tsx` -- Create: `website/components/source-code/CopySourceButton.tsx` -- Modify: `website/components/RecipeSource.tsx` - -**Interfaces:** - -- Produces: `highlightTsx(source: string): Promise`. -- `HighlightedLine = readonly HighlightedToken[]`. -- `HighlightedToken = { content: string; color: string; fontStyle?: number }`. -- `RecipeSourceProps = { filename: string; source: string }`. - -- [ ] **Step 1: Install Shiki as build-only infrastructure** - -Run: `npm install --save-dev shiki` - -Expected: only manifest and lockfile dependency changes. - -- [ ] **Step 2: Write failing tokenization tests** - -Assert deterministic line boundaries, preserved whitespace/text, distinct comment/string/keyword colors, and no HTML input execution: - -```ts -const lines = await highlightTsx('const label = "Sheet"\n// note') -expect( - lines.map((line) => line.map((token) => token.content).join('')).join('\n') -).toBe('const label = "Sheet"\n// note') -expect(new Set(lines.flat().map((token) => token.color)).size).toBeGreaterThan( - 2 -) -``` - -- [ ] **Step 3: Confirm the test fails** - -Run: `npx vitest run website/components/source-code/highlighter.test.ts` - -Expected: FAIL because the highlighter is missing. - -- [ ] **Step 4: Implement one long-lived TSX highlighter** - -Create a module-level promise from `createHighlighter` that loads only `langTsx` and a project theme. Derive foreground, comment, string, constant, keyword, function, type, and punctuation colors from the site's established palette. Use `codeToTokens`; do not emit or inject raw highlighted HTML. - -- [ ] **Step 5: Split server rendering from copy interaction** - -Make `RecipeSource` an async server component. Render line numbers with `aria-hidden="true"` and token spans with inline Shiki colors. Keep `CopySourceButton` as a small client component using Clipboard API plus the existing selection fallback. The scrollable `
` remains keyboard focusable and has an accessible label containing the filename.
-
-- [ ] **Step 6: Run focused tests and verify the client bundle boundary**
-
-Run: `npx vitest run website/components/source-code/highlighter.test.ts && npm run typecheck && npm run build:website`
-
-Expected: PASS. Inspect the static build output with:
-
-```bash
-rg -n 'data-code-token' website/out/examples/basic/index.html
-if rg -n 'source\.tsx|text\.html\.basic|onig\.wasm' website/out/_next/static; then exit 1; fi
-```
-
-The first command must find rendered tokens; the guarded search must find no Shiki grammar or WebAssembly payload in client chunks.
-
-- [ ] **Step 7: Commit Task 8**
-
-```bash
-git add package.json package-lock.json website/components/RecipeSource.tsx website/components/source-code
-git commit -m "feat(docs): highlight canonical recipe source"
-```
-
-### Task 9: Finish source layout and end-to-end coverage
-
-**Files:**
-
-- Modify: `website/app/site.css`
-- Modify: `e2e/website/recipes.spec.ts`
-- Modify: `scripts/check-website-css.test.mjs`
-
-**Interfaces:**
-
-- Source line elements expose `data-line` for stable styling and inspection.
-- Line-number columns are excluded from copying through `user-select: none` and `aria-hidden`.
-
-- [ ] **Step 1: Add failing presentation and copy tests**
-
-Assert the filename, multiple colored tokens, sequential line numbers, keyboard-focusable code scroller, successful copy status, and copied text equality with `readFileSync('website/recipes/basic/BasicSheet.tsx', 'utf8')` after excluding elements marked `aria-hidden="true"`.
-
-- [ ] **Step 2: Confirm the focused test fails**
-
-Run: `npx playwright test --config playwright.website.config.ts e2e/website/recipes.spec.ts --project=chromium --grep "highlighted source"`
-
-Expected: FAIL on missing source presentation behavior.
-
-- [ ] **Step 3: Add the project-specific source styles**
-
-Use a deep neutral surface, clear filename label, one bordered toolbar, tabular line numbers, comfortable code leading, visible focus outline, and horizontal scrolling. Do not add fake tabs, traffic-light controls, or editor branding. Meet WCAG AA contrast for every token against the code background.
-
-- [ ] **Step 4: Add responsive split/stack behavior**
-
-At widths where both columns retain useful reading space, place the lab and source in a balanced layout container. Below that threshold, retain document order and stack source after guidance. Add CSS contract assertions that prevent fixed-width overflow and ensure compact controls wrap.
-
-- [ ] **Step 5: Run the complete website matrix**
-
-Run:
-
-```bash
-npm run test:website
-npm run build:website
-npm run test:website:e2e -- --project=chromium --project=firefox --project=webkit
-```
-
-Expected: PASS across static contracts, build, accessibility, device configurations, and source interactions.
-
-- [ ] **Step 6: Commit Task 9**
-
-```bash
-git add website/app/site.css e2e/website/recipes.spec.ts scripts/check-website-css.test.mjs
-git commit -m "style(docs): refine recipe source presentation"
-```
-
-### Task 10: Final release-quality gate
-
-- [ ] **Step 1: Run the complete repository check from a clean tree**
-
-Run: `npm run check`
-
-Expected: PASS with no changed generated artifacts.
-
-- [ ] **Step 2: Run every website browser project**
-
-Run: `npm run test:website:e2e`
-
-Expected: PASS for Chromium, Firefox, WebKit, and configured touch coverage.
-
-- [ ] **Step 3: Inspect the production artifact**
-
-Serve `website/out`, open one ordinary recipe and its embed directly, and verify that headers appear only on the ordinary page, all four device URLs load, an open sheet survives orientation change, source copies exactly, and no page introduces horizontal scrolling.
-
-- [ ] **Step 4: Confirm repository state**
-
-Run: `git status --short && git log --oneline --decorate -12`
-
-Expected: an empty status and focused commits matching the tasks above.
diff --git a/docs/superpowers/plans/2026-09-04-adoption-conversion-foundation.md b/docs/superpowers/plans/2026-09-04-adoption-conversion-foundation.md
deleted file mode 100644
index 83d170b1..00000000
--- a/docs/superpowers/plans/2026-09-04-adoption-conversion-foundation.md
+++ /dev/null
@@ -1,323 +0,0 @@
-# Adoption Conversion Foundation Implementation Plan
-
-> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
-
-**Goal:** Give prospective adopters a clear repository introduction, a search-friendly migration destination, accurate GitHub metadata, and a private campaign record before outreach begins.
-
-**Architecture:** Keep marketing claims backed by existing release evidence and reuse the website's static Next.js content patterns. Add one dedicated static migration route as the canonical outreach destination, strengthen the README without duplicating the full documentation, mutate GitHub metadata only after code is published, and store contact tracking outside version control.
-
-**Tech Stack:** Markdown, Next.js 16 App Router/static export, React 19, TypeScript, Node test runner, Playwright, GitHub CLI.
-
-**Spec:** `docs/superpowers/specs/2026-09-04-adoption-campaign-design.md`
-
-## Global Constraints
-
-- Describe the project as an “independently maintained continuation,” never as the official successor without explicit original-maintainer authorization.
-- Lead with React 19 compatibility, accessibility, composability, and browser verification; maintenance is supporting evidence.
-- Preserve prominent attribution to Cody Olsen and Jasmine GH.
-- Back every compatibility, package, and browser claim with checked repository evidence.
-- Keep the site statically exportable and include the migration route in metadata, navigation, sitemap, accessibility, and narrow-layout verification.
-- Write public outreach in the first person as Nicholas.
-- Keep personal contact information and correspondence outside version control.
-- Do not request ownership transfer, npm access, deprecation, or an official endorsement without separate approval.
-
----
-
-### Task 1: README conversion surface
-
-**Files:**
-
-- Modify: `README.md`
-- Modify: `scripts/verify-website.test.mjs`
-
-**Interfaces:**
-
-- Consumes: the production documentation URL and existing project-lineage section.
-- Produces: a concise repository introduction with `Live demo`, `Migration from the original`, and `Why version 5` destinations.
-
-- [ ] **Step 1: Add failing README contract assertions**
-
-Extend the existing README verification test in `scripts/verify-website.test.mjs` to require the package name, production docs URL, the dedicated migration URL `/migration-from-react-spring-bottom-sheet/`, the exact phrase `independently maintained continuation`, React 19, accessibility, Chromium, Firefox, WebKit, Cody Olsen, and Jasmine GH. Reject the phrase `official successor`.
-
-```js
-assert.match(readme, /independently maintained continuation/i)
-assert.match(readme, /migration-from-react-spring-bottom-sheet/)
-assert.doesNotMatch(readme, /official successor/i)
-```
-
-- [ ] **Step 2: Run the README contract and verify RED**
-
-Run: `node --test scripts/verify-website.test.mjs`
-
-Expected: FAIL because the README does not yet link to the dedicated migration route or contain the approved positioning.
-
-- [ ] **Step 3: Rewrite the README opening and adoption sections**
-
-Keep the existing install and example code, but place this positioning directly below the title:
-
-```markdown
-Accessible, composable bottom sheets for React 19. An independently maintained
-continuation of the original `react-spring-bottom-sheet`, rebuilt with compound
-components, explicit styling contracts, and current-browser verification.
-```
-
-Add a compact navigation row linking to the live docs, examples, migration page, API reference, and npm. Add a `Why version 5` section covering React 19, accessible dialog/focus behavior, interruption-safe gestures and motion, replaceable styling, and the tested browser matrix. Add a short `Migrating from the original package` section that names both packages and links to the dedicated migration page and detailed repository guide. Retain the full lineage section and avoid decorative badge overload; include only npm version, CI, license, and React 19 badges whose targets are stable.
-
-- [ ] **Step 4: Verify the README contract and formatting**
-
-Run: `node --test scripts/verify-website.test.mjs && npx prettier --check README.md scripts/verify-website.test.mjs`
-
-Expected: PASS.
-
-- [ ] **Step 5: Commit the README conversion surface**
-
-```bash
-git add README.md scripts/verify-website.test.mjs
-git commit -m "docs: sharpen maintained continuation positioning"
-```
-
-### Task 2: Migration discovery route
-
-**Files:**
-
-- Create: `website/app/(site)/migration-from-react-spring-bottom-sheet/page.tsx`
-- Create: `website/content/migration.tsx`
-- Create: `website/content/migration.test.tsx`
-- Modify: `website/components/SiteHeader.tsx`
-- Modify: `website/components/SiteFooter.tsx`
-- Modify: `website/app/sitemap.ts`
-- Modify: `website/app/site.css`
-- Modify: `scripts/verify-website.test.mjs`
-- Modify: `scripts/check-website-css.test.mjs`
-- Modify: `e2e/website/docs.spec.ts`
-
-**Interfaces:**
-
-- Produces: static route `/migration-from-react-spring-bottom-sheet/` with canonical metadata and the reusable `MigrationPageContent` component.
-- Consumes: `CodeBlock`, existing documentation URLs, `@nipe-solutions/react-spring-bottom-sheet`, and the v4-to-v5 mapping in `docs/migration-v4-to-v5.md`.
-
-- [ ] **Step 1: Write failing content and static-route contracts**
-
-Create `website/content/migration.test.tsx` to render `MigrationPageContent` and require:
-
-```tsx
-expect(screen.getByRole('heading', {
-  level: 1,
-  name: /migrate from react-spring-bottom-sheet/i,
-})).toBeVisible()
-expect(screen.getByText(/independently maintained continuation/i)).toBeVisible()
-expect(screen.getByText('react-spring-bottom-sheet')).toBeVisible()
-expect(screen.getByText('@nipe-solutions/react-spring-bottom-sheet')).toBeVisible()
-expect(screen.getByRole('link', { name: /complete migration guide/i }))
-  .toHaveAttribute('href', '/docs/migration/')
-```
-
-Extend `scripts/verify-website.test.mjs` to require the new route, canonical URL, title containing `React 19`, and sitemap entry. Extend `e2e/website/docs.spec.ts` to require a visible header or footer link and successful navigation to the route.
-
-- [ ] **Step 2: Run the route contracts and verify RED**
-
-Run: `npx vitest run website/content/migration.test.tsx && node --test scripts/verify-website.test.mjs`
-
-Expected: FAIL because the component and route do not exist.
-
-- [ ] **Step 3: Implement factual migration content**
-
-Create a server-rendered page with these sections:
-
-1. Hero: independent continuation, React 19, and a direct installation command.
-2. `Choose your path`: evaluate v5 directly versus remain on the original package until migration is possible.
-3. Before/after controlled example using the existing server `CodeBlock`.
-4. API mapping table covering `open`, `blocking`, `onDismiss`, `snapPoints`, `defaultSnap`, `header`, `footer`, `BottomSheetRef`, `expandOnContentDrag`, and stylesheet imports.
-5. Requirements: React 19 and current Chromium, Firefox, and WebKit.
-6. Calls to action: examples, full migration guide, API reference, npm, and GitHub.
-7. Lineage note naming Cody Olsen, Jasmine GH, and independent NIPE Solutions maintenance.
-
-The page metadata must use:
-
-```ts
-export const metadata: Metadata = {
-  title: 'Migrate react-spring-bottom-sheet to React 19',
-  description:
-    'Move from the original react-spring-bottom-sheet to an independently maintained React 19 implementation with an explicit API and styling migration path.',
-  alternates: {
-    canonical: '/migration-from-react-spring-bottom-sheet/',
-  },
-}
-```
-
-- [ ] **Step 4: Add restrained navigation and sitemap discovery**
-
-Add one `Migration` link to the site footer and, if the header remains contained at 320px, to the primary header. Add the route to `website/app/sitemap.ts` with the same static base URL pattern as other entries. Do not displace Docs or Examples.
-
-- [ ] **Step 5: Add route-owned responsive styles and CSS contracts**
-
-Use only `docs-*` classes. Add a centered article measure, a responsive two-column before/after region that collapses at the existing compact breakpoint, an overflow-contained mapping table, and ordinary document typography. Extend `scripts/check-website-css.test.mjs` to assert `max-width`, `min-width: 0`, internal table overflow, and the compact single-column rule.
-
-- [ ] **Step 6: Run focused unit and static checks**
-
-Run: `npx vitest run website/content/migration.test.tsx && npm run test:website && npm run typecheck`
-
-Expected: PASS.
-
-- [ ] **Step 7: Run browser checks for discovery, accessibility, and containment**
-
-Extend `e2e/website/docs.spec.ts` with an accessibility scan and a 320px overflow assertion for the migration route.
-
-Run: `npm run test:website:e2e -- --project=chromium e2e/website/docs.spec.ts --grep "migration"`
-
-Expected: PASS with navigation, no detectable accessibility violations, and no document-level horizontal overflow.
-
-- [ ] **Step 8: Commit the migration discovery route**
-
-```bash
-git add website scripts/verify-website.test.mjs scripts/check-website-css.test.mjs e2e/website/docs.spec.ts
-git commit -m "feat(docs): add original-package migration page"
-```
-
-### Task 3: GitHub repository metadata
-
-**Files:**
-
-- No tracked files.
-
-**Interfaces:**
-
-- Consumes: published production documentation URL and the approved repository-description text.
-- Produces: GitHub description, homepage, and ten focused repository topics.
-
-- [ ] **Step 1: Capture current metadata**
-
-Run:
-
-```bash
-gh repo view NIPE-Solutions/react-spring-bottom-sheet \
-  --json description,homepageUrl,repositoryTopics,url
-```
-
-Save the returned values in the private campaign tracker before mutation.
-
-- [ ] **Step 2: Update description and homepage**
-
-Run:
-
-```bash
-gh repo edit NIPE-Solutions/react-spring-bottom-sheet \
-  --description "Accessible, composable React 19 bottom sheets — an independently maintained continuation of react-spring-bottom-sheet." \
-  --homepage "https://react-spring-bottom-sheet.nipesolutions.com"
-```
-
-- [ ] **Step 3: Replace topics with the approved focused set**
-
-Read the current topics first and preserve any existing topic that is both accurate and not redundant. Ensure the final set contains:
-
-```text
-react
-react-19
-bottom-sheet
-drawer
-dialog
-accessibility
-typescript
-gesture
-headless-ui
-react-spring-bottom-sheet
-```
-
-Use `gh repo edit --add-topic ` for missing topics and `--remove-topic ` only for clearly inaccurate topics.
-
-- [ ] **Step 4: Read back and verify metadata**
-
-Run:
-
-```bash
-gh repo view NIPE-Solutions/react-spring-bottom-sheet \
-  --json description,homepageUrl,repositoryTopics,url
-```
-
-Expected: exact approved description and homepage, with every approved topic present.
-
-### Task 4: Private campaign tracker
-
-**Files:**
-
-- Modify locally only: `.git/info/exclude`
-- Create locally only: `.campaign/adoption-tracker.md`
-
-**Interfaces:**
-
-- Produces: a persistent local record excluded from Git status.
-- Stores: target, dependency relationship, channel, public URL, date, status, last action, next follow-up, response, blocker, and resulting evidence.
-
-- [ ] **Step 1: Exclude the local campaign directory**
-
-Resolve the shared Git directory with `git rev-parse --git-common-dir`, append `/.campaign/` to its `info/exclude` only if absent, and verify `git check-ignore -v .campaign/probe` identifies the local exclude rule.
-
-- [ ] **Step 2: Create the tracker with no private addresses**
-
-Create `.campaign/adoption-tracker.md` with sections for repository metadata baseline, original-maintainer outreach, upstream dependency outreach, migration candidates, publications, and metrics. Use this table:
-
-```markdown
-| Target | Relationship | Channel | Public URL | Status | Last action | Follow-up | Response/blocker | Evidence |
-| --- | --- | --- | --- | --- | --- | --- | --- | --- |
-```
-
-Seed only already verified public facts: npm download windows, PR URLs, and repository URLs. Do not store access tokens or unpublished personal contact information.
-
-- [ ] **Step 3: Verify tracker privacy and persistence**
-
-Run: `git status --short --untracked-files=all && git check-ignore -v .campaign/adoption-tracker.md`
-
-Expected: the tracker does not appear in Git status and `git check-ignore` points to the shared local exclude file.
-
-### Task 5: Foundation integration gate
-
-**Files:**
-
-- Verify all files changed in Tasks 1–2; no new implementation files.
-
-**Interfaces:**
-
-- Consumes: README, migration route, GitHub metadata, and tracker outputs.
-- Produces: a reviewable feature branch and the canonical URL needed by the outreach plan.
-
-- [ ] **Step 1: Rebase onto the merged example-workbench branch**
-
-After PR #49 merges, fetch `origin/main`, rebase `feat/adoption-campaign` onto it, and resolve overlaps by retaining the workbench's shared `CodeBlock` system. Do not duplicate source-highlighting primitives.
-
-- [ ] **Step 2: Run the complete repository gate**
-
-Run: `npm run check`
-
-Expected: PASS with formatting, lint, unit tests, type checks, package checks, and the static website build.
-
-- [ ] **Step 3: Run the complete website browser matrix**
-
-Run: `npm run test:website:e2e`
-
-Expected locally: Chromium and Firefox pass. If local WebKit rejects `PushAPIEnabled`, record that exact environment limitation and require the PR's Linux WebKit job to pass before merge.
-
-- [ ] **Step 4: Verify public metadata and clean state**
-
-Run:
-
-```bash
-gh repo view NIPE-Solutions/react-spring-bottom-sheet \
-  --json description,homepageUrl,repositoryTopics,url
-git status --short --branch
-```
-
-Expected: approved GitHub metadata and no tracked or untracked campaign notes.
-
-- [ ] **Step 5: Push and open the foundation PR**
-
-Push `feat/adoption-campaign` and open a PR titled `docs: establish the adoption conversion foundation`. Describe the independent-continuation positioning, migration route, GitHub metadata, private tracker exclusion, and fresh verification evidence. Keep the worktree for review changes.
-
-## Deferred phase-specific plans
-
-After this foundation is published, create separate plans for:
-
-1. Original-maintainer and dependency-maintainer outreach, using the canonical migration URL.
-2. Candidate research and up to three target-repository migrations, after maintainers identify the correct ownership paths.
-3. Technical article and community launch, after the evidence threshold in the specification is met.
-
-These plans must use real recipients, repository APIs, and test commands discovered during the preceding phase; they must not invent targets or publication channels in advance.
diff --git a/docs/superpowers/plans/2026-09-04-example-workbench.md b/docs/superpowers/plans/2026-09-04-example-workbench.md
deleted file mode 100644
index 79e342b7..00000000
--- a/docs/superpowers/plans/2026-09-04-example-workbench.md
+++ /dev/null
@@ -1,458 +0,0 @@
-# Example Workbench Implementation Plan
-
-> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
-
-**Goal:** Turn recipe pages into focused device laboratories with an on-demand source inspector and give all substantial website snippets one accurate, server-rendered highlighting system.
-
-**Architecture:** Generalize the existing server-only Shiki boundary into a typed, language-aware `CodeBlock`, then compose it inside a client-owned accessible source inspector. Keep device selection in the existing URL state machine, using Next.js non-scrolling navigation so the iframe and document position remain stable.
-
-**Tech Stack:** Next.js 16 App Router/static export, React 19, TypeScript, Shiki core with the JavaScript regex engine, Vitest/Testing Library, Playwright, plain namespaced CSS.
-
-**Spec:** `docs/superpowers/specs/2026-09-04-example-workbench-design.md`
-
-## Global Constraints
-
-- Preserve the public npm package API and the static-export architecture.
-- Keep syntax highlighting server/build-only; no Shiki or grammar engine may enter client JavaScript.
-- Render highlighted tokens as React nodes and never inject highlighted HTML.
-- Preserve canonical source bytes, whitespace, blank lines, and terminal newlines.
-- Keep recipe iframe identity, open-sheet state, URL history, and morph interruption/rollback behavior across device changes.
-- Use only `docs-*` website classes and retain the isolated `rsbs-example-*` recipe namespace.
-- Support exactly `tsx`, `css`, and `shell` in the first shared code-block release.
-- Respect reduced motion, keyboard operation, focus restoration, safe-area insets, and 320 CSS-pixel containment.
-- Require Chromium, Firefox, and CI WebKit before merge; local WebKit remains unavailable because the pinned binary rejects `PushAPIEnabled`.
-
----
-
-### Task 1: Language-aware server code blocks
-
-**Files:**
-
-- Modify: `website/components/source-code/highlighter.ts`
-- Modify: `website/components/source-code/highlighter.test.ts`
-- Modify: `website/components/source-code/highlighter-singleton.test.ts`
-- Rename: `website/components/source-code/HighlightedCode.tsx` to `website/components/source-code/CodeTokens.tsx`
-- Create: `website/components/source-code/CodeBlock.tsx`
-- Create: `website/components/source-code/CodeBlock.test.tsx`
-- Modify: `package.json`
-- Modify: `package-lock.json`
-
-**Interfaces:**
-
-- Produces: `type CodeLanguage = 'tsx' | 'css' | 'shell'`.
-- Produces: `highlightCode(source: string, language: CodeLanguage): Promise`.
-- Produces: `CodeBlock(props: { source: string; language: CodeLanguage; filename?: string; label?: string; lineNumbers?: boolean; copy?: boolean; className?: string }): Promise`.
-- Produces: `CodeTokens({ source, lines, label, lineNumbers })`, preserving exact native selection bytes.
-
-- [ ] **Step 1: Write failing highlighter tests for all supported languages**
-
-Add table-driven tests which call `highlightCode` with TSX, CSS, and shell samples, restore token content, and require exact equality including a terminal newline. Require at least four distinct non-default semantic colors per language and explicit distinctions for TSX tags/attributes, CSS properties/values, and shell commands/flags.
-
-```ts
-const samples = {
-  tsx: 'const view = \n',
-  css: '.cart-sheet { color: var(--brand); }\n',
-  shell: 'npm install @nipe-solutions/react-spring-bottom-sheet\n',
-} as const
-
-for (const [language, source] of Object.entries(samples)) {
-  const lines = await highlightCode(source, language as CodeLanguage)
-  expect(restoreSource(lines)).toBe(source)
-  expect(
-    new Set(lines.flat().map((token) => token.color)).size,
-  ).toBeGreaterThan(3)
-}
-```
-
-- [ ] **Step 2: Run the focused tests and verify RED**
-
-Run: `npx vitest run website/components/source-code/highlighter.test.ts website/components/source-code/highlighter-singleton.test.ts`
-
-Expected: FAIL because `CodeLanguage` and `highlightCode` do not exist and the singleton currently loads only TSX.
-
-- [ ] **Step 3: Generalize the singleton highlighter and custom theme**
-
-Add fine-grained CSS and shell language imports, retain `shiki/core` plus `createJavaScriptRegexEngine`, and load all three grammars in the single module-level promise. Expand the custom theme with JSX tag/attribute/property scopes plus CSS and shell scopes. Keep all colors as explicit site-owned hex values and expose no production test hook.
-
-```ts
-export type CodeLanguage = 'tsx' | 'css' | 'shell'
-
-const highlighterPromise = createHighlighter({
-  engine: createJavaScriptRegexEngine(),
-  langs: [langTsx, langCss, langShell],
-  themes: [codeTheme],
-})
-
-export async function highlightCode(source: string, language: CodeLanguage) {
-  const highlighter = await highlighterPromise
-  return normalizeTokens(
-    highlighter.codeToTokens(source, { lang: language, theme: codeTheme.name })
-      .tokens,
-  )
-}
-```
-
-- [ ] **Step 4: Write failing `CodeBlock` render tests**
-
-Test minimal shell chrome, TSX with filename/line numbers/copy, an accessible scroll-region label, exact visible source text, and the absence of line numbers from the selectable code value.
-
-```tsx
-const block = await CodeBlock({
-  source: 'const open = true\n',
-  language: 'tsx',
-  filename: 'Example.tsx',
-  lineNumbers: true,
-  copy: true,
-})
-render(block)
-expect(
-  screen.getByRole('region', { name: 'Example.tsx source code' }),
-).toBeVisible()
-expect(screen.getByRole('button', { name: 'Copy source' })).toBeVisible()
-```
-
-- [ ] **Step 5: Run the component test and verify RED**
-
-Run: `npx vitest run website/components/source-code/CodeBlock.test.tsx`
-
-Expected: FAIL because `CodeBlock` and the generalized token renderer do not exist.
-
-- [ ] **Step 6: Implement `CodeTokens` and `CodeBlock` minimally**
-
-Move the reviewed literal-line-separator algorithm from `HighlightedCode` into `CodeTokens`. Make line numbers optional and keep the zero-size terminal-LF boundary. `CodeBlock` highlights on the server, renders optional metadata chrome, and composes the existing `CopySourceButton` only when `copy` is true.
-
-```tsx
-export async function CodeBlock(props: CodeBlockProps) {
-  const lines = await highlightCode(props.source, props.language)
-  const label =
-    props.label ??
-    (props.filename
-      ? `${props.filename} source code`
-      : `${props.language} code`)
-
-  return (
-    
- {props.filename || props.copy ? : null} - -
- ) -} -``` - -- [ ] **Step 7: Run focused tests and typecheck** - -Run: `npx vitest run website/components/source-code && npm run typecheck` - -Expected: all focused tests pass; the constructor-count test still observes one construction across languages. - -- [ ] **Step 8: Commit Task 1** - -```bash -git add package.json package-lock.json website/components/source-code -git commit -m "feat(docs): add shared highlighted code blocks" -``` - -### Task 2: Migrate homepage and documentation snippets - -**Files:** - -- Modify: `website/components/QuickStart.tsx` -- Modify: `website/components/LaunchPath.tsx` -- Modify: `website/app/(site)/docs/[slug]/page.tsx` -- Modify: `website/content/types.ts` -- Modify: `website/content/docs.ts` -- Modify: `website/content/learn/anatomy.tsx` -- Modify: `website/content/learn/installation.tsx` -- Modify: `website/content/learn/snap-points.tsx` -- Modify: `website/content/learn/styling.tsx` -- Create: `website/components/source-code/code-coverage.test.ts` -- Modify: `scripts/verify-website.test.mjs` - -**Interfaces:** - -- Consumes: `CodeBlock` and `CodeLanguage` from Task 1. -- Changes: `DocSection.code` from `string | undefined` to `{ source: string; language: CodeLanguage; lineNumbers?: boolean } | undefined`. -- Produces: an explicit `/examples/` CTA in the generic Examples documentation page. - -- [ ] **Step 1: Write failing migration and CTA tests** - -Create a source-contract test that scans website TSX files outside `CodeTokens.tsx` and rejects block-level raw `
` elements. Extend the website verifier to require the Examples page definition to expose `/examples/` through a typed `href` field.
-
-```ts
-for (const file of blockSnippetFiles) {
-  expect(readFileSync(file, 'utf8')).not.toMatch(/)/)
-}
-```
-
-- [ ] **Step 2: Run the focused tests and verify RED**
-
-Run: `npx vitest run website/components/source-code/code-coverage.test.ts && node --test scripts/verify-website.test.mjs`
-
-Expected: FAIL on current raw homepage/docs `
` blocks and missing Examples CTA metadata.
-
-- [ ] **Step 3: Add typed code and link metadata**
-
-Extend `DocSection` with the exact code object above and optional `link: { href: string; label: string }`. Give the Examples section this link:
-
-```ts
-link: { href: '/examples/', label: 'Open the example laboratory' }
-```
-
-Render generic page code with `CodeBlock` and section links with `next/link`.
-
-- [ ] **Step 4: Migrate explicit homepage and learn-guide snippets**
-
-Replace every block-level `
` with awaited server `CodeBlock` composition. Keep inline `` unchanged. Use `shell` for commands, `tsx` for component/import examples, and `css` for stylesheet examples. Preserve every existing source string byte-for-byte.
-
-- [ ] **Step 5: Run focused website checks**
-
-Run: `npx vitest run website/components/source-code/code-coverage.test.ts website/content/navigation.test.ts website/content/learn/installation.test.tsx && npm run test:website && npm run typecheck`
-
-Expected: all tests pass and no raw substantial code block remains.
-
-- [ ] **Step 6: Commit Task 2**
-
-```bash
-git add website scripts/verify-website.test.mjs
-git commit -m "feat(docs): highlight website code examples"
-```
-
-### Task 3: Accessible source inspector
-
-**Files:**
-
-- Create: `website/components/source-code/SourceInspector.tsx`
-- Create: `website/components/source-code/SourceInspector.test.tsx`
-- Modify: `website/components/RecipeSource.tsx`
-- Modify: `website/components/RecipePreview.tsx`
-- Modify: `website/app/(site)/examples/[slug]/page.tsx`
-- Modify: `website/app/site.css`
-
-**Interfaces:**
-
-- Consumes: `CodeBlock` from Task 1 with canonical recipe source.
-- Produces: `SourceInspector({ filename, children, triggerLabel?: string })` with a trigger and modal inspector.
-- Preserves: one server-highlighted source tree; opening the inspector never reloads the iframe.
-
-- [ ] **Step 1: Write failing inspector behavior tests**
-
-Cover closed-by-default state, accessible dialog name, initial close-button focus, Tab/Shift+Tab containment, Escape/backdrop/close-button dismissal, trigger-focus restoration, body scroll lock cleanup, reduced-motion class/state, and copy failure not blocking dismissal.
-
-```tsx
-render(
-  
-    
const open = true
-
, -) -const trigger = screen.getByRole('button', { name: 'View source' }) -await user.click(trigger) -expect( - screen.getByRole('dialog', { name: 'BasicSheet.tsx source' }), -).toBeVisible() -expect(screen.getByRole('button', { name: 'Close source' })).toHaveFocus() -await user.keyboard('{Escape}') -expect(screen.queryByRole('dialog')).not.toBeInTheDocument() -expect(trigger).toHaveFocus() -``` - -- [ ] **Step 2: Run the inspector test and verify RED** - -Run: `npx vitest run website/components/source-code/SourceInspector.test.tsx` - -Expected: FAIL because the inspector does not exist and source is a static details block. - -- [ ] **Step 3: Implement the inspector client shell** - -Use a portal-backed modal dialog with a labelled title and explicit backdrop. Store the trigger and dialog refs, focus the close button after opening, contain focus with a keydown handler, close on Escape/backdrop, lock body overflow while open, and restore the connected trigger with `{ preventScroll: true }`. Keep motion as CSS state driven by `data-state` and disable it under `prefers-reduced-motion`. - -- [ ] **Step 4: Compose server-highlighted source without client highlighting** - -Keep `RecipeSource` async/server-owned. Render `CodeBlock` once and pass the resulting React node as the inspector child. Move the source trigger into the Preview heading row through a `sourceAction` slot rather than coupling device controls to source state. - -```tsx -const code = await CodeBlock({ - source, - language: 'tsx', - filename, - lineNumbers: true, - copy: true, -}) -return {code} -``` - -- [ ] **Step 5: Simplify recipe document order** - -Remove the permanent source grid column. Render header, preview/source trigger, one guidance region containing prerequisites/behavior/accessibility, and related docs. Preserve semantic headings and searchable note text. - -- [ ] **Step 6: Add responsive inspector styles** - -Use a fixed overlay layer with a quiet backdrop. On wide screens cap the inline-end drawer at `min(48rem, 72vw)` and show part of the laboratory beneath; below 809px fill the viewport and apply safe-area padding. Code scrolls internally without wrapping or page overflow. Add one transform transition owned by open/close state and a reduced-motion override. - -- [ ] **Step 7: Run focused behavior, CSS, and accessibility tests** - -Run: `npx vitest run website/components/source-code/SourceInspector.test.tsx website/components/source-code/CopySourceButton.test.tsx && npm run test:website && npm run test:css && npm run typecheck` - -Expected: all tests pass with no accessibility-role or namespace violations. - -- [ ] **Step 8: Commit Task 3** - -```bash -git add website/components website/app/'(site)'/examples website/app/site.css -git commit -m "feat(docs): add recipe source inspector" -``` - -### Task 4: Preserve scroll during device navigation - -**Files:** - -- Modify: `website/components/device-lab/DeviceLab.tsx` -- Modify: `website/components/device-lab/use-scaled-frame.test.tsx` -- Modify: `e2e/website/recipes.spec.ts` - -**Interfaces:** - -- Preserves: existing `router.push(url)` history semantics for user changes. -- Changes: user `router.push(url, { scroll: false })` and normalization `router.replace(url, { scroll: false })`. - -- [ ] **Step 1: Write failing unit assertions for router options** - -Update mocked-router expectations for both a user change and invalid-query normalization: - -```ts -expect(navigation.push).toHaveBeenCalledWith( - '/examples/basic/?device=tablet&orientation=portrait', - { scroll: false }, -) -expect(navigation.replace).toHaveBeenCalledWith(normalizedUrl, { - scroll: false, -}) -``` - -- [ ] **Step 2: Write the failing browser scroll regression** - -Navigate to a recipe, scroll the document until the controls are near the top, record `scrollY`, change both orientation and device, wait for each morph to settle, and require the final `scrollY` to equal the recorded position within one CSS pixel. Also assert the same iframe handle and open sheet remain. - -- [ ] **Step 3: Run focused tests and verify RED** - -Run: `npx vitest run website/components/device-lab/use-scaled-frame.test.tsx` - -Expected: FAIL because calls currently omit `{ scroll: false }`. - -- [ ] **Step 4: Apply the root-cause fix** - -Pass `{ scroll: false }` to both App Router calls. Do not add manual scroll capture/restoration and do not alter morph state. - -- [ ] **Step 5: Run focused unit and Chromium browser tests** - -Run: `npx vitest run website/components/device-lab/use-scaled-frame.test.tsx` - -Run the scroll-tagged Playwright test through the ignored -`.superpowers/sdd/2026-09-04-example-workbench/local-playwright.config.ts` -configuration on verified-free port 4287 and Chromium. - -Expected: unit and browser tests pass; scroll, iframe identity, sheet state, and history assertions remain green. - -- [ ] **Step 6: Commit Task 4** - -```bash -git add website/components/device-lab e2e/website/recipes.spec.ts -git commit -m "fix(docs): preserve example scroll position" -``` - -### Task 5: Visual refinement and cross-browser proof - -**Files:** - -- Modify: `website/app/site.css` -- Modify: `e2e/website/home.spec.ts` -- Modify: `e2e/website/docs.spec.ts` -- Modify: `e2e/website/recipes.spec.ts` -- Modify: `scripts/check-website-css.test.mjs` -- Modify: `scripts/verify-website.test.mjs` - -**Interfaces:** - -- Consumes: shared CodeBlock, SourceInspector, and non-scrolling device navigation. -- Produces: final responsive/accessible behavior and static-output evidence. - -- [ ] **Step 1: Add failing browser and CSS contracts** - -Require highlighted tokens on homepage TSX and install command blocks, one TSX/CSS/shell documentation sample, and recipe source. At 1440px require an inline-end drawer overlay without preview geometry change; at 320px require a viewport inspector, contained code, reachable actions, and no document overflow. Require no code wrapping and visible keyboard focus. - -- [ ] **Step 2: Run focused Chromium tests and verify RED** - -Run the new home/docs/recipe tests with -`.superpowers/sdd/2026-09-04-example-workbench/local-playwright.config.ts` on -verified-free port 4287. - -Expected: FAIL until selectors, breakpoint behavior, and final palette/chrome are complete. - -- [ ] **Step 3: Refine the custom code and workbench styles** - -Apply the approved palette and technical manuscript treatment consistently. Remove obsolete two-column recipe/source and details styles. Keep the device lab centered, align its heading action, consolidate note spacing, and ensure drawer transitions affect only transform/backdrop opacity. - -- [ ] **Step 4: Run complete local verification** - -Run: `npm run check` - -Run: `npm run test:website:e2e -- --config .superpowers/sdd/2026-09-04-example-workbench/local-playwright.config.ts --project=chromium --project=firefox` - -Expected: repository checks pass; every Chromium/Firefox website test passes. - -- [ ] **Step 5: Inspect production artifacts** - -Serve `website/out` on verified-free port 4287. Confirm all 53 static pages exist, -highlighted token markup appears for all three languages, ordinary and embed -recipe routes remain distinct, and these commands return no client-runtime -matches: - -```bash -rg -ni 'shiki|onig\.wasm|@shikijs' website/out/_next/static || true -git diff --check -``` - -- [ ] **Step 6: Commit Task 5** - -```bash -git add website e2e scripts -git commit -m "style(docs): refine the example workbench" -``` - -### Task 6: Final review and pull-request gate - -**Files:** - -- Review: all files changed from `10474fbb9221549b55fae21bfc6fd884c1d26f40` to `HEAD` -- Update only if required by review: files already in Tasks 1–5 - -**Interfaces:** - -- Produces: a reviewed, clean branch ready for a pull request against `main` after PR #48 merges. - -- [ ] **Step 1: Audit spec coverage** - -Map each outcome, accessibility rule, responsive rule, failure case, and verification requirement from the spec to implementation and tests. Record any gap before requesting review. - -- [ ] **Step 2: Run the final repository and browser gates from the final tree** - -Run `npm run check`, then the full Chromium/Firefox website suite through -`.superpowers/sdd/2026-09-04-example-workbench/local-playwright.config.ts`. -Require zero failures and confirm the worktree contains only committed intended -changes. - -- [ ] **Step 3: Request code review** - -Review the complete diff for correctness, public API stability, server/client boundaries, exact source copying, navigation history/scroll behavior, focus lifecycle, responsive containment, reduced motion, and misleading claims. Address Critical and Important findings with focused regression tests. - -- [ ] **Step 4: Re-run affected checks and the final gate** - -After any review fix, run the focused regression first, then `npm run check`, Chromium/Firefox website tests, `git diff --check`, and production client-bundle inspection again. - -- [ ] **Step 5: Prepare the pull request** - -After PR #48 is merged, rebase or merge the latest `origin/main` without force-pushing, resolve only genuine follow-up conflicts, and rerun the final gate. Push only after user approval, open a PR against `main`, and require Quality, Chromium, Chromium Touch, Firefox, WebKit, and Vercel checks before merge. diff --git a/docs/superpowers/specs/2026-09-03-device-lab-design.md b/docs/superpowers/specs/2026-09-03-device-lab-design.md deleted file mode 100644 index 02733a2e..00000000 --- a/docs/superpowers/specs/2026-09-03-device-lab-design.md +++ /dev/null @@ -1,187 +0,0 @@ -# Interactive Device Lab Design - -## Summary - -The examples section will present every runnable recipe inside an isolated phone or tablet viewport. Readers can switch device class and orientation without resetting the example, share the selected configuration through the URL, and inspect highlighted source that is guaranteed to match the running component. - -The feature should feel like a precise testing instrument. The device transition is the primary visual gesture; the surrounding documentation remains restrained and keeps the bottom sheet itself as the focal point. - -## Goals - -- Run every recipe in a realistic, isolated browser viewport. -- Support phone and tablet presets in portrait and landscape orientations. -- Animate user-triggered device changes without reloading or resetting the recipe. -- Make device state shareable, testable, and compatible with browser history. -- Render accessible, project-specific TSX syntax highlighting at build time. -- Eliminate drift between the running example and its displayed source. -- Preserve static export, the current public package API, and the existing browser matrix. - -## Non-goals - -- A general-purpose online editor or executable code playground. -- Arbitrary device dimensions or user-provided preview URLs. -- Reproducing the chrome of VS Code or another editor. -- Wrapping prose-only documentation pages in device frames. -- Changing the library's public API to support the documentation site. - -## Route architecture - -Each recipe has a documentation route and a minimal embedded route: - -- `/examples/[slug]/` renders the explanation, device lab, guidance, and source. -- `/examples/[slug]/embed/` renders only the runnable example and its compact application surface. - -The embedded route uses the same allowlisted registry entry as the documentation route. It is same-origin so browser tests can inspect focus, portals, layout, and gestures. It must carry `noindex` metadata and must not render the site header, footer, or duplicate navigation. - -The iframe receives a recipe-specific accessible title. Its source URL does not change when the selected device changes, so resizing the frame does not remount the document or reset an open sheet. - -## Component architecture - -The documentation route is composed from: - -```text -DeviceLab -├── DeviceControls -├── DeviceFrame -│ └── RecipeEmbed -└── ViewportReadout - -RecipeSource -├── SourceHeader -├── CopySourceButton -└── HighlightedCode -``` - -Responsibilities are deliberately separated: - -- `DeviceLab` owns selected device state and URL synchronization. -- `DeviceControls` exposes semantic pressed buttons for device and orientation. -- `DeviceFrame` owns presentation, proportional scaling, and motion. -- `RecipeEmbed` owns iframe loading and fallback behavior. -- The embedded recipe owns its sheet state, document, focus, scrolling, and portals. -- `HighlightedCode` is a server component that performs build-time tokenization. -- `CopySourceButton` is the only client-side source-code control. - -Device presets and their labels, logical dimensions, and frame characteristics live in one typed configuration object. - -## Device state and URL behavior - -The default configuration is phone portrait. The selected state is encoded as: - -```text -?device=phone&orientation=portrait -``` - -Supported values are: - -- `device`: `phone` or `tablet` -- `orientation`: `portrait` or `landscape` - -Controls update the URL through normal navigation semantics so back and forward restore previous selections. Invalid or missing values fall back to phone portrait and are normalized without accepting arbitrary dimensions. - -The embedded URL remains stable across configuration changes. An open sheet therefore remains mounted and adapts while its viewport changes. - -## Viewport presets and scaling - -Logical viewport dimensions are: - -| Device | Portrait | Landscape | -| ------ | ---------: | ---------: | -| Phone | 390 × 780 | 780 × 390 | -| Tablet | 820 × 1080 | 1080 × 820 | - -The iframe retains the selected logical viewport dimensions. If the available documentation width cannot contain the device at full size, the complete frame scales proportionally. Scaling the presentation must not silently change the iframe's internal responsive breakpoint. - -The device stage has no decorative grid. It uses a neutral background, restrained bezel, subtle depth, and only enough hardware detail to communicate orientation. A small readout identifies the device and exact viewport dimensions. - -## Motion - -Changing device or orientation animates frame width, height, corner radius, and bezel proportions. The transition is user-triggered and must not reload the iframe. - -The motion should be calm and direct, without overshoot that distracts from the component demonstration. When `prefers-reduced-motion: reduce` is active, dimensions and frame styling change immediately. - -The implementation must avoid animating document layout in a way that causes surrounding content to jump unpredictably. The stage reserves or smoothly updates the required presentation height. - -## Recipe isolation - -An iframe is preferred over injected portal targets because it gives every example a genuine document and viewport boundary. Default portals then target the embedded document body exactly as they do in a consumer application. Fixed positioning, focus containment, scrolling, resize observation, and viewport-relative sizing can be exercised without documentation-only changes to recipe code. - -The custom-portal recipe retains its own application-owned portal target inside the embedded document. No internal portal context or alternate public API is introduced. - -## Canonical source pipeline - -The runnable recipe component file is the canonical source. The registry stores an allowlisted source-file reference alongside the component and metadata. - -During static generation: - -1. The server resolves the registered source path within the recipe directory. -2. It reads the exact component file. -3. Shiki tokenizes it as TSX using the project theme. -4. React renders static token spans and line numbers. -5. The raw source is passed only to the copy control. - -The current manually maintained source-string modules are removed after all recipes use the canonical pipeline. Validation fails when a registered source path is absent, escapes its allowed directory, or no longer corresponds to its recipe. - -Shiki is build-time infrastructure. Only the TSX grammar and the custom theme are loaded, and no highlighting runtime is shipped to the browser. - -## Source presentation - -The source block uses a distinct visual language derived from the existing website palette rather than mimicking a commercial editor. It includes: - -- a concise filename label; -- an accessible copy button with status feedback; -- stable line numbers that are not included in text selection; -- selectable code with horizontal scrolling; -- a project-specific, high-contrast token palette; -- visible keyboard focus around the scrollable region. - -There are no fake window controls, fake tabs, or decorative editor chrome. On wide layouts the source and device may form a balanced split view; on narrower layouts the source follows the preview. - -## Accessibility - -- Device and orientation selectors are ordinary buttons with `aria-pressed`. -- Labels remain visible and do not rely on icons alone. -- The viewport readout announces configuration changes through a polite live region. -- The iframe has a unique title based on the recipe. -- Device chrome is presentational and excluded from the accessibility tree where appropriate. -- Opening a modal recipe traps focus within the embedded document; closing restores focus to its embedded trigger. -- The parent documentation document is not incorrectly marked inert when an embedded sheet opens. -- Source token colors meet WCAG contrast requirements, and syntax meaning never depends on color alone. -- Reduced-motion preferences remove the device morph without removing state feedback. - -## Loading and failure behavior - -The frame presents a quiet loading state until the embedded document signals readiness. A failed or timed-out embed displays a useful message and a direct retry/open link. The fallback does not replace the iframe during ordinary device transitions. - -Copy failures retain the existing selection-based fallback and provide textual status. Unsupported or invalid URL state falls back safely to a known preset. - -## Responsive behavior - -The lab uses the available content width rather than assuming a desktop viewport. Device controls wrap without horizontal overflow. The logical preview remains accurate while its visual representation scales down. - -On wide documentation layouts, preview and source can share the row when both retain useful reading width. On compact layouts they stack in document order: controls, preview, guidance, source. No breakpoint may introduce horizontal page scrolling. - -## Verification strategy - -Automated coverage must verify: - -- every registered recipe produces a documentation page and embedded page; -- the source displayed for each recipe matches its canonical component file; -- all four device configurations resolve from URL state; -- invalid query state normalizes to phone portrait; -- back and forward navigation restore selections; -- device changes preserve the iframe document and an open sheet; -- the iframe's internal viewport matches the selected logical dimensions; -- reduced motion disables interpolation; -- portals, backdrop transitions, focus restoration, scrolling, gestures, and custom portal ownership work inside the embed; -- device controls and source controls are keyboard accessible; -- representative configurations pass automated accessibility checks; -- static export, unit tests, type checking, linting, formatting, package verification, and the supported browser matrix remain green. - -## Delivery slices - -1. Add embedded recipe routes, registry source references, canonical source loading, and source-drift checks. -2. Add URL-backed device controls, isolated frames, proportional scaling, loading behavior, and motion. -3. Add the custom Shiki theme, responsive source layout, accessibility polish, and complete browser coverage. - -Each slice is independently reviewable and must retain a green repository check before it is proposed for merge. diff --git a/docs/superpowers/specs/2026-09-04-adoption-campaign-design.md b/docs/superpowers/specs/2026-09-04-adoption-campaign-design.md deleted file mode 100644 index 162a44ab..00000000 --- a/docs/superpowers/specs/2026-09-04-adoption-campaign-design.md +++ /dev/null @@ -1,242 +0,0 @@ -# Maintainer-led adoption campaign - -## Purpose - -Grow adoption of `@nipe-solutions/react-spring-bottom-sheet` by helping users of -the original package discover a credible, actively maintained React 19 path. -The campaign is led personally by Nicholas, preserves the project's lineage, -and prioritizes useful migration work over bulk promotion. - -## Positioning - -The primary message is: - -> An independently maintained React 19 continuation of -> `react-spring-bottom-sheet`, rebuilt around accessible compound components, -> explicit styling contracts, and current-browser verification. - -The project must not describe itself as the official successor unless the -original maintainer explicitly grants that status. “Maintained continuation” -must always appear with the independent-maintenance and lineage context. - -Maintenance is evidence, not the whole value proposition. Public copy should -lead with React 19 compatibility, accessibility, composability, and verified -browser behavior. Claims must be backed by repository tests, release metadata, -or published documentation. - -## Audiences - -1. Existing direct users of `react-spring-bottom-sheet` who need React 19. -2. Maintainers whose dependency trees still contain the original package. -3. Component-library and application maintainers evaluating sheet primitives. -4. React and accessibility practitioners interested in the rebuild. - -## Repository conversion surface - -### README - -The README opening should answer, without scrolling: - -- what the package is; -- how it relates to the original project; -- why a team would choose it now; -- the supported React version; -- where to see a live example and migration guide; -- how to install it. - -Add a restrained proof row for the npm version, CI status, license, React 19, -and package size only where those badges resolve to maintained sources. Include -a compact feature list, a live-demo call to action, and a dedicated migration -section that links to the full guide. Preserve prominent attribution to Cody -Olsen and Jasmine GH. - -### GitHub metadata - -Set the repository description to a factual, search-friendly summary: - -> Accessible, composable React 19 bottom sheets — an independently maintained -> continuation of react-spring-bottom-sheet. - -Set the website field to the production documentation URL. Use focused topics: - -- `react` -- `react-19` -- `bottom-sheet` -- `drawer` -- `dialog` -- `accessibility` -- `typescript` -- `gesture` -- `headless-ui` -- `react-spring-bottom-sheet` - -Do not use unrelated or competitor names as tags. - -### Migration discovery page - -Add a first-class website route aimed at users searching for a maintained -version of the original package. It should include: - -- an explicit independent-continuation statement; -- package-name and installation changes; -- a minimal old/new controlled example; -- the major prop, callback, and CSS mappings; -- React and browser requirements; -- links to the complete guide, examples, API reference, npm, and GitHub; -- metadata targeting factual migration and React 19 queries without keyword - stuffing. - -The page becomes the canonical destination used in outreach and migration PRs. - -## Maintainer outreach - -Outreach is written in the first person as Nicholas. Messages should be short, -specific to the recipient, technically accurate, and free of pressure. - -### Original maintainers - -Contact the original project maintainer first. Ask whether they would be -comfortable adding a README pointer for users seeking an actively maintained -React 19 implementation. Offer the migration page as the destination. - -Do not ask for npm ownership, package transfer, deprecation, or an “official” -endorsement in the first message. Those may be discussed only if the maintainer -raises them or Nicholas separately approves a follow-up. - -### Dependency maintainers - -Contact maintainers only after tracing the exact dependency and API ownership. -For the Hyperlane case, explain that the path is -`starknetkit → @argent/x-ui → react-spring-bottom-sheet`, and direct the -migration proposal to the component that wraps the old API. Do not propose a -Hyperlane package-manager override as a migration. - -### Channels and records - -Prefer an existing repository discussion or narrowly scoped issue when no -private contact channel is connected. Avoid duplicate outreach across email, -issues, and social channels. Record the URL, date, recipient, purpose, status, -and follow-up date in a campaign tracker. Never publish private email addresses -in repository files. - -## Real-world migrations - -Research active public repositories that directly import the original package. -Score candidates on: - -- recent maintenance activity; -- React 19 compatibility or an active React 19 migration; -- direct rather than purely transitive usage; -- manageable API and styling surface; -- available automated tests or reproducible build; -- visible benefit from v5 accessibility and maintenance. - -Select at most three initial candidates. Before opening a PR, migrate the code -fully, preserve behavior and styling, run the repository's own verification, -and explain any intentional differences. Do not submit dependency-only PRs for -breaking migrations and do not automate bulk pull requests. - -If repeated migration friction reveals a small faithfully mappable legacy -surface, document the evidence and propose a compatibility adapter separately. -Do not build an adapter speculatively. - -## Technical launch content - -Prepare one substantial article with the working title: - -> Rebuilding react-spring-bottom-sheet for React 19: accessibility, gestures, -> and six years of ecosystem change - -The article should explain the lineage, engineering constraints, new component -model, accessibility choices, gesture and interruption behavior, styling -contract, browser matrix, and migration path. It must be useful independently -of the promotional call to action. - -Prepare channel-specific excerpts for developer communities, but do not publish -the same generic copy everywhere. Public launch follows the migration page and -at least one of: an upstream acknowledgement, an accepted migration, or a -documented production integration. This supplies external evidence before a -broad announcement. - -## Campaign tracker - -Keep a local, non-published tracker outside product documentation when it may -contain contact details or draft correspondence. The publishable repository may -contain a generic adoption checklist, but not personal data or private notes. - -For each action track: - -- target and dependency relationship; -- public URL, if any; -- current status; -- last action and next follow-up date; -- response or technical blocker; -- resulting referral, PR, or adoption evidence. - -Follow up at most once after a reasonable interval. A non-response ends the -sequence. - -## Execution phases - -### Phase 1: Conversion foundation - -1. Improve README positioning and calls to action. -2. Add and verify the migration discovery page. -3. Update GitHub description, website field, and topics. -4. Prepare the private campaign tracker. - -### Phase 2: Targeted outreach - -1. Contact the original maintainer. -2. Contact the owner of the `@argent/x-ui` integration or its reachable parent - project. -3. Inform Hyperlane with the upstream migration context where useful. -4. Research and rank direct-user migration candidates. - -### Phase 3: Adoption evidence - -1. Complete up to three tested migrations. -2. Incorporate recurring migration lessons into documentation. -3. Collect only verifiable public adoption evidence. - -### Phase 4: Technical launch - -1. Finish the technical article and channel-specific excerpts. -2. Publish only after the evidence threshold is met. -3. Respond to technical feedback and measure qualified traffic and migrations. - -## Verification - -Repository changes must pass `npm run check` and the relevant website browser -tests. The migration page must be included in navigation, sitemap, metadata, -link verification, narrow-layout coverage, and accessibility checks. - -GitHub metadata must be read back after mutation. Every public issue, discussion, -or PR must be opened against the intended repository from the intended account, -then read back and recorded. External migrations must pass the target project's -available checks before submission. - -## Success criteria - -Initial success is measured by qualified outcomes rather than raw impressions: - -- the migration page is indexed and receives relevant referrals; -- the original maintainer responds or adds a discovery pointer; -- at least one upstream dependency owner engages with the migration; -- at least one real application completes or accepts a migration; -- new-package downloads show sustained growth over multiple completed months; -- issues reveal successful usage rather than unresolved migration confusion. - -Download counts must be reported with their npm date window and must not be -presented as a count of active developers. - -## Authority and escalation - -Nicholas authorizes targeted public contact and technically complete public PRs -under the authenticated `Cylop` GitHub identity. Routine wording, issue creation, -and PR iteration are in scope. - -Return to Nicholas before accepting ownership transfers, npm access, legal or -commercial commitments, paid promotion, sponsorship terms, coordinated release -dates, or any request to characterize the project as official. Destructive or -irreversible repository actions remain out of scope. diff --git a/docs/superpowers/specs/2026-09-04-example-workbench-design.md b/docs/superpowers/specs/2026-09-04-example-workbench-design.md deleted file mode 100644 index 2a033c7d..00000000 --- a/docs/superpowers/specs/2026-09-04-example-workbench-design.md +++ /dev/null @@ -1,203 +0,0 @@ -# Example workbench and shared code presentation - -## Purpose - -Make examples feel like a focused laboratory instead of a long documentation -page, while giving every substantial code sample on the website consistent, -accurate syntax highlighting. Preserve the static-export architecture, the -existing public package API, and the stable recipe iframe during device changes. - -## Outcomes - -- The documentation page named “Examples” contains an explicit call to action - to open the example laboratory at `/examples/`. -- Each recipe page gives the interactive device preview visual priority. -- Recipe source opens on demand in a right-side inspector on wide screens and a - full-viewport inspector on compact screens. -- Documentation and homepage block snippets use the same server-rendered code - system as recipe source. -- Changing device or orientation keeps the current document scroll position. -- TSX highlighting distinguishes React/JSX constructs clearly without copying - a third-party editor theme or adding highlighting code to the client bundle. - -## Information architecture - -The recipe header remains concise: route, title, summary, and the link back to -all recipes. The laboratory follows immediately. Its heading row owns a -prominent `View source` action, so the relationship between the running example -and its implementation is explicit. - -Prerequisites, behavior, and accessibility guidance form one restrained notes -region below the laboratory. They remain ordinary document content and -therefore stay searchable, linkable, and available without opening an overlay. -Related documentation remains the final navigation region. - -The generic Examples documentation entry keeps its explanatory copy and adds a -clear `Open the example laboratory` link. It must not rely on readers noticing -the global header link. - -## Source inspector - -The source inspector overlays the page rather than changing the document grid. -This prevents the device preview from shrinking, reflowing, or losing its -current state when source is opened. - -On wide screens it enters from the inline end as a drawer sized for readable -code, capped so part of the underlying laboratory remains visible. On compact -screens it occupies the viewport. It has a quiet backdrop and one deliberate -open/close motion; reduced-motion users get an immediate state change. - -The inspector is a modal dialog with: - -- a visible title, filename, language, copy action, and close action; -- initial focus on the close action; -- focus containment while open; -- `Escape` dismissal; -- focus restoration to the `View source` trigger; -- background interaction suppression; -- internal vertical and horizontal scrolling without body-scroll leakage. - -Source is closed by default. Opening it does not alter the URL because it is a -temporary inspection state rather than shareable recipe state. Device and -orientation query parameters remain shareable. - -The highlighted token tree stays server-rendered. A small client shell owns only -dialog state, focus behavior, and copy feedback. The canonical source string is -still the sole input for display and copying. - -## Shared code-block system - -Introduce a server-rendered `CodeBlock` component for substantial examples. -It accepts exact source text, a supported language, and optional presentation -metadata such as filename, line numbers, and copy capability. It delegates to a -language-aware highlighter and renders tokens as React nodes; it never injects -highlighted HTML. - -Initial supported languages are: - -- `tsx` for React and TypeScript examples; -- `css` for styling examples; -- `shell` for install and registry commands. - -The recipe inspector uses the same rendering primitive with filename, line -numbers, and copy enabled. Homepage and documentation snippets use the smallest -appropriate chrome: commands do not need line numbers, while multiline TSX and -CSS examples do. Inline `code` remains a separate lightweight typographic -treatment and is not passed through Shiki. - -All existing block-level `pre > code` snippets on the homepage and in docs are -migrated. No duplicate source strings are introduced for recipe files. - -## Highlighting language - -Keep a custom dark palette derived from the website’s cool blue, violet, green, -and amber signals. Increase semantic separation instead of increasing visual -noise. TSX scopes must distinguish at minimum: - -- JSX component and intrinsic element names; -- JSX attributes and object properties; -- language keywords and storage modifiers; -- functions and calls; -- types and interfaces; -- strings, numbers, and constants; -- comments; -- punctuation and braces. - -CSS selectors, properties, values, strings, numbers, and comments receive the -same semantic hierarchy. Shell commands distinguish executables, flags, -strings, variables, and comments. Comments may be italic; ordinary source text -must remain upright. Every token and UI control must meet the site’s contrast -requirements. - -The code surface uses the project’s established squared, technical visual -language: a deep neutral manuscript, restrained one-pixel rules, tabular line -numbers, and no decorative traffic-light controls or imitation editor branding. - -## Scroll-preserving device state - -The observed jump originates at query navigation: Next.js App Router navigation -scrolls by default, and `DeviceLab` currently calls `router.push` and -`router.replace` without overriding it. - -Both user-driven device changes and automatic normalization pass -`{ scroll: false }`. Browser history remains intact for user changes, the iframe -identity remains stable, and the existing morph interruption/rollback behavior -is unchanged. No manual `window.scrollTo` restoration is used. - -## Components and boundaries - -- `CodeBlock` is the public website-level server component for block snippets. -- The highlighter module owns supported languages, singleton construction, and - the custom theme. -- A token renderer owns exact whitespace, native selection, optional line - numbers, and accessible labels. -- `SourceInspector` owns client dialog behavior and composes the rendered code - plus the existing copy control. -- `RecipePreview` exposes the source trigger beside the laboratory heading. -- `DeviceLab` remains responsible only for device selection, URL state, iframe - readiness, and morph coordination. - -These are website-internal contracts. No exported library component or type is -changed. - -## Responsive behavior - -- Wide recipe pages use one centered laboratory column; source no longer forms - a permanent second grid column. -- The wide drawer leaves a recognizable portion of the page visible and caps - code line length through its viewport, not by wrapping source. -- At the compact breakpoint, the inspector fills the available viewport and - accounts for safe-area insets. -- Code always scrolls horizontally; source text never wraps or forces document - overflow. -- At 320 CSS pixels, controls remain reachable and no page-level horizontal - scrollbar is introduced. - -## Failure handling - -- If highlighting fails during build, the build fails rather than silently - publishing misleading or incomplete source. -- Copy failures retain the existing explicit recovery message and native - selection fallback. -- The inspector remains closable and focus-restoring even if copying fails. -- Device navigation rollback retains its existing bounded timeout; disabling - scroll must not change that state machine. - -## Verification - -Use test-driven implementation with focused red/green coverage before broad -gates. - -Unit and render tests verify: - -- language loading and singleton highlighter reuse; -- exact source and trailing-newline preservation for TSX, CSS, and shell; -- meaningful token distinctions for each supported language; -- optional filename, line-number, and copy presentation; -- every former block snippet is migrated to `CodeBlock`; -- the Examples documentation call to action targets `/examples/`; -- dialog naming, focus entry, containment, Escape dismissal, restoration, and - reduced-motion behavior; -- both device navigation calls use the non-scrolling option. - -Browser tests verify in Chromium, Firefox, and CI WebKit: - -- opening and closing the inspector preserves the live iframe and sheet state; -- source is exact, selectable, copyable, and horizontally contained; -- the drawer/full-screen breakpoint behavior and 320-pixel containment; -- device and orientation changes preserve `scrollY`, focus, iframe identity, - query parameters, and morph behavior; -- homepage and docs snippets contain server-rendered highlighted tokens with no - hydration errors; -- keyboard and accessibility checks remain clean. - -The final repository gate is `npm run check`, followed by the complete website -browser matrix and inspection of static output to prove that Shiki and its -grammar engines are absent from client JavaScript. - -## Delivery - -This is a follow-up to the highlighted canonical recipe source change. It ships -as a separate feature branch and pull request after that dependency is merged. -CI WebKit is mandatory before merge because the pinned local macOS WebKit binary -cannot start in the current environment. diff --git a/package-lock.json b/package-lock.json index 9980253a..6f08d61c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "globals": "^17.3.0", "jsdom": "^30.0.1", "motion": "13.4.0", - "next": "^16.3.4", + "next": "^16.3.6", "postcss": "^8.5.27", "postcss-selector-parser": "^7.1.6", "prettier": "^3.9.0", @@ -1130,16 +1130,16 @@ "license": "MIT" }, "node_modules/@next/env": { - "version": "16.3.5", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.3.5.tgz", - "integrity": "sha512-NWEXVDMqoEo0ktmU6u0sE2Vg0LOcsD7NnOTJNo3/fEaTfsg+F1bMIxuDmQbda4e3yTIQwVdUREF2yIuMOusKtg==", + "version": "16.3.8", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.3.8.tgz", + "integrity": "sha512-Al9zqHVV7TJv0eFuOU4U7Lvv74PTih4Ch63sk2xCIpSTkE3udFnaOcnzP2lQVymiL7yS9Cj2iClUXlR3EQ5sEw==", "dev": true, "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.3.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.3.5.tgz", - "integrity": "sha512-pMmGgETfKvElucLHtVaeiMRbp2zUbvKx7b1yGko0liBz3cw1mKSggWN/Rp/wPz8z+E1O82u3r4L1Co+ZS5hokQ==", + "version": "16.3.8", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.3.8.tgz", + "integrity": "sha512-2JPRMh2nmQG5CiL7cXGL9AGwnPWJQ//cTtAUCT+w511QHk79SYz3LGv/pc5X643B/WEO0rvu3Yww0hqwt3kgeA==", "cpu": [ "arm64" ], @@ -1154,9 +1154,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.3.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.3.5.tgz", - "integrity": "sha512-76VaGYvf6HPa5/w12yLkE3dXTn9AfdEviI79oEL3aZoAmRLc9rWitjWqyjViVysK/ht/y9YKzFkBrUdi/wGkow==", + "version": "16.3.8", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.3.8.tgz", + "integrity": "sha512-GZtCCOBKJ4leVIT/Th0llWKhD1ca92lzbQiS5R5ON9QkoiFnilFsebDae1JU2a3HWoKMEmEZWGs1AGLavVM72Q==", "cpu": [ "x64" ], @@ -1171,9 +1171,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.3.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.3.5.tgz", - "integrity": "sha512-zKDELJ5jSQMHeO/hmXUQsAzagX4bQD4OiMi3pQ5FbUj+yK506oLVHnKA2YXMlbg1EHHqJYtyePOgByIDXD1lqw==", + "version": "16.3.8", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.3.8.tgz", + "integrity": "sha512-O659ygeQYqneJ1fBKMpFxIFqYkYswu8IAS1OCKK/4f3ZgJJm1dRz4fVJZRi/kLLWjnBKnebOePA4WNv+sV1pVA==", "cpu": [ "arm64" ], @@ -1191,9 +1191,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.3.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.3.5.tgz", - "integrity": "sha512-7Vql0pgzCoHagv6+FNOZoqmJqA52c6zeVbhtS/47qFozO1MSx4ms7x7GHiciY8R5CDsSMKMQjJEryoJLcsBIbA==", + "version": "16.3.8", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.3.8.tgz", + "integrity": "sha512-dSjKSyWpzxoO1d3DIZZcP4XJcNaKeLmxQMFOiYl5vuBRMmweIqnAhty8tAmRsvTss779cK1FtYnDMj40e4TQlg==", "cpu": [ "arm64" ], @@ -1211,9 +1211,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.3.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.3.5.tgz", - "integrity": "sha512-NH/xzehyHEFWE2nlcZon7TB/0+H4shfWCi7S1zka815XCOhJDYZhoeJtOYy0dh0WVRWACVXSyGNFFytoMxUhRg==", + "version": "16.3.8", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.3.8.tgz", + "integrity": "sha512-lbqOuz3RPRcv+o9msNsJw5x4+Y1ZwPTs6vmL6DCf7i0fZfvng/F59wyeDwqHIvV0mK//RBy/jJkZ+nCKsSMXjQ==", "cpu": [ "x64" ], @@ -1231,9 +1231,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.3.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.3.5.tgz", - "integrity": "sha512-lV4+EhWMfS8jcC+EH2nn/Cm5cn6XsgbE07bU9tMH8fCo0tNAqhyzi1b5wQ/Tn6NGFTvKDY65w3ZH95EjwBRAnQ==", + "version": "16.3.8", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.3.8.tgz", + "integrity": "sha512-+316WswI8ScVgZeUd+1KGaXkHhaYQzCjvH/05TZSpJ8zBizb1a4G7DtO7F12jcBIqMOtsz9ji1t48fmKtzqsGA==", "cpu": [ "x64" ], @@ -1251,9 +1251,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.3.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.3.5.tgz", - "integrity": "sha512-/wKzAREX2RF++MhicjDbg8tGn2AiBIM0+EFeTFKoUEUbW5D6amCJehd5Z5G1H5/gxNdgnwoXMcHz24H/c2tGkQ==", + "version": "16.3.8", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.3.8.tgz", + "integrity": "sha512-ji0gd4kMYUxO+1fJBIbiBVRCjzG/lloiyCccnlebvb1ZJ5qXCPZqYg4Jl1DrrixnWNMKylzgpmMWx0yNDYXlzw==", "cpu": [ "arm64" ], @@ -1268,9 +1268,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.3.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.3.5.tgz", - "integrity": "sha512-LNdCHzgLFc+UeqMS84LzXPaeBRKyqDN9OMyFAr1OrB0XrNw78IRrEVtZvvA7245W/HsaoeVOQX9jPjPk8jojwA==", + "version": "16.3.8", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.3.8.tgz", + "integrity": "sha512-WcTlaKt/TWkh5kUjdJcUmB1XgZ+1c6fz4Y9fDHL73YNSdGaUWjceeWrrlwF0nv19iABYWC4iAq1oX1w4Bn0vfg==", "cpu": [ "x64" ], @@ -2488,9 +2488,9 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3278,9 +3278,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", - "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", "dev": true, "funding": [ { @@ -4404,13 +4404,13 @@ } }, "node_modules/next": { - "version": "16.3.5", - "resolved": "https://registry.npmjs.org/next/-/next-16.3.5.tgz", - "integrity": "sha512-MdtsTgzyfCPRLC6uJ1mN8ao7lyJ4BB0U6Inhnx3gta1UcCIdHK3yxLG0E8OWQteWD8/Q0qb8A5o7wJaL8M9y2w==", + "version": "16.3.8", + "resolved": "https://registry.npmjs.org/next/-/next-16.3.8.tgz", + "integrity": "sha512-U7QEZaTini6wKrb8A8hqLLqYQyCetegKjCpJOyxk642vWoMoU1x5PyZCJFvgYgiptA8xc5j/9xYlZFO7w9Sjmw==", "dev": true, "license": "MIT", "dependencies": { - "@next/env": "16.3.5", + "@next/env": "16.3.8", "@swc/helpers": "0.5.23", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", @@ -4424,14 +4424,14 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.3.5", - "@next/swc-darwin-x64": "16.3.5", - "@next/swc-linux-arm64-gnu": "16.3.5", - "@next/swc-linux-arm64-musl": "16.3.5", - "@next/swc-linux-x64-gnu": "16.3.5", - "@next/swc-linux-x64-musl": "16.3.5", - "@next/swc-win32-arm64-msvc": "16.3.5", - "@next/swc-win32-x64-msvc": "16.3.5", + "@next/swc-darwin-arm64": "16.3.8", + "@next/swc-darwin-x64": "16.3.8", + "@next/swc-linux-arm64-gnu": "16.3.8", + "@next/swc-linux-arm64-musl": "16.3.8", + "@next/swc-linux-x64-gnu": "16.3.8", + "@next/swc-linux-x64-musl": "16.3.8", + "@next/swc-win32-arm64-msvc": "16.3.8", + "@next/swc-win32-x64-msvc": "16.3.8", "sharp": "^0.35.4" }, "peerDependencies": { @@ -5151,9 +5151,9 @@ "license": "MIT" }, "node_modules/serve-handler/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index ef8d27d2..ac4f239f 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "globals": "^17.3.0", "jsdom": "^30.0.1", "motion": "13.4.0", - "next": "^16.3.4", + "next": "^16.3.6", "postcss": "^8.5.27", "postcss-selector-parser": "^7.1.6", "prettier": "^3.9.0",