Skip to content

React 19 upgrade#576

Draft
Mukesh-FN wants to merge 19 commits intomainfrom
react-19-upgrade
Draft

React 19 upgrade#576
Mukesh-FN wants to merge 19 commits intomainfrom
react-19-upgrade

Conversation

@Mukesh-FN
Copy link
Contributor

What

Media

Why

How

Mukesh-FN and others added 3 commits March 24, 2026 15:14
Phase 1 — Tooling upgrades:
- TypeScript 4 → 5.8.3, typescript-plugin-styled-components 1 → 3
- ts-jest 26 → 29, Jest 26 → 29, @types/jest 25 → 29
- Add jest-environment-jsdom (Jest 29 no longer defaults to jsdom)
- eslint 7 → 8, @typescript-eslint v4 → v7, eslint-plugin-unicorn/jest/airbnb-typescript
- jest.config.js: add testEnvironment jsdom, ts-jest tuple transform format
- .eslintrc.js: rename recommended-requiring-type-checking → recommended-type-checked
- src/utils/testing.ts: update jest-dom import path (extend-expect removed in v6)
- Build scripts: ttsc → tsc (ttypescript incompatible with TS5)

Phase 2 — React 19.2.4:
- react/react-dom 18.2.0 → 19.2.4, @types/react v18 → v19
- @testing-library/react v14 → v16, jest-dom v5 → v6
- peerDependencies broadened to ^18.2.0 || ^19.0.0 for library consumers
- overrides: react-refresh 0.14.2, react-is 19.2.4, windowed-select types

Phase 3 — Remove defaultProps (removed in React 19 for FC/forwardRef):
- Styled-components (Button, TextButton, HelperText, Label, experimental/Text):
  defaultProps → .attrs<Props>({...})
- Function components (Checkbox, Modal, SelectList):
  defaultProps → destructuring defaults
- forwardRef components (Input, InnerInput):
  defaultProps → destructuring defaults

Phase 4 — TypeScript type fixes for @types/react@19:
- JSX global namespace removed: JSX.Element → React.JSX.Element
  (Breadcrumbs, TabBar/Link, Tooltip, DateField, DatePicker, Calendar,
   InfoBannerCard, experimental/Tooltip, withDeprecatedMessage, LabelWrapper)
- ReactDOM.findDOMNode removed: add nodeRef to all CSSTransition usages
  (Banner, Modal×2, Offcanvas×3) using react-transition-group v4 nodeRef API
- useRef<T>() requires arg: → useRef<T | null>(null)
  (Password, PhoneInput, DatepickerRangeInput, InnerInput)
- Render-prop functions no longer assignable to ReactNode:
  Chip: remove unnecessary Fragment wrapper
  RadioButton: narrow children type to ReactNode via Omit
- React.cloneElement stricter typing: cast to HTMLAttributes & RefAttributes
  (Tooltip)

Storybook fix:
- @storybook/react-dom-shim preset only enables createRoot shim for React 18
  (version.startsWith("18")). React 19 falls through to legacy react-16.js
  shim which calls ReactDOM.render() — removed in React 19.
- Fix: webpackFinal alias in .storybook/main.ts forces react-18 shim
  (createRoot) which is fully compatible with React 19.

Result: 58/58 test suites pass, build succeeds, tsc --noEmit clean,
Storybook renders correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use useDarkMode() from storybook-dark-mode in withColorScheme decorator
  (works in Storybook preview hook context, same as main branch)
- Fix docs.container dark mode using React hooks + addons.getChannel()
  to subscribe to DARK_MODE_EVENT_NAME, avoiding storybook preview-api
  hooks which throw outside decorator/story context
- Add missing ESLint plugins (import, react, react-hooks, jsx-a11y) to
  plugins array so ESLint 8 correctly resolves rules from extended configs
- Disable newly-triggered strict rules that fire on pre-existing code
- Fix no-floating-promises in useLocaleObject.ts
- Upgrade pretty-quick v3 to v4 for Prettier v3 compatibility
- Fix commit-msg hook for Husky v9 (use --edit $1 instead of HUSKY_GIT_PARAMS)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix type-only exports across all components (export type {}) for
  Vite/esbuild compatibility
- Add import type for all type-only imports (ESLint consistent-type-imports)
- Add @vite-ignore to dynamic imports in Flag.tsx and useLocaleObject.ts
- Fix CSSTransition nodeRef for React 19 (Modal, Offcanvas, Banner)
- Fix React 19 breaking changes: defaultProps, JSX namespace, useRef types,
  ReactNode functions, cloneElement typing
- Migrate react-popper to @floating-ui/react for Popover and Tooltip
- Update date-fns v3 locale dynamic imports
- Add Husky v9 pre-commit hook
- Update jscodeshift v17 codemod type casts
- Add UPGRADE_PLAN.md documenting all migration phases

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mukesh-FN and others added 11 commits March 24, 2026 16:51
… warnings

- Replace legacy .eslintrc.js with ESLint 10 flat config (eslint.config.mjs)
- Remove unmaintained eslint-config-airbnb-typescript; replace with
  typescript-eslint unified package + @eslint-react/eslint-plugin
- Add eslint-plugin-import-x (maintained fork), globals, eslint-import-resolver-typescript
- Fix all 14 ESLint errors: conditional hooks, missing keys, leaked conditional
  rendering, stale disable comments, array sort, autofocus, prefer-ternary
- Fix 56 of 103 warnings: lazy useState init, ref naming convention,
  import naming, forwardRef (turned off for React 18+19 compat), complex
  dep-array expressions extracted to variables
