Skip to content

Pull upstream 202604#38

Merged
craftzdog merged 12 commits intomainfrom
pull-upstream-202604
Apr 29, 2026
Merged

Pull upstream 202604#38
craftzdog merged 12 commits intomainfrom
pull-upstream-202604

Conversation

@craftzdog
Copy link
Copy Markdown
Contributor

Overview

Upgrade the Inkdrop API docs site to match the latest upstream Tailwind UI "Protocol" template. Two orthogonal axes of change executed in phases: (1) major dependency bumps (Next 14→16, React 18→19, framer-motion 10→12, zustand 4→5, flexsearch 0.7→0.8, ESLint 8→9 flat config, etc.) and (2) full JavaScript→TypeScript migration of all non-MDX source. All Inkdrop-specific customizations (Fathom analytics, Navigation structure, pink typography theme, solarized-dark Shiki theme, custom icons, search index customizations, /guides/list-of-commands h3 indexing, extra components) preserved.


Confirmed Decisions (2026-04-23)

  1. Prettier — Keep current explicit config. No formatting churn.
  2. fathom-client — Bump to ^3.7.2. (Ships own types — no shim.)
  3. src/mdx/*.mjs — User chose convert to TS. Outcome (Phase 6h): deferred. Next 16's next.config.ts compiles to CJS (exports.default = ...) but loads in ES module scope, throwing ReferenceError: exports is not defined in ES module scope. Renaming next.config.mjs.ts is the only way to import .ts files transitively (Node ESM can't load .ts), but the resulting compiled config crashes at startup. Upstream Protocol template also keeps these as .mjs. Reverted: 4 .mjs files retained, types.d.ts shim retained for @/mdx/search.mjs.
  4. Bundler--webpack on dev/build. Resolved Phase 3.
  5. Commits / PR — None. User reviews each phase.

Status

  • Phase 1 — TypeScript scaffolding ✅ 2026-04-23
  • Phase 2 — Tooling bumps (Prettier plugins, sharp) ✅ 2026-04-23 — ESLint 9 deferred to Phase 3
  • Phase 3 — Next 14→16 + React 18→19 + framer-motion + next-themes + HUI + react-highlight-words + ESLint 9 flat config ✅ 2026-04-23 — absorbed Phase 7
  • Phase 4 — zustand 4 → 5 ✅ 2026-04-23 — no code changes needed
  • Phase 5 — flexsearch 0.7 → 0.8 ✅ 2026-04-23 — no code changes needed
  • Phase 6a — Lib + primitives (remToPx, mdx-components, typography, tailwind.css) ✅ 2026-04-27
  • Phase 6b — Icons (28 from upstream + 5 Inkdrop-only typed) ✅ 2026-04-27
  • Phase 6c — Leaf components ✅ 2026-04-27 — Heading refactored to const resolvedLevel; react-hooks/immutability re-enabled
  • Phase 6d — Inkdrop-only components (Fathom, ListNavigationSection, MarkdownSourceLink) ✅ 2026-04-27
  • Phase 6e — Composite components (Search, mdx, Code) ✅ 2026-04-27 — Phase 3 patches preserved (<a> for external links, Children.toArray(children).find(isValidElement) in CodePanel)
  • Phase 6f — Navigation + Layout + Header + MobileNavigation + SectionProvider ✅ 2026-04-27 — Inkdrop nav tree (8 groups, 50+ entries) transplanted verbatim; pink ActivePageMarker preserved; "Developers" branding preserved
  • Phase 6g — App files (layout, providers, not-found) ✅ 2026-04-27 — <Fathom /> mount preserved
  • Phase 6h — MDX pipeline to TS — deferred (see Decision 3 above)
  • Phase 7 — next.config.mjs + scripts (--webpack) ✅ 2026-04-23 — absorbed into Phase 3
  • Phase 8 — Final sweep (lint, build, smoke)

Lint deferrals — final state after Phase 6

The three react-hooks@7 strict rules that were disabled in Phase 3 to match upstream Protocol patterns:

  • react-hooks/immutabilityre-enabled in Phase 6c. Heading.tsx now uses const resolvedLevel = level ?? (2 as Level) instead of mutating the destructured level parameter.
  • react-hooks/set-state-in-effect — still disabled. Affects setMounted(true) in ThemeToggle.tsx and setModifierKey(...) in Search.tsx. Both are SSR/CSR hydration-gate patterns inherited from upstream Protocol; refactor would be invasive (and out of scope).
  • react-hooks/refs — still disabled. Affects inputElement: inputRef.current passed during render in Search.tsx. Also upstream's pattern.

Phase 3 React 19 runtime patches — final state after Phase 6e

Both temporary patches survived TS conversion:

  • mdx.tsx: external-link wrapper still uses plain <a> (not <Link>). Upstream keeps export const a = Link (no external-icon decoration); we keep the Inkdrop external-icon decoration via plain <a>. Semantically correct for external links.
  • Code.tsx: CodePanel still uses Children.toArray(children).find(isValidElement) instead of Children.only. Comment in code documents the Phase 3 finding. Root cause not pinned.

Architecture Changes (final)

  • /tsconfig.json, /types.d.ts, /mdx-components.tsx, /typography.ts — TS landed (no jsconfig.json).
  • /eslint.config.mjs — flat config using eslint-config-next/core-web-vitals native flat export.
  • /next.config.mjs — top-level outputFileTracingIncludes, outputFileTracingRoot pinned. Stays .mjs.
  • /package.json — Next 16, React 19, ESLint 9, framer-motion 12, zustand 5, flexsearch 0.8, next-themes 0.4, HUI 2.2.6, fathom-client 3.7.2; removed @headlessui/tailwindcss; added @types/react@19.2.14/@types/react-dom@19.2.3 with overrides block; dev/build use --webpack, lint uses eslint ..
  • /src/app/*.tsx — layout, not-found, providers (Fathom mount preserved).
  • /src/components/*.tsx — all 21 components typed.
  • /src/components/icons/*.tsx — all 33 icons typed.
  • /src/lib/remToPx.ts.
  • /src/mdx/*.mjs — kept as .mjs (Decision 3 deferred).
  • /src/styles/tailwind.css@config '../../typography.ts'; article kbd rule preserved.
  • /tailwind.config.js — vestigial dead code in Tailwind v4 (compiler reads CSS-based config); not loaded; leaving for now.

Risks & Mitigations — final reconciliation

  • HIGH: Navigation re-application losing entries. Mitigated in Phase 6f: copied upstream typed Navigation skeleton, transplanted Inkdrop's navigation array verbatim, added link?: string to NavGroup interface for Inkdrop's group-level link field on App States and App Actions sections. Build green; user verification of every nav link is the smoke step.
  • HIGH: flexsearch 0.8 breaks search.mjs. Resolved Phase 5 — zero source changes needed; API surface preserved.
  • HIGH: React 19 type tightening. Realized Phase 3 — two prerender Children.only failures patched; both preserved through Phase 6 TS port.
  • MEDIUM: zustand v5 selector breakage. Resolved Phase 4 — zero changes needed.
  • MEDIUM: Next 15 async params. Resolved Phase 3 — zero hits.
  • MEDIUM: framer-motion 12 layoutScroll. Build-level smoke OK Phases 3 + 6f; visual smoke for user.
  • MEDIUM: eslint-config-next 14 + ESLint 9. Resolved Phase 3 — flat config via eslint-config-next/core-web-vitals native export.
  • LOW: fathom-client types. Ships own; no shim.
  • LOW: Tailwind @config path. Resolved Phase 6a.
  • LOW: HUI tailwind plugin removal. Resolved Phase 3.
  • NEW (Phase 3): Turbopack + custom MDX loader. Resolved with --webpack.
  • NEW (Phase 6h): next.config.ts ESM/CJS conflict. Reverted to .mjs.

Success Criteria

  • package.json matches upstream on Next, React, framer-motion, zustand, flexsearch, ESLint, next-themes, HUI (extras: fathom-client, unist-util-map).
  • typescript, @types/react@19.x, @types/react-dom@19.x, @types/node, @types/mdx, @types/react-highlight-words installed; overrides block present.
  • tsconfig.json and types.d.ts present; jsconfig.json removed.
  • All src/**/*.jsx and src/**/*.js renamed to .tsx/.ts (61 files); src/mdx/*.mjs retained per Decision 3 final outcome; npx tsc --noEmit green.
  • ESLint 9 flat config (eslint.config.mjs); npm run lint green (0 errors / 0 warnings).
  • npm run build green; 70/70 static pages.
  • Inkdrop customizations verified in dev (deferred to user smoke):
    • Fathom analytics loads
    • Custom icons render (DatabaseIcon, ImageFileIcon (FileIcon export), NotebookIcon, NoteIcon, UtilsIcon)
    • Full Navigation structure present
    • Pink typography palette
    • Solarized-dark code blocks
    • article kbd styling
    • ⌘K search returns hits in 3 scenarios
    • h3 auto-IDs present
  • Mobile nav, theme toggle, scroll-spy (deferred to user).
  • outputFileTracingIncludes at top level.
  • @headlessui/tailwindcss removed.

Execution Log

Phase 1 — TypeScript scaffolding (2026-04-23)

Added tsconfig.json, types.d.ts; deleted jsconfig.json; installed typescript@^5.8.3, @types/mdx, @types/node, @types/react-highlight-words. Skipped fathom-client shim. Deferred @types/react/@types/react-dom to Phase 3.

Verify gate: install/tsc/lint/build all green.

Phase 2 — Tooling bumps (2026-04-23)

Bumped prettier-plugin-tailwindcss 0.6.11→0.7.2, prettier-plugin-organize-imports 4.1.0→4.2.0, sharp 0.33.1→0.34.3.

ESLint 9 + flat config attempted & reverted: Next 14's next lint doesn't recognize flat config; bare eslint . fails on missing peer plugins from eslint-config-next@14. Deferred to Phase 3.

Verify gate: lint/build green on ESLint 8 baseline.

Phase 3 — Framework bump: Next 14→16 + React 18→19 + ESLint 9 (2026-04-23)

package.json: next 14→16.1.6, react/react-dom 18→19.2.4, @next/mdx 14→16.1.6, framer-motion 10→12.23.11, next-themes 0.2→0.4.6, @headlessui/react 2.2.2→2.2.6, react-highlight-words 0.20→0.21, fathom-client 3.6→3.7.2; removed @headlessui/tailwindcss. devDeps: eslint 8→9.32.0, eslint-config-next 14→16.1.6, @types/react@19.2.14, @types/react-dom@19.2.3. overrides block. dev/build += --webpack; lint next linteslint ..

tailwind.config.js plugin removal. next.config.mjs outputFileTracingIncludes unwrap + outputFileTracingRoot pin. .eslintrc.json deleted. eslint.config.mjs via eslint-config-next/core-web-vitals native flat. Three react-hooks@7 strict rules disabled with rationale.

mdx.jsx: external-link wrapper <Link><a> (React.Children.only crash on 3 pages). Code.jsx: CodePanel Children.onlyChildren.toArray + find(isValidElement) (3 prerender pages).

Async APIs audit: zero server-side hits.

Verify gate: install (vulns 12→5), tsc/lint/build all green; 70/70 pages.

Phase 4 — zustand 4 → 5 (2026-04-23)

zustand ^4.3.2 → ^5.0.6. Zero source changes — all call sites already v5-compatible.

Phase 5 — flexsearch 0.7 → 0.8 (2026-04-23)

flexsearch ^0.7.31 → ^0.8.205 (resolved 0.8.212). Zero source changes — Document constructor, tokenize: 'full', context: {resolution, depth, bidirectional}, .add(), .search(q, { enrich: true }), and EnrichedResults shape all preserved.

Phase 6a — Lib + primitives (2026-04-27)

Added remToPx.ts, mdx-components.tsx, typography.ts (pink palette restored, const config pattern fixes anonymous-default-export warning); updated tailwind.css @config path. Tailwind config.js noted as vestigial.

Phase 6b — Icons (2026-04-27)

Bulk-copied 28 upstream typed icons via cp (Bell, Bolt, Book, Calendar, Cart, ChatBubble, Check, ChevronRightLeft, Clipboard, Cog, Copy, Document, Envelope, FaceSmile, Folder, Link, List, MagnifyingGlass, MapPin, Package, PaperAirplane, PaperClip, Shapes, Shirt, SquaresPlus, Tag, User, Users). Wrote 5 Inkdrop-only icons typed (DatabaseIcon, ImageFileIcon (in FileIcon.tsx), NotebookIcon, NoteIcon, UtilsIcon). All use React.ComponentPropsWithoutRef<'svg'>. Required spread cast for non-standard SVG transformOrigin attribute: <g transform="..." {...{ transformOrigin: "12 12" } as any}>.

Phase 6c — Leaf components (2026-04-27)

cp from upstream: Button, Tag, Prose, GridPattern, Libraries (no Inkdrop deltas). Manual port preserving Inkdrop branding/content: Heading.tsx (added selector/warning props; refactored to const resolvedLevel = level ?? (2 as Level)enabled re-enabling react-hooks/immutability), Feedback.tsx (simple GitHub fork link, not upstream's complex form), HeroPattern.tsx (purple/pink #6760D4→#ff63c3 gradient, not upstream's emerald), ThemeToggle.tsx (preserved cursor-pointer), Footer.tsx (DiscourseIcon + Inkdrop social links: x.com/inkdrop_app, GitHub, forum.inkdrop.app), Guides.tsx (Inkdrop guide list), Resources.tsx (Inkdrop data-access cards with DatabaseIcon/ImageFileIcon/NoteIcon/NotebookIcon/TagIcon/UtilsIcon), Logo.tsx (Inkdrop logo SVG with gradient).

Phase 6d — Inkdrop-only components (2026-04-27)

Manual port (no upstream reference): Fathom.tsx (TrackPageView with usePathname/useSearchParams + load/trackPageview from fathom-client; types from package's bundled types/index.d.ts), ListNavigationSection.tsx (uses navigation.filter(s => s.link === currentPath) so the optional link?: string field on NavGroup is required), MarkdownSourceLink.tsx (GitHub-source link with pathname-based URL).

Phase 6e — Composite components (2026-04-27)

Search.tsx (443 lines): port of upstream Search.tsx pattern with Inkdrop pink branding (text-pink-500 for highlight, dark:text-pink-400 for loader, group-aria-selected:text-pink-500); preserved Phase 3 react-hooks/refs deferral via inputElement: inputRef.current.

Code.tsx (~370 lines): port of upstream Code.tsx with Inkdrop pink branding (bg-pink-400/10 ring-pink-400/20 on copy button, text-pink-400 for "Copied!", border-pink-500 text-pink-400 for active tab); added diff: 'Diff' to languageNames (Inkdrop has it, upstream doesn't); preserved Phase 3 Children.toArray + find patch in CodePanel with explanatory comment.

mdx.tsx (heavily customized): port of current mdx.jsx with all Inkdrop deltas — external-link wrapper using plain <a> + <ExternalIcon>, custom h1 wrapping <MarkdownSourceLink/>, h2/h3 wrappers via Heading, Note (emerald), Warning (orange), Row/Col/Properties/Property (Property has required? flag with pink "Required" badge that upstream lacks).

Phase 6f — Navigation + Layout (2026-04-27)

Navigation.tsx (365 lines): copied upstream typed skeleton, transplanted Inkdrop's full navigation array (8 groups: Guides, Resources, Core Modules, App States, App Actions, Components, Event Subscription, Appendix; ~70 nav entries total), added link?: string to NavGroup interface for Inkdrop's group-level link field on App States/Actions, preserved bg-pink-500 ActivePageMarker, preserved Inkdrop top-level nav (API, User Manual, Forum), preserved Log in → my.inkdrop.app.

Header.tsx: same Inkdrop top-level nav + Log in; preserved "Developers" text next to Logo for mobile.

Layout.tsx: preserved "Developers" text next to Logo for desktop sidebar.

MobileNavigation.tsx and SectionProvider.tsx: pure cp from upstream (no Inkdrop deltas).

Phase 6g — App files (2026-04-27)

not-found.tsx and providers.tsx: pure cp from upstream (identical content). layout.tsx: ported with Inkdrop title metadata ('%s - Inkdrop API Reference') and <Fathom /> mount.

Phase 6h — MDX pipeline to TS — deferred (2026-04-27)

Attempted full conversion of src/mdx/*.mjs to .ts per user Decision 3. Wrote recma.ts, remark.ts, rehype.ts, search.ts (with full Inkdrop deltas: extractLabelTextAsContent, url in vfile, h3 indexing for /guides/list-of-commands); added mdx-annotations and simple-functional-loader module declarations to types.d.ts; renamed next.config.mjsnext.config.ts (Node ESM cannot import .ts files, so the config must also be .ts for transitive imports to work).

tsc --noEmit and eslint . both passed. npm run build failed: Failed to load next.config.tsReferenceError: exports is not defined in ES module scope at next.config.compiled.js:2:23. Next 16's TS config loader compiles to CommonJS-style (exports.default = ...) but executes in ES module scope. Couldn't be quickly worked around with "type": "module" toggling without risking other regressions.

Reverted: restored next.config.mjs, src/mdx/*.mjs (all four files), types.d.ts shim for @/mdx/search.mjs, and Search.tsx import. Result matches upstream exactly (they also keep these as .mjs).

Final verify gate (post-Phase 6, 2026-04-27)

  • 0 .jsx or .js files in src/, mdx-components.*, or typography.*.
  • 61 .ts/.tsx files in src/.
  • 4 .mjs files in src/mdx/ (intentional).
  • npx tsc --noEmit ✓ no output.
  • npm run lint ✓ 0 errors / 0 warnings (with react-hooks/immutability re-enabled).
  • npm run build ✓ Compiled successfully; 70/70 static pages generated.

Status: ready for user review before Phase 8 (final sweep).

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 28, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
api-docs Ready Ready Preview, Comment Apr 28, 2026 7:40am

Request Review

@craftzdog craftzdog merged commit 56caf1a into main Apr 29, 2026
3 checks passed
@craftzdog craftzdog deleted the pull-upstream-202604 branch April 29, 2026 00:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant