Browse Source

[Beta] Code style tweaks (#5104)

* Use named React imports

* More manual edits

* Remove displayNames

* rm dead code
main
dan 2 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. 12
      beta/src/components/Icon/IconClose.tsx
  9. 6
      beta/src/components/Icon/IconCodeBlock.tsx
  10. 12
      beta/src/components/Icon/IconCopy.tsx
  11. 6
      beta/src/components/Icon/IconDeepDive.tsx
  12. 6
      beta/src/components/Icon/IconDownload.tsx
  13. 12
      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. 12
      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. 12
      beta/src/components/Icon/IconNote.tsx
  23. 6
      beta/src/components/Icon/IconRestart.tsx
  24. 12
      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. 12
      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';

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

@ -2,10 +2,11 @@
* 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 ( return (
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -22,7 +23,4 @@ export const IconClose = React.memo<JSX.IntrinsicElements['svg']>(
<line x1={6} y1={6} x2={18} y2={18} /> <line x1={6} y1={6} x2={18} y2={18} />
</svg> </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';

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

@ -2,10 +2,11 @@
* 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 ( return (
<svg <svg
className={className} className={className}
@ -28,7 +29,4 @@ export const IconCopy = React.memo<JSX.IntrinsicElements['svg']>(
/> />
</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';

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

@ -2,10 +2,11 @@
* 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 ( return (
<svg <svg
className={className} className={className}
@ -18,7 +19,4 @@ export const IconError = React.memo<JSX.IntrinsicElements['svg']>(
<path d="M14.2798 5.95996L6.22705 14.0127" stroke="white" /> <path d="M14.2798 5.95996L6.22705 14.0127" stroke="white" />
</svg> </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';

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

@ -2,11 +2,12 @@
* 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 ( return (
<svg <svg
className={cn('inline -mt-0.5', className)} className={cn('inline -mt-0.5', className)}
@ -20,7 +21,4 @@ export const IconHint = React.memo<JSX.IntrinsicElements['svg']>(
/> />
</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';

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

@ -2,10 +2,11 @@
* 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 ( return (
<svg <svg
className={className} className={className}
@ -20,7 +21,4 @@ export const IconNote = React.memo<JSX.IntrinsicElements['svg']>(
/> />
</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';

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

@ -2,10 +2,11 @@
* 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 ( return (
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -23,7 +24,4 @@ export const IconRss = React.memo<JSX.IntrinsicElements['svg']>(
<circle cx={5} cy={19} r={1} /> <circle cx={5} cy={19} r={1} />
</svg> </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;

12
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 React.cloneElement(child, { return 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