Skip to content

Editor: Add hover tooltips, intelligent completions, auto formatting, diagnostics #4720

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 71 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
2332834
wip
justjake May 24, 2022
84ca01c
fix race condition in type fetch logic
justjake May 25, 2022
0f4432a
Wrap sandbox editor in React.memo to avoid weird glitching
justjake May 25, 2022
a1095bb
remove unneeded component
justjake Jun 2, 2022
28941e5
clearer name for normalizePath
justjake Jun 2, 2022
da96af4
better comment on advanced autcomplete insertion
justjake Jun 2, 2022
fd40c1c
remove unneeded tooltip optimizations
justjake Jun 2, 2022
758ea90
minor cleanups and renaming for clarity
justjake Jun 2, 2022
e4d0f0e
extract required extensions
justjake Jun 2, 2022
261502b
extract format extension
justjake Jun 2, 2022
bb4aeae
extract diagnostic extension
justjake Jun 2, 2022
737f98f
extract autocompletion extension
justjake Jun 2, 2022
40964d4
extract hover tooltip extension
justjake Jun 2, 2022
a100175
normalize function declaration type
justjake Jun 2, 2022
5a03a56
improve tooltip size and word breaking
justjake Jun 2, 2022
fe197b4
note about renderToStaticMarkup use
justjake Jun 2, 2022
3af308e
Consistent return to fix build
justjake Jun 2, 2022
0ecf88c
disable eslint unused warning for type-heavy file
justjake Jun 2, 2022
0563226
Fix autocomplete buggy dismissal behavior
justjake Jun 2, 2022
b1da82f
use normal imports instead of importScript
justjake Jun 2, 2022
3cc6e67
switch back to position: fixed tooltips (default)
justjake Jun 2, 2022
7025bd4
improve toolip style, esp in dark mode. add rounded borders
justjake Jun 2, 2022
920e677
fix diagnostic color in dark mode
justjake Jun 2, 2022
cc54950
lazy-load the extension itself
justjake Jun 2, 2022
8f729c0
remove debug logging
justjake Jun 2, 2022
47dc6e6
remove debug from lockfile
justjake Jun 2, 2022
2eb8850
pre-package react type files
justjake Jun 2, 2022
8e4f14c
make constant more inline
justjake Jun 2, 2022
6a3dc05
Update beta/src/components/MDX/Sandpack/sandpack-tsserver/ensurePathB…
justjake Jun 3, 2022
92420ac
Add policy to hide/show types
justjake Jun 3, 2022
d35550e
Add policy to hide/show TSDoc tags like @see, etc
justjake Jun 3, 2022
3eb934f
Merge branch 'jake--tsserver' of https://github.com/justjake/reactjs.…
justjake Jun 3, 2022
28ebbc8
rename policy -> config; fix doc links; hide unused var suggestions
justjake Jun 3, 2022
141b61a
code paths
justjake Jun 3, 2022
0d3c948
Actually save ts-lib cache into localStorage
justjake Jun 3, 2022
4e4dcda
missing type
justjake Jun 4, 2022
2d2966c
hide most semantic diagnostic other than imports
justjake Jun 4, 2022
5ec8d62
heuristic to hide random global completions
justjake Jun 4, 2022
e1318a2
revert comment
justjake Jun 4, 2022
43cf82a
remove useless memo around editor
justjake Jun 4, 2022
b24628e
upgrade to sandpack-react@v0.19.8-experimental.5
justjake Jun 4, 2022
bcee493
remove useMemo around extensions list
justjake Jun 4, 2022
1d33643
Dont show tiny empty tooltip
justjake Jun 5, 2022
e366649
Add back bridge debug logging as config option
justjake Jun 5, 2022
abe98c5
terminate worker on unmount
justjake Jun 5, 2022
b25bcf5
use bridge to read cache instead of passing as param
justjake Jun 5, 2022
adcf358
Only create one worker
justjake Jun 6, 2022
5b569b7
lazily create global worker in provider
justjake Jun 6, 2022
00d6f3b
comment more configs
justjake Jun 6, 2022
b0d2eb2
fix updateFile codepath returns
justjake Jun 6, 2022
dca8af5
load the worker & extension logic once user interacts
justjake Jun 6, 2022
d791359
better name for this function
justjake Jun 6, 2022
c1392d9
Avoid creating worker twice
justjake Jun 6, 2022
d5f87b3
work around inconsistent load order
justjake Jun 6, 2022
6f4cf47
format code on enter (preserves caret position)
justjake Jun 7, 2022
ad85454
reduce tooltip max-width further
justjake Jun 7, 2022
667c896
intantiate typescript env after interaction
justjake Jun 7, 2022
c91c918
destroy typescript environment when editor scrolled off-screen
justjake Jun 7, 2022
b3e1ff1
clarify variable names
justjake Jun 7, 2022
67cdf9a
re-enable sandback error reporting
justjake Jun 7, 2022
0c9aa99
seperate config for .ts/.tsx files
justjake Jun 24, 2022
8af32cc
Add support for ```tsx examples
justjake Jun 24, 2022
9f92702
WIP: usestate.md: switch js -> tsx in many cases
justjake Jun 24, 2022
38901e3
Compile each TSX file to JS, allow user to edit either
justjake Jun 25, 2022
f689acd
format transpiled .js file
justjake Jun 26, 2022
e887ac7
fix transaction conflict issue
justjake Jun 26, 2022
e89797d
really fix this
justjake Jun 26, 2022
086cb39
make cache more reliable
justjake Jun 26, 2022
db29056
add prettier formatting
justjake Jun 27, 2022
4c79858
yarn??
justjake Jun 27, 2022
6ae7be1
fix lint error
justjake Jun 27, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions beta/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"check-all": "npm-run-all prettier lint:fix tsc"
},
"dependencies": {
"@codesandbox/sandpack-react": "v0.19.8-experimental.4",
"@codesandbox/sandpack-react": "v0.19.8-experimental.6",
"@docsearch/css": "3.0.0-alpha.41",
"@docsearch/react": "3.0.0-alpha.41",
"@headlessui/react": "^1.3.0",
Expand All @@ -48,10 +48,12 @@
"@types/mdx-js__react": "^1.5.2",
"@types/node": "^14.6.4",
"@types/parse-numeric-range": "^0.0.1",
"@types/prettier": "^2.6.3",
"@types/react": "^18.0.9",
"@types/react-dom": "^18.0.5",
"@typescript-eslint/eslint-plugin": "2.x",
"@typescript-eslint/parser": "2.x",
"@typescript/vfs": "^1.3.5",
"asyncro": "^3.0.0",
"autoprefixer": "^10.4.2",
"babel-eslint": "10.x",
Expand Down Expand Up @@ -87,7 +89,7 @@
"retext-smartypants": "^4.0.0",
"rss": "^1.2.2",
"tailwindcss": "^3.0.22",
"typescript": "^4.0.2",
"typescript": "^4.6.4",
"unist-util-visit": "^2.0.3",
"webpack-bundle-analyzer": "^4.5.0"
},
Expand Down
32 changes: 20 additions & 12 deletions beta/src/components/MDX/Sandpack/CustomPreset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,54 @@
*/
import React from 'react';
// @ts-ignore
import {flushSync} from 'react-dom';
import {
useSandpack,
useActiveCode,
SandpackCodeEditor,
SandpackThemeProvider,
SandpackReactDevTools,
SandpackThemeProvider,
useActiveCode,
useSandpack,
} from '@codesandbox/sandpack-react';
import scrollIntoView from 'scroll-into-view-if-needed';
import cn from 'classnames';
import {flushSync} from 'react-dom';
import scrollIntoView from 'scroll-into-view-if-needed';

import {IconChevron} from 'components/Icon/IconChevron';
import {NavigationBar} from './NavigationBar';
import {Preview} from './Preview';
import {useTypescriptExtension} from './sandpack-tsserver/useTypescriptExtension';
import {CustomTheme} from './Themes';
import {useSandpackLint} from './useSandpackLint';

// Workaround for https://github.com/reactjs/reactjs.org/issues/4686#issuecomment-1137402613.
const emptyArray: Array<any> = [];
import {useTypescriptCompiler} from './sandpack-tsserver/useTypescriptCompiler';

export function CustomPreset({
isSingleFile,
showDevTools,
showJsForTsxFiles,
onDevToolsLoad,
devToolsLoaded,
}: {
isSingleFile: boolean;
showDevTools: boolean;
showJsForTsxFiles: boolean;
devToolsLoaded: boolean;
onDevToolsLoad: () => void;
}) {
const {lintErrors, lintExtensions} = useSandpackLint();
const {extension: typescriptExtensions, envId: typescriptEnvId} =
useTypescriptExtension(showJsForTsxFiles ? 'visible' : 'interaction');
const {reset: resetTsToJs} = useTypescriptCompiler(
showJsForTsxFiles,
typescriptEnvId
);

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;
const code = sandpack.files[activePath]?.code || '';

if (!lineCountRef.current[activePath]) {
lineCountRef.current[activePath] = code.split('\n').length;
}
Expand All @@ -53,7 +62,7 @@ export function CustomPreset({
<div
className="shadow-lg dark:shadow-lg-dark rounded-lg"
ref={containerRef}>
<NavigationBar showDownload={isSingleFile} />
<NavigationBar showDownload={isSingleFile} onReset={resetTsToJs} />
<SandpackThemeProvider theme={CustomTheme}>
<div
ref={sandpack.lazyAnchorRef}
Expand All @@ -67,8 +76,7 @@ export function CustomPreset({
showInlineErrors
showTabs={false}
showRunButton={false}
extensions={lintExtensions}
extensionsKeymap={emptyArray}
extensions={[lintExtensions, typescriptExtensions]}
/>
<Preview
className="order-last xl:order-2"
Expand Down
9 changes: 8 additions & 1 deletion beta/src/components/MDX/Sandpack/NavigationBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ import {ResetButton} from './ResetButton';
import {DownloadButton} from './DownloadButton';
import {FilesDropdown} from './FilesDropdown';

export function NavigationBar({showDownload}: {showDownload: boolean}) {
export function NavigationBar({
showDownload,
onReset,
}: {
showDownload: boolean;
onReset: () => void;
}) {
const {sandpack} = useSandpack();
const [dropdownActive, setDropdownActive] = React.useState(false);
const {openPaths, clients} = sandpack;
Expand Down Expand Up @@ -42,6 +48,7 @@ export function NavigationBar({showDownload}: {showDownload: boolean}) {
}, [openPaths.length, resizeHandler]);

const handleReset = () => {
onReset();
sandpack.resetAllFiles();
refresh();
};
Expand Down
29 changes: 28 additions & 1 deletion beta/src/components/MDX/Sandpack/SandpackRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,30 +63,57 @@ ul {
}
`.trim();