- Bump tsconfig.json lib to es2023 (required for Array#toSorted)
- Add UPGRADE_PLAN_2026.md with 10-phase upgrade plan

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Upgrade styled-components ^5.3.8 → ^6.3.12; remove @types/styled-components (v6 ships own types)
- Add shouldForwardProp: isPropValid to all styled HTML element components to restore v5
  prop-filtering behavior (Box, Text, Headline, Button, Card, Link, Table, TabBar,
  Skeleton, Input, Select, Banner, Tag, Breadcrumbs, Datepicker, Popover, and more)
- Fix removed v6 types: StyledComponent→IStyledComponent, drop GlobalStyleComponent
  and ThemeProps, ReadonlyArray<string>→string[], use RuleSet for css return type
- Fix react-select components: replace styled(components.X) wrappers with inner styled
  divs to prevent theme-prop stripping (SingleValue, Option, DynamicWidthMenu)
- Update snapshots for stylis v4 CSS output (fewer vendor prefixes, gradient formatting)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Bump typescript devDep to ^6.0.2
- Add ignoreDeprecations: "6.0" to tsconfig for node10 moduleResolution deprecation
- Exclude src/codemods entirely from tsconfig type-checking (uses Node.js globals)
- Add src/global.d.ts for CSS module, warning, @styled-system/theme-get, and process declarations

TS6 breaking changes fixed across ~55 files:
- Implicit-any now enforced (TS7053/TS7006): typed object index expressions, callback params
- Optional callbacks require optional-chaining invocation (TS2722)
- React.createContext default value must match generic type
- useRef<T>(null) → RefObject<T | null>, requiring casts for useDay library compatibility
- FocusedInput null vs undefined strictness in @datepicker-react/hooks
- String indexing on typed objects requires keyof typeof cast
- Boolean coercion required for mixed-type setHasValue calls
- isValidDateText updated to accept Date | undefined
- SelectList triggerReference typed as HTMLDivElement | null with explicit callback ref
- Tooltip: fix potential leaked conditional rendering

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove ignoreDeprecations workaround by fixing all deprecated features:

- tsconfig.json: moduleResolution "node" → "bundler" (correct for a bundler-consumed library;
  avoids node16/nodenext requirement for explicit .js import extensions)
- package.json build:cjs: --target es5 → --target es2015 (ES5 target deprecated in TS6;
  consumers use bundlers that handle transpilation anyway)
- SelectList.tsx/styles.ts: fix size > 0 comparisons (size is 'medium'|'small', not a number;
  previously type errors were masked, now correctly use truthiness checks)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
moduleResolution "bundler" requires module to be "esnext" or "preserve".
Without an explicit module setting, TypeScript defaults to CommonJS which
is incompatible. The build scripts override --module on the CLI anyway,
so this only affects IDE type-checking.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
No config changes required — Storybook manages Vite internally.
Storybook 8 starts cleanly with Vite 8, library build unaffected.

Node ≥20.19 required by Vite 7+; running Node 24.13.1.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s in SelectList

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nd @types/node v22

Root causes:
- moduleResolution: "bundler" couldn't resolve jscodeshift/dist/testUtils (no exports field)
- @types/node v22 removed CJS globals (__dirname, module) from global scope

Fix:
- Add tsconfig.jest.json with moduleResolution: "node" + module: "commonjs" for codemods
- Add src/codemods/global.d.ts declaring __dirname, __filename, jscodeshift/dist/testUtils
- Split jest.config.js into two projects: components (jsdom) and codemods (node, diagnostics off)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…se 10)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mukesh-FN and others added 5 commits March 24, 2026 19:56
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e dead babel/stylelint configs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Re-add storybook-dark-mode@5.0.0 (compatible with storybook@^10.0.0)
- Restore useDarkMode() hook in withColorScheme decorator
- Restore channel-based dark mode tracking in docs container
- Restore darkMode parameters with lightClass/darkClass/stylePreview
- Fix preview background by using CSS variable directly on wrapper div
  instead of relying on background:inherit through EnforcedColorScheme
- Remove custom manager.ts (was for native colorScheme global approach)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…o Node 24

- ESLint config: add parserOptions blocks for .storybook/, docs/, scripts/;
  disableTypeChecked for root JS/MJS config files; ignore .github/, storybook-static/
- tsconfig.eslint.json: add rootDir='.', noEmit=true, fix .storybook glob pattern
- Convert import styled from 'styled-components' to named import { styled }
  across 120+ files (v6 exports styled as named export)
- Breadcrumbs: replace deprecated Children.toArray/map/cloneElement with plain array map
- useOnChange: replace useState+useEffect anti-pattern with useRef for prev value
- Modal, Offcanvas: wrap handleClose in useCallback, add to effect deps
- Fix missing exhaustive-deps across Search, MonthRangePicker, useMutationObserver,
  DatepickerRangeInput, DatepickerSingleInput, DatePicker (experimental)
- Add eslint-disable comments with explanations for intentional set-state-in-effect
  patterns (datepicker sync, input label float, color scheme sync, popover gate)
- Delete stale generated JS files: .storybook/main.js, preview.js,
  docs/components/*.js, docs/components/migration/*.js
- package.json: add npm overrides for @csstools/css-tokenizer and
  @csstools/css-parser-algorithms to fix Jest jsdom module resolution (hoisting bug)
- package.json: update lint:eslint script to eslint . (full project)
- CI: upgrade docs.yml from Node 18 to 24, gh-pages v3 to v4
- CI: add node-version 24 + cache npm to preview.yml (was missing entirely)
- CI: add --legacy-peer-deps to all npm ci install steps
- CI: add timeout-minutes and explicit permissions to all jobs
- CI: enable preview template in preview.yml (package is React 19 compatible)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 25, 2026

commit: 4516c68

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 25, 2026

commit: 4516c68

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant