Skip to content

feat: upgrade Next.js 12 to 15.5.9 and React 17 to 19#9

Open
joshmu wants to merge 11 commits intomasterfrom
claude/upgrade-nextjs-3JhlV
Open

feat: upgrade Next.js 12 to 15.5.9 and React 17 to 19#9
joshmu wants to merge 11 commits intomasterfrom
claude/upgrade-nextjs-3JhlV

Conversation

@joshmu
Copy link
Owner

@joshmu joshmu commented Dec 24, 2025

Major version upgrades:

  • Next.js: ^12.0.8 → ^15.5.9
  • React: 17.0.2 → ^19.0.0
  • React DOM: 17.0.2 → ^19.0.0
  • TypeScript: ^4.9.5 → ^5.0.0
  • framer-motion: ^6.2.1 → ^11.0.0
  • ESLint: ^8.57.1 → ^9.0.0

Testing library updates for React 19 compatibility:

  • @testing-library/react: ^12.1.2 → ^16.0.0
  • @testing-library/jest-dom: ^5.16.1 → ^6.0.0
  • @testing-library/user-event: ^13.5.0 → ^14.0.0
  • Removed deprecated @testing-library/react-hooks

Breaking changes addressed:

  • AnimatePresence exitBeforeEnter → mode="wait"
  • Link component no longer requires child
  • jest-dom import path change
  • renderHook moved to @testing-library/react

All 139 tests passing.

Major version upgrades:
- Next.js: ^12.0.8 → ^15.5.9
- React: 17.0.2 → ^19.0.0
- React DOM: 17.0.2 → ^19.0.0
- TypeScript: ^4.9.5 → ^5.0.0
- framer-motion: ^6.2.1 → ^11.0.0
- ESLint: ^8.57.1 → ^9.0.0

Testing library updates for React 19 compatibility:
- @testing-library/react: ^12.1.2 → ^16.0.0
- @testing-library/jest-dom: ^5.16.1 → ^6.0.0
- @testing-library/user-event: ^13.5.0 → ^14.0.0
- Removed deprecated @testing-library/react-hooks

Breaking changes addressed:
- AnimatePresence exitBeforeEnter → mode="wait"
- Link component no longer requires <a> child
- jest-dom import path change
- renderHook moved to @testing-library/react

All 139 tests passing.
@vercel
Copy link

vercel bot commented Dec 24, 2025

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

Project Deployment Review Updated (UTC)
videonote Ready Ready Preview, Comment Dec 25, 2025 5:23am

framer-motion v11 removed useViewportScroll in favor of useScroll.
Updated Parallax.tsx, Compressor.tsx, and test mocks accordingly.
- Update Reveal component to use whileInView instead of manual
  useAnimation + useInView pattern for better React 19 compatibility
- Add threshold option to useReveal hook for better intersection detection
- Use next/legacy/image for Overview component (via codemod)

The previous approach using useAnimation with react-intersection-observer
had compatibility issues with framer-motion v11 and React 19.
- Lower threshold to 0 and add rootMargin for earlier trigger
- Add 2-second fallback timer to ensure content is always visible
- This fixes issues where IntersectionObserver may not trigger
  correctly on mobile devices
- Run next-lint-to-eslint-cli codemod
- Update eslint.config.mjs to use FlatCompat for next/core-web-vitals
- Add ignores for .next, node_modules, and coverage directories
- Remove deprecated .eslintrc.json
- Remove useAnimation controls in favor of direct animate prop
- Simplify useReveal to return [ref, inView] instead of [ref, controls]
- Use declarative `animate={inView ? 'animate' : 'initial'}` pattern
- Increase rootMargin to 100px for earlier trigger on mobile

The previous approach using useAnimation().start() with useEffect
was causing issues on mobile devices. The new approach uses
framer-motion's declarative animation props which are more reliable.
Replace useReveal hook with native framer-motion whileInView prop
for each feature item. This is more reliable as each item has its
own viewport observer instead of sharing one observer for the container.
- Fix typo: text-themetext2 -> text-themeText2 (case sensitivity)
- Simplify Reveal to use framer-motion whileInView instead of
  react-intersection-observer useInView hook
- Remove dependency on external IntersectionObserver library for
  animation triggers

