/* Copyright 2026 Marimo. All rights reserved. */ import { useMemo, useRef, useState } from "react"; import type { EditorView } from "@codemirror/view"; import { useAtomValue } from "jotai"; import { CellEditor } from "@/components/editor/cell/code/cell-editor"; import { CellStatusComponent } from "@/components/editor/cell/CellStatus"; import { RunButton } from "@/components/editor/cell/RunButton"; import { StopButton } from "@/components/editor/cell/StopButton"; import { useRunCell } from "@/components/editor/cell/useRunCells"; import { Slide as CellOutputSlide } from "@/components/slides/slide"; import { useUserConfig } from "@/core/config/config"; import { cellNeedsRun, cellStatusClasses, isUninstantiated, } from "@/core/cells/utils"; import type { CellData, CellRuntimeState } from "@/core/cells/types"; import type { LanguageAdapterType } from "@/core/codemirror/language/types"; import { connectionAtom } from "@/core/network/connection"; import { useTheme } from "@/theme/useTheme"; import { cn } from "@/utils/cn"; import { ReadonlyCode } from "../editor/code/readonly-python-code"; import { languageAdapterFromCode } from "@/core/codemirror/language/extension"; type RuntimeCell = CellRuntimeState & CellData; /** * Renders a single cell in the slides view as an editable CodeMirror editor * stacked with its output, mirroring the notebook layout. Editing and * Ctrl/Cmd+Enter run the cell against the live kernel so presenters can iterate * without leaving the slide deck. */ export const SlideCellView = ({ cell }: { cell: RuntimeCell }) => { const [userConfig] = useUserConfig(); const { theme } = useTheme(); const runCell = useRunCell(cell.id); const connection = useAtomValue(connectionAtom); const editorViewRef = useRef(null); const editorViewParentRef = useRef(null); const [languageAdapter, setLanguageAdapter] = useState< LanguageAdapterType | undefined >(); const cellOutputPosition = userConfig.display.cell_output; const hasOutput = cell.output != null; const uninstantiated = isUninstantiated({ executionTime: cell.runElapsedTimeMs ?? cell.lastExecutionTime, status: cell.status, errored: cell.errored, interrupted: cell.interrupted, stopped: cell.stopped, }); const needsRun = cellNeedsRun({ edited: cell.edited, interrupted: cell.interrupted, staleInputs: cell.staleInputs, disabled: cell.config.disabled, status: cell.status, }); const editorWrapperClassName = cn( "marimo-cell", "hover-actions-parent", "interactive", cellStatusClasses({ needsRun, errored: cell.errored, stopped: cell.stopped, disabled: cell.config.disabled, status: cell.status, }), ); const output = ( ); const toolbar = (
); const editor = (
{ editorViewRef.current = ev; }} userConfig={userConfig} editorViewRef={editorViewRef} editorViewParentRef={editorViewParentRef} hasOutput={hasOutput} // hide_code is intentionally overridden in the slide view; the editor // is unmounted entirely when the user toggles code off. showHiddenCode={() => undefined} languageAdapter={languageAdapter} setLanguageAdapter={setLanguageAdapter} showLanguageToggles={false} outputArea={cellOutputPosition} /> {toolbar}
); return ( <> {cellOutputPosition === "above" && output} {editor} {cellOutputPosition === "below" && output} ); }; export const SlideCellReadOnlyView = ({ cell }: { cell: RuntimeCell }) => { const [userConfig] = useUserConfig(); const cellOutputPosition = userConfig.display.cell_output; const language = useMemo(() => { const adapter = languageAdapterFromCode(cell.code.trim()); return adapter.type === "sql" ? "sql" : "python"; }, [cell.code]); const output = ( ); const editor = (
); return ( <> {cellOutputPosition === "above" && output} {editor} {cellOutputPosition === "below" && output} ); };