Skip to content

fix(react-doctor): migrate components to React 19 APIs#347

Open
bntvllnt wants to merge 6 commits into
mainfrom
fix/268-react19-migration
Open

fix(react-doctor): migrate components to React 19 APIs#347
bntvllnt wants to merge 6 commits into
mainfrom
fix/268-react19-migration

Conversation

@bntvllnt
Copy link
Copy Markdown
Collaborator

@bntvllnt bntvllnt commented May 13, 2026

Summary

  • Migrates @vllnt/ui components from forwardRef to React 19 ref-as-prop functions.
  • Converts useContext call sites to React 19 use().
  • Raises @vllnt/ui React peer dependencies to >=19.0.0.
  • Documents the React 19 peer requirement and ref-as-prop/use() migration under the Unreleased changelog.
  • Replaces the CodeQL-flagged polynomial regex paths in AIArtifact filename slugging and Kbd shortcut tokenization with bounded string iteration/splitting.
  • Removes remaining React 19 / react-doctor cleanup blockers at the current head: FormBase now avoids the forbidden cast via Object.assign(FormInner, { displayName: "Form" }), max-lines suppressions were removed through extracted helpers/components, and registry copies were regenerated from the package sources.
  • Note: the official React 19 codemod was attempted, but this environment was missing libsecret-1.so.0/keytar support, so an equivalent local jscodeshift transform plus manual fixes was used.

Validation

Current head: c99d612d818405161cef0b1c67148798485eae41.

Current-head delta validation recorded for c99d612d818405161cef0b1c67148798485eae41:

  • git diff --check origin/main...HEAD — pass.
  • pnpm -F @vllnt/ui exec eslint src/components/form/form.tsx src/components/choropleth-map/choropleth-map.tsx src/components/geography-quiz-map/geography-quiz-map.tsx src/components/interactive-timeline/interactive-timeline.tsx src/components/sparkline-grid/sparkline-grid.tsx src/components/thread-bubble/thread-bubble.tsx src/components/tree-view/tree-view.tsx — pass.
  • pnpm -F @vllnt/ui exec tsc --noEmit --project tsconfig.build.json — pass.

Full React 19 migration validation from the PR history:

  • pnpm -F @vllnt/ui lint — pass.
  • pnpm -F @vllnt/ui exec tsc --noEmit --project tsconfig.build.json — pass.
  • pnpm -F @vllnt/ui-registry exec tsc --noEmit --project tsconfig.json — pass.
  • pnpm build — pass.
  • pnpm test:once — 216 files, 1215 tests passed.
  • npx --yes react-doctor . --offline --jsonno-react19-deprecated-apis=0.
  • npx --yes react-doctor . --diff origin/main --annotations --fail-on error --offline — pass.
  • Changelog remediation check at f854c2199efad3c1cf190f32fedca1f8a89d4352: git diff --check -- packages/ui/CHANGELOG.md, pnpm exec prettier --check packages/ui/CHANGELOG.md, and a script assertion that the React 19 peer-requirement entry is under [Unreleased] -> Changed all passed.
  • CodeQL remediation spot-check at 1f5496561043225e9e79b4104142a6f1cf48b79f: pnpm -F @vllnt/ui exec eslint src/components/ai-artifact/ai-artifact.tsx src/components/kbd/kbd.tsx passed.
  • CodeQL remediation spot-check at 1f5496561043225e9e79b4104142a6f1cf48b79f: pnpm -F @vllnt/ui exec tsc --noEmit --project tsconfig.build.json passed.

CI

  • Current head: c99d612d818405161cef0b1c67148798485eae41.
  • Live GitHub status rollup at current head is passing: Quality Gates, CodeQL, PR Issue Link, react-doctor, Storybook build/tests/visual/verify, build · sign · scan · deploy (storybook), build · sign · scan · deploy (ui-registry), and vllnt-pilot / preview deploy are all SUCCESS.
  • mergeStateStatus: CLEAN.

Closes #268

Copy link
Copy Markdown
Collaborator Author

@bntvllnt bntvllnt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking review note (GitHub would not allow REQUEST_CHANGES because this appears to be authored by the same account): this PR raises @vllnt/ui's React peer floor to React 19 and migrates the public component implementation/API surface, but it does not update packages/ui/CHANGELOG.md. The repo PR playbook requires user-facing changes to add an [Unreleased] changelog entry, and this is especially important because React 18 consumers will be excluded by the new peer dependency.

Observed gates: PR is linked to #268, mergeable/clean, and GitHub checks were green when queried (Quality Gates, build, Storybook, Storybook Tests, Verify Stories, Visual Regression, Vercel previews). I did not find another code-level blocker in the sampled React 19 migration patterns.

Comment thread packages/ui/package.json
"next-themes": ">=0.4.0",
"react": ">=18.0.0",
"react-dom": ">=18.0.0",
"react": ">=19.0.0",
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: this raises the public React peer floor from React 18 to React 19, but packages/ui/CHANGELOG.md was not changed. The repo playbook requires user-facing changes to add an [Unreleased] changelog entry; please document this under Changed (and call out that React 19 is now required) before merge.

