Browse Source

[Beta] Code style tweaks (#5104)

* Use named React imports

* More manual edits

* Remove displayNames

* rm dead code
main
dan 3 years ago
committed by GitHub
parent
commit
4c37115f3f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      beta/src/components/Breadcrumbs.tsx
  2. 1
      beta/src/components/ButtonLink.tsx
  3. 6
      beta/src/components/DocsFooter.tsx
  4. 4
      beta/src/components/ExternalLink.tsx
  5. 6
      beta/src/components/Icon/IconArrow.tsx
  6. 6
      beta/src/components/Icon/IconArrowSmall.tsx
  7. 6
      beta/src/components/Icon/IconChevron.tsx
  8. 44
      beta/src/components/Icon/IconClose.tsx
  9. 6
      beta/src/components/Icon/IconCodeBlock.tsx
  10. 56
      beta/src/components/Icon/IconCopy.tsx
  11. 6
      beta/src/components/Icon/IconDeepDive.tsx
  12. 6
      beta/src/components/Icon/IconDownload.tsx
  13. 36
      beta/src/components/Icon/IconError.tsx
  14. 4
      beta/src/components/Icon/IconFacebookCircle.tsx
  15. 6
      beta/src/components/Icon/IconGitHub.tsx
  16. 6
      beta/src/components/Icon/IconGotcha.tsx
  17. 6
      beta/src/components/Icon/IconHamburger.tsx
  18. 38
      beta/src/components/Icon/IconHint.tsx
  19. 4
      beta/src/components/Icon/IconInstagram.tsx
  20. 6
      beta/src/components/Icon/IconNavArrow.tsx
  21. 6
      beta/src/components/Icon/IconNewPage.tsx
  22. 40
      beta/src/components/Icon/IconNote.tsx
  23. 6
      beta/src/components/Icon/IconRestart.tsx
  24. 46
      beta/src/components/Icon/IconRss.tsx
  25. 6
      beta/src/components/Icon/IconSearch.tsx
  26. 6
      beta/src/components/Icon/IconSolution.tsx
  27. 6
      beta/src/components/Icon/IconTerminal.tsx
  28. 6
      beta/src/components/Icon/IconTwitter.tsx
  29. 6
      beta/src/components/Icon/IconWarning.tsx
  30. 4
      beta/src/components/Layout/Feedback.tsx
  31. 29
      beta/src/components/Layout/Nav/Nav.tsx
  32. 5
      beta/src/components/Layout/Page.tsx
  33. 5
      beta/src/components/Layout/Sidebar/SidebarLink.tsx
  34. 10
      beta/src/components/Layout/Sidebar/SidebarRouteTree.tsx
  35. 1
      beta/src/components/Layout/Toc.tsx
  36. 6
      beta/src/components/Layout/useRouteMeta.tsx
  37. 8
      beta/src/components/Layout/useTocHighlight.tsx
  38. 49
      beta/src/components/Layout/useTwitter.tsx
  39. 4
      beta/src/components/Logo.tsx
  40. 6
      beta/src/components/MDX/Challenges/Challenge.tsx
  41. 11
      beta/src/components/MDX/Challenges/Challenges.tsx
  42. 10
      beta/src/components/MDX/Challenges/Navigation.tsx
  43. 2
      beta/src/components/MDX/Challenges/index.tsx
  44. 10
      beta/src/components/MDX/CodeBlock/index.tsx
  45. 5
      beta/src/components/MDX/CodeDiagram.tsx
  46. 4
      beta/src/components/MDX/ConsoleBlock.tsx
  47. 1
      beta/src/components/MDX/Diagram.tsx
  48. 1
      beta/src/components/MDX/DiagramGroup.tsx
  49. 3
      beta/src/components/MDX/ExpandableCallout.tsx
  50. 2
      beta/src/components/MDX/Heading.tsx
  51. 1
      beta/src/components/MDX/HomepageHero.tsx
  52. 3
      beta/src/components/MDX/InlineCode.tsx
  53. 4
      beta/src/components/MDX/Intro.tsx
  54. 20
      beta/src/components/MDX/Link.tsx
  55. 7
      beta/src/components/MDX/MDXComponents.tsx
  56. 5
      beta/src/components/MDX/PackageImport.tsx
  57. 12
      beta/src/components/MDX/Sandpack/Console.tsx
  58. 8
      beta/src/components/MDX/Sandpack/CustomPreset.tsx
  59. 8
      beta/src/components/MDX/Sandpack/DownloadButton.tsx
  60. 2
      beta/src/components/MDX/Sandpack/Error.tsx
  61. 32
      beta/src/components/MDX/Sandpack/NavigationBar.tsx
  62. 1
      beta/src/components/MDX/Sandpack/OpenInCodeSandboxButton.tsx
  63. 26
      beta/src/components/MDX/Sandpack/Preview.tsx
  64. 4
      beta/src/components/MDX/Sandpack/ResetButton.tsx
  65. 9
      beta/src/components/MDX/Sandpack/SandpackRoot.tsx
  66. 12
      beta/src/components/MDX/Sandpack/index.tsx
  67. 7
      beta/src/components/MDX/TerminalBlock.tsx
  68. 1
      beta/src/components/PageHeading.tsx
  69. 19
      beta/src/components/Search.tsx
  70. 2
      beta/src/components/Seo.tsx
  71. 6
      beta/src/components/SocialBanner.tsx
  72. 1
      beta/src/components/Tag.tsx
  73. 8
      beta/src/hooks/usePendingRoute.ts
  74. 6
      beta/src/pages/_app.tsx
  75. 1
      beta/src/pages/_document.tsx
  76. 2
      beta/src/utils/toCommaSeparatedList.tsx

6
beta/src/components/Breadcrumbs.tsx

@ -2,7 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {Fragment} from 'react';
import {useRouteMeta} from 'components/Layout/useRouteMeta'; import {useRouteMeta} from 'components/Layout/useRouteMeta';
import Link from 'next/link'; import Link from 'next/link';
@ -15,7 +15,7 @@ function Breadcrumbs() {
(crumb, i) => (crumb, i) =>
crumb.path && ( crumb.path && (
<div className="flex mb-3 mt-0.5 items-center" key={i}> <div className="flex mb-3 mt-0.5 items-center" key={i}>
<React.Fragment key={crumb.path}> <Fragment key={crumb.path}>
<Link href={crumb.path}> <Link href={crumb.path}>
<a className="text-link dark:text-link-dark text-sm tracking-wide font-bold uppercase mr-1 hover:underline"> <a className="text-link dark:text-link-dark text-sm tracking-wide font-bold uppercase mr-1 hover:underline">
{crumb.title} {crumb.title}
@ -34,7 +34,7 @@ function Breadcrumbs() {
/> />
</svg> </svg>
</span> </span>
</React.Fragment> </Fragment>
</div> </div>
) )
)} )}

1
beta/src/components/ButtonLink.tsx

@ -2,7 +2,6 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react';
import cn from 'classnames'; import cn from 'classnames';
import NextLink from 'next/link'; import NextLink from 'next/link';

6
beta/src/components/DocsFooter.tsx

@ -3,7 +3,7 @@
*/ */
import NextLink from 'next/link'; import NextLink from 'next/link';
import * as React from 'react'; import {memo} from 'react';
import cn from 'classnames'; import cn from 'classnames';
import {removeFromLast} from 'utils/removeFromLast'; import {removeFromLast} from 'utils/removeFromLast';
import {IconNavArrow} from './Icon/IconNavArrow'; import {IconNavArrow} from './Icon/IconNavArrow';
@ -18,7 +18,7 @@ function areEqual(prevProps: DocsPageFooterProps, props: DocsPageFooterProps) {
return prevProps.route?.path === props.route?.path; return prevProps.route?.path === props.route?.path;
} }
export const DocsPageFooter = React.memo<DocsPageFooterProps>( export const DocsPageFooter = memo<DocsPageFooterProps>(
function DocsPageFooter({nextRoute, prevRoute, route}) { function DocsPageFooter({nextRoute, prevRoute, route}) {
if (!route || route?.heading) { if (!route || route?.heading) {
return null; return null;
@ -89,5 +89,3 @@ function FooterLink({
</NextLink> </NextLink>
); );
} }
DocsPageFooter.displayName = 'DocsPageFooter';

4
beta/src/components/ExternalLink.tsx

@ -2,8 +2,6 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react';
export function ExternalLink({ export function ExternalLink({
href, href,
target, target,
@ -16,5 +14,3 @@ export function ExternalLink({
</a> </a>
); );
} }
ExternalLink.displayName = 'ExternalLink';

6
beta/src/components/Icon/IconArrow.tsx

@ -2,10 +2,10 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
import cn from 'classnames'; import cn from 'classnames';
export const IconArrow = React.memo< export const IconArrow = memo<
JSX.IntrinsicElements['svg'] & { JSX.IntrinsicElements['svg'] & {
displayDirection: 'left' | 'right' | 'up' | 'down'; displayDirection: 'left' | 'right' | 'up' | 'down';
} }
@ -26,5 +26,3 @@ export const IconArrow = React.memo<
</svg> </svg>
); );
}); });
IconArrow.displayName = 'IconArrow';

6
beta/src/components/Icon/IconArrowSmall.tsx

@ -2,10 +2,10 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
import cn from 'classnames'; import cn from 'classnames';
export const IconArrowSmall = React.memo< export const IconArrowSmall = memo<
JSX.IntrinsicElements['svg'] & { JSX.IntrinsicElements['svg'] & {
displayDirection: 'left' | 'right' | 'up' | 'down'; displayDirection: 'left' | 'right' | 'up' | 'down';
} }
@ -29,5 +29,3 @@ export const IconArrowSmall = React.memo<
</svg> </svg>
); );
}); });
IconArrowSmall.displayName = 'IconArrowSmall';

6
beta/src/components/Icon/IconChevron.tsx

@ -2,10 +2,10 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
import cn from 'classnames'; import cn from 'classnames';
export const IconChevron = React.memo< export const IconChevron = memo<
JSX.IntrinsicElements['svg'] & { JSX.IntrinsicElements['svg'] & {
displayDirection: 'up' | 'down' | 'left' | 'right'; displayDirection: 'up' | 'down' | 'left' | 'right';
} }
@ -38,5 +38,3 @@ export const IconChevron = React.memo<
</svg> </svg>
); );
}); });
IconChevron.displayName = 'IconChevron';

44
beta/src/components/Icon/IconClose.tsx

@ -2,27 +2,25 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconClose = React.memo<JSX.IntrinsicElements['svg']>( export const IconClose = memo<JSX.IntrinsicElements['svg']>(function IconClose(
function IconClose(props) { props
return ( ) {
<svg return (
xmlns="http://www.w3.org/2000/svg" <svg
width="1.33em" xmlns="http://www.w3.org/2000/svg"
height="1.33em" width="1.33em"
viewBox="0 0 24 24" height="1.33em"
fill="none" viewBox="0 0 24 24"
stroke="currentColor" fill="none"
strokeWidth={2} stroke="currentColor"
strokeLinecap="round" strokeWidth={2}
strokeLinejoin="round" strokeLinecap="round"
{...props}> strokeLinejoin="round"
<line x1={18} y1={6} x2={6} y2={18} /> {...props}>
<line x1={6} y1={6} x2={18} y2={18} /> <line x1={18} y1={6} x2={6} y2={18} />
</svg> <line x1={6} y1={6} x2={18} y2={18} />
); </svg>
} );
); });
IconClose.displayName = 'IconClose';

6
beta/src/components/Icon/IconCodeBlock.tsx

@ -2,9 +2,9 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconCodeBlock = React.memo<JSX.IntrinsicElements['svg']>( export const IconCodeBlock = memo<JSX.IntrinsicElements['svg']>(
function IconCodeBlock({className}) { function IconCodeBlock({className}) {
return ( return (
<svg <svg
@ -22,5 +22,3 @@ export const IconCodeBlock = React.memo<JSX.IntrinsicElements['svg']>(
); );
} }
); );
IconCodeBlock.displayName = 'IconCodeBlock';

56
beta/src/components/Icon/IconCopy.tsx

@ -2,33 +2,31 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconCopy = React.memo<JSX.IntrinsicElements['svg']>( export const IconCopy = memo<JSX.IntrinsicElements['svg']>(function IconCopy({
function IconCopy({className}) { className,
return ( }) {
<svg return (
className={className} <svg
width="1em" className={className}
height="1em" width="1em"
viewBox="0 0 18 18" height="1em"
fill="none" viewBox="0 0 18 18"
xmlns="http://www.w3.org/2000/svg"> fill="none"
<path xmlns="http://www.w3.org/2000/svg">
fillRule="evenodd" <path
clipRule="evenodd" fillRule="evenodd"
d="M5.40382 15.3671C5.03332 15.1901 4.70081 14.9381 4.42481 14.6286C4.34831 14.5431 4.23931 14.5001 4.12981 14.5206L3.66181 14.6081C3.33531 14.6691 3.02032 14.4361 2.96232 14.0876L1.30981 4.12512C1.28181 3.95662 1.31731 3.7861 1.40981 3.6456C1.50231 3.5051 1.64082 3.41162 1.79932 3.38162L3.22131 3.00012C3.37681 2.97062 3.48981 2.82761 3.48981 2.65961V1.9101C3.48981 1.8276 3.49381 1.74561 3.49931 1.66461C3.50931 1.53461 3.35181 1.57211 3.35181 1.57211L1.64381 2.0076C1.18481 2.0936 0.751316 2.32662 0.451316 2.70612C0.0808162 3.17362 -0.0686885 3.77259 0.0293115 4.36459L1.68231 14.3281C1.84531 15.3081 2.65031 16.0001 3.55631 16.0001C3.66531 16.0001 3.77631 15.9896 3.88731 15.9691L5.36632 15.6916C5.52332 15.6626 5.54982 15.4366 5.40382 15.3671ZM14.9331 4.55801H12.9116C12.1351 4.55801 11.5001 3.91502 11.5001 3.12952V1.06802C11.5001 0.480524 11.0196 0 10.4321 0H7.44161C6.36911 0 5.50011 0.879508 5.50011 1.96451V12.1665C5.50011 13.179 6.33412 14 7.36262 14H14.1371C15.1661 14 16.0001 13.179 16.0001 12.1665V5.625C16.0001 5.038 15.5201 4.55801 14.9331 4.55801Z" clipRule="evenodd"
fill="currentColor" d="M5.40382 15.3671C5.03332 15.1901 4.70081 14.9381 4.42481 14.6286C4.34831 14.5431 4.23931 14.5001 4.12981 14.5206L3.66181 14.6081C3.33531 14.6691 3.02032 14.4361 2.96232 14.0876L1.30981 4.12512C1.28181 3.95662 1.31731 3.7861 1.40981 3.6456C1.50231 3.5051 1.64082 3.41162 1.79932 3.38162L3.22131 3.00012C3.37681 2.97062 3.48981 2.82761 3.48981 2.65961V1.9101C3.48981 1.8276 3.49381 1.74561 3.49931 1.66461C3.50931 1.53461 3.35181 1.57211 3.35181 1.57211L1.64381 2.0076C1.18481 2.0936 0.751316 2.32662 0.451316 2.70612C0.0808162 3.17362 -0.0686885 3.77259 0.0293115 4.36459L1.68231 14.3281C1.84531 15.3081 2.65031 16.0001 3.55631 16.0001C3.66531 16.0001 3.77631 15.9896 3.88731 15.9691L5.36632 15.6916C5.52332 15.6626 5.54982 15.4366 5.40382 15.3671ZM14.9331 4.55801H12.9116C12.1351 4.55801 11.5001 3.91502 11.5001 3.12952V1.06802C11.5001 0.480524 11.0196 0 10.4321 0H7.44161C6.36911 0 5.50011 0.879508 5.50011 1.96451V12.1665C5.50011 13.179 6.33412 14 7.36262 14H14.1371C15.1661 14 16.0001 13.179 16.0001 12.1665V5.625C16.0001 5.038 15.5201 4.55801 14.9331 4.55801Z"
/>{' '} fill="currentColor"
<path />{' '}
fillRule="evenodd" <path
clipRule="evenodd" fillRule="evenodd"
d="M12.5888 0.0914385C12.4493 0.00843847 12.5158 0.252449 12.5158 0.252449C12.5653 0.428449 12.5918 0.613451 12.5918 0.804451V2.90296C12.5918 3.17646 12.8158 3.40046 13.0903 3.40046H15.1718C15.3883 3.40046 15.5968 3.43495 15.7918 3.49845C15.7918 3.49845 15.9373 3.50844 15.9008 3.43494C15.8383 3.33744 15.7673 3.24494 15.6833 3.16044L12.8303 0.289467C12.7558 0.214467 12.6743 0.149438 12.5888 0.0914385Z" clipRule="evenodd"
fill="currentColor" d="M12.5888 0.0914385C12.4493 0.00843847 12.5158 0.252449 12.5158 0.252449C12.5653 0.428449 12.5918 0.613451 12.5918 0.804451V2.90296C12.5918 3.17646 12.8158 3.40046 13.0903 3.40046H15.1718C15.3883 3.40046 15.5968 3.43495 15.7918 3.49845C15.7918 3.49845 15.9373 3.50844 15.9008 3.43494C15.8383 3.33744 15.7673 3.24494 15.6833 3.16044L12.8303 0.289467C12.7558 0.214467 12.6743 0.149438 12.5888 0.0914385Z"
/> fill="currentColor"
</svg> />
); </svg>
} );
); });
IconCopy.displayName = 'IconCopy';

6
beta/src/components/Icon/IconDeepDive.tsx

@ -2,9 +2,9 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconDeepDive = React.memo<JSX.IntrinsicElements['svg']>( export const IconDeepDive = memo<JSX.IntrinsicElements['svg']>(
function IconDeepDive({className}) { function IconDeepDive({className}) {
return ( return (
<svg <svg
@ -22,5 +22,3 @@ export const IconDeepDive = React.memo<JSX.IntrinsicElements['svg']>(
); );
} }
); );
IconDeepDive.displayName = 'IconDeepDive';

6
beta/src/components/Icon/IconDownload.tsx

@ -2,9 +2,9 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconDownload = React.memo<JSX.IntrinsicElements['svg']>( export const IconDownload = memo<JSX.IntrinsicElements['svg']>(
function IconDownload({className}) { function IconDownload({className}) {
return ( return (
<svg <svg
@ -26,5 +26,3 @@ export const IconDownload = React.memo<JSX.IntrinsicElements['svg']>(
); );
} }
); );
IconDownload.displayName = 'IconDownload';

36
beta/src/components/Icon/IconError.tsx

@ -2,23 +2,21 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconError = React.memo<JSX.IntrinsicElements['svg']>( export const IconError = memo<JSX.IntrinsicElements['svg']>(function IconError({
function IconError({className}) { className,
return ( }) {
<svg return (
className={className} <svg
width="1.33em" className={className}
height="1.33em" width="1.33em"
viewBox="0 0 24 24" height="1.33em"
xmlns="http://www.w3.org/2000/svg"> viewBox="0 0 24 24"
<circle cx="10.1626" cy="9.99951" r="9.47021" fill="currentColor" /> xmlns="http://www.w3.org/2000/svg">
<path d="M6.22705 5.95996L14.2798 14.0127" stroke="white" /> <circle cx="10.1626" cy="9.99951" r="9.47021" fill="currentColor" />
<path d="M14.2798 5.95996L6.22705 14.0127" stroke="white" /> <path d="M6.22705 5.95996L14.2798 14.0127" stroke="white" />
</svg> <path d="M14.2798 5.95996L6.22705 14.0127" stroke="white" />
); </svg>
} );
); });
IconError.displayName = 'IconError';

4
beta/src/components/Icon/IconFacebookCircle.tsx

@ -2,9 +2,9 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconFacebookCircle = React.memo<JSX.IntrinsicElements['svg']>( export const IconFacebookCircle = memo<JSX.IntrinsicElements['svg']>(
function IconFacebookCircle(props) { function IconFacebookCircle(props) {
return ( return (
<svg <svg

6
beta/src/components/Icon/IconGitHub.tsx

@ -2,9 +2,9 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconGitHub = React.memo<JSX.IntrinsicElements['svg']>( export const IconGitHub = memo<JSX.IntrinsicElements['svg']>(
function IconGitHub(props) { function IconGitHub(props) {
return ( return (
<svg <svg
@ -18,5 +18,3 @@ export const IconGitHub = React.memo<JSX.IntrinsicElements['svg']>(
); );
} }
); );
IconGitHub.displayName = 'IconGitHub';

6
beta/src/components/Icon/IconGotcha.tsx

@ -2,9 +2,9 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconGotcha = React.memo<JSX.IntrinsicElements['svg']>( export const IconGotcha = memo<JSX.IntrinsicElements['svg']>(
function IconGotcha({className}) { function IconGotcha({className}) {
return ( return (
<svg <svg
@ -22,5 +22,3 @@ export const IconGotcha = React.memo<JSX.IntrinsicElements['svg']>(
); );
} }
); );
IconGotcha.displayName = 'IconGotcha';

6
beta/src/components/Icon/IconHamburger.tsx

@ -2,9 +2,9 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconHamburger = React.memo<JSX.IntrinsicElements['svg']>( export const IconHamburger = memo<JSX.IntrinsicElements['svg']>(
function IconHamburger(props) { function IconHamburger(props) {
return ( return (
<svg <svg
@ -24,5 +24,3 @@ export const IconHamburger = React.memo<JSX.IntrinsicElements['svg']>(
); );
} }
); );
IconHamburger.displayName = 'IconHamburger';

38
beta/src/components/Icon/IconHint.tsx

@ -2,25 +2,23 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
import cn from 'classnames'; import cn from 'classnames';
export const IconHint = React.memo<JSX.IntrinsicElements['svg']>( export const IconHint = memo<JSX.IntrinsicElements['svg']>(function IconHint({
function IconHint({className}) { className,
return ( }) {
<svg return (
className={cn('inline -mt-0.5', className)} <svg
width="12" className={cn('inline -mt-0.5', className)}
height="14" width="12"
viewBox="0 0 12 15" height="14"
xmlns="http://www.w3.org/2000/svg"> viewBox="0 0 12 15"
<path xmlns="http://www.w3.org/2000/svg">
d="M4.53487 11H5.21954V7.66665H6.55287V11H7.23754C7.32554 10.1986 7.7342 9.53732 8.39754 8.81532C8.47287 8.73398 8.9522 8.23732 9.00887 8.16665C9.47973 7.5784 9.77486 6.86913 9.86028 6.1205C9.9457 5.37187 9.81794 4.61434 9.4917 3.93514C9.16547 3.25594 8.65402 2.6827 8.01628 2.28143C7.37853 1.88016 6.64041 1.66719 5.88692 1.66703C5.13344 1.66686 4.39523 1.87953 3.75731 2.28052C3.11939 2.68152 2.60771 3.25454 2.28118 3.9336C1.95465 4.61266 1.82656 5.37014 1.91167 6.1188C1.99677 6.86747 2.2916 7.57687 2.7622 8.16532C2.81954 8.23665 3.3002 8.73398 3.3742 8.81465C4.0382 9.53732 4.44687 10.1986 4.53487 11ZM4.55287 12.3333V13H7.21954V12.3333H4.55287ZM1.7222 8.99998C1.09433 8.21551 0.700836 7.26963 0.587047 6.2713C0.473258 5.27296 0.643804 4.26279 1.07904 3.35715C1.51428 2.4515 2.19649 1.68723 3.04711 1.15237C3.89772 0.617512 4.88213 0.333824 5.88692 0.333984C6.89172 0.334145 7.87604 0.61815 8.72648 1.15328C9.57692 1.68841 10.2589 2.4529 10.6938 3.35869C11.1288 4.26447 11.299 5.27469 11.1849 6.27299C11.0708 7.27129 10.677 8.21705 10.0489 9.00132C9.63554 9.51598 8.55287 10.3333 8.55287 11.3333V13C8.55287 13.3536 8.41239 13.6927 8.16235 13.9428C7.9123 14.1928 7.57316 14.3333 7.21954 14.3333H4.55287C4.19925 14.3333 3.86011 14.1928 3.61006 13.9428C3.36001 13.6927 3.21954 13.3536 3.21954 13V11.3333C3.21954 10.3333 2.1362 9.51598 1.7222 8.99998Z" <path
fill="currentColor" d="M4.53487 11H5.21954V7.66665H6.55287V11H7.23754C7.32554 10.1986 7.7342 9.53732 8.39754 8.81532C8.47287 8.73398 8.9522 8.23732 9.00887 8.16665C9.47973 7.5784 9.77486 6.86913 9.86028 6.1205C9.9457 5.37187 9.81794 4.61434 9.4917 3.93514C9.16547 3.25594 8.65402 2.6827 8.01628 2.28143C7.37853 1.88016 6.64041 1.66719 5.88692 1.66703C5.13344 1.66686 4.39523 1.87953 3.75731 2.28052C3.11939 2.68152 2.60771 3.25454 2.28118 3.9336C1.95465 4.61266 1.82656 5.37014 1.91167 6.1188C1.99677 6.86747 2.2916 7.57687 2.7622 8.16532C2.81954 8.23665 3.3002 8.73398 3.3742 8.81465C4.0382 9.53732 4.44687 10.1986 4.53487 11ZM4.55287 12.3333V13H7.21954V12.3333H4.55287ZM1.7222 8.99998C1.09433 8.21551 0.700836 7.26963 0.587047 6.2713C0.473258 5.27296 0.643804 4.26279 1.07904 3.35715C1.51428 2.4515 2.19649 1.68723 3.04711 1.15237C3.89772 0.617512 4.88213 0.333824 5.88692 0.333984C6.89172 0.334145 7.87604 0.61815 8.72648 1.15328C9.57692 1.68841 10.2589 2.4529 10.6938 3.35869C11.1288 4.26447 11.299 5.27469 11.1849 6.27299C11.0708 7.27129 10.677 8.21705 10.0489 9.00132C9.63554 9.51598 8.55287 10.3333 8.55287 11.3333V13C8.55287 13.3536 8.41239 13.6927 8.16235 13.9428C7.9123 14.1928 7.57316 14.3333 7.21954 14.3333H4.55287C4.19925 14.3333 3.86011 14.1928 3.61006 13.9428C3.36001 13.6927 3.21954 13.3536 3.21954 13V11.3333C3.21954 10.3333 2.1362 9.51598 1.7222 8.99998Z"
/> fill="currentColor"
</svg> />
); </svg>
} );
); });
IconHint.displayName = 'IconHint';

4
beta/src/components/Icon/IconInstagram.tsx

@ -2,9 +2,9 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconInstagram = React.memo<JSX.IntrinsicElements['svg']>( export const IconInstagram = memo<JSX.IntrinsicElements['svg']>(
function IconInstagram(props) { function IconInstagram(props) {
return ( return (
<svg <svg

6
beta/src/components/Icon/IconNavArrow.tsx

@ -2,10 +2,10 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
import cn from 'classnames'; import cn from 'classnames';
export const IconNavArrow = React.memo< export const IconNavArrow = memo<
JSX.IntrinsicElements['svg'] & { JSX.IntrinsicElements['svg'] & {
displayDirection: 'right' | 'down' | 'left'; displayDirection: 'right' | 'down' | 'left';
} }
@ -40,5 +40,3 @@ export const IconNavArrow = React.memo<
</svg> </svg>
); );
}); });
IconNavArrow.displayName = 'IconNavArrow';

6
beta/src/components/Icon/IconNewPage.tsx

@ -2,9 +2,9 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconNewPage = React.memo<JSX.IntrinsicElements['svg']>( export const IconNewPage = memo<JSX.IntrinsicElements['svg']>(
function IconNewPage(props) { function IconNewPage(props) {
return ( return (
<svg <svg
@ -26,5 +26,3 @@ export const IconNewPage = React.memo<JSX.IntrinsicElements['svg']>(
); );
} }
); );
IconNewPage.displayName = 'IconNewPage';

40
beta/src/components/Icon/IconNote.tsx

@ -2,25 +2,23 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconNote = React.memo<JSX.IntrinsicElements['svg']>( export const IconNote = memo<JSX.IntrinsicElements['svg']>(function IconNote({
function IconNote({className}) { className,
return ( }) {
<svg return (
className={className} <svg
width="1em" className={className}
height="1.05em" width="1em"
viewBox="0 0 18 19" height="1.05em"
fill="none" viewBox="0 0 18 19"
xmlns="http://www.w3.org/2000/svg"> fill="none"
<path xmlns="http://www.w3.org/2000/svg">
d="M18 12.2632L12 18.2592L1.002 18.2632C0.737486 18.2642 0.483369 18.1603 0.295486 17.9741C0.107603 17.7879 0.00132309 17.5347 0 17.2702V1.25618C0 0.708184 0.445 0.263184 0.993 0.263184H17.007C17.555 0.263184 18 0.719183 18 1.26518V12.2632ZM16 2.26318H2V16.2632H10V11.2632C10 11.0183 10.09 10.7818 10.2527 10.5988C10.4155 10.4158 10.6397 10.2988 10.883 10.2702L11 10.2632L16 10.2622V2.26318ZM15.171 12.2622L12 12.2632V15.4322L15.171 12.2622Z" <path
fill="currentColor" d="M18 12.2632L12 18.2592L1.002 18.2632C0.737486 18.2642 0.483369 18.1603 0.295486 17.9741C0.107603 17.7879 0.00132309 17.5347 0 17.2702V1.25618C0 0.708184 0.445 0.263184 0.993 0.263184H17.007C17.555 0.263184 18 0.719183 18 1.26518V12.2632ZM16 2.26318H2V16.2632H10V11.2632C10 11.0183 10.09 10.7818 10.2527 10.5988C10.4155 10.4158 10.6397 10.2988 10.883 10.2702L11 10.2632L16 10.2622V2.26318ZM15.171 12.2622L12 12.2632V15.4322L15.171 12.2622Z"
/> fill="currentColor"
</svg> />
); </svg>
} );
); });
IconNote.displayName = 'IconNote';

6
beta/src/components/Icon/IconRestart.tsx

@ -2,9 +2,9 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconRestart = React.memo<JSX.IntrinsicElements['svg']>( export const IconRestart = memo<JSX.IntrinsicElements['svg']>(
function IconRestart({className}) { function IconRestart({className}) {
return ( return (
<svg <svg
@ -22,5 +22,3 @@ export const IconRestart = React.memo<JSX.IntrinsicElements['svg']>(
); );
} }
); );
IconRestart.displayName = 'IconRestart';

46
beta/src/components/Icon/IconRss.tsx

@ -2,28 +2,26 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconRss = React.memo<JSX.IntrinsicElements['svg']>( export const IconRss = memo<JSX.IntrinsicElements['svg']>(function IconRss(
function IconRss(props) { props
return ( ) {
<svg return (
xmlns="http://www.w3.org/2000/svg" <svg
width="1em" xmlns="http://www.w3.org/2000/svg"
height="1em" width="1em"
viewBox="0 0 24 24" height="1em"
fill="none" viewBox="0 0 24 24"
stroke="currentColor" fill="none"
strokeWidth={2} stroke="currentColor"
strokeLinecap="round" strokeWidth={2}
strokeLinejoin="round" strokeLinecap="round"
{...props}> strokeLinejoin="round"
<path d="M4 11a9 9 0 0 1 9 9" /> {...props}>
<path d="M4 4a16 16 0 0 1 16 16" /> <path d="M4 11a9 9 0 0 1 9 9" />
<circle cx={5} cy={19} r={1} /> <path d="M4 4a16 16 0 0 1 16 16" />
</svg> <circle cx={5} cy={19} r={1} />
); </svg>
} );
); });
IconRss.displayName = 'IconLogo';

6
beta/src/components/Icon/IconSearch.tsx

@ -2,9 +2,9 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconSearch = React.memo<JSX.IntrinsicElements['svg']>( export const IconSearch = memo<JSX.IntrinsicElements['svg']>(
function IconSearch(props) { function IconSearch(props) {
return ( return (
<svg width="1em" height="1em" viewBox="0 0 20 20" {...props}> <svg width="1em" height="1em" viewBox="0 0 20 20" {...props}>
@ -20,5 +20,3 @@ export const IconSearch = React.memo<JSX.IntrinsicElements['svg']>(
); );
} }
); );
IconSearch.displayName = 'IconSearch';

6
beta/src/components/Icon/IconSolution.tsx

@ -2,10 +2,10 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
import cn from 'classnames'; import cn from 'classnames';
export const IconSolution = React.memo<JSX.IntrinsicElements['svg']>( export const IconSolution = memo<JSX.IntrinsicElements['svg']>(
function IconSolution({className}) { function IconSolution({className}) {
return ( return (
<svg <svg
@ -22,5 +22,3 @@ export const IconSolution = React.memo<JSX.IntrinsicElements['svg']>(
); );
} }
); );
IconSolution.displayName = 'IconSolution';

6
beta/src/components/Icon/IconTerminal.tsx

@ -2,9 +2,9 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconTerminal = React.memo<JSX.IntrinsicElements['svg']>( export const IconTerminal = memo<JSX.IntrinsicElements['svg']>(
function IconTerminal({className}) { function IconTerminal({className}) {
return ( return (
<svg <svg
@ -22,5 +22,3 @@ export const IconTerminal = React.memo<JSX.IntrinsicElements['svg']>(
); );
} }
); );
IconTerminal.displayName = 'IconTerminal';

6
beta/src/components/Icon/IconTwitter.tsx

@ -2,9 +2,9 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconTwitter = React.memo<JSX.IntrinsicElements['svg']>( export const IconTwitter = memo<JSX.IntrinsicElements['svg']>(
function IconTwitter(props) { function IconTwitter(props) {
return ( return (
<svg <svg
@ -20,5 +20,3 @@ export const IconTwitter = React.memo<JSX.IntrinsicElements['svg']>(
); );
} }
); );
IconTwitter.displayName = 'IconTwitter';

6
beta/src/components/Icon/IconWarning.tsx

@ -2,9 +2,9 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {memo} from 'react';
export const IconWarning = React.memo<JSX.IntrinsicElements['svg']>( export const IconWarning = memo<JSX.IntrinsicElements['svg']>(
function IconWarning({className}) { function IconWarning({className}) {
return ( return (
<svg <svg
@ -24,5 +24,3 @@ export const IconWarning = React.memo<JSX.IntrinsicElements['svg']>(
); );
} }
); );
IconWarning.displayName = 'IconWarning';

4
beta/src/components/Layout/Feedback.tsx

@ -2,7 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {useState} from 'react';
import {useRouter} from 'next/router'; import {useRouter} from 'next/router';
import {ga} from '../../utils/analytics'; import {ga} from '../../utils/analytics';
@ -58,7 +58,7 @@ function sendGAEvent(isPositive: boolean) {
} }
function SendFeedback({onSubmit}: {onSubmit: () => void}) { function SendFeedback({onSubmit}: {onSubmit: () => void}) {
const [isSubmitted, setIsSubmitted] = React.useState(false); const [isSubmitted, setIsSubmitted] = useState(false);
return ( 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="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">
<p className="w-full font-bold text-primary dark:text-primary-dark text-lg mr-4"> <p className="w-full font-bold text-primary dark:text-primary-dark text-lg mr-4">

29
beta/src/components/Layout/Nav/Nav.tsx

@ -2,6 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import {useState, useRef, useContext, useEffect, Suspense} from 'react';
import * as React from 'react'; import * as React from 'react';
import cn from 'classnames'; import cn from 'classnames';
import NextLink from 'next/link'; import NextLink from 'next/link';
@ -93,20 +94,20 @@ const lightIcon = (
); );
export default function Nav() { export default function Nav() {
const [isOpen, setIsOpen] = React.useState(false); const [isOpen, setIsOpen] = useState(false);
const [showFeedback, setShowFeedback] = React.useState(false); const [showFeedback, setShowFeedback] = useState(false);
const scrollParentRef = React.useRef<HTMLDivElement>(null); const scrollParentRef = useRef<HTMLDivElement>(null);
const feedbackAutohideRef = React.useRef<any>(null); const feedbackAutohideRef = useRef<any>(null);
const section = useActiveSection(); const section = useActiveSection();
const {asPath} = useRouter(); const {asPath} = useRouter();
const feedbackPopupRef = React.useRef<null | HTMLDivElement>(null); const feedbackPopupRef = useRef<null | HTMLDivElement>(null);
// In desktop mode, use the route tree for current route. // In desktop mode, use the route tree for current route.
let routeTree: RouteItem = React.useContext(SidebarContext); let routeTree: RouteItem = useContext(SidebarContext);
// In mobile mode, let the user switch tabs there and back without navigating. // In mobile mode, let the user switch tabs there and back without navigating.
// Seed the tab state from the router, but keep it independent. // Seed the tab state from the router, but keep it independent.
const [tab, setTab] = React.useState(section); const [tab, setTab] = useState(section);
const [prevSection, setPrevSection] = React.useState(section); const [prevSection, setPrevSection] = useState(section);
if (prevSection !== section) { if (prevSection !== section) {
setPrevSection(section); setPrevSection(section);
setTab(section); setTab(section);
@ -130,7 +131,7 @@ export default function Nav() {
} }
// While the overlay is open, disable body scroll. // While the overlay is open, disable body scroll.
React.useEffect(() => { useEffect(() => {
if (isOpen) { if (isOpen) {
const preferredScrollParent = scrollParentRef.current!; const preferredScrollParent = scrollParentRef.current!;
disableBodyScroll(preferredScrollParent); disableBodyScroll(preferredScrollParent);
@ -141,13 +142,13 @@ export default function Nav() {
}, [isOpen]); }, [isOpen]);
// Close the overlay on any navigation. // Close the overlay on any navigation.
React.useEffect(() => { useEffect(() => {
setIsOpen(false); setIsOpen(false);
}, [asPath]); }, [asPath]);
// Also close the overlay if the window gets resized past mobile layout. // Also close the overlay if the window gets resized past mobile layout.
// (This is also important because we don't want to keep the body locked!) // (This is also important because we don't want to keep the body locked!)
React.useEffect(() => { useEffect(() => {
const media = window.matchMedia(`(max-width: 1023px)`); const media = window.matchMedia(`(max-width: 1023px)`);
function closeIfNeeded() { function closeIfNeeded() {
if (!media.matches) { if (!media.matches) {
@ -167,7 +168,7 @@ export default function Nav() {
} }
// Hide the Feedback widget on any click outside. // Hide the Feedback widget on any click outside.
React.useEffect(() => { useEffect(() => {
if (!showFeedback) { if (!showFeedback) {
return; return;
} }
@ -346,7 +347,7 @@ export default function Nav() {
style={{'--bg-opacity': '.2'} as React.CSSProperties} // Need to cast here because CSS vars aren't considered valid in TS types (cuz they could be anything) style={{'--bg-opacity': '.2'} as React.CSSProperties} // Need to cast here because CSS vars aren't considered valid in TS types (cuz they could be anything)
className="w-full lg:h-auto grow pr-0 lg:pr-5 pt-6 lg:py-6 md:pt-4 lg:pt-4 scrolling-touch scrolling-gpu"> className="w-full lg:h-auto grow pr-0 lg:pr-5 pt-6 lg:py-6 md:pt-4 lg:pt-4 scrolling-touch scrolling-gpu">
{/* No fallback UI so need to be careful not to suspend directly inside. */} {/* No fallback UI so need to be careful not to suspend directly inside. */}
<React.Suspense fallback={null}> <Suspense fallback={null}>
<SidebarRouteTree <SidebarRouteTree
// Don't share state between the desktop and mobile versions. // Don't share state between the desktop and mobile versions.
// This avoids unnecessary animations and visual flicker. // This avoids unnecessary animations and visual flicker.
@ -354,7 +355,7 @@ export default function Nav() {
routeTree={routeTree} routeTree={routeTree}
isForceExpanded={isOpen} isForceExpanded={isOpen}
/> />
</React.Suspense> </Suspense>
<div className="h-20" /> <div className="h-20" />
</nav> </nav>
<div className="fixed bottom-0 hidden lg:block"> <div className="fixed bottom-0 hidden lg:block">

5
beta/src/components/Layout/Page.tsx

@ -2,6 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import {Suspense} from 'react';
import * as React from 'react'; import * as React from 'react';
import {useRouter} from 'next/router'; import {useRouter} from 'next/router';
import {Nav} from './Nav'; import {Nav} from './Nav';
@ -41,7 +42,7 @@ export function Page({children, toc}: PageProps) {
<Nav /> <Nav />
</div> </div>
{/* No fallback UI so need to be careful not to suspend directly inside. */} {/* No fallback UI so need to be careful not to suspend directly inside. */}
<React.Suspense fallback={null}> <Suspense fallback={null}>
<main className="min-w-0"> <main className="min-w-0">
<div className="lg:hidden h-16 mb-2" /> <div className="lg:hidden h-16 mb-2" />
<article className="break-words" key={asPath}> <article className="break-words" key={asPath}>
@ -49,7 +50,7 @@ export function Page({children, toc}: PageProps) {
</article> </article>
<Footer /> <Footer />
</main> </main>
</React.Suspense> </Suspense>
<div className="hidden lg:max-w-xs 2xl:block"> <div className="hidden lg:max-w-xs 2xl:block">
{toc.length > 0 && <Toc headings={toc} key={asPath} />} {toc.length > 0 && <Toc headings={toc} key={asPath} />}
</div> </div>

5
beta/src/components/Layout/Sidebar/SidebarLink.tsx

@ -4,6 +4,7 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */ /* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */ /* eslint-disable jsx-a11y/click-events-have-key-events */
import {useRef, useEffect} from 'react';
import * as React from 'react'; import * as React from 'react';
import cn from 'classnames'; import cn from 'classnames';
import {IconNavArrow} from 'components/Icon/IconNavArrow'; import {IconNavArrow} from 'components/Icon/IconNavArrow';
@ -35,9 +36,9 @@ export function SidebarLink({
hideArrow, hideArrow,
isPending, isPending,
}: SidebarLinkProps) { }: SidebarLinkProps) {
const ref = React.useRef<HTMLAnchorElement>(null); const ref = useRef<HTMLAnchorElement>(null);
React.useEffect(() => { useEffect(() => {
if (selected && ref && ref.current) { if (selected && ref && ref.current) {
// @ts-ignore // @ts-ignore
if (typeof ref.current.scrollIntoViewIfNeeded === 'function') { if (typeof ref.current.scrollIntoViewIfNeeded === 'function') {

10
beta/src/components/Layout/Sidebar/SidebarRouteTree.tsx

@ -2,7 +2,8 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {useRef, useLayoutEffect} from 'react';
import cn from 'classnames'; import cn from 'classnames';
import {RouteItem} from 'components/Layout/useRouteMeta'; import {RouteItem} from 'components/Layout/useRouteMeta';
import {useRouter} from 'next/router'; import {useRouter} from 'next/router';
@ -10,7 +11,6 @@ import {removeFromLast} from 'utils/removeFromLast';
import {useRouteMeta} from '../useRouteMeta'; import {useRouteMeta} from '../useRouteMeta';
import {SidebarLink} from './SidebarLink'; import {SidebarLink} from './SidebarLink';
import useCollapse from 'react-collapsed'; import useCollapse from 'react-collapsed';
import {useLayoutEffect} from 'react';
import usePendingRoute from 'hooks/usePendingRoute'; import usePendingRoute from 'hooks/usePendingRoute';
interface SidebarRouteTreeProps { interface SidebarRouteTreeProps {
@ -28,15 +28,15 @@ function CollapseWrapper({
duration: number; duration: number;
children: any; children: any;
}) { }) {
const ref = React.useRef<HTMLDivElement | null>(null); const ref = useRef<HTMLDivElement | null>(null);
const timeoutRef = React.useRef<number | null>(null); const timeoutRef = useRef<number | null>(null);
const {getCollapseProps} = useCollapse({ const {getCollapseProps} = useCollapse({
isExpanded, isExpanded,
duration, duration,
}); });
// Disable pointer events while animating. // Disable pointer events while animating.
const isExpandedRef = React.useRef(isExpanded); const isExpandedRef = useRef(isExpanded);
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
// eslint-disable-next-line react-hooks/rules-of-hooks // eslint-disable-next-line react-hooks/rules-of-hooks
useLayoutEffect(() => { useLayoutEffect(() => {

1
beta/src/components/Layout/Toc.tsx

@ -3,7 +3,6 @@
*/ */
import cx from 'classnames'; import cx from 'classnames';
import * as React from 'react';
import {useTocHighlight} from './useTocHighlight'; import {useTocHighlight} from './useTocHighlight';
import type {Toc} from '../MDX/TocContext'; import type {Toc} from '../MDX/TocContext';

6
beta/src/components/Layout/useRouteMeta.tsx

@ -2,7 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {useContext, createContext} from 'react';
import {useRouter} from 'next/router'; import {useRouter} from 'next/router';
/** /**
@ -54,7 +54,7 @@ export interface RouteMeta {
} }
export function useRouteMeta(rootRoute?: RouteItem) { export function useRouteMeta(rootRoute?: RouteItem) {
const sidebarContext = React.useContext(SidebarContext); const sidebarContext = useContext(SidebarContext);
const routeTree = rootRoute || sidebarContext; const routeTree = rootRoute || sidebarContext;
const router = useRouter(); const router = useRouter();
if (router.pathname === '/404') { if (router.pathname === '/404') {
@ -70,7 +70,7 @@ export function useRouteMeta(rootRoute?: RouteItem) {
}; };
} }
export const SidebarContext = React.createContext<RouteItem>({title: 'root'}); export const SidebarContext = createContext<RouteItem>({title: 'root'});
// Performs a depth-first search to find the current route and its previous/next route // Performs a depth-first search to find the current route and its previous/next route
function getRouteMeta( function getRouteMeta(

8
beta/src/components/Layout/useTocHighlight.tsx

@ -2,7 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import React from 'react'; import {useState, useRef, useEffect} from 'react';
const TOP_OFFSET = 75; const TOP_OFFSET = 75;
@ -23,10 +23,10 @@ export function getHeaderAnchors(): HTMLAnchorElement[] {
* Sets up Table of Contents highlighting. * Sets up Table of Contents highlighting.
*/ */
export function useTocHighlight() { export function useTocHighlight() {
const [currentIndex, setCurrentIndex] = React.useState<number>(0); const [currentIndex, setCurrentIndex] = useState<number>(0);
const timeoutRef = React.useRef<number | null>(null); const timeoutRef = useRef<number | null>(null);
React.useEffect(() => { useEffect(() => {
function updateActiveLink() { function updateActiveLink() {
const pageHeight = document.body.scrollHeight; const pageHeight = document.body.scrollHeight;
const scrollPosition = window.scrollY + window.innerHeight; const scrollPosition = window.scrollY + window.innerHeight;

49
beta/src/components/Layout/useTwitter.tsx

@ -1,49 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
/**
* Ported from gatsby-plugin-twitter
* https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-plugin-twitter
*/
import * as React from 'react';
const injectTwitterScript = function injectTwitterScript() {
function addJS(jsCode: any) {
const s = document.createElement('script');
s.type = 'text/javascript';
s.innerText = jsCode;
document.getElementsByTagName('head')[0].appendChild(s);
}
addJS(
'\n window.twttr = (function(d, s, id) {\n var js,\n fjs = d.getElementsByTagName(s)[0],\n t = window.twttr || {};\n if (d.getElementById(id)) return t;\n js = d.createElement(s);\n js.id = id;\n js.src = "https://platform.twitter.com/widgets.js";\n fjs.parentNode.insertBefore(js, fjs);\n t._e = [];\n t.ready = function(f) {\n t._e.push(f);\n };\n return t;\n })(document, "script", "twitter-wjs");\n '
);
};
let injectedTwitterScript = false;
const embedClasses = [
'.twitter-tweet',
'.twitter-timeline',
'.twitter-follow-button',
'.twitter-share-button',
].join(',');
export function useTwitter() {
React.useEffect(() => {
if (document.querySelector(embedClasses) !== null) {
if (!injectedTwitterScript) {
injectTwitterScript();
injectedTwitterScript = true;
}
if (
typeof (window as any).twttr !== 'undefined' &&
(window as any).twttr.widgets &&
typeof (window as any).twttr.widgets.load === 'function'
) {
(window as any).twttr.widgets.load();
}
}
}, []);
}

4
beta/src/components/Logo.tsx

@ -2,8 +2,6 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react';
export function Logo(props: JSX.IntrinsicElements['svg']) { export function Logo(props: JSX.IntrinsicElements['svg']) {
return ( return (
<svg <svg
@ -24,5 +22,3 @@ export function Logo(props: JSX.IntrinsicElements['svg']) {
</svg> </svg>
); );
} }
Logo.displayName = 'Logo';

6
beta/src/components/MDX/Challenges/Challenge.tsx

@ -2,7 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {useState} from 'react';
import cn from 'classnames'; import cn from 'classnames';
import {Button} from 'components/Button'; import {Button} from 'components/Button';
import {ChallengeContents} from './Challenges'; import {ChallengeContents} from './Challenges';
@ -25,8 +25,8 @@ export function Challenge({
hasNextChallenge, hasNextChallenge,
handleClickNextChallenge, handleClickNextChallenge,
}: ChallengeProps) { }: ChallengeProps) {
const [showHint, setShowHint] = React.useState(false); const [showHint, setShowHint] = useState(false);
const [showSolution, setShowSolution] = React.useState(false); const [showSolution, setShowSolution] = useState(false);
const toggleHint = () => { const toggleHint = () => {
if (showSolution && !showHint) { if (showSolution && !showHint) {

11
beta/src/components/MDX/Challenges/Challenges.tsx

@ -2,6 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import {Children, useRef, useEffect, useState} from 'react';
import * as React from 'react'; import * as React from 'react';
import cn from 'classnames'; import cn from 'classnames';
import {H2} from 'components/MDX/Heading'; import {H2} from 'components/MDX/Heading';
@ -36,7 +37,7 @@ const parseChallengeContents = (
let challenge: Partial<ChallengeContents> = {}; let challenge: Partial<ChallengeContents> = {};
let content: React.ReactElement[] = []; let content: React.ReactElement[] = [];
React.Children.forEach(children, (child) => { Children.forEach(children, (child) => {
const {props, type} = child; const {props, type} = child;
switch ((type as any).mdxName) { switch ((type as any).mdxName) {
case 'Solution': { case 'Solution': {
@ -74,12 +75,12 @@ export function Challenges({
}: ChallengesProps) { }: ChallengesProps) {
const challenges = parseChallengeContents(children); const challenges = parseChallengeContents(children);
const totalChallenges = challenges.length; const totalChallenges = challenges.length;
const scrollAnchorRef = React.useRef<HTMLDivElement>(null); const scrollAnchorRef = useRef<HTMLDivElement>(null);
const queuedScrollRef = React.useRef<boolean>(false); const queuedScrollRef = useRef<boolean>(false);
const [activeIndex, setActiveIndex] = React.useState(0); const [activeIndex, setActiveIndex] = useState(0);
const currentChallenge = challenges[activeIndex]; const currentChallenge = challenges[activeIndex];
React.useEffect(() => { useEffect(() => {
if (queuedScrollRef.current === true) { if (queuedScrollRef.current === true) {
queuedScrollRef.current = false; queuedScrollRef.current = false;
scrollAnchorRef.current!.scrollIntoView({ scrollAnchorRef.current!.scrollIntoView({

10
beta/src/components/MDX/Challenges/Navigation.tsx

@ -2,7 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import React, {createRef} from 'react'; import {useRef, useCallback, useEffect, createRef} from 'react';
import cn from 'classnames'; import cn from 'classnames';
import {IconChevron} from 'components/Icon/IconChevron'; import {IconChevron} from 'components/Icon/IconChevron';
import {ChallengeContents} from './Challenges'; import {ChallengeContents} from './Challenges';
@ -19,8 +19,8 @@ export function Navigation({
currentChallenge: ChallengeContents; currentChallenge: ChallengeContents;
isRecipes?: boolean; isRecipes?: boolean;
}) { }) {
const containerRef = React.useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const challengesNavRef = React.useRef( const challengesNavRef = useRef(
challenges.map(() => createRef<HTMLButtonElement>()) challenges.map(() => createRef<HTMLButtonElement>())
); );
const scrollPos = currentChallenge.order - 1; const scrollPos = currentChallenge.order - 1;
@ -61,7 +61,7 @@ export function Navigation({
handleChange(index); handleChange(index);
}; };
const handleResize = React.useCallback(() => { const handleResize = useCallback(() => {
if (containerRef.current) { if (containerRef.current) {
const el = containerRef.current; const el = containerRef.current;
el.scrollLeft = el.scrollLeft =
@ -69,7 +69,7 @@ export function Navigation({
} }
}, [containerRef, challengesNavRef, scrollPos]); }, [containerRef, challengesNavRef, scrollPos]);
React.useEffect(() => { useEffect(() => {
handleResize(); handleResize();
window.addEventListener('resize', debounce(handleResize, 200)); window.addEventListener('resize', debounce(handleResize, 200));
return () => { return () => {

2
beta/src/components/MDX/Challenges/index.tsx

@ -2,7 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import React from 'react'; import * as React from 'react';
export {Challenges} from './Challenges'; export {Challenges} from './Challenges';
export function Hint({children}: {children: React.ReactNode}) { export function Hint({children}: {children: React.ReactNode}) {

10
beta/src/components/MDX/CodeBlock/index.tsx

@ -2,10 +2,10 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import cn from 'classnames'; import cn from 'classnames';
import * as React from 'react'; import {lazy, memo, Suspense} from 'react';
const CodeBlock = React.lazy(() => import('./CodeBlock')); const CodeBlock = lazy(() => import('./CodeBlock'));
export default React.memo(function CodeBlockWrapper(props: { export default memo(function CodeBlockWrapper(props: {
isFromPackageImport: boolean; isFromPackageImport: boolean;
children: string; children: string;
className?: string; className?: string;
@ -15,7 +15,7 @@ export default React.memo(function CodeBlockWrapper(props: {
}): any { }): any {
const {children, isFromPackageImport} = props; const {children, isFromPackageImport} = props;
return ( return (
<React.Suspense <Suspense
fallback={ fallback={
<pre <pre
className={cn( className={cn(
@ -28,6 +28,6 @@ export default React.memo(function CodeBlockWrapper(props: {
</pre> </pre>
}> }>
<CodeBlock {...props} /> <CodeBlock {...props} />
</React.Suspense> </Suspense>
); );
}); });

5
beta/src/components/MDX/CodeDiagram.tsx

@ -2,6 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import {Children} from 'react';
import * as React from 'react'; import * as React from 'react';
import CodeBlock from './CodeBlock'; import CodeBlock from './CodeBlock';
@ -11,10 +12,10 @@ interface CodeDiagramProps {
} }
export function CodeDiagram({children, flip = false}: CodeDiagramProps) { export function CodeDiagram({children, flip = false}: CodeDiagramProps) {
const illustration = React.Children.toArray(children).filter((child: any) => { const illustration = Children.toArray(children).filter((child: any) => {
return child.type === 'img'; return child.type === 'img';
}); });
const content = React.Children.toArray(children).map((child: any) => { const content = Children.toArray(children).map((child: any) => {
if (child.type?.mdxName === 'pre') { if (child.type?.mdxName === 'pre') {
return ( return (
<CodeBlock <CodeBlock

4
beta/src/components/MDX/ConsoleBlock.tsx

@ -2,6 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import {isValidElement} from 'react';
import * as React from 'react'; import * as React from 'react';
import cn from 'classnames'; import cn from 'classnames';
import {IconWarning} from '../Icon/IconWarning'; import {IconWarning} from '../Icon/IconWarning';
@ -27,13 +28,12 @@ const Box = ({
}) => ( }) => (
<div className={className} style={{width, height, ...customStyles}}></div> <div className={className} style={{width, height, ...customStyles}}></div>
); );
Box.displayName = 'Box';
function ConsoleBlock({level = 'error', children}: ConsoleBlockProps) { function ConsoleBlock({level = 'error', children}: ConsoleBlockProps) {
let message: React.ReactNode | null; let message: React.ReactNode | null;
if (typeof children === 'string') { if (typeof children === 'string') {
message = children; message = children;
} else if (React.isValidElement(children)) { } else if (isValidElement(children)) {
message = children.props.children; message = children.props.children;
} }

1
beta/src/components/MDX/Diagram.tsx

@ -2,7 +2,6 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react';
import Image from 'next/image'; import Image from 'next/image';
interface DiagramProps { interface DiagramProps {

1
beta/src/components/MDX/DiagramGroup.tsx

@ -2,7 +2,6 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react';
import {ReactNode} from 'react'; import {ReactNode} from 'react';
interface DiagramGroupProps { interface DiagramGroupProps {

3
beta/src/components/MDX/ExpandableCallout.tsx

@ -2,6 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import {useRef} from 'react';
import * as React from 'react'; import * as React from 'react';
import cn from 'classnames'; import cn from 'classnames';
import {IconNote} from '../Icon/IconNote'; import {IconNote} from '../Icon/IconNote';
@ -43,7 +44,7 @@ const variantMap = {
}; };
function ExpandableCallout({children, type}: ExpandableCalloutProps) { function ExpandableCallout({children, type}: ExpandableCalloutProps) {
const contentRef = React.useRef<HTMLDivElement>(null); const contentRef = useRef<HTMLDivElement>(null);
const variant = variantMap[type]; const variant = variantMap[type];
return ( return (

2
beta/src/components/MDX/Heading.tsx

@ -51,8 +51,6 @@ const Heading = forwardRefWithAs<HeadingProps, 'div'>(function Heading(
); );
}); });
Heading.displayName = 'Heading';
export const H1 = ({className, ...props}: HeadingProps) => ( export const H1 = ({className, ...props}: HeadingProps) => (
<Heading <Heading
as="h1" as="h1"

1
beta/src/components/MDX/HomepageHero.tsx

@ -2,7 +2,6 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react';
import {Logo} from 'components/Logo'; import {Logo} from 'components/Logo';
import YouWillLearnCard from 'components/MDX/YouWillLearnCard'; import YouWillLearnCard from 'components/MDX/YouWillLearnCard';

3
beta/src/components/MDX/InlineCode.tsx

@ -2,7 +2,6 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react';
import cn from 'classnames'; import cn from 'classnames';
interface InlineCodeProps { interface InlineCodeProps {
@ -26,6 +25,4 @@ function InlineCode({
); );
} }
InlineCode.displayName = 'InlineCode';
export default InlineCode; export default InlineCode;

4
beta/src/components/MDX/Intro.tsx

@ -2,7 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import React from 'react'; import * as React from 'react';
export interface IntroProps { export interface IntroProps {
children?: React.ReactNode; children?: React.ReactNode;
@ -16,6 +16,4 @@ function Intro({children}: IntroProps) {
); );
} }
Intro.displayName = 'Intro';
export default Intro; export default Intro;

20
beta/src/components/MDX/Link.tsx

@ -2,7 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {Children, cloneElement} from 'react';
import NextLink from 'next/link'; import NextLink from 'next/link';
import cn from 'classnames'; import cn from 'classnames';
@ -16,16 +16,14 @@ function Link({
}: JSX.IntrinsicElements['a']) { }: JSX.IntrinsicElements['a']) {
const classes = const classes =
'inline text-link dark:text-link-dark break-normal border-b border-link border-opacity-0 hover:border-opacity-100 duration-100 ease-in transition leading-normal'; 'inline text-link dark:text-link-dark break-normal border-b border-link border-opacity-0 hover:border-opacity-100 duration-100 ease-in transition leading-normal';
const modifiedChildren = React.Children.toArray(children).map( const modifiedChildren = Children.toArray(children).map((child: any) => {
(child: any) => { if (child.type?.mdxName && child.type?.mdxName === 'inlineCode') {
if (child.type?.mdxName && child.type?.mdxName === 'inlineCode') { return cloneElement(child, {
return React.cloneElement(child, { isLink: true,
isLink: true, });
});
}
return child;
} }
); return child;
});
if (!href) { if (!href) {
// eslint-disable-next-line jsx-a11y/anchor-has-content // eslint-disable-next-line jsx-a11y/anchor-has-content
@ -54,6 +52,4 @@ function Link({
); );
} }
Link.displayName = 'Link';
export default Link; export default Link;

7
beta/src/components/MDX/MDXComponents.tsx

@ -2,6 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import {Children, useContext, useMemo} from 'react';
import * as React from 'react'; import * as React from 'react';
import cn from 'classnames'; import cn from 'classnames';
@ -238,7 +239,7 @@ function IllustrationBlock({
sequential: boolean; sequential: boolean;
children: any; children: any;
}) { }) {
const imageInfos = React.Children.toArray(children).map( const imageInfos = Children.toArray(children).map(
(child: any) => child.props (child: any) => child.props
); );
const images = imageInfos.map((info, index) => ( const images = imageInfos.map((info, index) => (
@ -308,8 +309,8 @@ function calculateNestedToc(toc: Toc): NestedTocRoot {
} }
function InlineToc() { function InlineToc() {
const toc = React.useContext(TocContext); const toc = useContext(TocContext);
const root = React.useMemo(() => calculateNestedToc(toc), [toc]); const root = useMemo(() => calculateNestedToc(toc), [toc]);
return <InlineTocItem items={root.children} />; return <InlineTocItem items={root.children} />;
} }

5
beta/src/components/MDX/PackageImport.tsx

@ -2,6 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import {Children} from 'react';
import * as React from 'react'; import * as React from 'react';
import CodeBlock from './CodeBlock'; import CodeBlock from './CodeBlock';
@ -10,10 +11,10 @@ interface PackageImportProps {
} }
export function PackageImport({children}: PackageImportProps) { export function PackageImport({children}: PackageImportProps) {
const terminal = React.Children.toArray(children).filter((child: any) => { const terminal = Children.toArray(children).filter((child: any) => {
return child.type?.mdxName !== 'pre'; return child.type?.mdxName !== 'pre';
}); });
const code = React.Children.toArray(children).map((child: any, i: number) => { const code = Children.toArray(children).map((child: any, i: number) => {
if (child.type?.mdxName === 'pre') { if (child.type?.mdxName === 'pre') {
return ( return (
<CodeBlock <CodeBlock

12
beta/src/components/MDX/Sandpack/Console.tsx

@ -2,7 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import cn from 'classnames'; import cn from 'classnames';
import * as React from 'react'; import {useState, useRef, useEffect} from 'react';
import {IconChevron} from 'components/Icon/IconChevron'; import {IconChevron} from 'components/Icon/IconChevron';
import {SandpackCodeViewer, useSandpack} from '@codesandbox/sandpack-react'; import {SandpackCodeViewer, useSandpack} from '@codesandbox/sandpack-react';
@ -89,10 +89,10 @@ const MAX_MESSAGE_COUNT = 100;
export const SandpackConsole = ({visible}: {visible: boolean}) => { export const SandpackConsole = ({visible}: {visible: boolean}) => {
const {listen} = useSandpack(); const {listen} = useSandpack();
const [logs, setLogs] = React.useState<ConsoleData>([]); const [logs, setLogs] = useState<ConsoleData>([]);
const wrapperRef = React.useRef<HTMLDivElement>(null); const wrapperRef = useRef<HTMLDivElement>(null);
React.useEffect(() => { useEffect(() => {
let isActive = true; let isActive = true;
const unsubscribe = listen((message) => { const unsubscribe = listen((message) => {
if (!isActive) { if (!isActive) {
@ -140,9 +140,9 @@ export const SandpackConsole = ({visible}: {visible: boolean}) => {
}; };
}, [listen]); }, [listen]);
const [isExpanded, setIsExpanded] = React.useState(true); const [isExpanded, setIsExpanded] = useState(true);
React.useEffect(() => { useEffect(() => {
if (wrapperRef.current) { if (wrapperRef.current) {
wrapperRef.current.scrollTop = wrapperRef.current.scrollHeight; wrapperRef.current.scrollTop = wrapperRef.current.scrollHeight;
} }

8
beta/src/components/MDX/Sandpack/CustomPreset.tsx

@ -1,7 +1,7 @@
/* /*
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import React from 'react'; import {useRef, useState} from 'react';
import {flushSync} from 'react-dom'; import {flushSync} from 'react-dom';
import { import {
useSandpack, useSandpack,
@ -30,11 +30,11 @@ export function CustomPreset({
providedFiles: Array<string>; providedFiles: Array<string>;
}) { }) {
const {lintErrors, lintExtensions} = useSandpackLint(); const {lintErrors, lintExtensions} = useSandpackLint();
const lineCountRef = React.useRef<{[key: string]: number}>({}); const lineCountRef = useRef<{[key: string]: number}>({});
const containerRef = React.useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const {sandpack} = useSandpack(); const {sandpack} = useSandpack();
const {code} = useActiveCode(); const {code} = useActiveCode();
const [isExpanded, setIsExpanded] = React.useState(false); const [isExpanded, setIsExpanded] = useState(false);
const {activeFile} = sandpack; const {activeFile} = sandpack;
if (!lineCountRef.current[activeFile]) { if (!lineCountRef.current[activeFile]) {

8
beta/src/components/MDX/Sandpack/DownloadButton.tsx

@ -2,7 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {useSyncExternalStore} from 'react';
import {useSandpack} from '@codesandbox/sandpack-react'; import {useSandpack} from '@codesandbox/sandpack-react';
import {IconDownload} from '../../Icon/IconDownload'; import {IconDownload} from '../../Icon/IconDownload';
export interface DownloadButtonProps {} export interface DownloadButtonProps {}
@ -26,11 +26,7 @@ function useSupportsImportMap() {
return false; return false;
} }
return React.useSyncExternalStore( return useSyncExternalStore(subscribe, getCurrentValue, getServerSnapshot);
subscribe,
getCurrentValue,
getServerSnapshot
);
} }
const SUPPORTED_FILES = ['/App.js', '/styles.css']; const SUPPORTED_FILES = ['/App.js', '/styles.css'];

2
beta/src/components/MDX/Sandpack/Error.tsx

@ -2,8 +2,6 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react';
interface ErrorType { interface ErrorType {
title?: string; title?: string;
message: string; message: string;

32
beta/src/components/MDX/Sandpack/NavigationBar.tsx

@ -2,7 +2,14 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {
useRef,
useInsertionEffect,
useCallback,
useState,
useEffect,
Fragment,
} from 'react';
import cn from 'classnames'; import cn from 'classnames';
import { import {
FileTabs, FileTabs,
@ -17,11 +24,11 @@ import {Listbox} from '@headlessui/react';
// TODO: Replace with real useEvent. // TODO: Replace with real useEvent.
export function useEvent(fn: any): any { export function useEvent(fn: any): any {
const ref = React.useRef(null); const ref = useRef(null);
React.useInsertionEffect(() => { useInsertionEffect(() => {
ref.current = fn; ref.current = fn;
}, [fn]); }, [fn]);
return React.useCallback((...args: any) => { return useCallback((...args: any) => {
const f = ref.current!; const f = ref.current!;
// @ts-ignore // @ts-ignore
return f(...args); return f(...args);
@ -35,16 +42,16 @@ const getFileName = (filePath: string): string => {
export function NavigationBar({providedFiles}: {providedFiles: Array<string>}) { export function NavigationBar({providedFiles}: {providedFiles: Array<string>}) {
const {sandpack} = useSandpack(); const {sandpack} = useSandpack();
const containerRef = React.useRef<HTMLDivElement | null>(null); const containerRef = useRef<HTMLDivElement | null>(null);
const tabsRef = React.useRef<HTMLDivElement | null>(null); const tabsRef = useRef<HTMLDivElement | null>(null);
// By default, show the dropdown because all tabs may not fit. // By default, show the dropdown because all tabs may not fit.
// We don't know whether they'll fit or not until after hydration: // We don't know whether they'll fit or not until after hydration:
const [showDropdown, setShowDropdown] = React.useState(true); const [showDropdown, setShowDropdown] = useState(true);
const {activeFile, setActiveFile, visibleFiles, clients} = sandpack; const {activeFile, setActiveFile, visibleFiles, clients} = sandpack;
const clientId = Object.keys(clients)[0]; const clientId = Object.keys(clients)[0];
const {refresh} = useSandpackNavigation(clientId); const {refresh} = useSandpackNavigation(clientId);
const isMultiFile = visibleFiles.length > 1; const isMultiFile = visibleFiles.length > 1;
const hasJustToggledDropdown = React.useRef(false); const hasJustToggledDropdown = useRef(false);
// Keep track of whether we can show all tabs or just the dropdown. // Keep track of whether we can show all tabs or just the dropdown.
const onContainerResize = useEvent((containerWidth: number) => { const onContainerResize = useEvent((containerWidth: number) => {
@ -65,7 +72,7 @@ export function NavigationBar({providedFiles}: {providedFiles: Array<string>}) {
} }
}); });
React.useEffect(() => { useEffect(() => {
if (isMultiFile) { if (isMultiFile) {
const resizeObserver = new ResizeObserver((entries) => { const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) { for (const entry of entries) {
@ -111,7 +118,7 @@ export function NavigationBar({providedFiles}: {providedFiles: Array<string>}) {
)}> )}>
<FileTabs /> <FileTabs />
</div> </div>
<Listbox.Button as={React.Fragment}> <Listbox.Button as={Fragment}>
{({open}) => ( {({open}) => (
// If tabs don't fit, display the dropdown instead. // If tabs don't fit, display the dropdown instead.
// The dropdown is absolutely positioned inside the // The dropdown is absolutely positioned inside the
@ -143,10 +150,7 @@ export function NavigationBar({providedFiles}: {providedFiles: Array<string>}) {
{isMultiFile && showDropdown && ( {isMultiFile && showDropdown && (
<Listbox.Options className="absolute mt-0.5 bg-card dark:bg-card-dark px-2 left-0 right-0 mx-0 rounded-b-lg border-1 border-border dark:border-border-dark rounded-sm shadow-md"> <Listbox.Options className="absolute mt-0.5 bg-card dark:bg-card-dark px-2 left-0 right-0 mx-0 rounded-b-lg border-1 border-border dark:border-border-dark rounded-sm shadow-md">
{visibleFiles.map((filePath: string) => ( {visibleFiles.map((filePath: string) => (
<Listbox.Option <Listbox.Option key={filePath} value={filePath} as={Fragment}>
key={filePath}
value={filePath}
as={React.Fragment}>
{({active}) => ( {({active}) => (
<li <li
className={cn( className={cn(

1
beta/src/components/MDX/Sandpack/OpenInCodeSandboxButton.tsx

@ -2,7 +2,6 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react';
import {UnstyledOpenInCodeSandboxButton} from '@codesandbox/sandpack-react'; import {UnstyledOpenInCodeSandboxButton} from '@codesandbox/sandpack-react';
import {IconNewPage} from '../../Icon/IconNewPage'; import {IconNewPage} from '../../Icon/IconNewPage';

26
beta/src/components/MDX/Sandpack/Preview.tsx

@ -3,7 +3,7 @@
*/ */
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import * as React from 'react'; import {useRef, useState, useEffect, useMemo} from 'react';
import { import {
useSandpack, useSandpack,
LoadingOverlay, LoadingOverlay,
@ -28,9 +28,9 @@ type CustomPreviewProps = {
}; };
function useDebounced(value: any): any { function useDebounced(value: any): any {
const ref = React.useRef<any>(null); const ref = useRef<any>(null);
const [saved, setSaved] = React.useState(value); const [saved, setSaved] = useState(value);
React.useEffect(() => { useEffect(() => {
clearTimeout(ref.current); clearTimeout(ref.current);
ref.current = setTimeout(() => { ref.current = setTimeout(() => {
setSaved(value); setSaved(value);
@ -46,10 +46,10 @@ export function Preview({
lintErrors, lintErrors,
}: CustomPreviewProps) { }: CustomPreviewProps) {
const {sandpack, listen} = useSandpack(); const {sandpack, listen} = useSandpack();
const [isReady, setIsReady] = React.useState(false); const [isReady, setIsReady] = useState(false);
const [iframeComputedHeight, setComputedAutoHeight] = React.useState< const [iframeComputedHeight, setComputedAutoHeight] = useState<number | null>(
number | null null
>(null); );
let { let {
error: rawError, error: rawError,
@ -70,7 +70,7 @@ export function Preview({
} }
// Memoized because it's fed to debouncing. // Memoized because it's fed to debouncing.
const firstLintError = React.useMemo(() => { const firstLintError = useMemo(() => {
if (lintErrors.length === 0) { if (lintErrors.length === 0) {
return null; return null;
} else { } else {
@ -95,8 +95,8 @@ export function Preview({
// It changes too fast, causing flicker. // It changes too fast, causing flicker.
const error = useDebounced(rawError); const error = useDebounced(rawError);
const clientId = React.useRef<string>(generateRandomId()); const clientId = useRef<string>(generateRandomId());
const iframeRef = React.useRef<HTMLIFrameElement | null>(null); const iframeRef = useRef<HTMLIFrameElement | null>(null);
// SandpackPreview immediately registers the custom screens/components so the bundler does not render any of them // SandpackPreview immediately registers the custom screens/components so the bundler does not render any of them
// TODO: why are we doing this during render? // TODO: why are we doing this during render?
@ -104,7 +104,7 @@ export function Preview({
errorScreenRegisteredRef.current = true; errorScreenRegisteredRef.current = true;
loadingScreenRegisteredRef.current = true; loadingScreenRegisteredRef.current = true;
React.useEffect(function createBundler() { useEffect(function createBundler() {
const iframeElement = iframeRef.current!; const iframeElement = iframeRef.current!;
registerBundler(iframeElement, clientId.current); registerBundler(iframeElement, clientId.current);
@ -113,7 +113,7 @@ export function Preview({
}; };
}, []); }, []);
React.useEffect( useEffect(
function bundlerListener() { function bundlerListener() {
const unsubscribe = listen((message: any) => { const unsubscribe = listen((message: any) => {
if (message.type === 'resize') { if (message.type === 'resize') {

4
beta/src/components/MDX/Sandpack/ResetButton.tsx

@ -8,7 +8,7 @@ export interface ResetButtonProps {
onReset: () => void; onReset: () => void;
} }
export const ResetButton: React.FC<ResetButtonProps> = ({onReset}) => { export function ResetButton({onReset}: ResetButtonProps) {
return ( return (
<button <button
className="text-sm text-primary dark:text-primary-dark inline-flex items-center hover:text-link duration-100 ease-in transition mx-1" className="text-sm text-primary dark:text-primary-dark inline-flex items-center hover:text-link duration-100 ease-in transition mx-1"
@ -18,4 +18,4 @@ export const ResetButton: React.FC<ResetButtonProps> = ({onReset}) => {
<IconRestart className="inline ml-1 mr-1 relative" /> Reset <IconRestart className="inline ml-1 mr-1 relative" /> Reset
</button> </button>
); );
}; }

9
beta/src/components/MDX/Sandpack/SandpackRoot.tsx

@ -2,6 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import {Children, useState} from 'react';
import * as React from 'react'; import * as React from 'react';
import {SandpackProvider} from '@codesandbox/sandpack-react'; import {SandpackProvider} from '@codesandbox/sandpack-react';
import {SandpackLogLevel} from '@codesandbox/sandpack-client'; import {SandpackLogLevel} from '@codesandbox/sandpack-client';
@ -68,8 +69,8 @@ ul {
function SandpackRoot(props: SandpackProps) { function SandpackRoot(props: SandpackProps) {
let {children, autorun = true, showDevTools = false} = props; let {children, autorun = true, showDevTools = false} = props;
const [devToolsLoaded, setDevToolsLoaded] = React.useState(false); const [devToolsLoaded, setDevToolsLoaded] = useState(false);
const codeSnippets = React.Children.toArray(children) as React.ReactElement[]; const codeSnippets = Children.toArray(children) as React.ReactElement[];
const files = createFileMap(codeSnippets); const files = createFileMap(codeSnippets);
files['/styles.css'] = { files['/styles.css'] = {
@ -77,7 +78,7 @@ function SandpackRoot(props: SandpackProps) {
hidden: true, hidden: true,
}; };
let setup; let setup: SandpackSetup | undefined;
if (files['/package.json']) { if (files['/package.json']) {
setup = { setup = {
dependencies: JSON.parse(files['/package.json'].code).dependencies, dependencies: JSON.parse(files['/package.json'].code).dependencies,
@ -109,6 +110,4 @@ function SandpackRoot(props: SandpackProps) {
); );
} }
SandpackRoot.displayName = 'Sandpack';
export default SandpackRoot; export default SandpackRoot;

12
beta/src/components/MDX/Sandpack/index.tsx

@ -2,10 +2,10 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {lazy, memo, Children, Suspense} from 'react';
import {createFileMap} from './createFileMap'; import {createFileMap} from './createFileMap';
const SandpackRoot = React.lazy(() => import('./SandpackRoot')); const SandpackRoot = lazy(() => import('./SandpackRoot'));
const SandpackGlimmer = ({code}: {code: string}) => ( const SandpackGlimmer = ({code}: {code: string}) => (
<div className="sandpack my-8"> <div className="sandpack my-8">
@ -45,8 +45,8 @@ const SandpackGlimmer = ({code}: {code: string}) => (
</div> </div>
); );
export default React.memo(function SandpackWrapper(props: any): any { export default memo(function SandpackWrapper(props: any): any {
const codeSnippet = createFileMap(React.Children.toArray(props.children)); const codeSnippet = createFileMap(Children.toArray(props.children));
// To set the active file in the fallback we have to find the active file first. // To set the active file in the fallback we have to find the active file first.
// If there are no active files we fallback to App.js as default. // If there are no active files we fallback to App.js as default.
@ -63,8 +63,8 @@ export default React.memo(function SandpackWrapper(props: any): any {
} }
return ( return (
<React.Suspense fallback={<SandpackGlimmer code={activeCode} />}> <Suspense fallback={<SandpackGlimmer code={activeCode} />}>
<SandpackRoot {...props} /> <SandpackRoot {...props} />
</React.Suspense> </Suspense>
); );
}); });

7
beta/src/components/MDX/TerminalBlock.tsx

@ -2,6 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import {isValidElement, useState, useEffect} from 'react';
import * as React from 'react'; import * as React from 'react';
import {IconTerminal} from '../Icon/IconTerminal'; import {IconTerminal} from '../Icon/IconTerminal';
import {IconCopy} from 'components/Icon/IconCopy'; import {IconCopy} from 'components/Icon/IconCopy';
@ -29,7 +30,7 @@ function TerminalBlock({level = 'info', children}: TerminalBlockProps) {
if (typeof children === 'string') { if (typeof children === 'string') {
message = children; message = children;
} else if ( } else if (
React.isValidElement(children) && isValidElement(children) &&
typeof children.props.children === 'string' typeof children.props.children === 'string'
) { ) {
message = children.props.children; message = children.props.children;
@ -37,8 +38,8 @@ function TerminalBlock({level = 'info', children}: TerminalBlockProps) {
throw Error('Expected TerminalBlock children to be a plain string.'); throw Error('Expected TerminalBlock children to be a plain string.');
} }
const [copied, setCopied] = React.useState(false); const [copied, setCopied] = useState(false);
React.useEffect(() => { useEffect(() => {
if (!copied) { if (!copied) {
return; return;
} else { } else {

1
beta/src/components/PageHeading.tsx

@ -2,7 +2,6 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react';
import Breadcrumbs from 'components/Breadcrumbs'; import Breadcrumbs from 'components/Breadcrumbs';
import Tag from 'components/Tag'; import Tag from 'components/Tag';
import {RouteTag} from './Layout/useRouteMeta'; import {RouteTag} from './Layout/useRouteMeta';

19
beta/src/components/Search.tsx

@ -7,6 +7,7 @@ import {IconSearch} from 'components/Icon/IconSearch';
import Head from 'next/head'; import Head from 'next/head';
import Link from 'next/link'; import Link from 'next/link';
import Router from 'next/router'; import Router from 'next/router';
import {useState, useCallback, useEffect} from 'react';
import * as React from 'react'; import * as React from 'react';
import {createPortal} from 'react-dom'; import {createPortal} from 'react-dom';
import {siteConfig} from 'siteConfig'; import {siteConfig} from 'siteConfig';
@ -58,7 +59,7 @@ function useDocSearchKeyboardEvents({
onOpen: () => void; onOpen: () => void;
onClose: () => void; onClose: () => void;
}) { }) {
React.useEffect(() => { useEffect(() => {
function onKeyDown(event: any) { function onKeyDown(event: any) {
function open() { function open() {
// We check that no other DocSearch modal is showing before opening // We check that no other DocSearch modal is showing before opening
@ -94,14 +95,14 @@ const options = {
indexName: siteConfig.algolia.indexName, indexName: siteConfig.algolia.indexName,
}; };
let DocSearchModal: any = null; let DocSearchModal: any = null;
export const Search: React.FC<SearchProps> = ({ export function Search({
searchParameters = { searchParameters = {
hitsPerPage: 5, hitsPerPage: 5,
}, },
}) => { }: SearchProps) {
const [isShowing, setIsShowing] = React.useState(false); const [isShowing, setIsShowing] = useState(false);
const importDocSearchModalIfNeeded = React.useCallback( const importDocSearchModalIfNeeded = useCallback(
function importDocSearchModalIfNeeded() { function importDocSearchModalIfNeeded() {
if (DocSearchModal) { if (DocSearchModal) {
return Promise.resolve(); return Promise.resolve();
@ -117,7 +118,7 @@ export const Search: React.FC<SearchProps> = ({
[] []
); );
const onOpen = React.useCallback( const onOpen = useCallback(
function onOpen() { function onOpen() {
importDocSearchModalIfNeeded().then(() => { importDocSearchModalIfNeeded().then(() => {
setIsShowing(true); setIsShowing(true);
@ -126,7 +127,7 @@ export const Search: React.FC<SearchProps> = ({
[importDocSearchModalIfNeeded, setIsShowing] [importDocSearchModalIfNeeded, setIsShowing]
); );
const onClose = React.useCallback( const onClose = useCallback(
function onClose() { function onClose() {
setIsShowing(false); setIsShowing(false);
}, },
@ -191,6 +192,4 @@ export const Search: React.FC<SearchProps> = ({
)} )}
</> </>
); );
}; }
Search.displayName = 'Search';

2
beta/src/components/Seo.tsx

@ -2,7 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import React from 'react'; import * as React from 'react';
import Head from 'next/head'; import Head from 'next/head';
import {withRouter, Router} from 'next/router'; import {withRouter, Router} from 'next/router';

6
beta/src/components/SocialBanner.tsx

@ -3,7 +3,7 @@
* *
*/ */
import React from 'react'; import {useRef, useEffect} from 'react';
import cn from 'classnames'; import cn from 'classnames';
import {ExternalLink} from './ExternalLink'; import {ExternalLink} from './ExternalLink';
@ -12,8 +12,8 @@ const bannerLink = 'https://opensource.fb.com/support-ukraine';
const bannerLinkText = 'Help Provide Humanitarian Aid to Ukraine'; const bannerLinkText = 'Help Provide Humanitarian Aid to Ukraine';
export default function SocialBanner() { export default function SocialBanner() {
const ref = React.useRef<HTMLDivElement | null>(null); const ref = useRef<HTMLDivElement | null>(null);
React.useEffect(() => { useEffect(() => {
function patchedScrollTo(x: number, y: number) { function patchedScrollTo(x: number, y: number) {
if (y === 0) { if (y === 0) {
// We're trying to reset scroll. // We're trying to reset scroll.

1
beta/src/components/Tag.tsx

@ -2,7 +2,6 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react';
import cn from 'classnames'; import cn from 'classnames';
import {RouteTag} from './Layout/useRouteMeta'; import {RouteTag} from './Layout/useRouteMeta';

8
beta/src/hooks/usePendingRoute.ts

@ -3,13 +3,13 @@
*/ */
import {useRouter} from 'next/router'; import {useRouter} from 'next/router';
import React from 'react'; import {useState, useRef, useEffect} from 'react';
const usePendingRoute = () => { const usePendingRoute = () => {
const {events} = useRouter(); const {events} = useRouter();
const [pendingRoute, setPendingRoute] = React.useState<string | null>(null); const [pendingRoute, setPendingRoute] = useState<string | null>(null);
const currentRoute = React.useRef<string | null>(null); const currentRoute = useRef<string | null>(null);
React.useEffect(() => { useEffect(() => {
let routeTransitionTimer: any = null; let routeTransitionTimer: any = null;
const handleRouteChangeStart = (url: string) => { const handleRouteChangeStart = (url: string) => {

6
beta/src/pages/_app.tsx

@ -2,7 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react'; import {useEffect} from 'react';
import {AppProps} from 'next/app'; import {AppProps} from 'next/app';
import {useRouter} from 'next/router'; import {useRouter} from 'next/router';
import {ga} from '../utils/analytics'; import {ga} from '../utils/analytics';
@ -25,7 +25,7 @@ if (typeof window !== 'undefined') {
export default function MyApp({Component, pageProps}: AppProps) { export default function MyApp({Component, pageProps}: AppProps) {
const router = useRouter(); const router = useRouter();
React.useEffect(() => { useEffect(() => {
// Taken from StackOverflow. Trying to detect both Safari desktop and mobile. // Taken from StackOverflow. Trying to detect both Safari desktop and mobile.
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
if (isSafari) { if (isSafari) {
@ -40,7 +40,7 @@ export default function MyApp({Component, pageProps}: AppProps) {
} }
}, []); }, []);
React.useEffect(() => { useEffect(() => {
const handleRouteChange = (url: string) => { const handleRouteChange = (url: string) => {
ga('set', 'page', url); ga('set', 'page', url);
ga('send', 'pageview'); ga('send', 'pageview');

1
beta/src/pages/_document.tsx

@ -2,7 +2,6 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import * as React from 'react';
import {Html, Head, Main, NextScript} from 'next/document'; import {Html, Head, Main, NextScript} from 'next/document';
import {getSandpackCssText} from '@codesandbox/sandpack-react'; import {getSandpackCssText} from '@codesandbox/sandpack-react';

2
beta/src/utils/toCommaSeparatedList.tsx

@ -2,7 +2,7 @@
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Facebook, Inc. and its affiliates.
*/ */
import React from 'react'; import * as React from 'react';
const addString = (list: React.ReactNode[], string: string) => const addString = (list: React.ReactNode[], string: string) =>
list.push(<span key={`${list.length}-${string}`}>{string}</span>); list.push(<span key={`${list.length}-${string}`}>{string}</span>);

Loading…
Cancel
Save