diff --git a/sandpack-client/src/types.ts b/sandpack-client/src/types.ts index 85e513688..36b9c78d6 100644 --- a/sandpack-client/src/types.ts +++ b/sandpack-client/src/types.ts @@ -2,6 +2,7 @@ import type { ITemplate } from "codesandbox-import-util-types"; export interface SandpackBundlerFile { code: string; + readOnly?: boolean; } export type SandpackBundlerFiles = Record; diff --git a/sandpack-react/src/components/CodeEditor/CodeEditor.stories.tsx b/sandpack-react/src/components/CodeEditor/CodeEditor.stories.tsx index c9cba4750..7a9c38641 100644 --- a/sandpack-react/src/components/CodeEditor/CodeEditor.stories.tsx +++ b/sandpack-react/src/components/CodeEditor/CodeEditor.stories.tsx @@ -84,3 +84,60 @@ export const ExtensionAutocomplete: React.FC = () => ( ); + +export const ReadOnly: React.FC = () => { + return ( + <> +

Read-only by file

+ + +

Read-only global

+ + +

Read-only global and by file

+ + +

Read-only global, but no label

+ + +

Read-only by file, but no label

+ + + ); +}; diff --git a/sandpack-react/src/components/CodeEditor/CodeMirror.tsx b/sandpack-react/src/components/CodeEditor/CodeMirror.tsx index e97a9a15d..480ef4073 100644 --- a/sandpack-react/src/components/CodeEditor/CodeMirror.tsx +++ b/sandpack-react/src/components/CodeEditor/CodeMirror.tsx @@ -66,7 +66,15 @@ interface CodeMirrorProps { showInlineErrors?: boolean; wrapContent?: boolean; editorState?: SandpackEditorState; + /** + * 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; decorators?: Decorators; initMode: SandpackInitMode; id?: string; @@ -93,6 +101,7 @@ export const CodeMirror = React.forwardRef( wrapContent = false, editorState = "pristine", readOnly = false, + showReadOnly = true, decorators, initMode = "lazy", id, @@ -344,6 +353,10 @@ export const CodeMirror = React.forwardRef( {!shouldInitEditor && ( {code} )} + + {readOnly && showReadOnly && ( + Read-only + )} ); } diff --git a/sandpack-react/src/components/CodeEditor/index.tsx b/sandpack-react/src/components/CodeEditor/index.tsx index 57e9b9067..1772ac704 100644 --- a/sandpack-react/src/components/CodeEditor/index.tsx +++ b/sandpack-react/src/components/CodeEditor/index.tsx @@ -39,6 +39,15 @@ export interface CodeEditorProps { */ extensionsKeymap?: Array; id?: string; + /** + * This disables editing of the editor content by the user. + */ + readOnly?: boolean; + /** + * Controls the visibility of Read-only label, which will only + * appears when `readOnly` is `true` + */ + showReadOnly?: boolean; } export { CodeMirror as CodeEditor }; @@ -63,11 +72,13 @@ export const SandpackCodeEditor = React.forwardRef< extensions, extensionsKeymap, id, + readOnly, + showReadOnly, }, ref ) => { const { sandpack } = useSandpack(); - const { code, updateCode } = useActiveCode(); + const { code, updateCode, readOnly: readOnlyFile } = useActiveCode(); const { activePath, status, editorState } = sandpack; const shouldShowTabs = showTabs ?? sandpack.openPaths.length > 1; @@ -79,7 +90,7 @@ export const SandpackCodeEditor = React.forwardRef< return ( - {shouldShowTabs ? : null} + {shouldShowTabs && }
{showRunButton && status === "idle" ? : null} diff --git a/sandpack-react/src/components/CodeViewer/index.tsx b/sandpack-react/src/components/CodeViewer/index.tsx index 84d53fa73..258b27c58 100644 --- a/sandpack-react/src/components/CodeViewer/index.tsx +++ b/sandpack-react/src/components/CodeViewer/index.tsx @@ -61,6 +61,7 @@ export const SandpackCodeViewer = React.forwardRef< showLineNumbers={showLineNumbers} wrapContent={wrapContent} readOnly + showReadOnly={false} /> {sandpack.status === "idle" ? : null} diff --git a/sandpack-react/src/components/FileTabs/FileTabs.stories.tsx b/sandpack-react/src/components/FileTabs/FileTabs.stories.tsx index 4a6a45248..200465248 100644 --- a/sandpack-react/src/components/FileTabs/FileTabs.stories.tsx +++ b/sandpack-react/src/components/FileTabs/FileTabs.stories.tsx @@ -3,6 +3,7 @@ import * as React from "react"; import { SandpackLayout } from "../../common/Layout"; import { SandpackProvider } from "../../contexts/sandpackContext"; import { SandpackCodeViewer } from "../CodeViewer"; +import { Sandpack } from "../../"; import { FileTabs } from "./index"; diff --git a/sandpack-react/src/components/FileTabs/index.tsx b/sandpack-react/src/components/FileTabs/index.tsx index 3e0139940..97fe1c7ae 100644 --- a/sandpack-react/src/components/FileTabs/index.tsx +++ b/sandpack-react/src/components/FileTabs/index.tsx @@ -9,10 +9,15 @@ import { } from "../../utils/stringUtils"; export interface FileTabsProps { + /** + * This adds a close button next to each file with a unique trigger to close it. + */ closableTabs?: boolean; } /** + * FileTabs is a list of all open files, the active file, and its state. + * * @category Components */ export const FileTabs = ({ closableTabs }: FileTabsProps): JSX.Element => { @@ -80,11 +85,11 @@ export const FileTabs = ({ closableTabs }: FileTabsProps): JSX.Element => { type="button" > {getTriggerText(filePath)} - {closableTabs && openPaths.length > 1 ? ( + {closableTabs && openPaths.length > 1 && ( - ) : null} + )} ))}
diff --git a/sandpack-react/src/hooks/useActiveCode.ts b/sandpack-react/src/hooks/useActiveCode.ts index 6f7959d51..ad8c244cd 100644 --- a/sandpack-react/src/hooks/useActiveCode.ts +++ b/sandpack-react/src/hooks/useActiveCode.ts @@ -1,16 +1,21 @@ import { useSandpack } from "./useSandpack"; /** + * This returns the current state of the active file + * and a method to update its content. + * * @category Hooks */ export const useActiveCode = (): { code: string; + readOnly: boolean; updateCode: (newCode: string) => void; } => { const { sandpack } = useSandpack(); return { code: sandpack.files[sandpack.activePath].code, + readOnly: sandpack.files[sandpack.activePath].readOnly ?? false, updateCode: sandpack.updateCurrentFile, }; }; diff --git a/sandpack-react/src/presets/Playground.stories.tsx b/sandpack-react/src/presets/Playground.stories.tsx index 393a121fe..aaa7f1eb3 100644 --- a/sandpack-react/src/presets/Playground.stories.tsx +++ b/sandpack-react/src/presets/Playground.stories.tsx @@ -14,8 +14,8 @@ export const Main = (): JSX.Element => { return ( ); diff --git a/sandpack-react/src/presets/Sandpack.tsx b/sandpack-react/src/presets/Sandpack.tsx index 2688dd271..493300a46 100644 --- a/sandpack-react/src/presets/Sandpack.tsx +++ b/sandpack-react/src/presets/Sandpack.tsx @@ -57,6 +57,16 @@ export interface SandpackProps { recompileMode?: "immediate" | "delayed"; recompileDelay?: number; 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; }; } @@ -88,6 +98,8 @@ export const Sandpack: React.FC = (props) => { initMode: props.options?.initMode, extensions: props.options?.codeEditor?.extensions, extensionsKeymap: props.options?.codeEditor?.extensionsKeymap, + readOnly: props.options?.readOnly, + showReadOnly: props.options?.showReadOnly, }; const providerOptions: SandpackProviderProps = { diff --git a/sandpack-react/src/styles/index.css b/sandpack-react/src/styles/index.css index f91ced865..c930ebd0a 100644 --- a/sandpack-react/src/styles/index.css +++ b/sandpack-react/src/styles/index.css @@ -255,7 +255,8 @@ /* Common Styling */ .sp-tab-button { - display: block; + display: flex; + align-items: center; background: transparent; appearance: none; font-size: inherit; @@ -306,8 +307,6 @@ padding: var(--sp-space-1) var(--sp-space-3) var(--sp-space-1) var(--sp-space-2); border-radius: var(--sp-border-radius); - display: flex; - align-items: center; color: var(--sp-colors-fg-default); background-color: var(--sp-colors-bg-default); font-size: inherit; @@ -516,3 +515,16 @@ height: var(--sp-layout-height); width: 100%; } + +.sp-read-only { + font-family: var(--sp-font-mono); + font-size: 0.8em; + position: absolute; + right: var(--sp-space-2); + bottom: var(--sp-space-2); + z-index: 2; + color: var(--sp-colors-bg-active); + background-color: var(--sp-colors-fg-active); + border-radius: 99999px; + padding: calc(var(--sp-space-1) / 2) var(--sp-space-2); +} diff --git a/sandpack-react/src/types.ts b/sandpack-react/src/types.ts index d700a957e..d3bf5d1b8 100644 --- a/sandpack-react/src/types.ts +++ b/sandpack-react/src/types.ts @@ -86,6 +86,7 @@ export interface SandpackFile { code: string; hidden?: boolean; active?: boolean; + readOnly?: boolean; } export type SandpackFiles = Record; diff --git a/website/docs/docs/getting-started/custom-content.md b/website/docs/docs/getting-started/custom-content.md index a5bc23283..16da7cb42 100644 --- a/website/docs/docs/getting-started/custom-content.md +++ b/website/docs/docs/getting-started/custom-content.md @@ -134,12 +134,12 @@ default: ```jsx +``` + +**Globally:** + +```jsx + +``` + +Plus, you can hide the Read-only label which appears on top of the code editor: + +```jsx + +``` + ### openPaths and activePath You can override the entire hidden/active system with two settings (`openPaths` and `activePath`) inside the