Comment thread packages/ui/src/components/kbd/kbd.tsx Fixed
Copy link
Copy Markdown
Collaborator Author

@bntvllnt bntvllnt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — CodeQL remediation head check

Head reviewed: 1f5496561043225e9e79b4104142a6f1cf48b79f
Scope of this pass: delta since prior reviewed head f854c2199efad3c1cf190f32fedca1f8a89d4352, plus PR body and live status rollup.

BLOCKING

  • None found in the source changes reviewed for this remediation delta.

WARN / OPERATIONAL

  • Vercel – ui.vllnt.ai is still failing on the current head, but the live status description is Canceled from the Vercel Dashboard:

VERIFIED CLEAN

  • The only files changed since the prior reviewed head are:
    • packages/ui/src/components/ai-artifact/ai-artifact.tsx
    • packages/ui/src/components/kbd/kbd.tsx
  • AIArtifact replaced the CodeQL-flagged slug regexes with bounded character iteration and preserves the previous behavior: lowercase ASCII letters/digits are kept, invalid runs become separators, leading/trailing separators are dropped, and empty titles fall back to artifact.
  • Kbd replaced the shortcut separator regex with .split("+").map(trim).filter(Boolean), preserving mod+k / spaced shortcut tokenization without a polynomial regex path.
  • PR body matches the current head for this remediation: it names 1f5496561043225e9e79b4104142a6f1cf48b79f, includes the CodeQL remediation spot-checks, keeps Closes #268, and documents the canceled Vercel status.
  • Live checks at current head: CodeQL, Quality Gates, react-doctor, PR Issue Link, Storybook build/tests/visual/verify, Vercel Preview Comments, and Vercel – storybook are passing.

VALIDATION

  • Ran locally in the detached review checkout:
    • pnpm -F @vllnt/ui exec eslint src/components/ai-artifact/ai-artifact.tsx src/components/kbd/kbd.tsx — pass
    • pnpm -F @vllnt/ui exec tsc --noEmit --project tsconfig.build.json — pass
  • Re-checked live GitHub status rollup and commit statuses at current head.

Verdict: CodeQL remediation is clean. Do not treat the remaining Vercel – ui.vllnt.ai status as a code blocker, but it still needs redeploy/rerun + monitoring before final merge readiness.

Copy link
Copy Markdown
Collaborator Author

@bntvllnt bntvllnt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bntvllnt Review verdict: APPROVE recommended for reviewer triage — stale Vercel waived by PM decision

Head reviewed: 1f5496561043225e9e79b4104142a6f1cf48b79f

I re-checked the current status against the PM waiver in pm-decision.md: all GitHub Actions/code checks are green and Vercel – storybook is SUCCESS. The remaining Vercel – ui.vllnt.ai: FAILURE matches the accepted stale external UI preview status for reviewer triage only.

No new source-level blockers found beyond the prior current-head CodeQL remediation review. This is not merge/release approval and does not weaken branch protection; it only records that the stale UI preview status is waived for review triage under the PM decision.

@vllnt-pilot vllnt-pilot Bot had a problem deploying to Preview · pr-347-storybook May 18, 2026 17:14 Failure
@vllnt-pilot
Copy link
Copy Markdown

vllnt-pilot Bot commented May 18, 2026

Preview ready · pr-347-ui-registry

Service Status Preview
ui-registry Ready https://pr-347-ui-registry.preview.vllnt.ai
Inspect
  • Deployed to vllnt-cluster from b33f5ea
  • Reply with /clean to destroy this preview now

@vllnt vllnt deleted a comment from vllnt-pilot Bot May 18, 2026
@vllnt vllnt deleted a comment from vercel Bot May 18, 2026
@bntvllnt bntvllnt self-assigned this May 19, 2026
…p max-lines suppressions

- Replace forbidden `as` cast on FormBase with Object.assign(FormInner, { displayName: "Form" }) in both packages/ui and registry copies, preserving generic type parameter
- Extract SparklineItem sub-component from SparklineGrid render callback (packages/ui + registry)
- Extract ThreadBubbleHeader sub-component from ThreadBubble (packages/ui + registry)
- Extract useRegionSelection hook from ChoroplethMap (packages/ui + registry)
- Move zoom useState into useToolbarHandlers hook in InteractiveTimeline (packages/ui + registry)
- Replace single-use resolvedLabels useMemo with inline expression in GeographyQuizMap and TreeView (packages/ui + registry)
- All max-lines-per-function eslint-disable suppressions removed
bntvllnt

This comment was marked as outdated.

Copy link
Copy Markdown
Collaborator Author

@bntvllnt bntvllnt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bntvllnt Review verdict: COMMENT — manual approval recommended; final approval reserved for bntvllnt.

Head reviewed: c99d612d818405161cef0b1c67148798485eae41

BLOCKING

None remaining.

The earlier same-head metadata blocker is resolved: the PR body now lists Current head: c99d612d818405161cef0b1c67148798485eae41, includes current-head validation evidence, and the live head still matches that SHA.

