Skip to content
This repository was archived by the owner on Aug 5, 2026. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
e17ce13
Change BpkBadge font style from footnote to caption
adamwilson-ss Mar 24, 2026
0251078
Codemod installed and migration doc
Sybsw May 5, 2026
de37bdf
Changes to plan after re-audit
Sybsw May 5, 2026
24e3939
[LOOM-2442] React 19: types-react-codemod preset-19 (filtered)
Sybsw May 5, 2026
2173faf
[LOOM-2442] React 19: prop-types + defaultProps via custom transform
Sybsw May 5, 2026
2c234bf
build(deps-dev): bump typescript from 5.9.3 to 6.0.3
dependabot[bot] May 6, 2026
d44401b
[LOOM-2442] React 19: peerDep range, CI matrix, version-test widen
Sybsw May 6, 2026
c374cae
build(deps): bump release-drafter/release-drafter from 6.2.0 to 7.2.1
dependabot[bot] May 6, 2026
99ce9b4
[LOOM-2442] React 19: uninstall codemod packages + finalise docs
Sybsw May 6, 2026
b26ec00
Removed local file refs
Sybsw May 6, 2026
fe41f24
Merge branch 'main' into LOOM-2442
Sybsw May 6, 2026
908cb02
fixed registry urls in lockfiles
Sybsw May 6, 2026
dd11d0d
fix to react19 step build gulp
Sybsw May 6, 2026
3946337
Refactor ref types to be R18/R19 compatible (RefObject<T> β†’ Ref<T> or
Sybsw May 6, 2026
0bd4e9d
New scripts/jest/normalizeUseIdSerializer.js β€” wraps the default DOM …
Sybsw May 6, 2026
a3de2e8
nodeRef and setRefs added, fixed snapshots on infiniteScroll
Sybsw May 7, 2026
aa4ae8e
[LOOM-2442][BpkCalendar][BpkDatepicker] Migrate static defaultProps t…
Sybsw May 7, 2026
0e4abae
[LOOM-2442] Migrate render-only class-component defaultProps to destr…
Sybsw May 7, 2026
c688613
[LOOM-2442][BpkBannerAlert][BpkInfoBanner] Migrate twin-pair class-co…
Sybsw May 7, 2026
da8ee50
[LOOM-2442] Migrate remaining multi-method class-component defaultProps
Sybsw May 7, 2026
d31a227
[LOOM-2442][BpkPortal] Migrate static defaultProps to destructure def…
Sybsw May 7, 2026
d2cf7f3
Pass GitHub App token via `token:` input for release-drafter v7
IrinaWei May 8, 2026
44cc7ce
Merge branch 'main' into LOOM-2442
Sybsw May 8, 2026
baf119b
[CLOV-1600][BpkScrollableCalendar] Bump react-window to v2
kerrie-wu May 13, 2026
188c22e
[CLOV-1600] Point react-window + transitive deps to public npm registry
kerrie-wu May 13, 2026
b4fbbc4
[CLOV-1600] Add ResizeObserver mock + suppress v2 List default role
kerrie-wu May 13, 2026
ffa36ca
[CLOV-1600] Regenerate scrollable-calendar snapshots for v2 markup
kerrie-wu May 13, 2026
cf0023f
build(deps-dev): bump serialize-javascript from 6.0.2 to 7.0.5
dependabot[bot] May 20, 2026
a72ed2f
[NO-JIRA][BpkCardList] Remove initiallyInViewCardIndex prop
jimmycook May 22, 2026
3f6e148
Update Figma design tokens
github-actions[bot] May 25, 2026
f0e7f37
Merge branch 'main' into nojira-remove-initiallyInViewCardIndex
jimmycook May 25, 2026
d27004e
Merge PR #4318: Change BpkBadge font style from footnote to caption
May 26, 2026
98a77a2
Merge PR #4445: build(deps-dev): bump typescript from 5.9.3 to 6.0.3
May 26, 2026
68ba6b8
Merge PR #4454: build(deps): bump release-drafter/release-drafter fro…
May 26, 2026
0029b99
Merge PR #4455: LOOM-2442 Pt 1 React 19 Migration
May 26, 2026
96cf005
Merge PR #4464: LOOM-2442 Pt 3 React 19 Migration
May 26, 2026
5bd7714
Merge PR #4477: LOOM-2442 Pt 4 React 19 Migration
May 26, 2026
739629b
Merge PR #4503
May 26, 2026
932492a
Merge PR #4553
May 26, 2026
212831f
Merge PR #4636
May 26, 2026
2f33b2c
fix: regenerate package-lock.json to resolve typescript@5.9.3 nested …
May 26, 2026
2a14383
Fix TypeScript 6.0 deprecation errors in tsconfig.declaration.json
May 26, 2026
c5cc368
fix: resolve TypeScript 6.0 build errors in regression branch
May 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .github/workflows/_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,56 @@ jobs:
name: ${{env.BUILD_LOGS}}
path: ${{env.BUILD_LOGS}}.tar.br

React19:
# Forward-compatibility check: install React 19 + types into the cached
# node_modules (no save) and run typecheck + jest. Allowed to fail while
# the migration lands; flip to required once Repo 1 (backpack-web) is
# released and consumers can opt in.
runs-on: ubuntu-latest
needs: Build
continue-on-error: true
permissions:
statuses: write
pull-requests: write

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version-file: '.nvmrc'
registry-url: 'https://registry.npmjs.org'

- name: Restore Cache
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
id: npm-cache
with:
path: |
node_modules/
packages/node_modules/
key: ${{ env.CACHE_NAME }}-${{ hashFiles('package-lock.json', 'packages/package-lock.json') }}

- name: Override React to 19.2.5
# The inner packages/node_modules tree has its own copy of react/react-dom
# populated from the cache. Overlay the root install into it so jest
# (which resolves react-dom from packages/) sees R19 too.
run: |
npm install --no-save react@19.2.5 react-dom@19.2.5 @types/react@19 @types/react-dom@19 @types/prop-types
rm -rf packages/node_modules/react packages/node_modules/react-dom
cp -r node_modules/react packages/node_modules/
cp -r node_modules/react-dom packages/node_modules/

- name: Generate component code (icons, flare, spinners)
run: npm run build:gulp

- name: Run typecheck (React 19)
run: npm run typecheck

- name: Run jest (React 19)
run: TZ=Etc/UTC npm run jest

Danger:
runs-on: ubuntu-latest
needs: Build
Expand Down
10 changes: 7 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ jobs:
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}

