Skip to content

Commit a06099d

Browse files
Upgrade to React v19 (#73)
* Update Primer Brand to v0.60.0 * Add React 19 compatibility * Fix types * Regenerate package-lock * Add missing eslint-prettier dependency * Fix formatting * Update Primer Brand to v0.60.1 * Update Primer Brand in site * Add changeset * Update site React to 19.2.1 to address RCE vulnerability * Update Next.js to v15.5.7 * Add backwards compatibility note to changeset * Remove site from version bump * Update Primer React to latest version
1 parent 8b0b36f commit a06099d

File tree

14 files changed

+14556
-10193
lines changed

14 files changed

+14556
-10193
lines changed

.changeset/rotten-coins-teach.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
'@primer/doctocat-nextjs': minor
3+
---
4+
5+
Add React 19 support
6+
7+
This update is backwards compatible with React 18. However, it upgrades `@primer/react` to v38, which includes breaking changes such as the removal of the `Box` component and `sx` prop. Projects using this theme may need to update their code accordingly.
8+
9+
- Updated React peer dependency to support React 19
10+
- Updated @primer/react from v37.11.2 to v38.3.0
11+
- Updated `@primer/react-brand` from v0.54.0 to v0.60.1
12+
- Updated `framer-motion` from v12.4.0 to v12.23.24
13+
- Updated `react-focus-on` from v3.9.4 to v3.10.0
14+
- Migrated `Label` components to `Token` for React 19 compatibility
15+
- Fixed type errors in `ReactCodeBlock` and `getRelatedPages` for stricter React 19 types
16+
- Added explicit `as="button"` to `IconButton` and `as="input"` to `TextInput` components
17+
- Updated Next.js and related packages from v15.5.2 to v15.5.7

package-lock.json

Lines changed: 14479 additions & 10142 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,17 @@
3030
"@changesets/cli": "2.27.12",
3131
"@github/prettier-config": "^0.0.6",
3232
"@oddbird/popover-polyfill": "^0.5.2",
33-
"@primer/react": "38.0.0",
34-
"@primer/react-brand": "0.54.0",
33+
"@primer/react": "38.3.0",
34+
"@primer/react-brand": "0.60.1",
3535
"@types/node": "20.19.4",
36+
"@typescript-eslint/eslint-plugin": "8.29.0",
3637
"@typescript-eslint/parser": "8.29.0",
3738
"eslint": "^8",
38-
"eslint-config-next": "15.5.2",
39+
"eslint-config-next": "15.5.7",
3940
"eslint-plugin-github": "^5.0.1",
4041
"eslint-plugin-jsx-a11y": "^6.8.0",
4142
"eslint-plugin-mdx": "^2.2.0",
43+
"eslint-plugin-prettier": "^5.5.4",
4244
"eslint-plugin-primer-react": "^6.1.6",
4345
"eslint-plugin-react-hooks": "^4.6.0",
4446
"typescript": "5.8.2"

packages/site/package.json

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,17 @@
2323
"dependencies": {
2424
"@primer/doctocat-nextjs": "^0.7.0",
2525
"@primer/octicons-react": "19.15.1",
26-
"eslint-config-next": "15.5.2",
27-
"next": "15.5.2",
28-
"react": "18.3.1",
29-
"react-dom": "18.3.1"
26+
"eslint-config-next": "15.5.7",
27+
"next": "15.5.7",
28+
"react": "^19.2.1",
29+
"react-dom": "^19.2.1"
3030
},
3131
"devDependencies": {
3232
"@github/prettier-config": "^0.0.6",
33-
"@primer/react": "38.0.0",
34-
"@primer/react-brand": "0.54.0",
35-
"@types/node": "20.19.4"
33+
"@primer/react": "38.3.0",
34+
"@primer/react-brand": "0.60.1",
35+
"@types/node": "20.19.4",
36+
"@types/react": "^19.2.7",
37+
"@types/react-dom": "^19.2.3"
3638
}
3739
}

