@codesandbox/sandpack-react
Version:
<img style="width:100%" src="https://user-images.githubusercontent.com/4838076/143581035-ebee5ba2-9cb1-4fe8-a05b-2f44bd69bb4b.gif" alt="Component toolkit for live running code editing experiences" />
527 lines (526 loc) • 19.6 kB
TypeScript
import type { LanguageSupport } from "@codemirror/language";
import type { BundlerState, ListenerFunction, ReactDevToolsMode, SandpackBundlerFiles, SandpackClient, SandpackError, SandpackMessage, UnsubscribeFunction, SandpackLogLevel, NpmRegistry } from "@codesandbox/sandpack-client";
import type React from "react";
import type { ClientPropsOverride } from "./contexts/utils/useClient";
import type { SANDBOX_TEMPLATES } from "./templates";
import type { CodeEditorProps } from ".";
/**
* ------------------------ Public documentation ------------------------
*
* From this section on, all types are artificially created and maintained
* for public documentation purposes. So, this might not reflect precisely
* the component behavior, but it still needs to be reliable and clear for
* general usage.
*/
export interface SandpackProps {
/**
* It accepts an object, where each key is the relative
* path of that file in the sandbox folder structure. Files passed in
* through the files prop override those in the template structure.
*
* Since each template uses the same type to define the files, you can
* overwrite the contents of any of the template files.
*
* Example:
* ```js
* {
* "/App.js": "export default () => 'foo'"
* }
* ```
*/
files?: SandpackFiles;
/**
* Set of presets to easily initialize sandboxes. Each template contains
* its files, environment and dependencies, and you can overwrite it
* using `customSetup` or `dependencies`.
*/
template?: SandpackPredefinedTemplate;
/**
* Pass custom properties to set your own Sandpack environment.
*
* Since each template uses the same type to define the files, you can
* overwrite the contents of any of the template files.
*/
customSetup?: SandpackSetup;
/**
* The theme specifies the color set of the components, syntax highlight,
* and typography. Use this prop in order to match the design aspect of your website.
*
* Set as `auto` to turn it color scheme sensitive
*/
theme?: SandpackThemeProp;
/**
* Pass custom properties to customize the interface and the behavior
* of the sandbox, such as initialization mode, recompile mode, files resolver, etc.
*/
options?: SandpackOptions;
/**
* CodeSandbox team id: with this information, bundler can connect to CodeSandbox
* and unlock a few capabilities, like private dependencies.
*/
teamId?: string;
}
/**
* @category Setup
*/
export interface SandpackOptions {
/**
* List of files that will be visible for the user interacts with.
* It defaults to the main file from a given template.
*/
visibleFiles?: string[];
/**
* Use this to set a file as active by default in the editor component.
* It defaults to the main file from a given template.
*/
activeFile?: string;
editorWidthPercentage?: number;
editorHeight?: React.CSSProperties["height"];
classes?: Record<string, string>;
/**
* right to left layout
* @default false
*/
rtl?: boolean;
showNavigator?: boolean;
showLineNumbers?: boolean;
showInlineErrors?: boolean;
showRefreshButton?: boolean;
showTabs?: boolean;
showConsoleButton?: boolean;
showConsole?: boolean;
closableTabs?: boolean;
wrapContent?: boolean;
resizablePanels?: boolean;
codeEditor?: SandpackCodeOptions;
/**
* This disables editing of content by the user in all files.
*/
readOnly?: boolean;
/**
* Controls the visibility of Read-only label, which will only
* appears when `readOnly` is `true`
*/
showReadOnly?: boolean;
layout?: "preview" | "tests" | "console";
/**
* This provides a way to control how some components are going to
* be initialized on the page. The CodeEditor and the Preview components
* are quite expensive and might overload the memory usage, so this gives
* a certain control of when to initialize them.
*/
initMode?: SandpackInitMode;
initModeObserverOptions?: IntersectionObserverInit;
/**
* Determines whether or not the bundling process should start automatically
* for a component in Sandpack. By default, when the component gets closer
* to the viewport or when the page loads and the component is already in
* the viewport, the bundling process will start automatically. However,
* if this prop is set to false, the bundling process will only start when
* triggered manually by the user.
*/
autorun?: boolean;
/**
* Determines whether or not the component should automatically reload when
* changes are made to the code. When this prop is set to true, any changes
* made to the code will trigger an automatic reload of the component,
* allowing the user to see the changes immediately. However, if this prop
* is set to false, the component will need to be manually reloaded by the
* user to see the changes.
*/
autoReload?: boolean;
recompileMode?: "immediate" | "delayed";
recompileDelay?: number;
/**
* By default, Sandpack generates a random value to use as an id.
* Use this to override this value if you need predictable values.
*/
id?: string;
logLevel?: SandpackLogLevel;
bundlerURL?: string;
startRoute?: string;
skipEval?: boolean;
fileResolver?: FileResolver;
externalResources?: string[];
}
/**
* @category Setup
*/
export interface SandpackSetup {
/**
* Any template will include the needed dependencies,
* but you can specify any additional dependencies. The key
* should be the name of the package, while the value is the version,
* in exactly the same format as it would be inside package.json.
*
* Examples:
* ```js
* {
* "react": "latest",
* "@material-ui/core": "4.12.3",
* }
* ```
*/
dependencies?: Record<string, string>;
/**
* Sandpack doesn't install devDependencies, because most tools in there
* were build tools, which is not necessary to properly run a sandbox,
* but maybe required for running locally or export to CodeSandbox.
*
* Examples:
* ```js
* {
* "@types/react": "latest",
* }
* ```
*/
devDependencies?: Record<string, string>;
/**
* The entry file is the starting point of the bundle process.
*
* If you change the path of the entry file, make sure you control
* all the files that go into the bundle process, as prexisting
* settings in the template might not work anymore.
*/
entry?: string;
/**
* Each sandbox has its own bundler attached to them which are configured
* to support a specific framework and emulate their official CLI tools.
* They are not one-to-one implementations and thus do not support advanced
* configuration like custom webpack configurations or ejecting. However,
* they are designed to mirror the default behavior of the framework
*/
environment?: SandboxEnvironment;
/**
* The custom private npm registry setting makes it possible
* to retrieve npm packages from your own npm registry.
*
* Examples:
* ```js
* {
* enabledScopes: ["@codesandbox"],
* registryUrl: "//my-registry.domain.com",
* limitToScopes: true, // if false all packages will be fetched from custom registry
* registryAuthToken: "SECRET" // optional value, if public
* }
* ```
*/
npmRegistries?: NpmRegistry[];
exportOptions?: SandpackExportOptions;
}
interface SandpackExportOptions {
/**
* Workspace API key from codesandbox.io/t/permissions.
* When set, the sandbox will be create inside the given workspace id.
*/
apiToken: string;
/**
* The default visibility of the new sandboxes inside the workspace.
*
* @note Use `private` if there is a private registry or private NPM
* configured in your workspace.
*/
privacy: "private" | "public";
}
/**
* @category Setup
*/
export type SandboxEnvironment = "angular-cli" | "create-react-app" | "create-react-app-typescript" | "svelte" | "parcel" | "vue-cli" | "static" | "solid" | "node";
/**
* @category Setup
*/
export type SandpackPredefinedTemplate = keyof typeof SANDBOX_TEMPLATES;
/**
* @category Setup
*/
export interface SandpackFile {
code: string;
hidden?: boolean;
active?: boolean;
readOnly?: boolean;
}
/**
* `immediate`: It immediately mounts all components, such as the code-editor
* and the preview - this option might overload the memory usage
* and resource from the browser on a page with multiple instances;
*
* `lazy`: Only initialize the components when the user is about to scroll
* them to the viewport and keep these components mounted until the user
* leaves the page - this is the default value;
*
* `user-visible`: Only initialize the components when the user is about
* to scroll them to the viewport, but differently from lazy, this option
* unmounts those components once it's no longer in the viewport.
*
* @category Setup
*/
export type SandpackInitMode = "immediate" | "lazy" | "user-visible";
/**
* @category Setup
*/
export interface CustomLanguage {
name: string;
extensions: string[];
language: LanguageSupport;
}
/**
* @category Theme
*/
export type SandpackPredefinedTheme = "light" | "dark" | "auto";
/**
* @category Theme
*/
export interface SandpackTheme {
colors: {
surface1: string;
surface2: string;
surface3: string;
disabled: string;
base: string;
clickable: string;
hover: string;
accent: string;
error?: string;
errorSurface?: string;
warning?: string;
warningSurface?: string;
};
syntax: {
plain: string | SandpackSyntaxStyle;
comment: string | SandpackSyntaxStyle;
keyword: string | SandpackSyntaxStyle;
definition: string | SandpackSyntaxStyle;
punctuation: string | SandpackSyntaxStyle;
property: string | SandpackSyntaxStyle;
tag: string | SandpackSyntaxStyle;
static: string | SandpackSyntaxStyle;
string?: string | SandpackSyntaxStyle;
};
font: {
body: string;
mono: string;
size: string;
lineHeight: string;
};
}
/**
* @category Theme
*/
interface SandpackSyntaxStyle {
color?: string;
fontStyle?: "normal" | "italic";
fontWeight?: "normal" | "bold" | "100" | "200" | "300" | "400" | "500" | "600" | "700" | "800" | "900";
textDecoration?: "none" | "underline" | "line-through" | "underline line-through";
}
/**
* @category Theme
*/
export type SandpackThemeProp = SandpackPredefinedTheme | DeepPartial<SandpackTheme>;
/**
*
* ------------------------ Internal types ---------------------------
*
* From this section on, all types are hidden because most of them are
* strictly related to the internal typing system, and they are not
* helpful for public documentation.
*
* For public purpose use SandpackProps instead.
*/
export type TemplateFiles<Name extends SandpackPredefinedTemplate> = keyof typeof SANDBOX_TEMPLATES[Name]["files"];
export interface SandpackInternal {
<Files extends SandpackFiles | any, TemplateName extends SandpackPredefinedTemplate = "vanilla">(props: SandpackInternalProps<Files, TemplateName> & {
files?: Files;
template?: TemplateName;
}): JSX.Element;
}
export interface SandpackInternalProvider {
<Files extends SandpackFiles, TemplateName extends SandpackPredefinedTemplate>(
/**
* Infer files & template values
*/
props: React.PropsWithChildren<SandpackProviderProps<Files, TemplateName> & {
files?: Files;
template?: TemplateName;
}>): React.ReactElement<SandpackProviderProps, React.Provider<SandpackProviderState>> | null;
}
interface SandpackRootProps<Files extends SandpackFiles | any, TemplateName extends SandpackPredefinedTemplate> {
files?: Files;
template?: TemplateName;
customSetup?: SandpackSetup;
theme?: SandpackThemeProp;
teamId?: string;
sandboxId?: string;
}
export interface SandpackInternalOptions<Files extends SandpackFiles | any = any, TemplateName extends SandpackPredefinedTemplate = SandpackPredefinedTemplate> {
visibleFiles?: Array<Files extends SandpackFiles ? TemplateFiles<TemplateName> | keyof Files : TemplateFiles<TemplateName>>;
activeFile?: Files extends SandpackFiles ? TemplateFiles<TemplateName> | keyof Files : TemplateFiles<TemplateName>;
initMode?: SandpackInitMode;
initModeObserverOptions?: IntersectionObserverInit;
autorun?: boolean;
autoReload?: boolean;
recompileMode?: "immediate" | "delayed";
recompileDelay?: number;
id?: string;
logLevel?: SandpackLogLevel;
bundlerURL?: string;
bundlerTimeOut?: number;
startRoute?: string;
skipEval?: boolean;
fileResolver?: FileResolver;
externalResources?: string[];
classes?: Record<string, string>;
}
interface SandpackInternalProps<Files extends SandpackFiles | any, TemplateName extends SandpackPredefinedTemplate> extends SandpackRootProps<Files, TemplateName> {
options?: SandpackInternalOptions<Files, TemplateName> & {
editorWidthPercentage?: number;
editorHeight?: React.CSSProperties["height"];
/**
* right to left layout
* @default false
*/
rtl?: boolean;
showNavigator?: boolean;
showLineNumbers?: boolean;
showInlineErrors?: boolean;
showRefreshButton?: boolean;
showTabs?: boolean;
showConsoleButton?: boolean;
showConsole?: boolean;
closableTabs?: boolean;
wrapContent?: boolean;
resizablePanels?: boolean;
codeEditor?: SandpackCodeOptions;
/**
* This disables editing of content by the user in all files.
*/
readOnly?: boolean;
/**
* Controls the visibility of Read-only label, which will only
* appears when `readOnly` is `true`
*/
showReadOnly?: boolean;
layout?: "preview" | "tests" | "console";
};
}
export interface SandpackProviderProps<Files extends SandpackFiles = SandpackFiles, TemplateName extends SandpackPredefinedTemplate = SandpackPredefinedTemplate> extends SandpackRootProps<Files, TemplateName>, React.HTMLAttributes<HTMLDivElement> {
options?: SandpackInternalOptions<Files, TemplateName>;
children?: React.ReactNode;
}
export type SandpackClientDispatch = (msg: SandpackMessage, clientId?: string) => void;
export type SandpackClientListen = (listener: ListenerFunction, clientId?: string) => UnsubscribeFunction;
export type SandpackContext = SandpackState & {
dispatch: SandpackClientDispatch;
listen: SandpackClientListen;
};
export interface SandpackState {
bundlerState: BundlerState | undefined;
/**
* List the file path listed in the file tab,
* which will allow the user to interact with.
*/
visibleFiles: string[];
/**
* List the file path listed in the file tab,
* Can only be changed through the properties of SandpackProvider (files/options)
*
* @internal
*/
visibleFilesFromProps: string[];
/**
* Path to the file will be open in the code editor
* when the component mounts
*/
activeFile: string;
startRoute?: string;
autoReload: boolean;
/**
* Returns the current state of the editor, meaning that any
* changes from the original `files` must return a `dirty` value;
* otherwise, it'll return `pristine`
*/
editorState: EditorState;
teamId?: string;
exportOptions?: SandpackExportOptions;
error: SandpackError | null;
files: SandpackBundlerFiles;
environment?: SandboxEnvironment;
status: SandpackStatus;
initMode: SandpackInitMode;
clients: Record<string, InstanceType<typeof SandpackClient>>;
runSandpack: () => Promise<void>;
registerBundler: (iframe: HTMLIFrameElement, clientId: string, clientPropsOverride?: ClientPropsOverride) => Promise<void>;
unregisterBundler: (clientId: string) => void;
updateFile: (pathOrFiles: string | SandpackFiles, code?: string, shouldUpdatePreview?: boolean) => void;
addFile: (pathOrFiles: string | SandpackFiles, code?: string, shouldUpdatePreview?: boolean) => void;
updateCurrentFile: (newCode: string, shouldUpdatePreview?: boolean) => void;
openFile: (path: string) => void;
closeFile: (path: string) => void;
deleteFile: (path: string, shouldUpdatePreview?: boolean) => void;
setActiveFile: (path: string) => void;
resetFile: (path: string) => void;
resetAllFiles: () => void;
registerReactDevTools: (value: ReactDevToolsMode) => void;
/**
* Element refs
* Different components inside the SandpackProvider might register certain elements of interest for sandpack
* eg: lazy anchor - if no component registers this, then the sandpack runs on mount, without lazy mode
*/
lazyAnchorRef: React.RefObject<HTMLDivElement>;
unsubscribeClientListenersRef: React.MutableRefObject<Record<string, Record<string, UnsubscribeFunction>>>;
queuedListenersRef: React.MutableRefObject<Record<string, Record<string, ListenerFunction>>>;
}
export type SandpackStatus = "initial" | "idle" | "running" | "timeout" | "done";
export type EditorState = "pristine" | "dirty";
export interface SandboxTemplate {
files: SandpackBundlerFiles;
dependencies: Record<string, string>;
devDependencies?: Record<string, string>;
entry?: string;
main: string;
environment: SandboxEnvironment;
}
export type SandpackFiles = Record<string, string | SandpackFile>;
/**
* Custom properties to be used in the SandpackCodeEditor component,
* some of which are exclusive to customize the CodeMirror instance.
* @hidden
*/
export interface SandpackCodeOptions {
/**
* CodeMirror extensions for the editor state, which can
* provide extra features and functionalities to the editor component.
*/
extensions?: CodeEditorProps["extensions"];
/**
* Property to register CodeMirror extension keymap.
*/
extensionsKeymap?: CodeEditorProps["extensionsKeymap"];
/**
* Provides a way to add custom language modes by supplying a language
* type, applicable file extensions, and a LanguageSupport instance
* for that syntax mode
*/
additionalLanguages?: CodeEditorProps["additionalLanguages"];
}
export type DeepPartial<Type> = {
[Property in keyof Type]?: DeepPartial<Type[Property]>;
};
export interface FileResolver {
isFile: (path: string) => Promise<boolean>;
readFile: (path: string) => Promise<string>;
}
export interface SandpackProviderState {
files: SandpackBundlerFiles;
environment?: SandboxEnvironment;
visibleFiles: Array<TemplateFiles<SandpackPredefinedTemplate> | string>;
visibleFilesFromProps: Array<TemplateFiles<SandpackPredefinedTemplate> | string>;
activeFile: TemplateFiles<SandpackPredefinedTemplate> | string;
startRoute?: string;
initMode: SandpackInitMode;
bundlerState?: BundlerState;
error: SandpackError | null;
sandpackStatus: SandpackStatus;
editorState: EditorState;
reactDevTools?: ReactDevToolsMode;
}
export {};