From 9ce4afead624114d5f831c70ea31c14feb5965ce Mon Sep 17 00:00:00 2001
From: Daniel Lo Nigro
Date: Tue, 19 Dec 2023 17:23:51 -0800
Subject: [PATCH 01/21] Improve documentation for __html (#6499)
---
src/content/reference/react-dom/components/common.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/content/reference/react-dom/components/common.md b/src/content/reference/react-dom/components/common.md
index 11719112e..610742735 100644
--- a/src/content/reference/react-dom/components/common.md
+++ b/src/content/reference/react-dom/components/common.md
@@ -982,6 +982,8 @@ textarea { display: block; margin-top: 5px; margin-bottom: 10px; }
+The `{__html}` object should be created as close to where the HTML is generated as possible, like the above example does in the `renderMarkdownToHTML` function. This ensures that all raw HTML being used in your code is explicitly marked as such, and that only variables that you expect to contain HTML are passed to `dangerouslySetInnerHTML`. It is not recommended to create the object inline like `
`.
+
To see why rendering arbitrary HTML is dangerous, replace the code above with this:
```js {1-4,7,8}
From 3bf64e5ffdc1f7793d237a24f051e06986197913 Mon Sep 17 00:00:00 2001
From: Alina Listunova
Date: Thu, 21 Dec 2023 02:57:57 +0200
Subject: [PATCH 02/21] Fix diagram alt text in Your UI as a Tree page (#6507)
---
src/content/learn/understanding-your-ui-as-a-tree.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/content/learn/understanding-your-ui-as-a-tree.md b/src/content/learn/understanding-your-ui-as-a-tree.md
index f4528b346..2abf7affc 100644
--- a/src/content/learn/understanding-your-ui-as-a-tree.md
+++ b/src/content/learn/understanding-your-ui-as-a-tree.md
@@ -22,7 +22,7 @@ React, and many other UI libraries, model UI as a tree. Thinking of your app as
Trees are a relationship model between items and UI is often represented using tree structures. For example, browsers use tree structures to model HTML ([DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model/Introduction)) and CSS ([CSSOM](https://developer.mozilla.org/docs/Web/API/CSS_Object_Model)). Mobile platforms also use trees to represent their view hierarchy.
-
+
React creates a UI tree from your components. In this example, the UI tree is then used to render to the DOM.
From 3009d764ed362ae749c5835cbc38783dd29bfd57 Mon Sep 17 00:00:00 2001
From: Luna
Date: Wed, 20 Dec 2023 20:58:16 -0400
Subject: [PATCH 03/21] Fix error throw and for useTransition demo (#6510)
---
src/components/MDX/Sandpack/Preview.tsx | 2 +-
src/content/reference/react/useTransition.md | 13 +++++++------
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/src/components/MDX/Sandpack/Preview.tsx b/src/components/MDX/Sandpack/Preview.tsx
index 059645550..9669e5f4f 100644
--- a/src/components/MDX/Sandpack/Preview.tsx
+++ b/src/components/MDX/Sandpack/Preview.tsx
@@ -54,7 +54,7 @@ export function Preview({
// When throwing a new Error in Sandpack - we want to disable the dev error dialog
// to show the Error Boundary fallback
- if (rawError && rawError.message.includes(`throw Error('Example error')`)) {
+ if (rawError && rawError.message.includes('Example Error:')) {
rawError = null;
}
diff --git a/src/content/reference/react/useTransition.md b/src/content/reference/react/useTransition.md
index 37e89c0c9..49df279fb 100644
--- a/src/content/reference/react/useTransition.md
+++ b/src/content/reference/react/useTransition.md
@@ -1520,15 +1520,15 @@ import { ErrorBoundary } from "react-error-boundary";
export function AddCommentContainer() {
return (
⚠️Something went wrong
}>
-
+
);
}
function addComment(comment) {
// For demonstration purposes to show Error Boundary
- if(comment == null){
- throw Error('Example error')
+ if (comment == null) {
+ throw new Error("Example Error: An error thrown to trigger error boundary");
}
}
@@ -1544,9 +1544,10 @@ function AddCommentButton() {
// so error gets thrown
addComment();
});
- }}>
- Add comment
-
+ }}
+ >
+ Add comment
+
);
}
```
From bbb08a5a04b0221137e5d60472fc979747af2954 Mon Sep 17 00:00:00 2001
From: Ali Oguzhan Yildiz
Date: Thu, 21 Dec 2023 04:02:42 +0300
Subject: [PATCH 04/21] Add Turkish to deployed languages (#6449)
---
src/components/Seo.tsx | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/components/Seo.tsx b/src/components/Seo.tsx
index 5af169e13..dfc4f6104 100644
--- a/src/components/Seo.tsx
+++ b/src/components/Seo.tsx
@@ -24,6 +24,7 @@ const deployedTranslations = [
'es',
'fr',
'ja',
+ 'tr',
// We'll add more languages when they have enough content.
// Please DO NOT edit this list without a discussion in the reactjs/react.dev repo.
// It must be the same between all translations.
From fc32af86f1caad6e237e5eab89b4afc20e264fe4 Mon Sep 17 00:00:00 2001
From: Nepalivai <108126089+nepalivai@users.noreply.github.com>
Date: Fri, 5 Jan 2024 23:05:16 +0545
Subject: [PATCH 05/21] Text Display error in Go full-stack with a framework
(#6483)
* Text Display error in Go full-stack with a framework
Fix error #27816
What dose this PR do?
It fixes the issue with the landing page of the react website.
* Update HomeContent.js
* Set styles on
* Add padding too
---------
Co-authored-by: Ricky
---
src/components/Layout/HomeContent.js | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/src/components/Layout/HomeContent.js b/src/components/Layout/HomeContent.js
index 02338b1c5..e1fab6d71 100644
--- a/src/components/Layout/HomeContent.js
+++ b/src/components/Layout/HomeContent.js
@@ -1499,7 +1499,7 @@ function ConferenceLayout({conf, children}) {
navigate(e.target.value);
});
}}
- className="appearance-none pe-8 bg-transparent text-primary-dark text-2xl font-bold mb-0.5"
+ className="appearance-none pe-8 ps-2 bg-transparent text-primary-dark text-2xl font-bold mb-0.5"
style={{
backgroundSize: '4px 4px, 4px 4px',
backgroundRepeat: 'no-repeat',
@@ -1508,8 +1508,16 @@ function ConferenceLayout({conf, children}) {
backgroundImage:
'linear-gradient(45deg,transparent 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,transparent 50%)',
}}>
- React Conf 2021
- React Conf 2019
+
+ React Conf 2021
+
+
+ React Conf 2019
+
From 7a28cf6bf5ee892abe35d41474d5298b021c26ae Mon Sep 17 00:00:00 2001
From: Ahmed Abdelbaset
Date: Sat, 6 Jan 2024 01:59:01 +0200
Subject: [PATCH 06/21] Fix missing function keyword (#6527)
* Update use-server.md
* revert export default
---
src/content/reference/react/use-server.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/content/reference/react/use-server.md b/src/content/reference/react/use-server.md
index 638163369..0d0fc8404 100644
--- a/src/content/reference/react/use-server.md
+++ b/src/content/reference/react/use-server.md
@@ -153,7 +153,7 @@ export default async function requestUsername(formData) {
// UsernameForm.js
'use client';
-import {useFormState} from 'react-dom';
+import { useFormState } from 'react-dom';
import requestUsername from './requestUsername';
function UsernameForm() {
@@ -208,7 +208,7 @@ function LikeButton() {
'use server';
let likeCount = 0;
-export default async incrementLike() {
+export default async function incrementLike() {
likeCount++;
return likeCount;
}
From 315cb7a38a1645623fc55501429285ab680b8a6a Mon Sep 17 00:00:00 2001
From: wnhlee <40269597+2wheeh@users.noreply.github.com>
Date: Mon, 8 Jan 2024 01:06:41 +0900
Subject: [PATCH 07/21] fix wrong quotes around inline codes (#6523)
* fix wrong way quotes
* bump up to clear mdx cache
---
plugins/remark-smartypants.js | 47 ++++++++++++++++++++++++++++++++---
src/utils/prepareMDX.js | 2 +-
2 files changed, 45 insertions(+), 4 deletions(-)
diff --git a/plugins/remark-smartypants.js b/plugins/remark-smartypants.js
index 7dd1b0c4a..4694ff674 100644
--- a/plugins/remark-smartypants.js
+++ b/plugins/remark-smartypants.js
@@ -1,3 +1,8 @@
+/*!
+ * Based on 'silvenon/remark-smartypants'
+ * https://github.com/silvenon/remark-smartypants/pull/80
+ */
+
const visit = require('unist-util-visit');
const retext = require('retext');
const smartypants = require('retext-smartypants');
@@ -9,12 +14,48 @@ function check(parent) {
}
module.exports = function (options) {
- const processor = retext().use(smartypants, options);
+ const processor = retext().use(smartypants, {
+ ...options,
+ // Do not replace ellipses, dashes, backticks because they change string
+ // length, and we couldn't guarantee right splice of text in second visit of
+ // tree
+ ellipses: false,
+ dashes: false,
+ backticks: false,
+ });
+
+ const processor2 = retext().use(smartypants, {
+ ...options,
+ // Do not replace quotes because they are already replaced in the first
+ // processor
+ quotes: false,
+ });
function transformer(tree) {
- visit(tree, 'text', (node, index, parent) => {
- if (check(parent)) node.value = String(processor.processSync(node.value));
+ let allText = '';
+ let startIndex = 0;
+ const textOrInlineCodeNodes = [];
+
+ visit(tree, ['text', 'inlineCode'], (node, _, parent) => {
+ if (check(parent)) {
+ if (node.type === 'text') allText += node.value;
+ // for the case when inlineCode contains just one part of quote: `foo'bar`
+ else allText += 'A'.repeat(node.value.length);
+ textOrInlineCodeNodes.push(node);
+ }
});
+
+ // Concat all text into one string, to properly replace quotes around non-"text" nodes
+ allText = String(processor.processSync(allText));
+
+ for (const node of textOrInlineCodeNodes) {
+ const endIndex = startIndex + node.value.length;
+ if (node.type === 'text') {
+ const processedText = allText.slice(startIndex, endIndex);
+ node.value = String(processor2.processSync(processedText));
+ }
+ startIndex = endIndex;
+ }
}
return transformer;
diff --git a/src/utils/prepareMDX.js b/src/utils/prepareMDX.js
index 639d7db90..20a22577d 100644
--- a/src/utils/prepareMDX.js
+++ b/src/utils/prepareMDX.js
@@ -7,7 +7,7 @@ import {Children} from 'react';
// TODO: This logic could be in MDX plugins instead.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-export const PREPARE_MDX_CACHE_BREAKER = 2;
+export const PREPARE_MDX_CACHE_BREAKER = 3;
// !!! IMPORTANT !!! Bump this if you change any logic.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
From bb0ac87ce43cc8216601d67a5b2ab653039c259c Mon Sep 17 00:00:00 2001
From: probeiuscorp <70288813+probeiuscorp@users.noreply.github.com>
Date: Mon, 8 Jan 2024 19:33:29 -0600
Subject: [PATCH 08/21] Fix typo in experimental_taintObjectReference (#6536)
Change untained -> untainted
---
.../reference/react/experimental_taintObjectReference.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/content/reference/react/experimental_taintObjectReference.md b/src/content/reference/react/experimental_taintObjectReference.md
index 335f659c6..b5b9e513d 100644
--- a/src/content/reference/react/experimental_taintObjectReference.md
+++ b/src/content/reference/react/experimental_taintObjectReference.md
@@ -64,11 +64,11 @@ experimental_taintObjectReference(
#### Caveats {/*caveats*/}
-- Recreating or cloning a tainted object creates a new untained object which may contain sensitive data. For example, if you have a tainted `user` object, `const userInfo = {name: user.name, ssn: user.ssn}` or `{...user}` will create new objects which are not tainted. `taintObjectReference` only protects against simple mistakes when the object is passed through to a Client Component unchanged.
+- Recreating or cloning a tainted object creates a new untainted object which may contain sensitive data. For example, if you have a tainted `user` object, `const userInfo = {name: user.name, ssn: user.ssn}` or `{...user}` will create new objects which are not tainted. `taintObjectReference` only protects against simple mistakes when the object is passed through to a Client Component unchanged.
-**Do not rely on just tainting for security.** Tainting an object doesn't prevent leaking of every possible derived value. For example, the clone of a tainted object will create a new untained object. Using data from a tainted object (e.g. `{secret: taintedObj.secret}`) will create a new value or object that is not tainted. Tainting is a layer of protection; a secure app will have multiple layers of protection, well designed APIs, and isolation patterns.
+**Do not rely on just tainting for security.** Tainting an object doesn't prevent leaking of every possible derived value. For example, the clone of a tainted object will create a new untainted object. Using data from a tainted object (e.g. `{secret: taintedObj.secret}`) will create a new value or object that is not tainted. Tainting is a layer of protection; a secure app will have multiple layers of protection, well designed APIs, and isolation patterns.
From 083c308de8365ba1b9ef6db85d536e5cfc844ec0 Mon Sep 17 00:00:00 2001
From: Abdul Rahman
Date: Tue, 9 Jan 2024 07:52:15 +0530
Subject: [PATCH 09/21] Fix(Bug) Update Feedback.tsx component visiblity issue
(#6533)
* Update Feedback.tsx
* Update Feedback.tsx
Time reduced to 1.5 seconds, also going to update css
* Update index.css
CSS updated for feedback component animation.
* Update Feedback.tsx
* Update index.css
---------
Co-authored-by: Ricky
---
src/components/Layout/Feedback.tsx | 7 ++++++-
src/styles/index.css | 6 ++++++
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/src/components/Layout/Feedback.tsx b/src/components/Layout/Feedback.tsx
index 8639ce12c..0bdbc6b7c 100644
--- a/src/components/Layout/Feedback.tsx
+++ b/src/components/Layout/Feedback.tsx
@@ -4,6 +4,7 @@
import {useState} from 'react';
import {useRouter} from 'next/router';
+import cn from 'classnames';
export function Feedback({onSubmit = () => {}}: {onSubmit?: () => void}) {
const {asPath} = useRouter();
@@ -60,7 +61,11 @@ function sendGAEvent(isPositive: boolean) {
function SendFeedback({onSubmit}: {onSubmit: () => void}) {
const [isSubmitted, setIsSubmitted] = useState(false);
return (
-
+
{isSubmitted ? 'Thank you for your feedback!' : 'Is this page useful?'}
diff --git a/src/styles/index.css b/src/styles/index.css
index 9e1ec4aaa..f22784ce0 100644
--- a/src/styles/index.css
+++ b/src/styles/index.css
@@ -719,3 +719,9 @@ ol.mdx-illustration-block {
width: 100%;
}
}
+
+.exit {
+ opacity: 0;
+ transition: opacity 500ms ease-out;
+ transition-delay: 1s;
+}
From 10d4a4dfb3f23dda455519fb73c24ef9a6fc6d26 Mon Sep 17 00:00:00 2001
From: Ricky
Date: Mon, 8 Jan 2024 22:07:08 -0500
Subject: [PATCH 10/21] Fix forwardRef and useRef links (#6537)
---
src/content/reference/react/forwardRef.md | 2 +-
src/content/reference/react/useRef.md | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/content/reference/react/forwardRef.md b/src/content/reference/react/forwardRef.md
index e1e96a200..04d69287c 100644
--- a/src/content/reference/react/forwardRef.md
+++ b/src/content/reference/react/forwardRef.md
@@ -42,7 +42,7 @@ const MyInput = forwardRef(function MyInput(props, ref) {
#### Caveats {/*caveats*/}
-* In Strict Mode, React will **call your render function twice** in order to [help you find accidental impurities.](#my-initializer-or-updater-function-runs-twice) This is development-only behavior and does not affect production. If your render function is pure (as it should be), this should not affect the logic of your component. The result from one of the calls will be ignored.
+* In Strict Mode, React will **call your render function twice** in order to [help you find accidental impurities.](/reference/react/useState#my-initializer-or-updater-function-runs-twice) This is development-only behavior and does not affect production. If your render function is pure (as it should be), this should not affect the logic of your component. The result from one of the calls will be ignored.
---
diff --git a/src/content/reference/react/useRef.md b/src/content/reference/react/useRef.md
index 4af7e9535..fcecae714 100644
--- a/src/content/reference/react/useRef.md
+++ b/src/content/reference/react/useRef.md
@@ -50,7 +50,7 @@ On the next renders, `useRef` will return the same object.
* You can mutate the `ref.current` property. Unlike state, it is mutable. However, if it holds an object that is used for rendering (for example, a piece of your state), then you shouldn't mutate that object.
* When you change the `ref.current` property, React does not re-render your component. React is not aware of when you change it because a ref is a plain JavaScript object.
* Do not write _or read_ `ref.current` during rendering, except for [initialization.](#avoiding-recreating-the-ref-contents) This makes your component's behavior unpredictable.
-* In Strict Mode, React will **call your component function twice** in order to [help you find accidental impurities.](#my-initializer-or-updater-function-runs-twice) This is development-only behavior and does not affect production. Each ref object will be created twice, but one of the versions will be discarded. If your component function is pure (as it should be), this should not affect the behavior.
+* In Strict Mode, React will **call your component function twice** in order to [help you find accidental impurities.](/reference/react/useState#my-initializer-or-updater-function-runs-twice) This is development-only behavior and does not affect production. Each ref object will be created twice, but one of the versions will be discarded. If your component function is pure (as it should be), this should not affect the behavior.
---
From 53a1f4940ece4f5add7e6d53b10c3052d9ae5e01 Mon Sep 17 00:00:00 2001
From: Kiran Abburi
Date: Tue, 9 Jan 2024 23:16:22 +0530
Subject: [PATCH 11/21] Added React Nexus 2024 conference to the conference
list (#6538)
---
src/content/community/conferences.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/content/community/conferences.md b/src/content/community/conferences.md
index 9f020966e..b3d9603a7 100644
--- a/src/content/community/conferences.md
+++ b/src/content/community/conferences.md
@@ -20,6 +20,11 @@ June 12 - June 14, 2024. Atlanta, GA, USA
[Website](https://renderatl.com) - [Discord](https://www.renderatl.com/discord) - [Twitter](https://twitter.com/renderATL) - [Instagram](https://www.instagram.com/renderatl/) - [Facebook](https://www.facebook.com/renderatl/) - [LinkedIn](https://www.linkedin.com/company/renderatl) - [Podcast](https://www.renderatl.com/culture-and-code#/)
+### React Nexus 2024 {/*react-nexus-2024*/}
+July 04 & 05, 2024. Bangalore, India (In-person event)
+
+[Website](https://reactnexus.com/) - [Twitter](https://twitter.com/ReactNexus) - [Linkedin](https://www.linkedin.com/company/react-nexus) - [YouTube](https://www.youtube.com/reactify_in)
+
### React India 2024 {/*react-india-2024*/}
October 17 - 19, 2024. In-person in Goa, India (hybrid event) + Oct 15 2024 - remote day
From 6f8d4e60999f335ef2dd4eb2650e701deb7bb581 Mon Sep 17 00:00:00 2001
From: Ricky
Date: Tue, 9 Jan 2024 12:59:49 -0500
Subject: [PATCH 12/21] Add pointer-events:none to .exit (#6541)
---
src/styles/index.css | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/styles/index.css b/src/styles/index.css
index f22784ce0..cfd82dc0b 100644
--- a/src/styles/index.css
+++ b/src/styles/index.css
@@ -724,4 +724,5 @@ ol.mdx-illustration-block {
opacity: 0;
transition: opacity 500ms ease-out;
transition-delay: 1s;
+ pointer-events: none;
}
From 983bda90ccc10b52d4615bfd4769a2dfbe6802ba Mon Sep 17 00:00:00 2001
From: TymeeK <38594702+TymeeK@users.noreply.github.com>
Date: Wed, 10 Jan 2024 12:53:05 -0800
Subject: [PATCH 13/21] Removed unused nextId variable (#6470)
---
src/content/learn/updating-arrays-in-state.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/content/learn/updating-arrays-in-state.md b/src/content/learn/updating-arrays-in-state.md
index ea861931e..61e4f4e2d 100644
--- a/src/content/learn/updating-arrays-in-state.md
+++ b/src/content/learn/updating-arrays-in-state.md
@@ -409,7 +409,6 @@ For example:
```js
import { useState } from 'react';
-let nextId = 3;
const initialList = [
{ id: 0, title: 'Big Bellies' },
{ id: 1, title: 'Lunar Landscape' },
From 9d8c5add07179839a00017f0678bffb70d3ba211 Mon Sep 17 00:00:00 2001
From: Ricky
Date: Wed, 10 Jan 2024 17:46:48 -0500
Subject: [PATCH 14/21] Revert "Add useState semicolon (#5823)" (#6543)
This reverts commit e18bb3b25731411acfd554a44efd0b7189f577bb.
---
src/content/reference/react/useState.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/content/reference/react/useState.md b/src/content/reference/react/useState.md
index ee86f0e8f..48d96f8ee 100644
--- a/src/content/reference/react/useState.md
+++ b/src/content/reference/react/useState.md
@@ -7,7 +7,7 @@ title: useState
`useState` is a React Hook that lets you add a [state variable](/learn/state-a-components-memory) to your component.
```js
-const [state, setState] = useState(initialState);
+const [state, setState] = useState(initialState)
```
From eff3955836a3391d5795821d22328b86fc9f7e8e Mon Sep 17 00:00:00 2001
From: Taz Singh
Date: Thu, 11 Jan 2024 19:25:58 +0000
Subject: [PATCH 15/21] Update meetups.md (#6540)
---
src/content/community/meetups.md | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/content/community/meetups.md b/src/content/community/meetups.md
index 000eeb43c..a12a5349c 100644
--- a/src/content/community/meetups.md
+++ b/src/content/community/meetups.md
@@ -72,7 +72,8 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet
## England (UK) {/*england-uk*/}
* [Manchester](https://www.meetup.com/Manchester-React-User-Group/)
* [React.JS Girls London](https://www.meetup.com/ReactJS-Girls-London/)
-* [React London : Bring Your Own Project](https://www.meetup.com/React-London-Bring-Your-Own-Project/)
+* [React Advanced London](https://guild.host/react-advanced-london)
+* [React Native London](https://guild.host/RNLDN)
## France {/*france*/}
* [Nantes](https://www.meetup.com/React-Nantes/)
@@ -86,7 +87,7 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet
* [Karlsruhe](https://www.meetup.com/react_ka/)
* [Kiel](https://www.meetup.com/Kiel-React-Native-Meetup/)
* [Munich](https://www.meetup.com/ReactJS-Meetup-Munich/)
-* [React Berlin](https://www.meetup.com/React-Open-Source/)
+* [React Berlin](https://guild.host/react-berlin)
## Greece {/*greece*/}
* [Athens](https://www.meetup.com/React-To-React-Athens-MeetUp/)
@@ -108,7 +109,7 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet
* [Indonesia](https://www.meetup.com/reactindonesia/)
## Ireland {/*ireland*/}
-* [Dublin](https://www.meetup.com/ReactJS-Dublin/)
+* [Dublin](https://guild.host/reactjs-dublin)
## Israel {/*israel*/}
* [Tel Aviv](https://www.meetup.com/ReactJS-Israel/)
@@ -124,7 +125,7 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet
* [Penang](https://www.facebook.com/groups/reactpenang/)
## Netherlands {/*netherlands*/}
-* [Amsterdam](https://www.meetup.com/React-Amsterdam/)
+* [Amsterdam](https://guild.host/react-amsterdam)
## New Zealand {/*new-zealand*/}
* [Wellington](https://www.meetup.com/React-Wellington/)
@@ -201,6 +202,7 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet
* [New York, NY - React Ladies](https://www.meetup.com/React-Ladies/)
* [New York, NY - React Native](https://www.meetup.com/React-Native-NYC/)
* [New York, NY - useReactNYC](https://www.meetup.com/useReactNYC/)
+* [New York, NY - React.NYC](https://guild.host/react-nyc)
* [Omaha, NE - ReactJS/React Native](https://www.meetup.com/omaha-react-meetup-group/)
* [Palo Alto, CA - React Native](https://www.meetup.com/React-Native-Silicon-Valley/)
* [Philadelphia, PA - ReactJS](https://www.meetup.com/Reactadelphia/)
From a3f5b133a18be27ddcc44189a0f39375744bd3df Mon Sep 17 00:00:00 2001
From: Zoey <38047633+zoephyr@users.noreply.github.com>
Date: Thu, 11 Jan 2024 15:28:02 -0500
Subject: [PATCH 16/21] fix: Grammar in versioning-policy.md (#6539)
Adds a missing word in the documentation describing canary versioning
---
src/content/community/versioning-policy.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/content/community/versioning-policy.md b/src/content/community/versioning-policy.md
index eb38f8c29..fad926c57 100644
--- a/src/content/community/versioning-policy.md
+++ b/src/content/community/versioning-policy.md
@@ -80,7 +80,7 @@ This section will be most relevant to developers who work on frameworks, librari
Each of React's release channels is designed for a distinct use case:
- [**Latest**](#latest-channel) is for stable, semver React releases. It's what you get when you install React from npm. This is the channel you're already using today. **User-facing applications that consume React directly use this channel.**
-- [**Canary**](#canary-channel) tracks the main branch of the React source code repository. Think of these as release candidates for the next semver release. **[Frameworks or other curated setups may choose to use this channel with a pinned version of React.](/blog/2023/05/03/react-canaries) You can also Canaries for integration testing between React and third party projects.**
+- [**Canary**](#canary-channel) tracks the main branch of the React source code repository. Think of these as release candidates for the next semver release. **[Frameworks or other curated setups may choose to use this channel with a pinned version of React.](/blog/2023/05/03/react-canaries) You can also use Canaries for integration testing between React and third party projects.**
- [**Experimental**](#experimental-channel) includes experimental APIs and features that aren't available in the stable releases. These also track the main branch, but with additional feature flags turned on. Use this to try out upcoming features before they are released.
All releases are published to npm, but only Latest uses semantic versioning. Prereleases (those in the Canary and Experimental channels) have versions generated from a hash of their contents and the commit date, e.g. `18.3.0-canary-388686f29-20230503` for Canary and `0.0.0-experimental-388686f29-20230503` for Experimental.
From 097254168350cbb78d6a121653acfa278b84ab1a Mon Sep 17 00:00:00 2001
From: Ben Amor Aymen
Date: Fri, 12 Jan 2024 21:22:35 +0100
Subject: [PATCH 17/21] Add React Paris 2024 conference + React Brussels videos
link (#6547)
Co-authored-by: Aimen Ben Amor
---
src/content/community/conferences.md | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/content/community/conferences.md b/src/content/community/conferences.md
index b3d9603a7..7e3f66725 100644
--- a/src/content/community/conferences.md
+++ b/src/content/community/conferences.md
@@ -10,6 +10,11 @@ Do you know of a local React.js conference? Add it here! (Please keep the list c
## Upcoming Conferences {/*upcoming-conferences*/}
+### React Paris 2024 {/*react-paris-2024*/}
+March 22, 2024. In-person in Paris, France + Remote (hybrid)
+
+[Website](https://react.paris/) - [Twitter](https://twitter.com/BeJS_) - [LinkedIn](https://www.linkedin.com/events/7150816372074192900/comments/)
+
### App.js Conf 2024 {/*appjs-conf-2024*/}
May 22 - 24, 2024. In-person in Kraków, Poland + remote
@@ -55,7 +60,7 @@ October 20 & 23, 2023. In-person in London, UK + remote first interactivity (hyb
### React Brussels 2023 {/*react-brussels-2023*/}
October 13th 2023. In-person in Brussels, Belgium + Remote (hybrid)
-[Website](https://www.react.brussels/) - [Twitter](https://twitter.com/BrusselsReact)
+[Website](https://www.react.brussels/) - [Twitter](https://twitter.com/BrusselsReact) - [Videos](https://www.youtube.com/playlist?list=PL53Z0yyYnpWh85KeMomUoVz8_brrmh_aC)
### React India 2023 {/*react-india-2023*/}
October 5 - 7, 2023. In-person in Goa, India (hybrid event) + Oct 3 2023 - remote day
From 6987f0fb30899e00f5adf6945088c3fa3492e452 Mon Sep 17 00:00:00 2001
From: Prajwal Kulkarni
Date: Sat, 13 Jan 2024 02:45:04 +0530
Subject: [PATCH 18/21] Fix overflowing text content in footer link (#6519)
* Fix overflowing text content in footer link
Add an ellipsis to overflowing text in the footer section for navigating between different references.
* Add min and max width to nextlink class
* Add minwidth to tailwind config
* Wrap string beyond max width
* Remove title attribute from span element
---
src/components/DocsFooter.tsx | 16 +++++++++-------
tailwind.config.js | 5 +++++
2 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/src/components/DocsFooter.tsx b/src/components/DocsFooter.tsx
index 2fdbb0460..5f2330e7e 100644
--- a/src/components/DocsFooter.tsx
+++ b/src/components/DocsFooter.tsx
@@ -27,7 +27,7 @@ export const DocsPageFooter = memo(
<>
{prevRoute?.path || nextRoute?.path ? (
<>
-
+
{prevRoute?.path ? (
-
-
+
+
{type}
- {title}
-
+
+ {title}
+
+
);
}
diff --git a/tailwind.config.js b/tailwind.config.js
index d528ff494..a9488ccc7 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -57,8 +57,13 @@ module.exports = {
'meta-gradient-dark': "url('/images/meta-gradient-dark.png')",
},
maxWidth: {
+ ...defaultTheme.maxWidth,
xs: '21rem',
},
+ minWidth:{
+ ...defaultTheme.minWidth,
+ 80: '20rem',
+ },
outline: {
blue: ['1px auto ' + colors.link, '3px'],
},
From 8d2664b8062a2eea1306e4b63dcecc0a17febe8c Mon Sep 17 00:00:00 2001
From: Sukka
Date: Sat, 13 Jan 2024 05:18:21 +0800
Subject: [PATCH 19/21] Feat: error-decoder (#6214)
* Feat: port error-decoder
* Fix: do not choke on empty invariant
* Refactor: read url query from `useRouter`
* Fix: argsList can contains `undefined`
* Fix: handle empty string arg
* Feat: move error decoder to the separate page
* Fix: wrap error decoder header in
* Perf: cache GitHub RAW requests
* Refactor: apply code review suggestions
* Fix: build error
* Refactor: apply code review suggestions
* Discard changes to src/content/index.md
* Fix: animation duration/delay
* Refactor: read error page from markdown
* Fix lint
* Fix /error being 404
* Prevent `_default.md` being included in `[[...markdownPath]].md`
* Fix custom error markdown reading
* Updates
---------
Co-authored-by: Ricky Hanlon
---
src/components/ErrorDecoderContext.tsx | 23 ++++
src/components/MDX/ErrorDecoder.tsx | 107 +++++++++++++++++
src/components/MDX/MDXComponents.tsx | 3 +
src/content/errors/377.md | 13 ++
src/content/errors/generic.md | 11 ++
src/content/errors/index.md | 10 ++
src/pages/[[...markdownPath]].js | 148 ++---------------------
src/pages/errors/[errorCode].tsx | 157 +++++++++++++++++++++++++
src/pages/errors/index.tsx | 3 +
src/utils/compileMDX.ts | 153 ++++++++++++++++++++++++
tailwind.config.js | 11 ++
11 files changed, 504 insertions(+), 135 deletions(-)
create mode 100644 src/components/ErrorDecoderContext.tsx
create mode 100644 src/components/MDX/ErrorDecoder.tsx
create mode 100644 src/content/errors/377.md
create mode 100644 src/content/errors/generic.md
create mode 100644 src/content/errors/index.md
create mode 100644 src/pages/errors/[errorCode].tsx
create mode 100644 src/pages/errors/index.tsx
create mode 100644 src/utils/compileMDX.ts
diff --git a/src/components/ErrorDecoderContext.tsx b/src/components/ErrorDecoderContext.tsx
new file mode 100644
index 000000000..080969efe
--- /dev/null
+++ b/src/components/ErrorDecoderContext.tsx
@@ -0,0 +1,23 @@
+// Error Decoder requires reading pregenerated error message from getStaticProps,
+// but MDX component doesn't support props. So we use React Context to populate
+// the value without prop-drilling.
+// TODO: Replace with React.cache + React.use when migrating to Next.js App Router
+
+import {createContext, useContext} from 'react';
+
+const notInErrorDecoderContext = Symbol('not in error decoder context');
+
+export const ErrorDecoderContext = createContext<
+ | {errorMessage: string | null; errorCode: string | null}
+ | typeof notInErrorDecoderContext
+>(notInErrorDecoderContext);
+
+export const useErrorDecoderParams = () => {
+ const params = useContext(ErrorDecoderContext);
+
+ if (params === notInErrorDecoderContext) {
+ throw new Error('useErrorDecoder must be used in error decoder pages only');
+ }
+
+ return params;
+};
diff --git a/src/components/MDX/ErrorDecoder.tsx b/src/components/MDX/ErrorDecoder.tsx
new file mode 100644
index 000000000..daa713285
--- /dev/null
+++ b/src/components/MDX/ErrorDecoder.tsx
@@ -0,0 +1,107 @@
+import {useEffect, useState} from 'react';
+import {useErrorDecoderParams} from '../ErrorDecoderContext';
+import cn from 'classnames';
+
+function replaceArgs(
+ msg: string,
+ argList: Array,
+ replacer = '[missing argument]'
+): string {
+ let argIdx = 0;
+ return msg.replace(/%s/g, function () {
+ const arg = argList[argIdx++];
+ // arg can be an empty string: ?args[0]=&args[1]=count
+ return arg === undefined || arg === '' ? replacer : arg;
+ });
+}
+
+/**
+ * Sindre Sorhus
+ * Released under MIT license
+ * https://github.com/sindresorhus/linkify-urls/blob/edd75a64a9c36d7025f102f666ddbb6cf0afa7cd/index.js#L4C25-L4C137
+ *
+ * The regex is used to extract URL from the string for linkify.
+ */
+const urlRegex =
+ /((? {
+ if (i % 2 === 1) {
+ return (
+
+ {message}
+
+ );
+ }
+ return message;
+ });
+}
+
+// `?args[]=foo&args[]=bar`
+// or `// ?args[0]=foo&args[1]=bar`
+function parseQueryString(search: string): Array {
+ const rawQueryString = search.substring(1);
+ if (!rawQueryString) {
+ return [];
+ }
+
+ const args: Array = [];
+
+ const queries = rawQueryString.split('&');
+ for (let i = 0; i < queries.length; i++) {
+ const query = decodeURIComponent(queries[i]);
+ if (query.startsWith('args[')) {
+ args.push(query.slice(query.indexOf(']=') + 2));
+ }
+ }
+
+ return args;
+}
+
+export default function ErrorDecoder() {
+ const {errorMessage} = useErrorDecoderParams();
+ /** error messages that contain %s require reading location.search */
+ const hasParams = errorMessage?.includes('%s');
+ const [message, setMessage] = useState(() =>
+ errorMessage ? urlify(errorMessage) : null
+ );
+
+ const [isReady, setIsReady] = useState(errorMessage == null || !hasParams);
+
+ useEffect(() => {
+ if (errorMessage == null || !hasParams) {
+ return;
+ }
+
+ setMessage(
+ urlify(
+ replaceArgs(
+ errorMessage,
+ parseQueryString(window.location.search),
+ '[missing argument]'
+ )
+ )
+ );
+ setIsReady(true);
+ }, [hasParams, errorMessage]);
+
+ return (
+
+ {message}
+
+ );
+}
diff --git a/src/components/MDX/MDXComponents.tsx b/src/components/MDX/MDXComponents.tsx
index 74ab788ba..3528a9a16 100644
--- a/src/components/MDX/MDXComponents.tsx
+++ b/src/components/MDX/MDXComponents.tsx
@@ -31,6 +31,8 @@ import {TocContext} from './TocContext';
import type {Toc, TocItem} from './TocContext';
import {TeamMember} from './TeamMember';
+import ErrorDecoder from './ErrorDecoder';
+
function CodeStep({children, step}: {children: any; step: number}) {
return (
+
+In the minified production build of React, we avoid sending down full error messages in order to reduce the number of bytes sent over the wire.
+
+
+
+We highly recommend using the development build locally when debugging your app since it tracks additional debug info and provides helpful warnings about potential problems in your apps, but if you encounter an exception while using the production build, this page will reassemble the original error message.
+
+The full text of the error you just encountered is:
+
+
+
+This error occurs when you pass a BigInt value from a Server Component to a Client Component.
diff --git a/src/content/errors/generic.md b/src/content/errors/generic.md
new file mode 100644
index 000000000..27c3ca52d
--- /dev/null
+++ b/src/content/errors/generic.md
@@ -0,0 +1,11 @@
+
+
+In the minified production build of React, we avoid sending down full error messages in order to reduce the number of bytes sent over the wire.
+
+
+
+We highly recommend using the development build locally when debugging your app since it tracks additional debug info and provides helpful warnings about potential problems in your apps, but if you encounter an exception while using the production build, this page will reassemble the original error message.
+
+The full text of the error you just encountered is:
+
+
diff --git a/src/content/errors/index.md b/src/content/errors/index.md
new file mode 100644
index 000000000..25746d25d
--- /dev/null
+++ b/src/content/errors/index.md
@@ -0,0 +1,10 @@
+
+
+In the minified production build of React, we avoid sending down full error messages in order to reduce the number of bytes sent over the wire.
+
+
+
+
+We highly recommend using the development build locally when debugging your app since it tracks additional debug info and provides helpful warnings about potential problems in your apps, but if you encounter an exception while using the production build, the error message will include just a link to the docs for the error.
+
+For an example, see: [https://react.dev/errors/149](/errors/421).
diff --git a/src/pages/[[...markdownPath]].js b/src/pages/[[...markdownPath]].js
index d1df93d3c..76532361b 100644
--- a/src/pages/[[...markdownPath]].js
+++ b/src/pages/[[...markdownPath]].js
@@ -4,14 +4,14 @@
import {Fragment, useMemo} from 'react';
import {useRouter} from 'next/router';
-import {MDXComponents} from 'components/MDX/MDXComponents';
import {Page} from 'components/Layout/Page';
import sidebarHome from '../sidebarHome.json';
import sidebarLearn from '../sidebarLearn.json';
import sidebarReference from '../sidebarReference.json';
import sidebarCommunity from '../sidebarCommunity.json';
import sidebarBlog from '../sidebarBlog.json';
-
+import {MDXComponents} from 'components/MDX/MDXComponents';
+import compileMDX from 'utils/compileMDX';
export default function Layout({content, toc, meta}) {
const parsedContent = useMemo(
() => JSON.parse(content, reviveNodeOnClient),
@@ -94,20 +94,10 @@ function reviveNodeOnClient(key, val) {
}
}
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// ~~~~ IMPORTANT: BUMP THIS IF YOU CHANGE ANY CODE BELOW ~~~
-const DISK_CACHE_BREAKER = 7;
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
// Put MDX output into JSON for client.
export async function getStaticProps(context) {
const fs = require('fs');
- const {
- prepareMDX,
- PREPARE_MDX_CACHE_BREAKER,
- } = require('../utils/prepareMDX');
const rootDir = process.cwd() + '/src/content/';
- const mdxComponentNames = Object.keys(MDXComponents);
// Read MDX from the file.
let path = (context.params.markdownPath || []).join('/') || 'index';
@@ -118,132 +108,14 @@ export async function getStaticProps(context) {
mdx = fs.readFileSync(rootDir + path + '/index.md', 'utf8');
}
- // See if we have a cached output first.
- const {FileStore, stableHash} = require('metro-cache');
- const store = new FileStore({
- root: process.cwd() + '/node_modules/.cache/react-docs-mdx/',
- });
- const hash = Buffer.from(
- stableHash({
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // ~~~~ IMPORTANT: Everything that the code below may rely on.
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- mdx,
- mdxComponentNames,
- DISK_CACHE_BREAKER,
- PREPARE_MDX_CACHE_BREAKER,
- lockfile: fs.readFileSync(process.cwd() + '/yarn.lock', 'utf8'),
- })
- );
- const cached = await store.get(hash);
- if (cached) {
- console.log(
- 'Reading compiled MDX for /' + path + ' from ./node_modules/.cache/'
- );
- return cached;
- }
- if (process.env.NODE_ENV === 'production') {
- console.log(
- 'Cache miss for MDX for /' + path + ' from ./node_modules/.cache/'
- );
- }
-
- // If we don't add these fake imports, the MDX compiler
- // will insert a bunch of opaque components we can't introspect.
- // This will break the prepareMDX() call below.
- let mdxWithFakeImports =
- mdx +
- '\n\n' +
- mdxComponentNames
- .map((key) => 'import ' + key + ' from "' + key + '";\n')
- .join('\n');
-
- // Turn the MDX we just read into some JS we can execute.
- const {remarkPlugins} = require('../../plugins/markdownToHtml');
- const {compile: compileMdx} = await import('@mdx-js/mdx');
- const visit = (await import('unist-util-visit')).default;
- const jsxCode = await compileMdx(mdxWithFakeImports, {
- remarkPlugins: [
- ...remarkPlugins,
- (await import('remark-gfm')).default,
- (await import('remark-frontmatter')).default,
- ],
- rehypePlugins: [
- // Support stuff like ```js App.js {1-5} active by passing it through.
- function rehypeMetaAsAttributes() {
- return (tree) => {
- visit(tree, 'element', (node) => {
- if (node.tagName === 'code' && node.data && node.data.meta) {
- node.properties.meta = node.data.meta;
- }
- });
- };
- },
- ],
- });
- const {transform} = require('@babel/core');
- const jsCode = await transform(jsxCode, {
- plugins: ['@babel/plugin-transform-modules-commonjs'],
- presets: ['@babel/preset-react'],
- }).code;
-
- // Prepare environment for MDX.
- let fakeExports = {};
- const fakeRequire = (name) => {
- if (name === 'react/jsx-runtime') {
- return require('react/jsx-runtime');
- } else {
- // For each fake MDX import, give back the string component name.
- // It will get serialized later.
- return name;
- }
- };
- const evalJSCode = new Function('require', 'exports', jsCode);
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // THIS IS A BUILD-TIME EVAL. NEVER DO THIS WITH UNTRUSTED MDX (LIKE FROM CMS)!!!
- // In this case it's okay because anyone who can edit our MDX can also edit this file.
- evalJSCode(fakeRequire, fakeExports);
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- const reactTree = fakeExports.default({});
-
- // Pre-process MDX output and serialize it.
- let {toc, children} = prepareMDX(reactTree.props.children);
- if (path === 'index') {
- toc = [];
- }
-
- // Parse Frontmatter headers from MDX.
- const fm = require('gray-matter');
- const meta = fm(mdx).data;
-
- const output = {
+ const {toc, content, meta} = await compileMDX(mdx, path, {});
+ return {
props: {
- content: JSON.stringify(children, stringifyNodeOnServer),
- toc: JSON.stringify(toc, stringifyNodeOnServer),
+ toc,
+ content,
meta,
},
};
-
- // Serialize a server React tree node to JSON.
- function stringifyNodeOnServer(key, val) {
- if (val != null && val.$$typeof === Symbol.for('react.element')) {
- // Remove fake MDX props.
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- const {mdxType, originalType, parentName, ...cleanProps} = val.props;
- return [
- '$r',
- typeof val.type === 'string' ? val.type : mdxType,
- val.key,
- cleanProps,
- ];
- } else {
- return val;
- }
- }
-
- // Cache it on the disk.
- await store.set(hash, output);
- return output;
}
// Collect all MDX files for static generation.
@@ -266,7 +138,12 @@ export async function getStaticPaths() {
: res.slice(rootDir.length + 1);
})
);
- return files.flat().filter((file) => file.endsWith('.md'));
+ return (
+ files
+ .flat()
+ // ignores `errors/*.md`, they will be handled by `pages/errors/[errorCode].tsx`
+ .filter((file) => file.endsWith('.md') && !file.startsWith('errors/'))
+ );
}
// 'foo/bar/baz.md' -> ['foo', 'bar', 'baz']
@@ -280,6 +157,7 @@ export async function getStaticPaths() {
}
const files = await getFiles(rootDir);
+
const paths = files.map((file) => ({
params: {
markdownPath: getSegments(file),
diff --git a/src/pages/errors/[errorCode].tsx b/src/pages/errors/[errorCode].tsx
new file mode 100644
index 000000000..f1a54a3d6
--- /dev/null
+++ b/src/pages/errors/[errorCode].tsx
@@ -0,0 +1,157 @@
+import {Fragment, useMemo} from 'react';
+import {Page} from 'components/Layout/Page';
+import {MDXComponents} from 'components/MDX/MDXComponents';
+import sidebarLearn from 'sidebarLearn.json';
+import type {RouteItem} from 'components/Layout/getRouteMeta';
+import {GetStaticPaths, GetStaticProps, InferGetStaticPropsType} from 'next';
+import {ErrorDecoderContext} from 'components/ErrorDecoderContext';
+import compileMDX from 'utils/compileMDX';
+
+interface ErrorDecoderProps {
+ errorCode: string | null;
+ errorMessage: string | null;
+ content: string;
+ toc: string;
+ meta: any;
+}
+
+export default function ErrorDecoderPage({
+ errorMessage,
+ errorCode,
+ content,
+}: InferGetStaticPropsType) {
+ const parsedContent = useMemo(
+ () => JSON.parse(content, reviveNodeOnClient),
+ [content]
+ );
+
+ return (
+
+
+ {parsedContent}
+ {/*
+
+ We highly recommend using the development build locally when debugging
+ your app since it tracks additional debug info and provides helpful
+ warnings about potential problems in your apps, but if you encounter
+ an exception while using the production build, this page will
+ reassemble the original error message.
+
+
+ */}
+
+
+ );
+}
+
+// Deserialize a client React tree from JSON.
+function reviveNodeOnClient(key: unknown, val: any) {
+ if (Array.isArray(val) && val[0] == '$r') {
+ // Assume it's a React element.
+ let type = val[1];
+ let key = val[2];
+ let props = val[3];
+ if (type === 'wrapper') {
+ type = Fragment;
+ props = {children: props.children};
+ }
+ if (type in MDXComponents) {
+ type = MDXComponents[type as keyof typeof MDXComponents];
+ }
+ if (!type) {
+ console.error('Unknown type: ' + type);
+ type = Fragment;
+ }
+ return {
+ $$typeof: Symbol.for('react.element'),
+ type: type,
+ key: key,
+ ref: null,
+ props: props,
+ _owner: null,
+ };
+ } else {
+ return val;
+ }
+}
+
+/**
+ * Next.js Page Router doesn't have a way to cache specific data fetching request.
+ * But since Next.js uses limited number of workers, keep "cachedErrorCodes" as a
+ * module level memory cache can reduce the number of requests down to once per worker.
+ *
+ * TODO: use `next/unstable_cache` when migrating to Next.js App Router
+ */
+let cachedErrorCodes: Record | null = null;
+
+export const getStaticProps: GetStaticProps = async ({
+ params,
+}) => {
+ const errorCodes: {[key: string]: string} = (cachedErrorCodes ||= await (
+ await fetch(
+ 'https://raw.githubusercontent.com/facebook/react/main/scripts/error-codes/codes.json'
+ )
+ ).json());
+
+ const code = typeof params?.errorCode === 'string' ? params?.errorCode : null;
+ if (code && !errorCodes[code]) {
+ return {
+ notFound: true,
+ };
+ }
+
+ const fs = require('fs');
+ const rootDir = process.cwd() + '/src/content/errors';
+
+ // Read MDX from the file.
+ let path = params?.errorCode || 'index';
+ let mdx;
+ try {
+ mdx = fs.readFileSync(rootDir + '/' + path + '.md', 'utf8');
+ } catch {
+ // if [errorCode].md is not found, fallback to generic.md
+ mdx = fs.readFileSync(rootDir + '/generic.md', 'utf8');
+ }
+
+ const {content, toc, meta} = await compileMDX(mdx, path, {code, errorCodes});
+
+ return {
+ props: {
+ content,
+ toc,
+ meta,
+ errorCode: code,
+ errorMessage: code ? errorCodes[code] : null,
+ },
+ };
+};
+
+export const getStaticPaths: GetStaticPaths = async () => {
+ /**
+ * Fetch error codes from GitHub
+ */
+ const errorCodes = (cachedErrorCodes ||= await (
+ await fetch(
+ 'https://raw.githubusercontent.com/facebook/react/main/scripts/error-codes/codes.json'
+ )
+ ).json());
+
+ const paths = Object.keys(errorCodes).map((code) => ({
+ params: {
+ errorCode: code,
+ },
+ }));
+
+ return {
+ paths,
+ fallback: 'blocking',
+ };
+};
diff --git a/src/pages/errors/index.tsx b/src/pages/errors/index.tsx
new file mode 100644
index 000000000..d7742f03a
--- /dev/null
+++ b/src/pages/errors/index.tsx
@@ -0,0 +1,3 @@
+import ErrorDecoderPage from './[errorCode]';
+export default ErrorDecoderPage;
+export {getStaticProps} from './[errorCode]';
diff --git a/src/utils/compileMDX.ts b/src/utils/compileMDX.ts
new file mode 100644
index 000000000..5f54d12b4
--- /dev/null
+++ b/src/utils/compileMDX.ts
@@ -0,0 +1,153 @@
+import {MDXComponents} from 'components/MDX/MDXComponents';
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// ~~~~ IMPORTANT: BUMP THIS IF YOU CHANGE ANY CODE BELOW ~~~
+const DISK_CACHE_BREAKER = 8;
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+export default async function compileMDX(
+ mdx: string,
+ path: string | string[],
+ params: {[key: string]: any}
+): Promise<{content: string; toc: string; meta: any}> {
+ const fs = require('fs');
+ const {
+ prepareMDX,
+ PREPARE_MDX_CACHE_BREAKER,
+ } = require('../utils/prepareMDX');
+ const mdxComponentNames = Object.keys(MDXComponents);
+
+ // See if we have a cached output first.
+ const {FileStore, stableHash} = require('metro-cache');
+ const store = new FileStore({
+ root: process.cwd() + '/node_modules/.cache/react-docs-mdx/',
+ });
+ const hash = Buffer.from(
+ stableHash({
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // ~~~~ IMPORTANT: Everything that the code below may rely on.
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ mdx,
+ ...params,
+ mdxComponentNames,
+ DISK_CACHE_BREAKER,
+ PREPARE_MDX_CACHE_BREAKER,
+ lockfile: fs.readFileSync(process.cwd() + '/yarn.lock', 'utf8'),
+ })
+ );
+ const cached = await store.get(hash);
+ if (cached) {
+ console.log(
+ 'Reading compiled MDX for /' + path + ' from ./node_modules/.cache/'
+ );
+ return cached;
+ }
+ if (process.env.NODE_ENV === 'production') {
+ console.log(
+ 'Cache miss for MDX for /' + path + ' from ./node_modules/.cache/'
+ );
+ }
+
+ // If we don't add these fake imports, the MDX compiler
+ // will insert a bunch of opaque components we can't introspect.
+ // This will break the prepareMDX() call below.
+ let mdxWithFakeImports =
+ mdx +
+ '\n\n' +
+ mdxComponentNames
+ .map((key) => 'import ' + key + ' from "' + key + '";\n')
+ .join('\n');
+
+ // Turn the MDX we just read into some JS we can execute.
+ const {remarkPlugins} = require('../../plugins/markdownToHtml');
+ const {compile: compileMdx} = await import('@mdx-js/mdx');
+ const visit = (await import('unist-util-visit')).default;
+ const jsxCode = await compileMdx(mdxWithFakeImports, {
+ remarkPlugins: [
+ ...remarkPlugins,
+ (await import('remark-gfm')).default,
+ (await import('remark-frontmatter')).default,
+ ],
+ rehypePlugins: [
+ // Support stuff like ```js App.js {1-5} active by passing it through.
+ function rehypeMetaAsAttributes() {
+ return (tree) => {
+ visit(tree, 'element', (node) => {
+ if (
+ // @ts-expect-error -- tagName is a valid property
+ node.tagName === 'code' &&
+ node.data &&
+ node.data.meta
+ ) {
+ // @ts-expect-error -- properties is a valid property
+ node.properties.meta = node.data.meta;
+ }
+ });
+ };
+ },
+ ],
+ });
+ const {transform} = require('@babel/core');
+ const jsCode = await transform(jsxCode, {
+ plugins: ['@babel/plugin-transform-modules-commonjs'],
+ presets: ['@babel/preset-react'],
+ }).code;
+
+ // Prepare environment for MDX.
+ let fakeExports = {};
+ const fakeRequire = (name: string) => {
+ if (name === 'react/jsx-runtime') {
+ return require('react/jsx-runtime');
+ } else {
+ // For each fake MDX import, give back the string component name.
+ // It will get serialized later.
+ return name;
+ }
+ };
+ const evalJSCode = new Function('require', 'exports', jsCode);
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // THIS IS A BUILD-TIME EVAL. NEVER DO THIS WITH UNTRUSTED MDX (LIKE FROM CMS)!!!
+ // In this case it's okay because anyone who can edit our MDX can also edit this file.
+ evalJSCode(fakeRequire, fakeExports);
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ // @ts-expect-error -- default exports is existed after eval
+ const reactTree = fakeExports.default({});
+
+ // Pre-process MDX output and serialize it.
+ let {toc, children} = prepareMDX(reactTree.props.children);
+ if (path === 'index') {
+ toc = [];
+ }
+
+ // Parse Frontmatter headers from MDX.
+ const fm = require('gray-matter');
+ const meta = fm(mdx).data;
+
+ const output = {
+ content: JSON.stringify(children, stringifyNodeOnServer),
+ toc: JSON.stringify(toc, stringifyNodeOnServer),
+ meta,
+ };
+
+ // Serialize a server React tree node to JSON.
+ function stringifyNodeOnServer(key: unknown, val: any) {
+ if (val != null && val.$$typeof === Symbol.for('react.element')) {
+ // Remove fake MDX props.
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const {mdxType, originalType, parentName, ...cleanProps} = val.props;
+ return [
+ '$r',
+ typeof val.type === 'string' ? val.type : mdxType,
+ val.key,
+ cleanProps,
+ ];
+ } else {
+ return val;
+ }
+ }
+
+ // Cache it on the disk.
+ await store.set(hash, output);
+ return output;
+}
diff --git a/tailwind.config.js b/tailwind.config.js
index a9488ccc7..cf34559bb 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -106,6 +106,7 @@ module.exports = {
marquee2: 'marquee2 40s linear infinite',
'large-marquee': 'large-marquee 80s linear infinite',
'large-marquee2': 'large-marquee2 80s linear infinite',
+ 'fade-up': 'fade-up 1s 100ms both',
},
keyframes: {
shimmer: {
@@ -143,6 +144,16 @@ module.exports = {
'0%': {transform: 'translateX(200%)'},
'100%': {transform: 'translateX(0%)'},
},
+ 'fade-up': {
+ '0%': {
+ opacity: '0',
+ transform: 'translateY(2rem)',
+ },
+ '100%': {
+ opacity: '1',
+ transform: 'translateY(0)',
+ },
+ },
},
colors,
gridTemplateColumns: {
From df8f301c2bc78f80244453c86b6b815a184e0c38 Mon Sep 17 00:00:00 2001
From: Bartosz Klonowski <70535775+BartoszKlonowski@users.noreply.github.com>
Date: Sat, 13 Jan 2024 00:43:55 +0100
Subject: [PATCH 20/21] Use 'trim()' method in `useContext` page to prevent
form from accepting whitespaces (#6549)
---
src/content/reference/react/useContext.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/content/reference/react/useContext.md b/src/content/reference/react/useContext.md
index bba445d0d..ce06e7035 100644
--- a/src/content/reference/react/useContext.md
+++ b/src/content/reference/react/useContext.md
@@ -457,7 +457,7 @@ function LoginForm() {
const {setCurrentUser} = useContext(CurrentUserContext);
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
- const canLogin = firstName !== '' && lastName !== '';
+ const canLogin = firstName.trim() !== '' && lastName.trim() !== '';
return (
<>
From 6bfde58c109ec86fd6c5767421404cb679ffba9a Mon Sep 17 00:00:00 2001
From: Alen Ajam
Date: Sun, 14 Jan 2024 05:41:17 +0100
Subject: [PATCH 21/21] docs: fix grammar (#6465)
---
src/content/reference/react-dom/components/form.md | 6 +++---
src/content/reference/react-dom/components/input.md | 2 +-
src/content/reference/react-dom/hooks/useFormState.md | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/content/reference/react-dom/components/form.md b/src/content/reference/react-dom/components/form.md
index 7a4b26b3f..4b7d5d8a0 100644
--- a/src/content/reference/react-dom/components/form.md
+++ b/src/content/reference/react-dom/components/form.md
@@ -5,7 +5,7 @@ canary: true
-React's extensions to `
@@ -118,7 +118,7 @@ function AddToCart({productId}) {
}
```
-In lieu of using hidden form fields to provide data to the `