WARN

None.

VERIFIED CLEAN

  • Full changed-file review coverage is complete for the current head. The PR remains a React 19 migration/remediation: forwardRef -> ref-as-prop components, useContext -> use(), React peer dependency/changelog updates, registry regeneration, and the later react-doctor/CodeQL cleanup deltas.
  • The current-head remediation delta remains clean: FormBase avoids the forbidden cast via Object.assign, max-lines suppressions were removed through extracted helpers/components, and regenerated registry copies match the source direction.
  • Live GitHub checks are green at the current head; mergeStateStatus is CLEAN.
  • PR metadata now matches the reviewed head and validation evidence.

VALIDATION

  • Live prepublish check: PR #347 is OPEN, non-draft, mergeStateStatus=CLEAN, head c99d612d818405161cef0b1c67148798485eae41.
  • Live GitHub checks: passing (gh pr checks 347 --repo vllnt/ui, exit 0).
  • Current PR body was re-fetched and verified to contain the current head SHA and current-head validation section.
  • Prior current-head review artifact on this same head recorded the local validation: git diff --check origin/main...HEAD, targeted @vllnt/ui ESLint on the remediation files, and pnpm -F @vllnt/ui exec tsc --noEmit --project tsconfig.build.json all passed.

No automatic approval was submitted.

Copy link
Copy Markdown
Collaborator Author

@bntvllnt bntvllnt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review follow-up — 1 blocking operational finding

Head reviewed: c99d612d818405161cef0b1c67148798485eae41

BLOCKING

  • C1 — preview deploy check is green but the published preview endpoint returns 503
    • Evidence: gh pr checks 347 --repo vllnt/ui reports vllnt-pilot / preview deploy as SUCCESS and links to https://pr-347-ui-registry.preview.vllnt.ai; direct probe of that link returns HTTP/2 503 with body no available server.
    • Why it matters: the PR body says the live status rollup is passing, including the preview deploy, but the user-facing preview artifact is not actually reachable. That makes the validation evidence incomplete for a UI/registry migration until the preview route is healthy or explicitly waived by the human owner.
    • Fix: restore the PR preview route/deployment for this head, update the PR body with the re-check evidence, or get an explicit PM/owner waiver if preview access is not required for this PR.

WARN

None.

VERIFIED CLEAN

  • PR is open and non-draft at the requested head.
  • PR links issue #268 and the body records the current head SHA.
  • Live GitHub checks are green at the current head: Quality Gates, CodeQL, issue-link enforcement, Storybook build/tests/visual/verify, registry/storybook deploy jobs, and the preview deploy check all report SUCCESS.
  • Local git diff --check origin/main...HEAD passed.
  • Changed-file coverage was reviewed at the gate level: 330 changed paths total, including 172 packages/ui paths, 157 apps/registry paths, and pnpm-lock.yaml. The React 19 migration pattern removes changed-file forwardRef/useContext matches and raises React/React DOM peers to >=19.0.0 with a changelog entry.

VALIDATION

  • Ran: gh pr view 347 --repo vllnt/ui --json ...
  • Ran: gh pr checks 347 --repo vllnt/ui --json name,state,workflow,startedAt,completedAt,link,bucket
  • Ran: git diff --check origin/main...HEAD
  • Ran: curl -sS -I -L --max-time 20 https://pr-347-ui-registry.preview.vllnt.ai
  • Ran: curl -sS -L --max-time 20 https://pr-347-ui-registry.preview.vllnt.ai
  • Not run locally: full pnpm workspace gates; relied on current-head PR body evidence and green GitHub checks for those.

Review verdict: COMMENT with blocking recommendation; final formal approval/request-changes remains reserved for bntvllnt.

@bntvllnt
Copy link
Copy Markdown
Collaborator Author

Preview availability gate update (Hermes task t_9bc389a9):

  • Re-checked the linked preview URL for current head c99d612d818405161cef0b1c67148798485eae41: https://pr-347-ui-registry.preview.vllnt.ai returns HTTP 503 with body no available server.
  • Re-ran the build · sign · scan · deploy (ui-registry) job from workflow run 26112737939; rerun job 76867717538 completed SUCCESS at 2026-05-20 01:05 UTC.
  • The deployer action response for the rerun reported status: deployed, env: preview, service: ui-registry, and the same URL.
  • GitHub now shows a fresh vllnt-pilot / preview deploy check SUCCESS (76867808433) for this head, but direct HTTP validation still returns 503 / no available server after repeated probes through 2026-05-20 01:10 UTC.

Conclusion: the GitHub check/deployer response is not sufficient preview-health evidence for this PR right now. The PR should remain blocked on preview availability until either the preview route/server is restored and the URL returns a real page, or an explicit PM/owner waiver records that preview availability is not required for this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

react-doctor Reported by react-doctor (codebase health) tech-debt Refactoring or cleanup

Projects

None yet

Development

Successfully merging this pull request may close these issues.

react-doctor: React 19 migration — no-react19-deprecated-apis (439 warnings)

2 participants