The text-themetext2 typo caused feature content to have no text color.
The Reveal component now uses the same whileInView pattern as Features
for more consistent and reliable animation behavior.
Simplified Reveal and Features components to render content without
animations to test if content visibility issue is animation-related.
Replace framer-motion whileInView with CSS transitions and
react-intersection-observer for more reliable mobile behavior.
Includes 2-second fallback timer to ensure content visibility.
Implement proper scroll-triggered animations using framer-motion's
whileInView prop with viewport options per official documentation.
Removed fallback timer that was causing premature content reveal.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR upgrades the application from Next.js 12 to 15.5.9, React 17 to 19, and updates related dependencies including framer-motion (v6 to v11), TypeScript (v4.9 to v5), and ESLint (v8 to v9). The changes address breaking changes in these major version upgrades while maintaining all 139 passing tests.

Key changes:

  • Migrated from deprecated framer-motion APIs (useViewportScrolluseScroll, AnimatePresence exitBeforeEntermode="wait")
  • Updated Next.js Link component to remove deprecated <a> child pattern
  • Refactored animation hooks to use modern framer-motion patterns (simplified useReveal hook and Reveal component)

Reviewed changes

Copilot reviewed 21 out of 23 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
package.json Updated major dependencies including Next.js, React, framer-motion, TypeScript, and testing libraries
eslint.config.mjs New ESLint v9 flat config format replacing legacy .eslintrc.json
.eslintrc.json Removed legacy ESLint configuration file
src/hooks/useReveal.tsx Simplified hook to return inView state instead of animation controls
src/components/shared/ux/Reveal.tsx Refactored to use whileInView instead of manual animation controls
src/components/shared/ux/Parallax.tsx Updated useViewportScroll to useScroll API
src/components/shared/ux/Compressor.tsx Updated useViewportScroll to useScroll API
src/components/shared/ThemeToggle/ThemeToggle.tsx Changed exitBeforeEnter to mode="wait"
src/components/NoteList/NoteList.tsx Changed exitBeforeEnter to mode="wait"
src/components/ActionInput/ActionSymbols/ActionSymbols.tsx Changed exitBeforeEnter to mode="wait"
pages/_app.tsx Changed exitBeforeEnter to mode="wait"
src/context/globalContext.tsx Removed deprecated child from Link components
src/components/Sidebar/SidebarHeader/Menu/Menu.tsx Removed deprecated child from Link component
src/components/LoginPage/RegisterModal/RegisterModal.tsx Removed deprecated child from Link component
src/components/LoginPage/LoginModal/LoginModal.tsx Removed deprecated child from Link component
src/components/Layout/Footer/Footer.tsx Removed deprecated child and moved className to Link
src/components/HelloPage/Overview/Overview.tsx Updated to use next/legacy/image
src/components/HelloPage/Features/Features.tsx Refactored to use new Reveal component pattern with staggered delays
src/context/tests/videoContext.test.tsx Updated renderHook import from @testing-library/react
src/context/tests/noteContext.test.tsx Updated renderHook import and removed waitForNextUpdate
src/test/setupTests.tsx Updated jest-dom import path and useScroll mock

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +103 to +105
<Link href='/hello'>

<Heading2 className='text-center'>VideoNote</Heading2>
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

Empty line after Link opening tag creates orphaned whitespace. The Heading2 component should be directly nested within Link without line breaks.

Copilot uses AI. Check for mistakes.
Comment on lines +105 to 107
<Heading2 className='text-center'>VideoNote</Heading2>

</Link>
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

Empty line before Link closing tag creates orphaned whitespace. The closing tag should immediately follow the Heading2 component.

Copilot uses AI. Check for mistakes.
Comment on lines +102 to +104
<Link href='/hello'>

<Heading2 className='text-center'>VideoNote</Heading2>
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

Empty line after Link opening tag creates orphaned whitespace. The Heading2 component should be directly nested within Link without line breaks.

Copilot uses AI. Check for mistakes.
Comment on lines +104 to 106
<Heading2 className='text-center'>VideoNote</Heading2>

</Link>
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

Empty line before Link closing tag creates orphaned whitespace. The closing tag should immediately follow the Heading2 component.

Copilot uses AI. Check for mistakes.
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.

2 participants