Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"@babel/preset-react": "^7.18.6",
"@mdx-js/mdx": "^2.1.3",
"@resvg/resvg-js": "^2.6.2",
"@shuding/opentype.js": "1.4.0-beta.0",
"@types/body-scroll-lock": "^2.6.1",
"@types/classnames": "^2.2.10",
"@types/debounce": "^1.2.1",
Expand Down
30 changes: 29 additions & 1 deletion scripts/generateOgImages.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import path from 'path';
import satori from 'satori';
import {Resvg} from '@resvg/resvg-js';
import matter from 'gray-matter';
import opentype from '@shuding/opentype.js';

const ROOT = process.cwd();
const CONTENT_DIR = path.join(ROOT, 'src', 'content');
Expand All @@ -34,6 +35,33 @@ const medium = fs.readFileSync(
path.join(ROOT, 'public', 'fonts', 'Optimistic_Display_W_Md.ttf')
);

// Title area width: card width minus the horizontal padding (80px per side).
const TITLE_MAX_WIDTH = 1200 - 80 * 2;
const TITLE_MAX_FONT = 96;
const TITLE_MIN_FONT = 56;
// Small margin so borderline titles don't wrap and orphan a single trailing
// character (e.g. the "p" in "renderToStaticMarkup", which is 1px too wide
// to fit on one line at 96px).
const TITLE_SAFETY = 8;

const boldFont = opentype.parse(
bold.buffer.slice(bold.byteOffset, bold.byteOffset + bold.byteLength)
);

// Multi-word titles wrap cleanly at spaces, so a length bucket is fine for
// them. Single-word titles (most API names) can only break mid-word, which
// leaves an orphaned letter on its own line, so instead shrink them just
// enough to fit on a single line.
function titleFontSize(title) {
const trimmed = title.trim();
if (/\s/.test(trimmed)) {
return trimmed.length > 24 ? 72 : 96;
}
const widthPerPx = boldFont.getAdvanceWidth(trimmed, 1);
const fit = Math.floor((TITLE_MAX_WIDTH - TITLE_SAFETY) / widthPerPx);
return Math.max(TITLE_MIN_FONT, Math.min(TITLE_MAX_FONT, fit));
}

function el(type, style, children) {
return {type, props: {style, children}};
}
Expand Down Expand Up @@ -103,7 +131,7 @@ function card(title, pagePath) {
flexGrow: 1,
display: 'flex',
alignItems: 'center',
fontSize: title.length > 24 ? 72 : 96,
fontSize: titleFontSize(title),
fontFamily: 'Optimistic Display Bold',
color: '#f6f7f9',
lineHeight: 1.1,
Expand Down
34 changes: 24 additions & 10 deletions src/content/community/conferences.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,41 @@ Do you know of a local React.js conference? Add it here! (Please keep the list c

## Upcoming Conferences {/*upcoming-conferences*/}

### React Paris 2026 {/*react-paris-2026*/}
March 26 - 27, 2026. In-person in Paris, France (hybrid event)
### ZurichJS Conf 2026 {/*zurichjs-conf-2026*/}
September 10-11, 2026. In-person in Zurich, Switzerland

[Website](https://react.paris/) - [Twitter](https://x.com/BeJS_)
[Website](https://conf.zurichjs.com?utm_campaign=ZurichJS_Conf&utm_source=referral&utm_content=reactjs_community_conferences) - [Twitter](https://x.com/zurichjs) - [LinkedIn](https://www.linkedin.com/company/zurichjs/)

### CityJS London 2026 {/*cityjs-london-2026*/}
April 14-17, 2026. In-person in London
### React Alicante 2026 {/*react-alicante-2026*/}
Sep 24 - 26, 2026. In-person in Alicante

[Website](https://india.cityjsconf.org/) - [Twitter](https://x.com/cityjsconf) - [Bluesky](https://bsky.app/profile/cityjsconf.bsky.social)
[Website](https://reactalicante.es//) - [Twitter](https://x.com/ReactAlicante)

### ZurichJS Conf 2026 {/*zurichjs-conf-2026*/}
September 10-11, 2026. In-person in Zurich, Switzerland
### CityJS Athens 2026 {/*cityjs-athens-2026*/}
October 21-23, 2026. In-person in Athens

[Website](https://athens.cityjsconf.org/) - [Twitter](https://x.com/cityjsconf) - [Bluesky](https://bsky.app/profile/cityjsconf.bsky.social)


## Past Conferences {/*past-conferences*/}

[Website](https://conf.zurichjs.com?utm_campaign=ZurichJS_Conf&utm_source=referral&utm_content=reactjs_community_conferences) - [Twitter](https://x.com/zurichjs) - [LinkedIn](https://www.linkedin.com/company/zurichjs/)

### React Conf Japan 2027 {/*react-conf-japan-2027*/}
April 24, 2027. In-person in Tokyo, Japan

[Website](https://reactconf.jp/) - [Twitter](https://x.com/reactconfjp)

## Past Conferences {/*past-conferences*/}
### CityJS London 2026 {/*cityjs-london-2026*/}
April 14-17, 2026. In-person in London

[Website](https://india.cityjsconf.org/) - [Twitter](https://x.com/cityjsconf) - [Bluesky](https://bsky.app/profile/cityjsconf.bsky.social)


### React Paris 2026 {/*react-paris-2026*/}
March 26 - 27, 2026. In-person in Paris, France (hybrid event)

[Website](https://react.paris/) - [Twitter](https://x.com/BeJS_)


### CityJS New Delhi 2026 {/*cityjs-newdelhi-2026*/}
February 12-13, 2026. In-person in New Delhi, India
Expand Down
2 changes: 1 addition & 1 deletion src/content/reference/react/use.md
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ This cache pattern is the foundation for [re-fetching data](#re-fetching-data-in

<Pitfall>

Don't skip calling `use` based on whether a Promise is already settled.
##### Don't skip calling `use` based on whether a Promise is already settled. {/*conditional-use*/}

Unlike other hooks, `use` can be called inside conditions and loops — but it must always be called for the Promise itself. Never read `promise.status` or `promise.value` directly to bypass `use`; always pass the Promise to `use` and let React handle it.

Expand Down
5 changes: 5 additions & 0 deletions vercel.json
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,11 @@
"destination": "/warnings/invalid-hook-call-warning#mismatching-versions-of-react-and-react-dom",
"permanent": false
},
{
"source": "/warnings/conditional-use-of-use",
"destination": "/reference/react/use#conditional-use",
"permanent": false
},
{
"source": "/reference/react/directives",
"destination": "/reference/rsc/directives",
Expand Down
Loading