- name: Draft release notes
uses: release-drafter/release-drafter@6db134d15f3909ccc9eefd369f02bd1e9cffdf97 # v6.2.0
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
uses: release-drafter/release-drafter@563bf132657a13ded0b01fcb723c5a58cdd824e2 # v7.2.1
# release-drafter v7 no longer reads the GITHUB_TOKEN env var; the
# token must be passed via the `token` input or it falls back to the
# default `github.token`, which lacks the GitHub App permissions we
# rely on for drafting releases.
with:
token: ${{ steps.app-token.outputs.token }}
73 changes: 73 additions & 0 deletions REACT_19_MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# React 19 Migration β€” `@skyscanner/backpack-web`

(This repo is **Repo 1 of 5** in the Skyscanner shared-library React 19 pre-release codemod pass.)

## What this thread should do

1. Read the master plan's "Repo 1" section. It contains the full audit baseline, recipe checklist, and empty result fields to fill in.
2. Execute the recipe inside this directory.
3. As you progress, update the master plan's Repo 1 section with results (codemod diff summary, test outcomes, surprises).
4. When done, append a one-paragraph "Surprises / runbook insights" entry, and open follow-up PRs against `web-documentation` and `web-migration-scripts` if any reusable insights came out.

## Audit baseline (2026-05-05) β€” corrected after re-audit on 2026-05-05

The original baseline overstated several categories. Re-audit confirmed:

