diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index 07271cef6..87dcfdc73 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -16,7 +16,7 @@ jobs: - name: Set up node uses: actions/setup-node@v1 with: - node-version: "14.x" + node-version: '20.x' - name: Install dependencies uses: bahmutov/npm-install@v1.7.10 diff --git a/.github/workflows/site_lint.yml b/.github/workflows/site_lint.yml index bf446393a..560e22643 100644 --- a/.github/workflows/site_lint.yml +++ b/.github/workflows/site_lint.yml @@ -11,14 +11,14 @@ jobs: lint: runs-on: ubuntu-latest - name: Lint on node 12.x and ubuntu-latest + name: Lint on node 20.x and ubuntu-latest steps: - uses: actions/checkout@v1 - - name: Use Node.js 12.x + - name: Use Node.js 20.x uses: actions/setup-node@v1 with: - node-version: 12.x + node-version: 20.x - name: Install deps and build (with cache) uses: bahmutov/npm-install@v1.7.10 diff --git a/next.config.js b/next.config.js index 2ea3e916e..414728580 100644 --- a/next.config.js +++ b/next.config.js @@ -9,10 +9,10 @@ const nextConfig = { pageExtensions: ['jsx', 'js', 'ts', 'tsx', 'mdx', 'md'], reactStrictMode: true, experimental: { - plugins: true, + // TODO: Remove after https://github.com/vercel/next.js/issues/49355 is fixed + appDir: false, scrollRestoration: true, legacyBrowsers: false, - browsersListForSwc: true, }, env: { SANDPACK_BARE_COMPONENTS: process.env.SANDPACK_BARE_COMPONENTS, diff --git a/package.json b/package.json index b0b35b5ca..de79ae2eb 100644 --- a/package.json +++ b/package.json @@ -33,12 +33,12 @@ "debounce": "^1.2.1", "ga-lite": "^2.1.4", "github-slugger": "^1.3.0", - "next": "12.3.2-canary.7", + "next": "^13.4.1", "next-remote-watch": "^1.0.0", "parse-numeric-range": "^1.2.0", - "react": "0.0.0-experimental-cb5084d1c-20220924", + "react": "^0.0.0-experimental-16d053d59-20230506", "react-collapsed": "npm:@gaearon/react-collapsed@3.1.0-forked.1", - "react-dom": "0.0.0-experimental-cb5084d1c-20220924", + "react-dom": "^0.0.0-experimental-16d053d59-20230506", "remark-frontmatter": "^4.0.1", "remark-gfm": "^3.0.1" }, @@ -99,7 +99,7 @@ "webpack-bundle-analyzer": "^4.5.0" }, "engines": { - "node": ">=12.x" + "node": "^16.8.0 || ^18.0.0 || ^19.0.0 || ^20.0.0" }, "nextBundleAnalysis": { "budget": null, diff --git a/patches/next+12.3.2-canary.7.patch b/patches/next+12.3.2-canary.7.patch deleted file mode 100644 index ee8d132de..000000000 --- a/patches/next+12.3.2-canary.7.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/node_modules/next/dist/server/render.js b/node_modules/next/dist/server/render.js -index 3a141de..72a8749 100644 ---- a/node_modules/next/dist/server/render.js -+++ b/node_modules/next/dist/server/render.js -@@ -752,9 +752,14 @@ async function renderToHTML(req, res, pathname, query, renderOpts) { - // Enabling react concurrent rendering mode: __NEXT_REACT_ROOT = true - const renderShell = async (EnhancedApp, EnhancedComponent)=>{ - const content = renderContent(EnhancedApp, EnhancedComponent); -- return await (0, _nodeWebStreamsHelper).renderToInitialStream({ -- ReactDOMServer, -- element: content -+ return new Promise((resolve, reject) => { -+ (0, _nodeWebStreamsHelper).renderToInitialStream({ -+ ReactDOMServer, -+ element: content, -+ streamOptions: { -+ onError: reject -+ } -+ }).then(resolve, reject); - }); - }; - const createBodyResult = (initialStream, suffix)=>{ diff --git a/patches/next+13.4.1.patch b/patches/next+13.4.1.patch new file mode 100644 index 000000000..6de490aa4 --- /dev/null +++ b/patches/next+13.4.1.patch @@ -0,0 +1,22 @@ +diff --git a/node_modules/next/dist/server/render.js b/node_modules/next/dist/server/render.js +index a1f8648..1b3d608 100644 +--- a/node_modules/next/dist/server/render.js ++++ b/node_modules/next/dist/server/render.js +@@ -758,9 +758,14 @@ async function renderToHTML(req, res, pathname, query, renderOpts) { + // Always using react concurrent rendering mode with required react version 18.x + const renderShell = async (EnhancedApp, EnhancedComponent)=>{ + const content = renderContent(EnhancedApp, EnhancedComponent); +- return await (0, _nodewebstreamshelper.renderToInitialStream)({ +- ReactDOMServer: _serverbrowser.default, +- element: content ++ return new Promise((resolve, reject) => { ++ (0, _nodewebstreamshelper.renderToInitialStream)({ ++ ReactDOMServer: _serverbrowser.default, ++ element: content, ++ streamOptions: { ++ onError: reject ++ } ++ }).then(resolve, reject); + }); + }; + const createBodyResult = (0, _tracer.getTracer)().wrap(_constants2.RenderSpan.createBodyResult, (initialStream, suffix)=>{ diff --git a/src/components/Breadcrumbs.tsx b/src/components/Breadcrumbs.tsx index ca3afa851..8eead2302 100644 --- a/src/components/Breadcrumbs.tsx +++ b/src/components/Breadcrumbs.tsx @@ -15,10 +15,10 @@ function Breadcrumbs({breadcrumbs}: {breadcrumbs: RouteItem[]}) { !crumb.skipBreadcrumb && (
- - - {crumb.title} - + + {crumb.title} & ButtonLinkProps) { const classes = cn( className, 'active:scale-[.98] transition-transform inline-flex font-bold items-center outline-none focus:outline-none focus-visible:outline focus-visible:outline-link focus:outline-offset-2 focus-visible:dark:focus:outline-link-dark leading-snug', @@ -34,10 +34,13 @@ function ButtonLink({ } ); return ( - - - {children} - + + {children} ); } diff --git a/src/components/DocsFooter.tsx b/src/components/DocsFooter.tsx index d2c2c25de..a5c7324e2 100644 --- a/src/components/DocsFooter.tsx +++ b/src/components/DocsFooter.tsx @@ -66,25 +66,24 @@ function FooterLink({ type: 'Previous' | 'Next'; }) { return ( - - - - - - {type} - - {title} + + + + + {type} - + {title} + ); } diff --git a/src/components/Layout/Footer.tsx b/src/components/Layout/Footer.tsx index 9a6de35e9..ad1229681 100644 --- a/src/components/Layout/Footer.tsx +++ b/src/components/Layout/Footer.tsx @@ -388,8 +388,8 @@ function FooterLink({ return (
- - {children} + + {children}
); diff --git a/src/components/Layout/HomeContent.js b/src/components/Layout/HomeContent.js index d97281f94..19f19f39f 100644 --- a/src/components/Layout/HomeContent.js +++ b/src/components/Layout/HomeContent.js @@ -1184,13 +1184,14 @@ async function Talks({ confId }) { function useNestedScrollLock(ref) { useEffect(() => { + let node = ref.current; let isLocked = false; let lastScroll = performance.now(); function handleScroll() { if (!isLocked) { isLocked = true; - ref.current.style.pointerEvents = 'none'; + node.style.pointerEvents = 'none'; } lastScroll = performance.now(); } @@ -1198,7 +1199,7 @@ function useNestedScrollLock(ref) { function updateLock() { if (isLocked && performance.now() - lastScroll > 150) { isLocked = false; - ref.current.style.pointerEvents = ''; + node.style.pointerEvents = ''; } } diff --git a/src/components/Layout/Sidebar/SidebarLink.tsx b/src/components/Layout/Sidebar/SidebarLink.tsx index 6889a4b10..050bf7c71 100644 --- a/src/components/Layout/Sidebar/SidebarLink.tsx +++ b/src/components/Layout/Sidebar/SidebarLink.tsx @@ -49,44 +49,43 @@ export function SidebarLink({ target = '_blank'; } return ( - - 0, - 'pl-5': level < 2, - 'text-base font-bold': level === 0, - 'text-primary dark:text-primary-dark': level === 0 && !selected, - 'text-base text-secondary dark:text-secondary-dark': - level > 0 && !selected, - 'text-base text-link dark:text-link-dark bg-highlight dark:bg-highlight-dark border-blue-40 hover:bg-highlight hover:text-link dark:hover:bg-highlight-dark dark:hover:text-link-dark': - selected, - 'dark:bg-gray-70 bg-gray-3 dark:hover:bg-gray-70 hover:bg-gray-3': - isPending, - } - )}> - {/* This here needs to be refactored ofc */} + 0, + 'pl-5': level < 2, + 'text-base font-bold': level === 0, + 'text-primary dark:text-primary-dark': level === 0 && !selected, + 'text-base text-secondary dark:text-secondary-dark': + level > 0 && !selected, + 'text-base text-link dark:text-link-dark bg-highlight dark:bg-highlight-dark border-blue-40 hover:bg-highlight hover:text-link dark:hover:bg-highlight-dark dark:hover:text-link-dark': + selected, + 'dark:bg-gray-70 bg-gray-3 dark:hover:bg-gray-70 hover:bg-gray-3': + isPending, + } + )}> + {/* This here needs to be refactored ofc */} + + {title} + + {isExpanded != null && !hideArrow && ( - {title} + - {isExpanded != null && !hideArrow && ( - - - - )} - + )} ); } diff --git a/src/components/Layout/TopNav/TopNav.tsx b/src/components/Layout/TopNav/TopNav.tsx index f7331fb27..53696baa6 100644 --- a/src/components/Layout/TopNav/TopNav.tsx +++ b/src/components/Layout/TopNav/TopNav.tsx @@ -90,15 +90,17 @@ const githubIcon = ( ); -function Link({href, children, ...props}: JSX.IntrinsicElements['a']) { +function Link({ + href, + children, + ...props +}: React.AnchorHTMLAttributes) { return ( - - {/* eslint-disable-next-line jsx-a11y/anchor-has-content */} - - {children} - + + {children} ); } @@ -247,16 +249,15 @@ export default function TopNav({ {isOpen ? : }
- - - - React - + + + React
diff --git a/src/components/MDX/BlogCard.tsx b/src/components/MDX/BlogCard.tsx index 9d86f9211..ba610b111 100644 --- a/src/components/MDX/BlogCard.tsx +++ b/src/components/MDX/BlogCard.tsx @@ -16,62 +16,62 @@ export interface BlogCardProps { function BlogCard({title, badge, date, icon, url, children}: BlogCardProps) { return ( - - -
-
-

- {title} -

-
-
-
- {icon === 'labs' && ( - - - - )} - {icon === 'blog' && ( - - - - )} - {date} - {badge ? ( -
- New -
- ) : null} -
- - {children} - - {children != null && ( -
- Read more -
+ +
+
+

+ {title} +

+
+
+
+ {icon === 'labs' && ( + + + )} + {icon === 'blog' && ( + + + + )} + {date} + {badge ? ( +
+ New +
+ ) : null}
+ + {children} + + {children != null && ( +
+ Read more +
+ )}
-
+
); } diff --git a/src/components/MDX/Link.tsx b/src/components/MDX/Link.tsx index 8986d07a5..7bf041e56 100644 --- a/src/components/MDX/Link.tsx +++ b/src/components/MDX/Link.tsx @@ -13,7 +13,7 @@ function Link({ className, children, ...props -}: JSX.IntrinsicElements['a']) { +}: React.AnchorHTMLAttributes) { const classes = 'inline text-link dark:text-link-dark border-b border-link border-opacity-0 hover:border-opacity-100 duration-100 ease-in transition leading-normal'; const modifiedChildren = Children.toArray(children).map((child: any) => { @@ -41,11 +41,8 @@ function Link({ {modifiedChildren} ) : ( - - {/* eslint-disable-next-line jsx-a11y/anchor-has-content */} - - {modifiedChildren} - + + {modifiedChildren} )} diff --git a/src/components/MDX/Sandpack/DownloadButton.tsx b/src/components/MDX/Sandpack/DownloadButton.tsx index 4181dbe95..4d206fff8 100644 --- a/src/components/MDX/Sandpack/DownloadButton.tsx +++ b/src/components/MDX/Sandpack/DownloadButton.tsx @@ -7,19 +7,22 @@ import {useSandpack} from '@codesandbox/sandpack-react'; import {IconDownload} from '../../Icon/IconDownload'; export interface DownloadButtonProps {} -let supportsImportMap: boolean | void; +let supportsImportMap = false; + +function subscribe(cb: () => void) { + // This shouldn't actually need to update, but this works around + // https://github.com/facebook/react/issues/26095 + let timeout = setTimeout(() => { + supportsImportMap = + (HTMLScriptElement as any).supports && + (HTMLScriptElement as any).supports('importmap'); + cb(); + }, 0); + return () => clearTimeout(timeout); +} function useSupportsImportMap() { - function subscribe() { - // It never updates. - return () => {}; - } function getCurrentValue() { - if (supportsImportMap === undefined) { - supportsImportMap = - (HTMLScriptElement as any).supports && - (HTMLScriptElement as any).supports('importmap'); - } return supportsImportMap; } function getServerSnapshot() { diff --git a/src/components/Search.tsx b/src/components/Search.tsx index 0e8f84f0d..2a9743ec3 100644 --- a/src/components/Search.tsx +++ b/src/components/Search.tsx @@ -22,11 +22,7 @@ export interface SearchProps { } function Hit({hit, children}: any) { - return ( - - {children} - - ); + return {children}; } // Copy-pasted from @docsearch/react to avoid importing the whole bundle. diff --git a/src/content/learn/responding-to-events.md b/src/content/learn/responding-to-events.md index 782b6c0f1..4450c4613 100644 --- a/src/content/learn/responding-to-events.md +++ b/src/content/learn/responding-to-events.md @@ -313,6 +313,12 @@ button { margin-right: 10px; } Notice how the `App` component does not need to know *what* `Toolbar` will do with `onPlayMovie` or `onUploadImage`. That's an implementation detail of the `Toolbar`. Here, `Toolbar` passes them down as `onClick` handlers to its `Button`s, but it could later also trigger them on a keyboard shortcut. Naming props after app-specific interactions like `onPlayMovie` gives you the flexibility to change how they're used later. + + + +Make sure that you use the appropriate HTML tags for your event handlers. For example, to handle clicks, use [`