packages/theme/components/layout/article/AccessibilityLabel.module.css

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
.reviewedLabel {
2-
display: flex;
3-
align-items: center;
4-
gap: var(--base-size-8);
52
background-color: var(--base-color-scale-purple-0);
6-
border-color: transparent;
7-
color: var(--brand-color-text-default);
3+
color: var(--brand-color-text-default) !important;
84
font-weight: var(--brand-text-weight-300);
95
}
106

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
'use client'
2-
import {Label} from '@primer/react'
2+
import {Token} from '@primer/react'
33
import {AccessibilityInsetIcon} from '@primer/octicons-react'
44
import React from 'react'
55

@@ -11,9 +11,12 @@ type AccessibilityLabelProps = {
1111

1212
export function AccessibilityLabel({short}: AccessibilityLabelProps) {
1313
return (
14-
<Label size="large" className={styles.reviewedLabel}>
15-
<AccessibilityInsetIcon className={styles.icon} />
16-
{short ? 'Reviewed' : 'Reviewed for accessibility'}
17-
</Label>
14+
<Token
15+
as="span"
16+
size="large"
17+
className={styles.reviewedLabel}
18+
leadingVisual={() => <AccessibilityInsetIcon className={styles.icon} aria-hidden="true" />}
19+
text={short ? 'Reviewed' : 'Reviewed for accessibility'}
20+
/>
1821
)
1922
}

packages/theme/components/layout/article/ReadinessLabel.module.css

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
.label {
2-
display: flex;
3-
align-items: center;
4-
gap: var(--base-size-8);
52
background-color: var(--base-color-scale-green-0);
6-
border-color: transparent;
7-
color: var(--brand-color-text-default);
3+
color: var(--brand-color-text-default) !important;
84
font-weight: var(--brand-text-weight-300);
95
}
106

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
'use client'
22
import React from 'react'
3-
import {Label} from '@primer/react'
3+
import {Token} from '@primer/react'
44
import {CheckIcon} from '@primer/octicons-react'
55

66
import styles from './ReadinessLabel.module.css'
77

88
export function ReadinessLabel() {
99
return (
10-
<Label size="large" className={styles.label}>
11-
<CheckIcon className={styles.icon} />
12-
Ready to use
13-
</Label>
10+
<Token
11+
as="span"
12+
size="large"
13+
className={styles.label}
14+
leadingVisual={() => <CheckIcon className={styles.icon} aria-hidden="true" />}
15+
text="Ready to use"
16+
/>
1417
)
1518
}

packages/theme/components/layout/code-block/ReactCodeBlock.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,13 +205,13 @@ export function ReactCodeBlock(props: ReactCodeBlockProps) {
205205
* Helper function to turn Nextra <code> children into plain text
206206
*/
207207
function getCodeFromChildren(children: React.ReactNode) {
208-
if (!React.isValidElement(children) || !children.props?.children) return ''
209-
210-
// Flattens the nested spans and combine their text content if it's a react child
211208
const extractText = (node: React.ReactNode): string => {
212209
if (typeof node === 'string') return node
213210
if (Array.isArray(node)) return node.map(extractText).join('')
214-
if (React.isValidElement(node) && node.props?.children) return extractText(node.props.children)
211+
if (React.isValidElement(node)) {
212+
const element = node as React.ReactElement<{children?: React.ReactNode}>
213+
return extractText(element.props.children)
214+
}
215215
return ''
216216
}
217217

packages/theme/components/layout/global-search/GlobalSearch.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ export const GlobalSearch = forwardRef<HTMLInputElement, GlobalSearchProps>(
170170
<FormControl>
171171
<FormControl.Label visuallyHidden>Search</FormControl.Label>
172172
<TextInput
173+
as="input"
173174
contrast
174175
type="search"
175176
className={styles.GlobalSearch__searchInput}

0 commit comments

Comments
 (0)