Browse Source
* Initial Commit * play with it * oops * easier repro * import type * remove `suspense: true` * Add patch for next * Patch package * Add fallback * Enable flag * Fixes local dev env and adds better fallback for codeblock * Adds fallback for sandpack (should work fine) * turn off concurrentFeatures * Revert "turn off concurrentFeatures" This reverts commit 50158ecbd33969e707a2a91a54e822e90c2ebfde. * Update SandpackWrapper.tsx * Removed flags and setTimeouts * add timeouts and promise again * Adds bottom bezel and scroll to sandpack fallback * tinker bottombezel and remove console * Update CodeBlock.tsx * Update SandpackWrapper.tsx * removing overflows to avoid explicit scrolls * upgrade nextjs to canary * Rm patch * Fix TS * Bump Next * No more CSS jumping * Reverts the canary to use the latest Next.js `12.0.10` Co-authored-by: Dan Abramov <dan.abramov@gmail.com> Co-authored-by: Dan Abramov <dan.abramov@me.com>main
Strek
3 years ago
committed by
GitHub
14 changed files with 357 additions and 262 deletions
@ -1,7 +0,0 @@ |
|||||
/* |
|
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
|
||||
*/ |
|
||||
|
|
||||
.codeViewer { |
|
||||
padding: 6px 0.5rem !important; |
|
||||
} |
|
@ -1,7 +1,34 @@ |
|||||
/* |
/* |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
*/ |
*/ |
||||
|
import cn from 'classnames'; |
||||
|
import * as React from 'react'; |
||||
|
const CodeBlock = React.lazy(() => import('./CodeBlock')); |
||||
|
|
||||
import CodeBlock from './CodeBlock'; |
export default React.memo(function CodeBlockWrapper(props: { |
||||
|
isFromAPIAnatomy: boolean; |
||||
export default CodeBlock; |
isFromPackageImport: boolean; |
||||
|
children: string; |
||||
|
className?: string; |
||||
|
metastring: string; |
||||
|
noMargin?: boolean; |
||||
|
noMarkers?: boolean; |
||||
|
}): any { |
||||
|
const {children, isFromAPIAnatomy, isFromPackageImport} = props; |
||||
|
return ( |
||||
|
<React.Suspense |
||||
|
fallback={ |
||||
|
<pre |
||||
|
className={cn( |
||||
|
'rounded-lg leading-6 h-full w-full overflow-x-auto flex items-center bg-wash dark:bg-gray-95 shadow-lg text-[13.6px] overflow-hidden', |
||||
|
!isFromPackageImport && !isFromAPIAnatomy && 'my-8' |
||||
|
)}> |
||||
|
<div className="py-[18px] pl-5 font-normal "> |
||||
|
<p className="sp-pre-placeholder overflow-hidden">{children}</p> |
||||
|
</div> |
||||
|
</pre> |
||||
|
}> |
||||
|
<CodeBlock {...props} /> |
||||
|
</React.Suspense> |
||||
|
); |
||||
|
}); |
||||
|
@ -0,0 +1,102 @@ |
|||||
|
/* |
||||
|
* Copyright (c) Facebook, Inc. and its affiliates. |
||||
|
*/ |
||||
|
|
||||
|
import React from 'react'; |
||||
|
import { |
||||
|
SandpackProvider, |
||||
|
SandpackSetup, |
||||
|
SandpackFile, |
||||
|
} from '@codesandbox/sandpack-react'; |
||||
|
|
||||
|
import {CustomPreset} from './CustomPreset'; |
||||
|
|
||||
|
type SandpackProps = { |
||||
|
children: React.ReactChildren; |
||||
|
autorun?: boolean; |
||||
|
setup?: SandpackSetup; |
||||
|
showDevTools?: boolean; |
||||
|
}; |
||||
|
import {reducedCodeSnippet} from './utils'; |
||||
|
|
||||
|
const sandboxStyle = ` |
||||
|
* { |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
|
||||
|
body { |
||||
|
font-family: sans-serif; |
||||
|
margin: 20px; |
||||
|
padding: 0; |
||||
|
} |
||||
|
|
||||
|
h1 { |
||||
|
margin-top: 0; |
||||
|
font-size: 22px; |
||||
|
} |
||||
|
|
||||
|
h2 { |
||||
|
margin-top: 0; |
||||
|
font-size: 20px; |
||||
|
} |
||||
|
|
||||
|
h3 { |
||||
|
margin-top: 0; |
||||
|
font-size: 18px; |
||||
|
} |
||||
|
|
||||
|
h4 { |
||||
|
margin-top: 0; |
||||
|
font-size: 16px; |
||||
|
} |
||||
|
|
||||
|
h5 { |
||||
|
margin-top: 0; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
|
||||
|
h6 { |
||||
|
margin-top: 0; |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
|
||||
|
ul { |
||||
|
padding-left: 20px; |
||||
|
} |
||||
|
`.trim();
|
||||
|
|
||||
|
function SandpackWrapper(props: SandpackProps) { |
||||
|
let {children, setup, autorun = true, showDevTools = false} = props; |
||||
|
const [devToolsLoaded, setDevToolsLoaded] = React.useState(false); |
||||
|
let codeSnippets = React.Children.toArray(children) as React.ReactElement[]; |
||||
|
let isSingleFile = true; |
||||
|
|
||||
|
const files = reducedCodeSnippet(codeSnippets); |
||||
|
|
||||
|
files['/styles.css'] = { |
||||
|
code: [sandboxStyle, files['/styles.css']?.code ?? ''].join('\n\n'), |
||||
|
hidden: true, |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<div className="sandpack-container my-8" translate="no"> |
||||
|
<SandpackProvider |
||||
|
template="react" |
||||
|
customSetup={{...setup, files: files}} |
||||
|
autorun={autorun} |
||||
|
initMode="user-visible" |
||||
|
initModeObserverOptions={{rootMargin: '1400px 0px'}}> |
||||
|
<CustomPreset |
||||
|
isSingleFile={isSingleFile} |
||||
|
showDevTools={showDevTools} |
||||
|
onDevToolsLoad={() => setDevToolsLoaded(true)} |
||||
|
devToolsLoaded={devToolsLoaded} |
||||
|
/> |
||||
|
</SandpackProvider> |
||||
|
</div> |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
SandpackWrapper.displayName = 'Sandpack'; |
||||
|
|
||||
|
export default SandpackWrapper; |
@ -1,146 +1,68 @@ |
|||||
/* |
import * as React from 'react'; |
||||
* Copyright (c) Facebook, Inc. and its affiliates. |
import {reducedCodeSnippet} from './utils'; |
||||
*/ |
const Sandpack = React.lazy(() => import('./SandpackWrapper')); |
||||
|
|
||||
import React from 'react'; |
const SandpackFallBack = ({code}: {code: string}) => ( |
||||
import { |
<div className="sandpack-container my-8"> |
||||
SandpackProvider, |
<div className="shadow-lg dark:shadow-lg-dark rounded-lg"> |
||||
SandpackSetup, |
<div className="bg-wash h-10 dark:bg-card-dark flex justify-between items-center relative z-10 border-b border-border dark:border-border-dark rounded-t-lg rounded-b-none"> |
||||
SandpackFile, |
<div className="px-4 lg:px-6"> |
||||
} from '@codesandbox/sandpack-react'; |
<div className="sp-tabs"></div> |
||||
|
</div> |
||||
import {CustomPreset} from './CustomPreset'; |
<div className="px-3 flex items-center justify-end flex-grow text-right"></div> |
||||
|
</div> |
||||
type SandpackProps = { |
<div className="sp-wrapper"> |
||||
children: React.ReactChildren; |
<div className="sp-layout sp-custom-layout min-h-[216px]"> |
||||
autorun?: boolean; |
<div className="sp-stack max-h-[406px] h-auto"> |
||||
setup?: SandpackSetup; |
<div className="sp-code-editor"> |
||||
showDevTools?: boolean; |
<div className="sp-cm sp-pristine overflow-auto"> |
||||
}; |
<div className="cm-editor"> |
||||
|
<div> |
||||
const sandboxStyle = ` |
<div className="cm-gutters pl-9 sticky min-h-[192px]"> |
||||
* { |
<div className="cm-gutter cm-lineNumbers whitespace-pre sp-pre-placeholder"> |
||||
box-sizing: border-box; |
{code} |
||||
} |
</div> |
||||
|
</div> |
||||
body { |
</div> |
||||
font-family: sans-serif; |
</div> |
||||
margin: 20px; |
</div> |
||||
padding: 0; |
</div> |
||||
} |
</div> |
||||
|
<div className="sp-stack order-last xl:order-2 max-h-[406px] h-auto"> |
||||
h1 { |
<div className="p-0 sm:p-2 md:p-4 lg:p-8 bg-card dark:bg-wash-dark h-full relative rounded-b-lg lg:rounded-b-none overflow-auto"></div> |
||||
margin-top: 0; |
</div> |
||||
font-size: 22px; |
{code.split('\n').length > 16 && ( |
||||
} |
<div className="flex h-[42px] 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"></div> |
||||
|
)} |
||||
h2 { |
</div> |
||||
margin-top: 0; |
</div> |
||||
font-size: 20px; |
</div> |
||||
} |
</div> |
||||
|
); |
||||
h3 { |
|
||||
margin-top: 0; |
|
||||
font-size: 18px; |
|
||||
} |
|
||||
|
|
||||
h4 { |
|
||||
margin-top: 0; |
|
||||
font-size: 16px; |
|
||||
} |
|
||||
|
|
||||
h5 { |
|
||||
margin-top: 0; |
|
||||
font-size: 14px; |
|
||||
} |
|
||||
|
|
||||
h6 { |
|
||||
margin-top: 0; |
|
||||
font-size: 12px; |
|
||||
} |
|
||||
|
|
||||
ul { |
|
||||
padding-left: 20px; |
|
||||
} |
|
||||
`.trim();
|
|
||||
|
|
||||
function Sandpack(props: SandpackProps) { |
|
||||
let {children, setup, autorun = true, showDevTools = false} = props; |
|
||||
const [devToolsLoaded, setDevToolsLoaded] = React.useState(false); |
|
||||
let codeSnippets = React.Children.toArray(children) as React.ReactElement[]; |
|
||||
let isSingleFile = true; |
|
||||
|
|
||||
const files = codeSnippets.reduce( |
|
||||
(result: Record<string, SandpackFile>, codeSnippet: React.ReactElement) => { |
|
||||
if (codeSnippet.props.mdxType !== 'pre') { |
|
||||
return result; |
|
||||
} |
|
||||
const {props} = codeSnippet.props.children; |
|
||||
let filePath; // path in the folder structure
|
|
||||
let fileHidden = false; // if the file is available as a tab
|
|
||||
let fileActive = false; // if the file tab is shown by default
|
|
||||
|
|
||||
if (props.metastring) { |
export default React.memo(function SandpackWrapper(props: any): any { |
||||
const [name, ...params] = props.metastring.split(' '); |
const codeSnippet = reducedCodeSnippet( |
||||
filePath = '/' + name; |
React.Children.toArray(props.children) |
||||
if (params.includes('hidden')) { |
|
||||
fileHidden = true; |
|
||||
} |
|
||||
if (params.includes('active')) { |
|
||||
fileActive = true; |
|
||||
} |
|
||||
isSingleFile = false; |
|
||||
} else { |
|
||||
if (props.className === 'language-js') { |
|
||||
filePath = '/App.js'; |
|
||||
} else if (props.className === 'language-css') { |
|
||||
filePath = '/styles.css'; |
|
||||
} else { |
|
||||
throw new Error( |
|
||||
`Code block is missing a filename: ${props.children}` |
|
||||
); |
); |
||||
} |
|
||||
} |
|
||||
if (result[filePath]) { |
|
||||
throw new Error( |
|
||||
`File ${filePath} was defined multiple times. Each file snippet should have a unique path name` |
|
||||
); |
|
||||
} |
|
||||
result[filePath] = { |
|
||||
code: (props.children as string).trim(), |
|
||||
hidden: fileHidden, |
|
||||
active: fileActive, |
|
||||
}; |
|
||||
|
|
||||
return result; |
// 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
|
||||
}, |
let activeCodeSnippet = Object.keys(codeSnippet).filter( |
||||
{} |
(fileName) => |
||||
|
codeSnippet[fileName]?.active === true && |
||||
|
codeSnippet[fileName]?.hidden === false |
||||
); |
); |
||||
|
let activeCode; |
||||
files['/styles.css'] = { |
if (!activeCodeSnippet.length) { |
||||
code: [sandboxStyle, files['/styles.css']?.code ?? ''].join('\n\n'), |
activeCode = codeSnippet['/App.js'].code; |
||||
hidden: true, |
} else { |
||||
}; |
activeCode = codeSnippet[activeCodeSnippet[0]].code; |
||||
|
} |
||||
|
|
||||
return ( |
return ( |
||||
<div className="sandpack-container my-8" translate="no"> |
<> |
||||
<SandpackProvider |
<React.Suspense fallback={<SandpackFallBack code={activeCode} />}> |
||||
template="react" |
<Sandpack {...props} /> |
||||
customSetup={{...setup, files: files}} |
</React.Suspense> |
||||
autorun={autorun} |
</> |
||||
initMode="user-visible" |
|
||||
initModeObserverOptions={{rootMargin: '1400px 0px'}}> |
|
||||
<CustomPreset |
|
||||
isSingleFile={isSingleFile} |
|
||||
showDevTools={showDevTools} |
|
||||
onDevToolsLoad={() => setDevToolsLoaded(true)} |
|
||||
devToolsLoaded={devToolsLoaded} |
|
||||
/> |
|
||||
</SandpackProvider> |
|
||||
</div> |
|
||||
); |
); |
||||
} |
}); |
||||
|
|
||||
Sandpack.displayName = 'Sandpack'; |
|
||||
|
|
||||
export default Sandpack; |
|
||||
|
Loading…
Reference in new issue