- Lerna-style monorepo, published from `packages/package.json`
- React peerDep: `17.0.2 - 18.3.1` β†’ narrowed-and-shifted to `18.3.1 - 19.2.5` (We shouldn't have any consumers below 18)
- `static defaultProps` / `defaultProps =`: **84 files** (manual sweep, no codemod)
- `forwardRef`: 14 files (none combined with `defaultProps`)
- `prop-types` imports: **67 files** (mostly `.js`; manual conversion β€” see runbook insight below)
- `act` from `react-dom/test-utils`: **0** (audit said 7; re-grep finds none)
- `ReactDOM.render` / `hydrate`: **0** (audit said 1; the only hit is example text inside a `<BpkCodeBlock>` JSX literal in `BpkCode.stories.tsx`, not a real call)
- String refs (`ref="..."`): **0**
- `findDOMNode`: **0**
- Legacy context API (`childContextTypes` / `getChildContext`): **0**
- `useFormState`: **0**
- Zero-arg `useRef()`: 0
- TS 5.9.2; `@types/react` 18.3.1
- Tests: Jest + `@testing-library/react` 16.3.0
- CI: `.github/workflows/{release,pr,main}.yml` β€” `npm publish` after transpile

### Runbook insight: `react/19/migration-recipe` is destructive on this codebase

Dry-running `react/19/migration-recipe` (codemod 1.9.1, which silently invokes legacy codemod 0.18.13) on backpack:

- **Strips Apache 2.0 license headers** from every modified file. Backpack requires these.
- Generates **wrong TypeScript interfaces** when files already have proper TS types (e.g. `BpkBasicMapMarker.tsx` keeps the existing `type Props = { children: ReactNode, position: LatLong }` orphaned and points the component at a new redundant `interface { ...; position: unknown }`).
- Only matched **6 of 67** prop-types files in this repo despite the recipe including `prop-types-typescript`.

We are skipping the bundled recipe. The four mechanical sub-codemods (`replace-act-import`, `replace-reactdom-render`, `replace-string-ref`, `replace-use-form-state`) all dry-run as 0-changes here, so they are also skipped. Only `types-react-codemod` (TS-types only, much narrower scope) is being run.

The `prop-types` and `defaultProps` migrations are being done with a custom jscodeshift transform tailored to backpack, preserving license headers and faithful types.

### Runbook insight: peerDep range narrowed instead of widened

Our intention is to **drop React 17 support** as part of this PR, to `18.3.1 - 19.2.5`. React 17 is unsupported upstream, no consumer is still on it, and dropping it shrinks the test/CI matrix surface.

## Recipe summary β€” adapted for this repo

1. [x] Pin `codemod` + `types-react-codemod` as devDeps with `--save-exact` (no `npx`/`pnpm dlx` β€” Skyscanner Security stance).
2. [x] ~~`react/19/migration-recipe`~~ β€” **skipped** (destructive on this codebase; see runbook insight above).
3. [x] ~~Individual mechanical codemods~~ β€” **skipped** (dry-runs as 0-changes for all four).
4. [x] `types-react-codemod preset-19` β€” applied with `refobject-defaults` and `useRef-required-initial` excluded (those two only typecheck against `@types/react@19`; deferred to the future `@types/react` bump PR).
5. [x] `types-react-codemod react-element-default-any-props` β€” confirmed no-op (already covered by preset-19).
6. [x] Custom jscodeshift transform applied (`scripts/react-19/transforms/strip-proptypes.js`, see scripts/react-19/README.md). Touched 27 files: removed prop-types from `.tsx`, migrated function-component `.defaultProps` to ES6 destructure defaults across `.js` and `.tsx`. License headers preserved.
7. [x] Manual cleanup of edge cases the transform left (1 eslint-disable + 2 dead-import removals).
8. [x] `forwardRef` ref-callback implicit-return scan β€” 0 issues, all 14 sites use block-body callbacks.
9. [x] Update `peerDependencies` in `packages/package.json` to `18.3.1 - 19.2.5` (drops React 17, adds 19; range syntax matching the existing peerDep style).
10. [x] Add CI matrix entry running tests against React 19.2.5 (`continue-on-error: true` initially).
11. [x] Uninstall codemod packages.
12. [ ] Coordinate version bump with the Backpack team.

## Deferred to follow-up PRs

The current PR establishes the scaffolding (peerDep range, CI matrix, codemod tooling, `.tsx` prop-types/defaultProps cleanup). The following items land in separate PRs:

- **35 class components with `static defaultProps`** (27 `.tsx` + 8 `.js`) β€” React 19 makes these no-ops, so defaults silently stop applying. Each needs either conversion to a functional component (preferred) or destructure-with-defaults inside `render()` (quick fix). See the React19 CI matrix output for the failure surface; group by package to keep PRs reviewable.
- **13 `.js` story/HOC files with leftover `Component.defaultProps = ...`** β€” Phase B of the transform couldn't merge defaults because the function bodies are implicit-return arrows or otherwise ineligible. React 19 silently ignores these.
- **`.js` (Flow) prop-types removal** β€” intentionally skipped by the transform because the project's `react/prop-types` lint rule treats removed prop-types as missing prop validation on `.js` files. Full removal happens during the parallel TS migration; React 19 ignores `propTypes` silently in the meantime.
- **`@types/react@19` bump** β€” running `types-react-codemod preset-19`'s `refobject-defaults` and `useRef-required-initial` sub-transforms together with bumping `@types/react` to 19. These were skipped here because they emit code that only typechecks against `@types/react@19`.
- **Track and fix the React19 CI matrix failures** β€” typecheck has 8 known errors (the deferred sub-transforms above plus a missing `@types/prop-types`), and jest has 326 suite failures (mostly transitive deps still using removed React 18 internals like `ReactCurrentDispatcher`). Once green, flip the matrix from `continue-on-error: true` to required.
- **Move the custom transform to `web-migration-scripts/migrations/2026-05-react-19/transforms/`** when that migration directory is set up.

6 changes: 1 addition & 5 deletions libs/backpack-storybook-utils/src/BpkDarkExampleWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import STYLES from './BpkDarkExampleWrapper.module.scss';
const getClassName = cssModules(STYLES);

const BpkDarkExampleWrapper = (props: { padded: boolean }) => {
const { padded, ...rest } = props;
const { padded = false, ...rest } = props;
return (
/* $FlowFixMe[cannot-spread-inexact] - inexact rest. See 'decisions/flowfixme.md'. */
<div
Expand All @@ -37,8 +37,4 @@ const BpkDarkExampleWrapper = (props: { padded: boolean }) => {
);
};

BpkDarkExampleWrapper.defaultProps = {
padded: false,
};

export default BpkDarkExampleWrapper;
Loading
Loading