beta/src/components/MDX/Sandpack/CustomPreset.tsx (94 lines of code) (raw):

/* * Copyright (c) Facebook, Inc. and its affiliates. */ import React from 'react'; // @ts-ignore import {flushSync} from 'react-dom'; import { useSandpack, useActiveCode, SandpackCodeEditor, SandpackThemeProvider, SandpackReactDevTools, } from '@codesandbox/sandpack-react'; import scrollIntoView from 'scroll-into-view-if-needed'; import cn from 'classnames'; import {IconChevron} from 'components/Icon/IconChevron'; import {NavigationBar} from './NavigationBar'; import {Preview} from './Preview'; import {CustomTheme} from './Themes'; export function CustomPreset({ isSingleFile, showDevTools, onDevToolsLoad, devToolsLoaded, }: { isSingleFile: boolean; showDevTools: boolean; devToolsLoaded: boolean; onDevToolsLoad: () => void; }) { const lineCountRef = React.useRef<{[key: string]: number}>({}); const containerRef = React.useRef<HTMLDivElement>(null); const {sandpack} = useSandpack(); const {code} = useActiveCode(); const [isExpanded, setIsExpanded] = React.useState(false); const {activePath} = sandpack; if (!lineCountRef.current[activePath]) { lineCountRef.current[activePath] = code.split('\n').length; } const lineCount = lineCountRef.current[activePath]; const isExpandable = lineCount > 16 || isExpanded; return ( <> <div className="shadow-lg dark:shadow-lg-dark rounded-lg" ref={containerRef}> <NavigationBar showDownload={isSingleFile} /> <SandpackThemeProvider theme={CustomTheme}> <div ref={sandpack.lazyAnchorRef} className={cn( 'sp-layout sp-custom-layout', showDevTools && devToolsLoaded && 'sp-layout-devtools', isExpanded && 'sp-layout-expanded' )}> <SandpackCodeEditor showLineNumbers showInlineErrors showTabs={false} showRunButton={false} /> <Preview className="order-last xl:order-2" isExpanded={isExpanded} /> {isExpandable && ( <button translate="yes" className="flex text-base justify-between dark:border-card-dark bg-wash dark:bg-card-dark items-center z-10 rounded-t-none p-1 w-full order-2 xl:order-last border-b-1 relative top-0" onClick={() => { const nextIsExpanded = !isExpanded; flushSync(() => { setIsExpanded(nextIsExpanded); }); if (!nextIsExpanded && containerRef.current !== null) { scrollIntoView(containerRef.current, { scrollMode: 'if-needed', block: 'nearest', inline: 'nearest', }); } }}> <span className="flex p-2 focus:outline-none text-primary dark:text-primary-dark"> <IconChevron className="inline mr-1.5 text-xl" displayDirection={isExpanded ? 'up' : 'down'} /> {isExpanded ? 'Show less' : 'Show more'} </span> </button> )} </div> {showDevTools && ( <SandpackReactDevTools onLoadModule={onDevToolsLoad} /> )} </SandpackThemeProvider> </div> </> ); }