From a30e1f954dce2a67985caa8b2376a1839dbfa6cf Mon Sep 17 00:00:00 2001 From: Brandon Dail Date: Mon, 10 Jul 2023 03:26:39 -0500 Subject: [PATCH 001/396] update link to fault tolerance blog post (#6142) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this is the canonical link now 🫡 --- src/content/reference/react/Component.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/Component.md b/src/content/reference/react/Component.md index 006ade5d..569bf19f 100644 --- a/src/content/reference/react/Component.md +++ b/src/content/reference/react/Component.md @@ -1393,7 +1393,7 @@ Then you can wrap a part of your component tree with it: If `Profile` or its child component throws an error, `ErrorBoundary` will "catch" that error, display a fallback UI with the error message you've provided, and send a production error report to your error reporting service. -You don't need to wrap every component into a separate error boundary. When you think about the [granularity of error boundaries,](https://aweary.dev/fault-tolerance-react/) consider where it makes sense to display an error message. For example, in a messaging app, it makes sense to place an error boundary around the list of conversations. It also makes sense to place one around every individual message. However, it wouldn't make sense to place a boundary around every avatar. +You don't need to wrap every component into a separate error boundary. When you think about the [granularity of error boundaries,](https://www.brandondail.com/posts/fault-tolerance-react) consider where it makes sense to display an error message. For example, in a messaging app, it makes sense to place an error boundary around the list of conversations. It also makes sense to place one around every individual message. However, it wouldn't make sense to place a boundary around every avatar. From b9eea4da28db66591ae5935898f98acdf009a0ad Mon Sep 17 00:00:00 2001 From: Ricky Date: Fri, 21 Jul 2023 19:24:36 -0400 Subject: [PATCH 002/396] Fix lint warnings (#6174) --- .eslintrc | 3 +- src/components/Layout/HomeContent.js | 32 +++++++------------ src/components/Layout/Sidebar/SidebarLink.tsx | 1 + .../Layout/SidebarNav/SidebarNav.tsx | 1 - src/components/Layout/TopNav/TopNav.tsx | 3 +- src/components/Layout/getRouteMeta.tsx | 2 +- src/components/MDX/BlogCard.tsx | 1 + src/components/MDX/MDXComponents.tsx | 3 +- src/components/MDX/Sandpack/CustomPreset.tsx | 1 - src/components/MDX/Sandpack/NavigationBar.tsx | 8 +++-- src/components/MDX/Sandpack/Preview.tsx | 1 - src/components/MDX/TeamMember.tsx | 1 - src/components/Search.tsx | 3 +- src/hooks/usePendingRoute.ts | 2 +- 14 files changed, 27 insertions(+), 35 deletions(-) diff --git a/.eslintrc b/.eslintrc index 147e5460..f617dea2 100644 --- a/.eslintrc +++ b/.eslintrc @@ -5,7 +5,8 @@ "plugins": ["@typescript-eslint"], "rules": { "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": "warn" + "@typescript-eslint/no-unused-vars": ["error", { "varsIgnorePattern": "^_" }], + "react-hooks/exhaustive-deps": "error" }, "env": { "node": true, diff --git a/src/components/Layout/HomeContent.js b/src/components/Layout/HomeContent.js index ba3ff6ef..e1b1b440 100644 --- a/src/components/Layout/HomeContent.js +++ b/src/components/Layout/HomeContent.js @@ -8,12 +8,10 @@ import { useState, useContext, useId, - Fragment, Suspense, useEffect, useRef, useTransition, - useReducer, } from 'react'; import cn from 'classnames'; import NextLink from 'next/link'; @@ -26,7 +24,6 @@ import {IconSearch} from 'components/Icon/IconSearch'; import {Logo} from 'components/Logo'; import Link from 'components/MDX/Link'; import CodeBlock from 'components/MDX/CodeBlock'; -import {IconNavArrow} from 'components/Icon/IconNavArrow'; import {ExternalLink} from 'components/ExternalLink'; import sidebarBlog from '../../sidebarBlog.json'; @@ -67,14 +64,6 @@ function Para({children}) { ); } -function Left({children}) { - return ( -
- {children} -
- ); -} - function Center({children}) { return (
@@ -90,19 +79,23 @@ function FullBleed({children}) { } function CurrentTime() { - const msPerMinute = 60 * 1000; - const date = new Date(); - let nextMinute = Math.floor(+date / msPerMinute + 1) * msPerMinute; - + const [date, setDate] = useState(new Date()); const currentTime = date.toLocaleTimeString([], { hour: 'numeric', minute: 'numeric', }); - let [, forceUpdate] = useReducer((n) => n + 1, 0); useEffect(() => { - const timeout = setTimeout(forceUpdate, nextMinute - Date.now()); + const msPerMinute = 60 * 1000; + let nextMinute = Math.floor(+date / msPerMinute + 1) * msPerMinute; + + const timeout = setTimeout(() => { + if (Date.now() > nextMinute) { + setDate(new Date()); + } + }, nextMinute - Date.now()); return () => clearTimeout(timeout); }, [date]); + return {currentTime}; } @@ -831,7 +824,7 @@ function ExampleLayout({ .filter((s) => s !== null); setOverlayStyles(nextOverlayStyles); } - }, [activeArea]); + }, [activeArea, hoverTopOffset]); return (
@@ -1211,7 +1204,7 @@ function useNestedScrollLock(ref) { window.removeEventListener('scroll', handleScroll); clearInterval(interval); }; - }, []); + }, [ref]); } function ExamplePanel({ @@ -1220,7 +1213,6 @@ function ExamplePanel({ noShadow, height, contentMarginTop, - activeArea, }) { return (
0 ? breadcrumbs : [routeTree], diff --git a/src/components/MDX/BlogCard.tsx b/src/components/MDX/BlogCard.tsx index ba610b11..1a16013a 100644 --- a/src/components/MDX/BlogCard.tsx +++ b/src/components/MDX/BlogCard.tsx @@ -18,6 +18,7 @@ function BlogCard({title, badge, date, icon, url, children}: BlogCardProps) { return (
diff --git a/src/components/MDX/MDXComponents.tsx b/src/components/MDX/MDXComponents.tsx index ba531c9f..8ddf371c 100644 --- a/src/components/MDX/MDXComponents.tsx +++ b/src/components/MDX/MDXComponents.tsx @@ -369,7 +369,8 @@ function YouTubeIframe(props: any) { } function Image(props: any) { - return ; + const {alt, ...rest} = props; + return {alt}; } export const MDXComponents = { diff --git a/src/components/MDX/Sandpack/CustomPreset.tsx b/src/components/MDX/Sandpack/CustomPreset.tsx index 6e086256..46e0ca25 100644 --- a/src/components/MDX/Sandpack/CustomPreset.tsx +++ b/src/components/MDX/Sandpack/CustomPreset.tsx @@ -54,7 +54,6 @@ export const CustomPreset = memo(function CustomPreset({ const SandboxShell = memo(function SandboxShell({ showDevTools, - onDevToolsLoad, devToolsLoaded, providedFiles, lintErrors, diff --git a/src/components/MDX/Sandpack/NavigationBar.tsx b/src/components/MDX/Sandpack/NavigationBar.tsx index 8c884a5d..94e2eb4b 100644 --- a/src/components/MDX/Sandpack/NavigationBar.tsx +++ b/src/components/MDX/Sandpack/NavigationBar.tsx @@ -90,15 +90,17 @@ export function NavigationBar({providedFiles}: {providedFiles: Array}) { } else { return; } - }, [isMultiFile]); + + // Note: in a real useEvent, onContainerResize would be omitted. + }, [isMultiFile, onContainerResize]); const handleReset = () => { /** * resetAllFiles must come first, otherwise - * the previous content will appears for a second + * the previous content will appear for a second * when the iframe loads. * - * Plus, it should only prompts if there's any file changes + * Plus, it should only prompt if there's any file changes */ if ( sandpack.editorState === 'dirty' && diff --git a/src/components/MDX/Sandpack/Preview.tsx b/src/components/MDX/Sandpack/Preview.tsx index 2e140360..6b7a6d18 100644 --- a/src/components/MDX/Sandpack/Preview.tsx +++ b/src/components/MDX/Sandpack/Preview.tsx @@ -49,7 +49,6 @@ export function Preview({ errorScreenRegisteredRef, openInCSBRegisteredRef, loadingScreenRegisteredRef, - status, } = sandpack; if ( diff --git a/src/components/MDX/TeamMember.tsx b/src/components/MDX/TeamMember.tsx index 887e9f69..0db067e1 100644 --- a/src/components/MDX/TeamMember.tsx +++ b/src/components/MDX/TeamMember.tsx @@ -7,7 +7,6 @@ import Image from 'next/image'; import {IconTwitter} from '../Icon/IconTwitter'; import {IconGitHub} from '../Icon/IconGitHub'; import {ExternalLink} from '../ExternalLink'; -import {IconNewPage} from 'components/Icon/IconNewPage'; import {H3} from './Heading'; import {IconLink} from 'components/Icon/IconLink'; diff --git a/src/components/Search.tsx b/src/components/Search.tsx index 2a9743ec..8bc47297 100644 --- a/src/components/Search.tsx +++ b/src/components/Search.tsx @@ -5,11 +5,10 @@ import Head from 'next/head'; import Link from 'next/link'; import Router from 'next/router'; -import {lazy, useCallback, useEffect} from 'react'; +import {lazy, useEffect} from 'react'; import * as React from 'react'; import {createPortal} from 'react-dom'; import {siteConfig} from 'siteConfig'; -import cn from 'classnames'; export interface SearchProps { appId?: string; diff --git a/src/hooks/usePendingRoute.ts b/src/hooks/usePendingRoute.ts index 73ff0b8a..229a36e6 100644 --- a/src/hooks/usePendingRoute.ts +++ b/src/hooks/usePendingRoute.ts @@ -33,7 +33,7 @@ const usePendingRoute = () => { events.off('routeChangeComplete', handleRouteChangeComplete); clearTimeout(routeTransitionTimer); }; - }, []); + }, [events]); return pendingRoute; }; From d86cfc47634a3a3b94f683e99075b9815ac35a30 Mon Sep 17 00:00:00 2001 From: Ricky Date: Mon, 24 Jul 2023 10:05:08 -0400 Subject: [PATCH 003/396] Update useInsertionEffect docs (#6172) --- src/content/reference/react/useInsertionEffect.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/content/reference/react/useInsertionEffect.md b/src/content/reference/react/useInsertionEffect.md index 175b4476..0238facf 100644 --- a/src/content/reference/react/useInsertionEffect.md +++ b/src/content/reference/react/useInsertionEffect.md @@ -10,7 +10,7 @@ title: useInsertionEffect -`useInsertionEffect` is a version of [`useEffect`](/reference/react/useEffect) that fires before any DOM mutations. +`useInsertionEffect` allows inserting elements into the DOM before any layout effects fire. ```js useInsertionEffect(setup, dependencies?) @@ -26,7 +26,7 @@ useInsertionEffect(setup, dependencies?) ### `useInsertionEffect(setup, dependencies?)` {/*useinsertioneffect*/} -Call `useInsertionEffect` to insert the styles before any DOM mutations: +Call `useInsertionEffect` to insert styles before any effects fire that may need to read layout: ```js import { useInsertionEffect } from 'react'; @@ -44,7 +44,7 @@ function useCSS(rule) { #### Parameters {/*parameters*/} -* `setup`: The function with your Effect's logic. Your setup function may also optionally return a *cleanup* function. Before your component is added to the DOM, React will run your setup function. After every re-render with changed dependencies, React will first run the cleanup function (if you provided it) with the old values, and then run your setup function with the new values. Before your component is removed from the DOM, React will run your cleanup function. +* `setup`: The function with your Effect's logic. Your setup function may also optionally return a *cleanup* function. When your component is added to the DOM, but before any layout effects fire, React will run your setup function. After every re-render with changed dependencies, React will first run the cleanup function (if you provided it) with the old values, and then run your setup function with the new values. When your component is removed from the DOM, React will run your cleanup function. * **optional** `dependencies`: The list of all reactive values referenced inside of the `setup` code. Reactive values include props, state, and all the variables and functions declared directly inside your component body. If your linter is [configured for React](/learn/editor-setup#linting), it will verify that every reactive value is correctly specified as a dependency. The list of dependencies must have a constant number of items and be written inline like `[dep1, dep2, dep3]`. React will compare each dependency with its previous value using the [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) comparison algorithm. If you don't specify the dependencies at all, your Effect will re-run after every re-render of the component. @@ -56,8 +56,9 @@ function useCSS(rule) { * Effects only run on the client. They don't run during server rendering. * You can't update state from inside `useInsertionEffect`. -* By the time `useInsertionEffect` runs, refs are not attached yet, and DOM is not yet updated. - +* By the time `useInsertionEffect` runs, refs are not attached yet. +* `useInsertionEffect` may run either before or after the DOM has been updated. You shouldn't rely on the DOM being updated at any particular time. +* Unlike other types of Effects, which fire cleanup for every Effect and then setup for every Effect, `useInsertionEffect` will fire both cleanup and setup one component at a time. This results in an "interleaving" of the cleanup and setup functions. --- ## Usage {/*usage*/} @@ -87,7 +88,7 @@ If you use CSS-in-JS, we recommend a combination of the first two approaches (CS The first problem is not solvable, but `useInsertionEffect` helps you solve the second problem. -Call `useInsertionEffect` to insert the styles before any DOM mutations: +Call `useInsertionEffect` to insert the styles before any layout effects fire: ```js {4-11} // Inside your CSS-in-JS library From cf4ad1999a766f417bee506f11b37a6d05ac9342 Mon Sep 17 00:00:00 2001 From: Soichiro Miki Date: Tue, 25 Jul 2023 09:57:55 +0900 Subject: [PATCH 004/396] Fix typo: "server-only" to "client-only" (#6164) --- src/content/reference/react/Suspense.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/Suspense.md b/src/content/reference/react/Suspense.md index 27add603..dd931205 100644 --- a/src/content/reference/react/Suspense.md +++ b/src/content/reference/react/Suspense.md @@ -2513,7 +2513,7 @@ However, now imagine you're navigating between two different user profiles. In t --- -### Providing a fallback for server errors and server-only content {/*providing-a-fallback-for-server-errors-and-server-only-content*/} +### Providing a fallback for server errors and client-only content {/*providing-a-fallback-for-server-errors-and-client-only-content*/} If you use one of the [streaming server rendering APIs](/reference/react-dom/server) (or a framework that relies on them), React will also use your `` boundaries to handle errors on the server. If a component throws an error on the server, React will not abort the server render. Instead, it will find the closest `` component above it and include its fallback (such as a spinner) into the generated server HTML. The user will see a spinner at first. From a132d8f35597d0380f0f738c1b095b5dc56736ba Mon Sep 17 00:00:00 2001 From: Soichiro Miki Date: Tue, 25 Jul 2023 09:59:14 +0900 Subject: [PATCH 005/396] Remove junk lines in common.md (#6167) --- src/content/reference/react-dom/components/common.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/content/reference/react-dom/components/common.md b/src/content/reference/react-dom/components/common.md index f1e4fcd0..fb007890 100644 --- a/src/content/reference/react-dom/components/common.md +++ b/src/content/reference/react-dom/components/common.md @@ -149,7 +149,6 @@ These standard DOM props are also supported for all built-in components: * [`onWheel`](https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event): A [`WheelEvent` handler](#wheelevent-handler) function. Fires when the user rotates a wheel button. * `onWheelCapture`: A version of `onWheel` that fires in the [capture phase.](/learn/responding-to-events#capture-phase-events) * [`role`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles): A string. Specifies the element role explicitly for assistive technologies. -nt. * [`slot`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles): A string. Specifies the slot name when using shadow DOM. In React, an equivalent pattern is typically achieved by passing JSX as props, for example `} right={} />`. * [`spellCheck`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/spellcheck): A boolean or null. If explicitly set to `true` or `false`, enables or disables spellchecking. * [`tabIndex`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex): A number. Overrides the default Tab button behavior. [Avoid using values other than `-1` and `0`.](https://www.tpgi.com/using-the-tabindex-attribute/) @@ -169,7 +168,6 @@ These events fire only for the [``](https://developer.mozilla.org/en-US/ * [`onCancel`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/cancel_event): An [`Event` handler](#event-handler) function. Fires when the user tries to dismiss the dialog. * `onCancelCapture`: A version of `onCancel` that fires in the [capture phase.](/learn/responding-to-events#capture-phase-events) -capture-phase-events) * [`onClose`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/close_event): An [`Event` handler](#event-handler) function. Fires when a dialog has been closed. * `onCloseCapture`: A version of `onClose` that fires in the [capture phase.](/learn/responding-to-events#capture-phase-events) @@ -177,7 +175,6 @@ These events fire only for the [`
`](https://developer.mozilla.org/en-US * [`onToggle`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDetailsElement/toggle_event): An [`Event` handler](#event-handler) function. Fires when the user toggles the details. * `onToggleCapture`: A version of `onToggle` that fires in the [capture phase.](/learn/responding-to-events#capture-phase-events) -capture-phase-events) These events fire for [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img), [` diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 11459b70..7076e76f 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -4,7 +4,7 @@ "routes": [ { "hasSectionHeader": true, - "sectionHeader": "react@18.2.0" + "sectionHeader": "react@{{version}}" }, { "title": "Overview", @@ -156,7 +156,7 @@ }, { "hasSectionHeader": true, - "sectionHeader": "react-dom@18.2.0" + "sectionHeader": "react-dom@{{version}}" }, { "title": "Hooks", diff --git a/src/siteConfig.js b/src/siteConfig.js index 0ada6b93..6d37e10f 100644 --- a/src/siteConfig.js +++ b/src/siteConfig.js @@ -3,6 +3,7 @@ */ exports.siteConfig = { + version: '18.3.1', // -------------------------------------- // Translations should replace these lines: languageCode: 'en', diff --git a/vercel.json b/vercel.json index 957c2502..509d72b4 100644 --- a/vercel.json +++ b/vercel.json @@ -4,6 +4,50 @@ }, "trailingSlash": false, "redirects": [ + { + "source": "/", + "has": [ + { + "type": "host", + "value": "18.react.dev" + } + ], + "permanent": false, + "destination": "https://react.dev/" + }, + { + "source": "/", + "has": [ + { + "type": "host", + "value": "17.react.dev" + } + ], + "permanent": true, + "destination": "https://17.reactjs.org/" + }, + { + "source": "/", + "has": [ + { + "type": "host", + "value": "16.react.dev" + } + ], + "permanent": true, + "destination": "https://17.reactjs.org/" + }, + { + "source": "/", + "has": [ + { + "type": "host", + "value": "15.react.dev" + } + ], + "permanent": true, + "destination": "https://react-legacy.netlify.app/" + }, { "source": "/reference", "destination": "/reference/react", From 86d306f6cefbc2fd8e542df3b5959e86384129b9 Mon Sep 17 00:00:00 2001 From: Ricky Date: Mon, 29 Apr 2024 22:27:44 -0400 Subject: [PATCH 268/396] rm new redirects (#6816) --- vercel.json | 44 -------------------------------------------- 1 file changed, 44 deletions(-) diff --git a/vercel.json b/vercel.json index 509d72b4..957c2502 100644 --- a/vercel.json +++ b/vercel.json @@ -4,50 +4,6 @@ }, "trailingSlash": false, "redirects": [ - { - "source": "/", - "has": [ - { - "type": "host", - "value": "18.react.dev" - } - ], - "permanent": false, - "destination": "https://react.dev/" - }, - { - "source": "/", - "has": [ - { - "type": "host", - "value": "17.react.dev" - } - ], - "permanent": true, - "destination": "https://17.reactjs.org/" - }, - { - "source": "/", - "has": [ - { - "type": "host", - "value": "16.react.dev" - } - ], - "permanent": true, - "destination": "https://17.reactjs.org/" - }, - { - "source": "/", - "has": [ - { - "type": "host", - "value": "15.react.dev" - } - ], - "permanent": true, - "destination": "https://react-legacy.netlify.app/" - }, { "source": "/reference", "destination": "/reference/react", From 6d0aca18d59c0adaa7eae2e49e02ec174c47b037 Mon Sep 17 00:00:00 2001 From: E <2061889+bozoputer@users.noreply.github.com> Date: Mon, 29 Apr 2024 22:42:35 -0400 Subject: [PATCH 269/396] Fix punctuation. (#6815) * Update typescript.md Fix punctuation. * Update src/content/learn/typescript.md --------- Co-authored-by: Ricky --- src/content/learn/typescript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index 6f49c765..7edf8eb6 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -137,7 +137,7 @@ The [`useState` Hook](/reference/react/useState) will re-use the value passed in const [enabled, setEnabled] = useState(false); ``` -Will assign the type of `boolean` to `enabled`, and `setEnabled` will be a function accepting either a `boolean` argument, or a function that returns a `boolean`. If you want to explicitly provide a type for the state, you can do so by providing a type argument to the `useState` call: +This will assign the type of `boolean` to `enabled`, and `setEnabled` will be a function accepting either a `boolean` argument, or a function that returns a `boolean`. If you want to explicitly provide a type for the state, you can do so by providing a type argument to the `useState` call: ```ts // Explicitly set the type to "boolean" From e538800cfecd4be204ebf52f0df4c1d658fc74e9 Mon Sep 17 00:00:00 2001 From: Strek Date: Tue, 30 Apr 2024 08:21:14 +0530 Subject: [PATCH 270/396] Update react-19.md (#6813) --- src/content/blog/2024/04/25/react-19.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/blog/2024/04/25/react-19.md b/src/content/blog/2024/04/25/react-19.md index 42490bcb..f8559d31 100644 --- a/src/content/blog/2024/04/25/react-19.md +++ b/src/content/blog/2024/04/25/react-19.md @@ -186,7 +186,7 @@ Actions are also integrated with React 19's new `
` features for `react-dom When a `` Action succeeds, React will automatically reset the form for uncontrolled components. If you need to reset the `` manually, you can call the new `requestFormReset` React DOM API. -For more information, see the `react-dom` docs for [``](/reference/react-dom/components/form), [``](/reference/react-dom/components/input), and [`
+
+ Logo by + + @sawaratsuki1004 + +
diff --git a/src/components/Layout/HomeContent.js b/src/components/Layout/HomeContent.js index e1fab6d7..6ae0cf35 100644 --- a/src/components/Layout/HomeContent.js +++ b/src/components/Layout/HomeContent.js @@ -26,6 +26,7 @@ import Link from 'components/MDX/Link'; import CodeBlock from 'components/MDX/CodeBlock'; import {ExternalLink} from 'components/ExternalLink'; import sidebarBlog from '../../sidebarBlog.json'; +import * as React from 'react'; function Section({children, background = null}) { return ( @@ -115,12 +116,15 @@ export function HomeContent() { <>
+
+ +
-

+

React

@@ -489,7 +493,13 @@ export function HomeContent() {

- +
+ +
+
Welcome to the
React community diff --git a/src/components/Layout/TopNav/TopNav.tsx b/src/components/Layout/TopNav/TopNav.tsx index 021c735f..7139d8e1 100644 --- a/src/components/Layout/TopNav/TopNav.tsx +++ b/src/components/Layout/TopNav/TopNav.tsx @@ -249,16 +249,25 @@ export default function TopNav({ {isMenuOpen ? : }
- - - React - +
+ + + +
+
+ + + React + +
{ }} /> +