Skip to content

Commit

Permalink
Merge pull request #549 from reactjs/sync-6bfde58c
Browse files Browse the repository at this point in the history
Sync with react.dev @ 6bfde58
  • Loading branch information
AhmedBaset authored Jan 29, 2024
2 parents 192abd3 + dd19001 commit 46cd7fc
Show file tree
Hide file tree
Showing 26 changed files with 560 additions and 161 deletions.
16 changes: 9 additions & 7 deletions src/components/DocsFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const DocsPageFooter = memo<DocsPageFooterProps>(
<>
{prevRoute?.path || nextRoute?.path ? (
<>
<div className="max-w-7xl mx-auto grid grid-cols-1 md:grid-cols-2 gap-4 py-4 md:py-12">
<div className="grid grid-cols-1 gap-4 py-4 mx-auto max-w-7xl md:grid-cols-2 md:py-12">
{prevRoute?.path ? (
<FooterLink
type="Previous"
Expand Down Expand Up @@ -69,21 +69,23 @@ function FooterLink({
<NextLink
href={href}
className={cn(
'flex gap-x-4 md:gap-x-6 items-center w-full md:w-80 px-4 md:px-5 py-6 border-2 border-transparent text-base leading-base text-link dark:text-link-dark rounded-lg group focus:text-link dark:focus:text-link-dark focus:bg-highlight focus:border-link dark:focus:bg-highlight-dark dark:focus:border-link-dark focus:border-opacity-100 focus:border-2 focus:ring-1 focus:ring-offset-4 focus:ring-blue-40 active:ring-0 active:ring-offset-0 hover:bg-gray-5 dark:hover:bg-gray-80',
'flex gap-x-4 md:gap-x-6 items-center w-full md:min-w-80 md:w-fit md:max-w-md px-4 md:px-5 py-6 border-2 border-transparent text-base leading-base text-link dark:text-link-dark rounded-lg group focus:text-link dark:focus:text-link-dark focus:bg-highlight focus:border-link dark:focus:bg-highlight-dark dark:focus:border-link-dark focus:border-opacity-100 focus:border-2 focus:ring-1 focus:ring-offset-4 focus:ring-blue-40 active:ring-0 active:ring-offset-0 hover:bg-gray-5 dark:hover:bg-gray-80',
{
'flex-row-reverse justify-self-end text-end': type === 'Next',
}
)}>
<IconNavArrow
className="text-tertiary dark:text-tertiary-dark inline group-focus:text-link dark:group-focus:text-link-dark"
className="inline text-tertiary dark:text-tertiary-dark group-focus:text-link dark:group-focus:text-link-dark"
displayDirection={type === 'Previous' ? 'start' : 'end'}
/>
<span>
<span className="block no-underline text-sm tracking-wide text-secondary dark:text-secondary-dark uppercase font-bold group-focus:text-link dark:group-focus:text-link-dark group-focus:text-opacity-100">
<div className="flex flex-col overflow-hidden">
<span className="text-sm font-bold tracking-wide no-underline uppercase text-secondary dark:text-secondary-dark group-focus:text-link dark:group-focus:text-link-dark group-focus:text-opacity-100">
{type}
</span>
<span className="block text-lg group-hover:underline">{title}</span>
</span>
<span className="text-lg break-words group-hover:underline">
{title}
</span>
</div>
</NextLink>
);
}
23 changes: 23 additions & 0 deletions src/components/ErrorDecoderContext.tsx
Original file line number Diff line number Diff line change
@@ -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;
};
7 changes: 6 additions & 1 deletion src/components/Layout/Feedback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -60,7 +61,11 @@ function sendGAEvent(isPositive: boolean) {
function SendFeedback({onSubmit}: {onSubmit: () => void}) {
const [isSubmitted, setIsSubmitted] = useState(false);
return (
<div className="max-w-xs w-80 lg:w-auto py-3 shadow-lg rounded-lg m-4 bg-wash dark:bg-gray-95 px-4 flex">
<div
className={cn(
'max-w-xs w-80 lg:w-auto py-3 shadow-lg rounded-lg m-4 bg-wash dark:bg-gray-95 px-4 flex',
{exit: isSubmitted}
)}>
<p className="w-full font-bold text-primary dark:text-primary-dark text-lg me-4">
{isSubmitted ? 'Thank you for your feedback!' : 'Is this page useful?'}
</p>
Expand Down
107 changes: 107 additions & 0 deletions src/components/MDX/ErrorDecoder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import {useEffect, useState} from 'react';
import {useErrorDecoderParams} from '../ErrorDecoderContext';
import cn from 'classnames';

function replaceArgs(
msg: string,
argList: Array<string | undefined>,
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 <https://sindresorhus.com>
* 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 =
/((?<!\+)https?:\/\/(?:www\.)?(?:[-\w.]+?[.@][a-zA-Z\d]{2,}|localhost)(?:[-\w.:%+~#*$!?&/=@]*?(?:,(?!\s))*?)*)/g;

// When the message contains a URL (like https://fb.me/react-refs-must-have-owner),
// make it a clickable link.
function urlify(str: string): React.ReactNode[] {
const segments = str.split(urlRegex);

return segments.map((message, i) => {
if (i % 2 === 1) {
return (
<a
key={i}
target="_blank"
className="underline"
rel="noopener noreferrer"
href={message}>
{message}
</a>
);
}
return message;
});
}

// `?args[]=foo&args[]=bar`
// or `// ?args[0]=foo&args[1]=bar`
function parseQueryString(search: string): Array<string | undefined> {
const rawQueryString = search.substring(1);
if (!rawQueryString) {
return [];
}

const args: Array<string | undefined> = [];

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<React.ReactNode | null>(() =>
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 (
<code
className={cn(
'block bg-red-100 text-red-600 py-4 px-6 mt-5 rounded-lg',
isReady ? 'opacity-100' : 'opacity-0'
)}>
<b>{message}</b>
</code>
);
}
3 changes: 3 additions & 0 deletions src/components/MDX/MDXComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<span
Expand Down Expand Up @@ -441,6 +443,7 @@ export const MDXComponents = {
Solution,
CodeStep,
YouTubeIframe,
ErrorDecoder,
};

for (let key in MDXComponents) {
Expand Down
12 changes: 11 additions & 1 deletion src/content/community/conferences.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -20,6 +25,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

Expand Down Expand Up @@ -50,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
Expand Down
10 changes: 6 additions & 4 deletions src/content/community/meetups.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/)
Expand All @@ -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/)
Expand All @@ -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/)
Expand All @@ -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/)
Expand Down Expand Up @@ -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/)
Expand Down
2 changes: 1 addition & 1 deletion src/content/community/versioning-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
13 changes: 13 additions & 0 deletions src/content/errors/377.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Intro>

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.

</Intro>

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:

<ErrorDecoder />

This error occurs when you pass a BigInt value from a Server Component to a Client Component.
11 changes: 11 additions & 0 deletions src/content/errors/generic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Intro>

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.

</Intro>

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:

<ErrorDecoder />
10 changes: 10 additions & 0 deletions src/content/errors/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Intro>

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.

</Intro>


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://ar.react.dev/errors/149](/errors/421).
1 change: 0 additions & 1 deletion src/content/learn/updating-arrays-in-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
Expand Down
6 changes: 3 additions & 3 deletions src/content/reference/react-dom/components/form.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ canary: true

<Canary>

React's extensions to `<form>` are currently only available in React's canary and experimental channels. In stable releases of React `<form>` works only as a [built-in browser HTML component](https://react.dev/reference/react-dom/components#all-html-components). Learn more about [React's release channels here](/community/versioning-policy#all-release-channels).
React's extensions to `<form>` are currently only available in React's canary and experimental channels. In stable releases of React, `<form>` works only as a [built-in browser HTML component](https://react.dev/reference/react-dom/components#all-html-components). Learn more about [React's release channels here](/community/versioning-policy#all-release-channels).

</Canary>

Expand Down Expand Up @@ -118,7 +118,7 @@ function AddToCart({productId}) {
}
```

In lieu of using hidden form fields to provide data to the `<form>`'s action, you can call the <CodeStep step={1}>`bind`</CodeStep> method to supply it with extra arguments. This will bind a new argument (<CodeStep step={2}>`productId`</CodeStep>) to the function in addition to the <CodeStep step={3}>`formData`</CodeStep> that is passed as a argument to the function.
In lieu of using hidden form fields to provide data to the `<form>`'s action, you can call the <CodeStep step={1}>`bind`</CodeStep> method to supply it with extra arguments. This will bind a new argument (<CodeStep step={2}>`productId`</CodeStep>) to the function in addition to the <CodeStep step={3}>`formData`</CodeStep> that is passed as an argument to the function.

```jsx [[1, 8, "bind"], [2,8, "productId"], [2,4, "productId"], [3,4, "formData"]]
import { updateCart } from './lib.js';
Expand Down Expand Up @@ -278,7 +278,7 @@ export async function deliverMessage(message) {

### Handling form submission errors {/*handling-form-submission-errors*/}

In some cases the function called by a `<form>`'s `action` prop throw an error. You can handle these errors by wrapping `<form>` in an Error Boundary. If the function called by a `<form>`'s `action` prop throws an error, the fallback for the error boundary will be displayed.
In some cases the function called by a `<form>`'s `action` prop throws an error. You can handle these errors by wrapping `<form>` in an Error Boundary. If the function called by a `<form>`'s `action` prop throws an error, the fallback for the error boundary will be displayed.

<Sandpack>

Expand Down
2 changes: 1 addition & 1 deletion src/content/reference/react-dom/components/input.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ To display an input, render the [built-in browser `<input>`](https://developer.m

<Canary>

React's extensions to the `formAction` prop are currently only available in React's Canary and experimental channels. In stable releases of React `formAction` works only as a [built-in browser HTML component](https://react.dev/reference/react-dom/components#all-html-components). Learn more about [React's release channels here](/community/versioning-policy#all-release-channels).
React's extensions to the `formAction` prop are currently only available in React's Canary and experimental channels. In stable releases of React, `formAction` works only as a [built-in browser HTML component](https://react.dev/reference/react-dom/components#all-html-components). Learn more about [React's release channels here](/community/versioning-policy#all-release-channels).
</Canary>

[`formAction`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#formaction): A string or function. Overrides the parent `<form action>` for `type="submit"` and `type="image"`. When a URL is passed to `action` the form will behave like a standard HTML form. When a function is passed to `formAction` the function will handle the form submission. See [`<form action>`](/reference/react-dom/components/form#props).
Expand Down
Loading

0 comments on commit 46cd7fc

Please sign in to comment.