const TSCONFIG = {
include: ['./**/*'],
compilerOptions: {
target: 'es2021',
module: 'es2020',
lib: ['es2021', 'es2020', 'dom', 'dom.iterable'],
esModuleInterop: true,
allowJs: true,
checkJs: true,
resolveJsonModule: true,
// jsx: 'react-jsx',
jsx: 'preserve',
},
};
const TSCONFIG_AS_JSON = JSON.stringify(TSCONFIG, null, ' ');

function SandpackRoot(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 = createFileMap(codeSnippets);
const template = files['/App.tsx'] ? 'react-ts' : 'react';

files['/styles.css'] = {
code: [sandboxStyle, files['/styles.css']?.code ?? ''].join('\n\n'),
hidden: true,
};

// Always add a tsconfig that supports JS, so we can use TS superpowers like
// imports & tab completion in JS examples.
if (!files['/tsconfig.json']) {
files['/tsconfig.json'] = {
code: TSCONFIG_AS_JSON,
hidden: true,
};
}

return (
<div className="sandpack-container my-8" translate="no">
<SandpackProvider
template="react"
template={template}
customSetup={{...setup, files: files}}
autorun={autorun}
initMode="user-visible"
initModeObserverOptions={{rootMargin: '1400px 0px'}}
bundlerURL="https://3f1bb162.sandpack-bundler.pages.dev"
logLevel={SandpackLogLevel.None}>
<CustomPreset
showJsForTsxFiles={template === 'react-ts'}
isSingleFile={isSingleFile}
showDevTools={showDevTools}
onDevToolsLoad={() => setDevToolsLoaded(true)}
Expand Down
2 changes: 2 additions & 0 deletions beta/src/components/MDX/Sandpack/createFileMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export const createFileMap = (codeSnippets: any) => {
filePath = '/App.js';
} else if (props.className === 'language-css') {
filePath = '/styles.css';
} else if (props.className === 'language-tsx') {
filePath = '/App.tsx';
} else {
throw new Error(
`Code block is missing a filename: ${props.children}`
Expand Down
5 changes: 3 additions & 2 deletions beta/src/components/MDX/Sandpack/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,16 @@ export default React.memo(function SandpackWrapper(props: any): any {
const codeSnippet = createFileMap(React.Children.toArray(props.children));

// 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,tsx} as default.
let activeCodeSnippet = Object.keys(codeSnippet).filter(
(fileName) =>
codeSnippet[fileName]?.active === true &&
codeSnippet[fileName]?.hidden === false
);
let activeCode;
if (!activeCodeSnippet.length) {
activeCode = codeSnippet['/App.js'].code;
const defaultActiveFile = codeSnippet['/App.js'] || codeSnippet['/App.tsx'];
activeCode = defaultActiveFile.code;
} else {
activeCode = codeSnippet[activeCodeSnippet[0]].code;
}
Expand Down
Loading