@marimo-team/frontend 0.23.16-dev3 → 0.23.16-dev34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{CellStatus-BalYv0pK.js → CellStatus-CmojVYzm.js} +1 -1
- package/dist/assets/{ConnectedDataExplorerComponent-DI7mV-Gw.js → ConnectedDataExplorerComponent-CMaZapRd.js} +1 -1
- package/dist/assets/{ErrorBoundary-C7_5jjWi.js → ErrorBoundary-DzTD8LVq.js} +1 -1
- package/dist/assets/{ImperativeModal-BIavOiUv.js → ImperativeModal-fY-ZfT0b.js} +1 -1
- package/dist/assets/{JsonOutput-CkCD-FgM.js → JsonOutput-BwwRpByA.js} +12 -12
- package/dist/assets/{LazyAnyLanguageCodeMirror-sVm_hz8A.js → LazyAnyLanguageCodeMirror-B2JvSXP-.js} +2 -2
- package/dist/assets/{MarimoErrorOutput-DO2k2fA5.js → MarimoErrorOutput-BWte8vjk.js} +4 -4
- package/dist/assets/{RSPContexts-CgC81f0I.js → RSPContexts-WiCgGm__.js} +1 -1
- package/dist/assets/RenderHTML-DRltV71H.js +1 -0
- package/dist/assets/{RunButton-BKRupqr7.js → RunButton-DIegd2mN.js} +1 -1
- package/dist/assets/{add-cell-with-ai-CEZtaZCK.js → add-cell-with-ai-BBFD-M9V.js} +17 -17
- package/dist/assets/add-connection-dialog-CECJ8507.js +170 -0
- package/dist/assets/{agent-panel-CHB6t7Zy.js → agent-panel-YaS0WXP1.js} +5 -5
- package/dist/assets/ai-model-dropdown-BpVBUZnz.js +5 -0
- package/dist/assets/{alert-dialog-BXegNC0I.js → alert-dialog-Bb8Lz8ko.js} +1 -1
- package/dist/assets/{any-language-editor-DCpZRrpx.js → any-language-editor--tRHs8C_.js} +1 -1
- package/dist/assets/{app-config-button-NrM9ywXA.js → app-config-button-BW-w01aF.js} +1 -1
- package/dist/assets/{button-eIihcbUw.js → button-DDGiD1NW.js} +1 -1
- package/dist/assets/{cache-panel-wllSTlbM.js → cache-panel-DcQUeUpg.js} +1 -1
- package/dist/assets/{capabilities-B09j1Eor.js → capabilities-DoEg0XwL.js} +1 -1
- package/dist/assets/{cell-editor-B5JVq7_q.js → cell-editor-EV-1IccQ.js} +10 -10
- package/dist/assets/cell-link-C5gpAn3R.js +1 -0
- package/dist/assets/cells-6yd8nOAu.js +231 -0
- package/dist/assets/{chat-display-BG08ltQ3.js → chat-display-8BbC5B-D.js} +1 -1
- package/dist/assets/{chat-panel-P2CzCtXJ.js → chat-panel-CMOZp5xW.js} +3 -3
- package/dist/assets/{chat-ui-fAJZAoTD.js → chat-ui-DWhJ2Ozy.js} +1 -1
- package/dist/assets/{column-preview-Dne1dIt0.js → column-preview-DeXESYpM.js} +1 -1
- package/dist/assets/{command-CAJLPEBq.js → command-Dqxie4gq.js} +1 -1
- package/dist/assets/{command-palette-iOCqUIs1.js → command-palette-Dx6AkiPd.js} +1 -1
- package/dist/assets/{common-CD6Mj8n6.js → common-XVELED_O.js} +1 -1
- package/dist/assets/components-BLHpmhXx.js +1 -0
- package/dist/assets/config-B-Q7J_6d.js +1 -0
- package/dist/assets/{config-COUOIPEq.js → config-BJVx3eBW.js} +1 -1
- package/dist/assets/{copy-BtTOqPTS.js → copy-Bxb1_Gtw.js} +1 -1
- package/dist/assets/{copy-icon-C2pG0ZNK.js → copy-icon-neDQUo4Q.js} +1 -1
- package/dist/assets/{createReducer-C7kZ8zEe.js → createReducer-DGx5Af-C.js} +1 -1
- package/dist/assets/{datasource-ySAiC9gr.js → datasource-CTqa8bf-.js} +2 -2
- package/dist/assets/{dates-D-kIKDYA.js → dates-C2LWzsCZ.js} +1 -1
- package/dist/assets/{dependency-graph-panel-BF23EwcD.js → dependency-graph-panel-C4Nzcddp.js} +4 -4
- package/dist/assets/{dialog-D1DEsRZ2.js → dialog-BCVepWLJ.js} +1 -1
- package/dist/assets/{dist-ByVeMWkr.js → dist-BLN8PNJV.js} +1 -1
- package/dist/assets/dist-CiVShZKM.js +2 -0
- package/dist/assets/{documentation-panel-e9Fi9R7e.js → documentation-panel-Bym4G7IS.js} +1 -1
- package/dist/assets/download-HKgqJX4l.js +9 -0
- package/dist/assets/{dropdown-menu-BFZLnWeO.js → dropdown-menu-dHmZR8bI.js} +1 -1
- package/dist/assets/{edit-page-DSEkwJ4O.js → edit-page-Jtp6Qqjl.js} +6 -6
- package/dist/assets/{error-banner-B6eIlxzg.js → error-banner-BSxEOIn2.js} +1 -1
- package/dist/assets/{error-entries-Birw-8VX.js → error-entries-CxyvaxEM.js} +2 -2
- package/dist/assets/{error-panel-DdsUL6b7.js → error-panel-CfSy7uUr.js} +1 -1
- package/dist/assets/{es-1D83cgiu.js → es-gYgfF8y5.js} +1 -1
- package/dist/assets/{esm-BL7jQmzn.js → esm-B30N1GS0.js} +1 -1
- package/dist/assets/{field-BeZbVzXA.js → field-BsxD35VE.js} +1 -1
- package/dist/assets/file-explorer-panel-Dd5Xn2TK.js +26 -0
- package/dist/assets/{file-icons-Cb54mIL8.js → file-icons-CSjJ3JC6.js} +1 -1
- package/dist/assets/{file-name-input-BWFcK1ey.js → file-name-input-CrKtrXMl.js} +1 -1
- package/dist/assets/floating-outline-ByQ8vvif.js +1 -0
- package/dist/assets/focus-CVONl-Dy.js +1 -0
- package/dist/assets/{form-B6BkSCJb.js → form-Ca3yd_Od.js} +1 -1
- package/dist/assets/{formats-ClEFGPy-.js → formats-DzmLpc9A.js} +1 -1
- package/dist/assets/{formatting-B_41gSF5.js → formatting-CDf6w1Kt.js} +1 -1
- package/dist/assets/{fullscreen-dUjPYOmm.js → fullscreen-CTDqNQr6.js} +1 -1
- package/dist/assets/{gallery-page-CWQQAYpa.js → gallery-page-CJ3ms1Hn.js} +1 -1
- package/dist/assets/{glide-data-editor-lMARFWHS.js → glide-data-editor-j2igs9Y_.js} +1 -1
- package/dist/assets/home-page-FpAawj9s.js +4 -0
- package/dist/assets/{html-to-image-CwmX28T9.js → html-to-image-C-4ysbGe.js} +2 -2
- package/dist/assets/index-CiJmYQBT.js +38 -0
- package/dist/assets/index-xs-zSSrX.css +2 -0
- package/dist/assets/{input-CqrUjynb.js → input-JxFwu-3G.js} +1 -1
- package/dist/assets/kiosk-mode-BumOFEtY.js +1 -0
- package/dist/assets/{label-BElwWzf0.js → label-CqjrpwRC.js} +1 -1
- package/dist/assets/{layout-CUlZijwG.js → layout-Dtql_o_T.js} +5 -5
- package/dist/assets/{links-CToBjIIj.js → links-CZr5bjvo.js} +1 -1
- package/dist/assets/{logs-panel-iFV4ZJ9b.js → logs-panel-5u1wUBn1.js} +1 -1
- package/dist/assets/{markdown-renderer-QvXG0CRk.js → markdown-renderer-dABDqZDw.js} +2 -2
- package/dist/assets/{menu-items-DbSLBfXR.js → menu-items-CCi6aOPm.js} +1 -1
- package/dist/assets/{mermaid-Bh0flEIb.js → mermaid-CYN0wOyG.js} +1 -1
- package/dist/assets/name-cell-input-Y4knmEIU.js +1 -0
- package/dist/assets/node-sql-parser-Si4oZ2P-.js +68 -0
- package/dist/assets/{numbers-CeeaFKqu.js → numbers-rmawRqQP.js} +1 -1
- package/dist/assets/outline-panel-CQ_KWLip.js +1 -0
- package/dist/assets/{packages-panel-BzQF60rG.js → packages-panel-Ijt7d51P.js} +1 -1
- package/dist/assets/pair-with-agent-modal-BCRSACei.js +4 -0
- package/dist/assets/panels-DfU1Oikj.js +4 -0
- package/dist/assets/{popover-DrHQ3KEt.js → popover-Bcz1Zikb.js} +1 -1
- package/dist/assets/process-output-Dd11YI04.js +1 -0
- package/dist/assets/{radio-group-CLBjGkt5.js → radio-group-22eWJ9fv.js} +1 -1
- package/dist/assets/readonly-code-display-BjK-TEri.js +1 -0
- package/dist/assets/{readonly-python-code-CW_G5e4E.js → readonly-python-code-n_TrLmsR.js} +1 -1
- package/dist/assets/{renderShortcut-BZLr8D7H.js → renderShortcut-Bl8_FVn8.js} +1 -1
- package/dist/assets/{reveal-component-BLMTmd8T.js → reveal-component-CCLTV1q6.js} +60 -60
- package/dist/assets/{run-page-B6pgDYEJ.js → run-page-DbezK7Qs.js} +1 -1
- package/dist/assets/{runs-D51Xwrsk.js → runs-DBTXqJHS.js} +1 -1
- package/dist/assets/scratchpad-panel-C2wAEv5n.js +1 -0
- package/dist/assets/{scroll-to-bottom-button-Cgr10kaJ.js → scroll-to-bottom-button-C8yfT4wq.js} +1 -1
- package/dist/assets/{secrets-panel-Cc5KDBk6.js → secrets-panel-6J6wcuVR.js} +1 -1
- package/dist/assets/{select-B5TFNjmU.js → select-BP75_5jJ.js} +1 -1
- package/dist/assets/{session-CEFnN9Cq.js → session-BmukRjSi.js} +1 -1
- package/dist/assets/{session-panel-Y0Oon0sD.js → session-panel-BZGNcZmp.js} +1 -1
- package/dist/assets/{share-CYpcX4N4.js → share-852X_cqy.js} +1 -1
- package/dist/assets/{skeleton-D3QPxqWC.js → skeleton-BzlKcq21.js} +1 -1
- package/dist/assets/slides-DkEgzTJB.css +1 -0
- package/dist/assets/{snippets-panel-CXpGflMO.js → snippets-panel-DNaNtkR0.js} +1 -1
- package/dist/assets/{spec-CzqcmYQk.js → spec-C7opZZRp.js} +1 -1
- package/dist/assets/{state-BvdK8eiw.js → state-D10U2MwA.js} +1 -1
- package/dist/assets/{state-WBgc7MiA.js → state-DDag0B_B.js} +1 -1
- package/dist/assets/state-DFPAfLw7.js +3 -0
- package/dist/assets/{state-DBzEQtWz.js → state-jCdh8Dcx.js} +1 -1
- package/dist/assets/{strings-Djnbwmfl.js → strings--BknHX9C.js} +1 -1
- package/dist/assets/{swiper-component-DInvCxhI.js → swiper-component-g8EXE911.js} +1 -1
- package/dist/assets/switch-OVajJBPR.js +1 -0
- package/dist/assets/{terminal-D3IQBBYo.js → terminal-217O8hlZ.js} +1 -1
- package/dist/assets/{textarea-CpFfEUet.js → textarea-DuEtSOCl.js} +1 -1
- package/dist/assets/{tooltip-CFX4fYHU.js → tooltip-4bZlU7jl.js} +1 -1
- package/dist/assets/{tooltip-HLb6RxVp.js → tooltip-B7U4xkIN.js} +1 -1
- package/dist/assets/{tracing-panel-BU-o_LCd.js → tracing-panel-rVAa3En0.js} +2 -2
- package/dist/assets/{tracing-CKn3gWHw.js → tracing-ttUd3J7U.js} +1 -1
- package/dist/assets/{tree-actions-CsC2XmGo.js → tree-actions-UCr1tMHw.js} +1 -1
- package/dist/assets/{useBoolean-D89u30n-.js → useBoolean-CFj86iac.js} +1 -1
- package/dist/assets/useCellActionButton-CJknR0XY.js +1 -0
- package/dist/assets/{useDeleteCell-EPH4kcG7.js → useDeleteCell-PrgejW8A.js} +1 -1
- package/dist/assets/{useDependencyPanelTab-CZnK7N2L.js → useDependencyPanelTab-5jc-_-hy.js} +1 -1
- package/dist/assets/useEventListener-C0195JsF.js +1 -0
- package/dist/assets/{useHotkey-DIuRH8Wu.js → useHotkey-DLZvrRZT.js} +1 -1
- package/dist/assets/{useIframeCapabilities-Ccb4fvKc.js → useIframeCapabilities-j6fR_dBA.js} +1 -1
- package/dist/assets/{useInstallPackage-BRbUAUFn.js → useInstallPackage-WiYBwhUO.js} +1 -1
- package/dist/assets/{useInterval-CC0vKpWm.js → useInterval-CWBTUy5W.js} +1 -1
- package/dist/assets/useNotebookActions-4vw_NiRs.js +12 -0
- package/dist/assets/useRunCells-DHsd7HGL.js +1 -0
- package/dist/assets/{useSplitCell-9Qz93yPZ.js → useSplitCell-MZpER0Bh.js} +1 -1
- package/dist/assets/{useTheme-KXqAyDPC.js → useTheme-Bxv9B31g.js} +1 -1
- package/dist/assets/{utils-Z80SV4_d.js → utils-BWBBpCkT.js} +1 -1
- package/dist/assets/{vega-component-Cie3ag_T.js → vega-component-Db8KjZJG.js} +1 -1
- package/dist/assets/{write-secret-modal-DEEn7sZV.js → write-secret-modal-3-v-dHVj.js} +1 -1
- package/dist/index.html +68 -68
- package/package.json +2 -2
- package/src/__mocks__/requests.ts +45 -4
- package/src/components/data-table/__tests__/__snapshots__/chart-spec-model.test.ts.snap +174 -21
- package/src/components/data-table/__tests__/chart-spec-model.test.ts +102 -1
- package/src/components/data-table/column-summary/chart-spec-model.tsx +163 -103
- package/src/components/data-table/column-summary/legacy-chart-spec.ts +15 -7
- package/src/components/data-table/column-summary/utils.ts +26 -7
- package/src/components/data-table/types.ts +1 -1
- package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +99 -18
- package/src/components/editor/actions/__tests__/pdf-export.test.ts +0 -4
- package/src/components/editor/actions/pair-with-agent-commands.ts +21 -10
- package/src/components/editor/actions/pair-with-agent-modal.tsx +2 -2
- package/src/components/editor/actions/pdf-export.ts +1 -4
- package/src/components/editor/actions/useNotebookActions.tsx +7 -13
- package/src/components/editor/connections/storage/__tests__/__snapshots__/as-code.test.ts.snap +50 -0
- package/src/components/editor/connections/storage/__tests__/as-code.test.ts +87 -8
- package/src/components/editor/connections/storage/as-code.ts +40 -21
- package/src/components/editor/connections/storage/schemas.ts +83 -42
- package/src/components/editor/file-tree/__tests__/file-render-mode.test.ts +27 -0
- package/src/components/editor/file-tree/__tests__/file-viewer.test.tsx +150 -0
- package/src/components/editor/file-tree/file-preview-metadata.tsx +51 -0
- package/src/components/editor/file-tree/file-render-mode.ts +32 -0
- package/src/components/editor/file-tree/file-viewer.tsx +76 -50
- package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +1 -1
- package/src/components/slides/__tests__/cell-output-block.test.tsx +40 -0
- package/src/components/slides/__tests__/slide-cell-view.test.tsx +33 -0
- package/src/components/slides/__tests__/slide-scroll-hint.test.tsx +198 -0
- package/src/components/slides/reveal-component.tsx +25 -19
- package/src/components/slides/slide-cell-view.tsx +1 -1
- package/src/components/slides/slide-scroll-hint.tsx +161 -0
- package/src/components/slides/slides.css +4 -2
- package/src/components/static-html/share-modal.tsx +1 -1
- package/src/components/ui/input.tsx +1 -1
- package/src/core/codemirror/find-replace/__tests__/navigate.test.ts +42 -30
- package/src/core/codemirror/find-replace/navigate.ts +2 -0
- package/src/core/codemirror/go-to-definition/__tests__/commands.test.ts +24 -3
- package/src/core/codemirror/go-to-definition/commands.ts +3 -0
- package/src/core/codemirror/keymaps/__tests__/keymaps.test.ts +31 -2
- package/src/core/codemirror/keymaps/keymaps.ts +12 -0
- package/src/core/codemirror/language/__tests__/sql.test.ts +443 -61
- package/src/core/codemirror/language/languages/sql/completion-store.ts +5 -1
- package/src/core/codemirror/language/languages/sql/sql.ts +210 -3
- package/src/core/codemirror/utils.ts +28 -0
- package/src/core/hotkeys/hotkeys.ts +0 -2
- package/src/core/islands/__tests__/bridge.test.ts +107 -0
- package/src/core/islands/bridge.ts +16 -0
- package/src/core/mode.ts +10 -0
- package/src/core/network/__tests__/api.test.ts +42 -0
- package/src/core/network/__tests__/connection.test.ts +45 -0
- package/src/core/network/__tests__/requests-lazy.test.ts +32 -1
- package/src/core/network/__tests__/requests-network.test.ts +21 -0
- package/src/core/network/api.ts +27 -0
- package/src/core/network/connection.ts +15 -0
- package/src/core/network/requests-lazy.ts +1 -0
- package/src/core/network/requests-network.ts +14 -8
- package/src/core/network/requests-static.ts +1 -0
- package/src/core/network/requests-toasting.tsx +1 -0
- package/src/core/network/types.ts +25 -7
- package/src/core/static/download-html.ts +5 -14
- package/src/core/wasm/bridge.ts +4 -2
- package/src/core/wasm/worker/types.ts +5 -2
- package/src/plugins/impl/FormPlugin.tsx +1 -1
- package/src/plugins/impl/__tests__/FormPlugin.test.tsx +162 -0
- package/src/utils/__tests__/download.test.tsx +24 -1
- package/src/utils/download.ts +11 -6
- package/dist/assets/RenderHTML-BCvU9dYz.js +0 -1
- package/dist/assets/add-connection-dialog-B-jCRNTN.js +0 -170
- package/dist/assets/ai-model-dropdown-DXgLphFa.js +0 -5
- package/dist/assets/cell-link-DqBkyAFe.js +0 -1
- package/dist/assets/cells-Cf7bHHq3.js +0 -229
- package/dist/assets/components-BH6gDVv6.js +0 -1
- package/dist/assets/config-BbOTTCYY.js +0 -1
- package/dist/assets/dist-BCMBu0rO.js +0 -2
- package/dist/assets/download-BomYt3nl.js +0 -9
- package/dist/assets/file-explorer-panel-BfXM2BOd.js +0 -26
- package/dist/assets/floating-outline-wz-WSRgP.js +0 -1
- package/dist/assets/focus-DiEyfiAG.js +0 -1
- package/dist/assets/home-page-DJ4jJsZj.js +0 -4
- package/dist/assets/index-A71LAt6h.css +0 -2
- package/dist/assets/index-Dbc5mg7a.js +0 -38
- package/dist/assets/kiosk-mode-ABm3oYgq.js +0 -1
- package/dist/assets/name-cell-input-C6cukQ9k.js +0 -1
- package/dist/assets/node-sql-parser-BWgUjcfV.js +0 -68
- package/dist/assets/outline-panel-BPlg9_CE.js +0 -1
- package/dist/assets/pair-with-agent-modal-CKOYwOYw.js +0 -4
- package/dist/assets/panels-Dj45fW-v.js +0 -4
- package/dist/assets/process-output-BEhIGfkO.js +0 -1
- package/dist/assets/readonly-code-display-D63oRtBP.js +0 -1
- package/dist/assets/scratchpad-panel-B0mEqBNk.js +0 -1
- package/dist/assets/slides-MCbMDtlY.css +0 -1
- package/dist/assets/state-BZQc7xxL.js +0 -3
- package/dist/assets/switch-CvweaCXq.js +0 -1
- package/dist/assets/useCellActionButton-CRfIEVB5.js +0 -1
- package/dist/assets/useEventListener-B_w3A283.js +0 -1
- package/dist/assets/useNotebookActions-DTXAoukG.js +0 -12
- package/dist/assets/useRunCells-CSSF_mJ0.js +0 -1
|
@@ -25,11 +25,11 @@ import { copyToClipboard } from "@/utils/copy";
|
|
|
25
25
|
import type { Base64String } from "@/utils/json/base64";
|
|
26
26
|
import { downloadFile } from "./download";
|
|
27
27
|
import { FilePreviewHeader } from "./file-header";
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
import { FilePreviewMetadata } from "./file-preview-metadata";
|
|
29
|
+
import { getFileRenderMode } from "./file-render-mode";
|
|
30
|
+
import { FileContentRenderer } from "./renderers";
|
|
31
|
+
|
|
32
|
+
export const MAX_FILE_PREVIEW_BYTES = 10 * 1024 * 1024;
|
|
33
33
|
|
|
34
34
|
interface Props {
|
|
35
35
|
file: FileInfo;
|
|
@@ -50,9 +50,15 @@ export const FileViewer: React.FC<Props> = ({ file, onOpenNotebook }) => {
|
|
|
50
50
|
|
|
51
51
|
const { data, isPending, error, setData, refetch } =
|
|
52
52
|
useAsyncData(async () => {
|
|
53
|
-
const details = await sendFileDetails({
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
const details = await sendFileDetails({
|
|
54
|
+
path: file.path,
|
|
55
|
+
maxBytes: MAX_FILE_PREVIEW_BYTES,
|
|
56
|
+
});
|
|
57
|
+
const mode = getFileRenderMode(details.mimeType, details.isBase64);
|
|
58
|
+
if (!details.isTooLarge && mode === "text") {
|
|
59
|
+
const contents = details.contents || "";
|
|
60
|
+
setInternalValue(unsavedContentsForFile.get(file.path) ?? contents);
|
|
61
|
+
}
|
|
56
62
|
return details;
|
|
57
63
|
}, [file.path]);
|
|
58
64
|
|
|
@@ -72,13 +78,19 @@ export const FileViewer: React.FC<Props> = ({ file, onOpenNotebook }) => {
|
|
|
72
78
|
);
|
|
73
79
|
};
|
|
74
80
|
|
|
75
|
-
// On file change or unmount, save the unsaved contents
|
|
81
|
+
// On file change or unmount, save the unsaved contents. Only editable text
|
|
82
|
+
// previews participate in editor state; oversized and non-text responses
|
|
83
|
+
// carry no draft to preserve.
|
|
76
84
|
// We use a ref for internalValue so we don't call this effect on each keystroke
|
|
77
85
|
const internalValueRef = useRef<string>(internalValue);
|
|
78
86
|
internalValueRef.current = internalValue;
|
|
79
87
|
useEffect(() => {
|
|
80
88
|
return () => {
|
|
81
|
-
if (
|
|
89
|
+
if (
|
|
90
|
+
data?.contents == null ||
|
|
91
|
+
data.isTooLarge ||
|
|
92
|
+
getFileRenderMode(data.mimeType, data.isBase64) !== "text"
|
|
93
|
+
) {
|
|
82
94
|
return;
|
|
83
95
|
}
|
|
84
96
|
const draft = internalValueRef.current;
|
|
@@ -88,7 +100,13 @@ export const FileViewer: React.FC<Props> = ({ file, onOpenNotebook }) => {
|
|
|
88
100
|
unsavedContentsForFile.set(file.path, draft);
|
|
89
101
|
}
|
|
90
102
|
};
|
|
91
|
-
}, [
|
|
103
|
+
}, [
|
|
104
|
+
file.path,
|
|
105
|
+
data?.contents,
|
|
106
|
+
data?.isTooLarge,
|
|
107
|
+
data?.mimeType,
|
|
108
|
+
data?.isBase64,
|
|
109
|
+
]);
|
|
92
110
|
|
|
93
111
|
if (error) {
|
|
94
112
|
return <ErrorBanner error={error} />;
|
|
@@ -99,7 +117,10 @@ export const FileViewer: React.FC<Props> = ({ file, onOpenNotebook }) => {
|
|
|
99
117
|
}
|
|
100
118
|
|
|
101
119
|
const mimeType = data.mimeType || "text/plain";
|
|
102
|
-
const
|
|
120
|
+
const renderMode = getFileRenderMode(data.mimeType, data.isBase64);
|
|
121
|
+
const isText = renderMode === "text";
|
|
122
|
+
const isCsv = renderMode === "csv";
|
|
123
|
+
const isMedia = renderMode === "media";
|
|
103
124
|
const isActiveNotebook =
|
|
104
125
|
currentNotebookFilename &&
|
|
105
126
|
data.file.isMarimoFile &&
|
|
@@ -108,22 +129,27 @@ export const FileViewer: React.FC<Props> = ({ file, onOpenNotebook }) => {
|
|
|
108
129
|
// but this is an okay heuristic for now.
|
|
109
130
|
file.path.endsWith(`/${currentNotebookFilename}`));
|
|
110
131
|
|
|
111
|
-
if (!data.contents && !isEditable) {
|
|
112
|
-
// Show details instead of contents
|
|
113
|
-
return (
|
|
114
|
-
<div className="grid grid-cols-2 gap-2 p-6">
|
|
115
|
-
<div className="font-bold text-muted-foreground">Name</div>
|
|
116
|
-
<div>{data.file.name}</div>
|
|
117
|
-
<div className="font-bold text-muted-foreground">Type</div>
|
|
118
|
-
<div>{mimeType}</div>
|
|
119
|
-
</div>
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
132
|
const handleDownload = async () => {
|
|
124
133
|
await downloadFile(file.path, data.file.name);
|
|
125
134
|
};
|
|
126
135
|
|
|
136
|
+
const saveKeymapExtension = keymap.of([
|
|
137
|
+
{
|
|
138
|
+
key: hotkeys.getHotkey("global.save").key,
|
|
139
|
+
stopPropagation: true,
|
|
140
|
+
run: () => {
|
|
141
|
+
if (internalValue !== data.contents) {
|
|
142
|
+
void handleSaveFile();
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
return false;
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
]);
|
|
149
|
+
|
|
150
|
+
// Defined before the metadata-only returns so refresh, download, and
|
|
151
|
+
// open-notebook stay available while edit-only copy/save are withheld from
|
|
152
|
+
// non-text previews.
|
|
127
153
|
const header = (
|
|
128
154
|
<FilePreviewHeader
|
|
129
155
|
filename={data.file.name}
|
|
@@ -142,7 +168,7 @@ export const FileViewer: React.FC<Props> = ({ file, onOpenNotebook }) => {
|
|
|
142
168
|
</Button>
|
|
143
169
|
</Tooltip>
|
|
144
170
|
)}
|
|
145
|
-
{
|
|
171
|
+
{isText && (
|
|
146
172
|
<>
|
|
147
173
|
<Tooltip content="Copy contents to clipboard">
|
|
148
174
|
<Button
|
|
@@ -172,8 +198,23 @@ export const FileViewer: React.FC<Props> = ({ file, onOpenNotebook }) => {
|
|
|
172
198
|
/>
|
|
173
199
|
);
|
|
174
200
|
|
|
175
|
-
|
|
176
|
-
|
|
201
|
+
if (data.isTooLarge || renderMode === "unsupported") {
|
|
202
|
+
return (
|
|
203
|
+
<>
|
|
204
|
+
{header}
|
|
205
|
+
<FilePreviewMetadata
|
|
206
|
+
file={data.file}
|
|
207
|
+
mimeType={mimeType}
|
|
208
|
+
message={
|
|
209
|
+
data.isTooLarge
|
|
210
|
+
? "File is too large to preview."
|
|
211
|
+
: "This file type cannot be previewed."
|
|
212
|
+
}
|
|
213
|
+
onDownload={disableFileDownloads ? undefined : handleDownload}
|
|
214
|
+
/>
|
|
215
|
+
</>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
177
218
|
|
|
178
219
|
const warningBanner = isText && isActiveNotebook && (
|
|
179
220
|
<Alert variant="warning" className="rounded-none">
|
|
@@ -192,35 +233,20 @@ export const FileViewer: React.FC<Props> = ({ file, onOpenNotebook }) => {
|
|
|
192
233
|
<FileContentRenderer
|
|
193
234
|
mimeType={mimeType}
|
|
194
235
|
contents={
|
|
195
|
-
|
|
196
|
-
?
|
|
197
|
-
:
|
|
198
|
-
?
|
|
199
|
-
:
|
|
236
|
+
isText
|
|
237
|
+
? internalValue
|
|
238
|
+
: isCsv
|
|
239
|
+
? (data.contents ?? undefined)
|
|
240
|
+
: undefined
|
|
200
241
|
}
|
|
201
242
|
mediaSource={
|
|
202
|
-
isMedia
|
|
243
|
+
isMedia && data.contents
|
|
203
244
|
? { base64: data.contents as Base64String, mime: mimeType }
|
|
204
245
|
: undefined
|
|
205
246
|
}
|
|
206
247
|
readOnly={!isText}
|
|
207
|
-
onChange={setInternalValue}
|
|
208
|
-
extensions={[
|
|
209
|
-
// Command S for save
|
|
210
|
-
keymap.of([
|
|
211
|
-
{
|
|
212
|
-
key: hotkeys.getHotkey("global.save").key,
|
|
213
|
-
stopPropagation: true,
|
|
214
|
-
run: () => {
|
|
215
|
-
if (internalValue !== data.contents) {
|
|
216
|
-
handleSaveFile();
|
|
217
|
-
return true;
|
|
218
|
-
}
|
|
219
|
-
return false;
|
|
220
|
-
},
|
|
221
|
-
},
|
|
222
|
-
]),
|
|
223
|
-
]}
|
|
248
|
+
onChange={isText ? setInternalValue : undefined}
|
|
249
|
+
extensions={isText ? [saveKeymapExtension] : []}
|
|
224
250
|
/>
|
|
225
251
|
</>
|
|
226
252
|
);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { render } from "@testing-library/react";
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import { cellId } from "@/__tests__/branded";
|
|
6
|
+
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
7
|
+
import { CellOutputId } from "@/core/cells/ids";
|
|
8
|
+
import { createCell, createCellRuntimeState } from "@/core/cells/types";
|
|
9
|
+
import { CellOutputBlock } from "../reveal-component";
|
|
10
|
+
|
|
11
|
+
describe("CellOutputBlock", () => {
|
|
12
|
+
it("renders the cell's data-cell-id and data-cell-name so it can be targeted by custom CSS", () => {
|
|
13
|
+
const id = cellId("test");
|
|
14
|
+
const cell = {
|
|
15
|
+
...createCell({ id, name: "title" }),
|
|
16
|
+
...createCellRuntimeState({
|
|
17
|
+
output: {
|
|
18
|
+
channel: "output",
|
|
19
|
+
mimetype: "text/plain",
|
|
20
|
+
data: "hello",
|
|
21
|
+
timestamp: 0,
|
|
22
|
+
},
|
|
23
|
+
}),
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const { container } = render(
|
|
27
|
+
<TooltipProvider>
|
|
28
|
+
<CellOutputBlock cell={cell} />
|
|
29
|
+
</TooltipProvider>,
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const cellElement = container.querySelector(`[data-cell-id="${id}"]`);
|
|
33
|
+
expect(cellElement).toBeTruthy();
|
|
34
|
+
expect(cellElement?.getAttribute("data-cell-name")).toBe("title");
|
|
35
|
+
|
|
36
|
+
// The wrapper's `data-cell-id` must coexist with the output's own
|
|
37
|
+
// `CellOutputId`-derived id, without colliding.
|
|
38
|
+
expect(document.getElementById(CellOutputId.create(id))).toBeTruthy();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { render } from "@testing-library/react";
|
|
4
|
+
import { beforeAll, describe, expect, it } from "vitest";
|
|
5
|
+
import { SetupMocks } from "@/__mocks__/common";
|
|
6
|
+
import { cellId } from "@/__tests__/branded";
|
|
7
|
+
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
8
|
+
import { createCell, createCellRuntimeState } from "@/core/cells/types";
|
|
9
|
+
import { SlideCellReadOnlyView } from "../slide-cell-view";
|
|
10
|
+
|
|
11
|
+
beforeAll(() => {
|
|
12
|
+
SetupMocks.resizeObserver();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe("SlideCellReadOnlyView", () => {
|
|
16
|
+
it("renders the cell's data-cell-id and data-cell-name so it can be targeted by custom CSS", () => {
|
|
17
|
+
const id = cellId("test");
|
|
18
|
+
const cell = {
|
|
19
|
+
...createCell({ id, name: "title", code: "x = 1" }),
|
|
20
|
+
...createCellRuntimeState(),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const { container } = render(
|
|
24
|
+
<TooltipProvider>
|
|
25
|
+
<SlideCellReadOnlyView cell={cell} />
|
|
26
|
+
</TooltipProvider>,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const cellElement = container.querySelector(`[data-cell-id="${id}"]`);
|
|
30
|
+
expect(cellElement).toBeTruthy();
|
|
31
|
+
expect(cellElement?.getAttribute("data-cell-name")).toBe("title");
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { act, render, screen } from "@testing-library/react";
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import {
|
|
6
|
+
shouldShowScrollHint,
|
|
7
|
+
SlideScrollContainer,
|
|
8
|
+
} from "../slide-scroll-hint";
|
|
9
|
+
|
|
10
|
+
describe("shouldShowScrollHint", () => {
|
|
11
|
+
it("shows when content overflows and scroll is at the top", () => {
|
|
12
|
+
expect(
|
|
13
|
+
shouldShowScrollHint({
|
|
14
|
+
scrollHeight: 800,
|
|
15
|
+
clientHeight: 400,
|
|
16
|
+
scrollTop: 0,
|
|
17
|
+
}),
|
|
18
|
+
).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("hides when content fits", () => {
|
|
22
|
+
expect(
|
|
23
|
+
shouldShowScrollHint({
|
|
24
|
+
scrollHeight: 300,
|
|
25
|
+
clientHeight: 400,
|
|
26
|
+
scrollTop: 0,
|
|
27
|
+
}),
|
|
28
|
+
).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("hides after the user scrolls down", () => {
|
|
32
|
+
expect(
|
|
33
|
+
shouldShowScrollHint({
|
|
34
|
+
scrollHeight: 800,
|
|
35
|
+
clientHeight: 400,
|
|
36
|
+
scrollTop: 40,
|
|
37
|
+
}),
|
|
38
|
+
).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("ignores sub-pixel overflow", () => {
|
|
42
|
+
expect(
|
|
43
|
+
shouldShowScrollHint({
|
|
44
|
+
scrollHeight: 401,
|
|
45
|
+
clientHeight: 400,
|
|
46
|
+
scrollTop: 0,
|
|
47
|
+
}),
|
|
48
|
+
).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("still shows within the top threshold", () => {
|
|
52
|
+
expect(
|
|
53
|
+
shouldShowScrollHint({
|
|
54
|
+
scrollHeight: 800,
|
|
55
|
+
clientHeight: 400,
|
|
56
|
+
scrollTop: 8,
|
|
57
|
+
}),
|
|
58
|
+
).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe("SlideScrollContainer", () => {
|
|
63
|
+
const resizeObservers: Array<{
|
|
64
|
+
callback: ResizeObserverCallback;
|
|
65
|
+
observe: ReturnType<typeof vi.fn>;
|
|
66
|
+
disconnect: ReturnType<typeof vi.fn>;
|
|
67
|
+
}> = [];
|
|
68
|
+
|
|
69
|
+
beforeEach(() => {
|
|
70
|
+
resizeObservers.length = 0;
|
|
71
|
+
vi.stubGlobal("requestAnimationFrame", (cb: FrameRequestCallback) => {
|
|
72
|
+
cb(0);
|
|
73
|
+
return 0;
|
|
74
|
+
});
|
|
75
|
+
vi.stubGlobal("cancelAnimationFrame", vi.fn());
|
|
76
|
+
vi.stubGlobal(
|
|
77
|
+
"ResizeObserver",
|
|
78
|
+
class MockResizeObserver {
|
|
79
|
+
callback: ResizeObserverCallback;
|
|
80
|
+
observe = vi.fn();
|
|
81
|
+
unobserve = vi.fn();
|
|
82
|
+
disconnect = vi.fn();
|
|
83
|
+
|
|
84
|
+
constructor(callback: ResizeObserverCallback) {
|
|
85
|
+
this.callback = callback;
|
|
86
|
+
resizeObservers.push(this);
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
vi.stubGlobal(
|
|
91
|
+
"MutationObserver",
|
|
92
|
+
class MockMutationObserver {
|
|
93
|
+
observe = vi.fn();
|
|
94
|
+
disconnect = vi.fn();
|
|
95
|
+
takeRecords = vi.fn(() => []);
|
|
96
|
+
},
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
afterEach(() => {
|
|
101
|
+
vi.unstubAllGlobals();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
function stubOverflow(
|
|
105
|
+
el: HTMLElement,
|
|
106
|
+
metrics: {
|
|
107
|
+
scrollHeight: number;
|
|
108
|
+
clientHeight: number;
|
|
109
|
+
scrollTop?: number;
|
|
110
|
+
},
|
|
111
|
+
) {
|
|
112
|
+
Object.defineProperty(el, "scrollHeight", {
|
|
113
|
+
configurable: true,
|
|
114
|
+
get: () => metrics.scrollHeight,
|
|
115
|
+
});
|
|
116
|
+
Object.defineProperty(el, "clientHeight", {
|
|
117
|
+
configurable: true,
|
|
118
|
+
get: () => metrics.clientHeight,
|
|
119
|
+
});
|
|
120
|
+
Object.defineProperty(el, "scrollTop", {
|
|
121
|
+
configurable: true,
|
|
122
|
+
get: () => metrics.scrollTop ?? 0,
|
|
123
|
+
set: (value: number) => {
|
|
124
|
+
metrics.scrollTop = value;
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
it("renders a scroll hint when content overflows", () => {
|
|
130
|
+
render(
|
|
131
|
+
<SlideScrollContainer>
|
|
132
|
+
<div>tall content</div>
|
|
133
|
+
</SlideScrollContainer>,
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
const container = screen.getByTestId("slide-scroll-container");
|
|
137
|
+
stubOverflow(container, { scrollHeight: 900, clientHeight: 400 });
|
|
138
|
+
|
|
139
|
+
act(() => {
|
|
140
|
+
for (const observer of resizeObservers) {
|
|
141
|
+
observer.callback([], observer as unknown as ResizeObserver);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
expect(screen.getByTestId("slide-scroll-hint")).toBeTruthy();
|
|
146
|
+
expect(screen.getByText("Scroll for more")).toBeTruthy();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("hides the hint after scrolling", () => {
|
|
150
|
+
const metrics = {
|
|
151
|
+
scrollHeight: 900,
|
|
152
|
+
clientHeight: 400,
|
|
153
|
+
scrollTop: 0,
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
render(
|
|
157
|
+
<SlideScrollContainer>
|
|
158
|
+
<div>tall content</div>
|
|
159
|
+
</SlideScrollContainer>,
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
const container = screen.getByTestId("slide-scroll-container");
|
|
163
|
+
stubOverflow(container, metrics);
|
|
164
|
+
|
|
165
|
+
act(() => {
|
|
166
|
+
for (const observer of resizeObservers) {
|
|
167
|
+
observer.callback([], observer as unknown as ResizeObserver);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
expect(screen.getByTestId("slide-scroll-hint")).toBeTruthy();
|
|
171
|
+
|
|
172
|
+
act(() => {
|
|
173
|
+
metrics.scrollTop = 50;
|
|
174
|
+
container.dispatchEvent(new Event("scroll"));
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
expect(screen.queryByTestId("slide-scroll-hint")).toBeNull();
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("does not show a hint when content fits", () => {
|
|
181
|
+
render(
|
|
182
|
+
<SlideScrollContainer>
|
|
183
|
+
<div>short content</div>
|
|
184
|
+
</SlideScrollContainer>,
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
const container = screen.getByTestId("slide-scroll-container");
|
|
188
|
+
stubOverflow(container, { scrollHeight: 200, clientHeight: 400 });
|
|
189
|
+
|
|
190
|
+
act(() => {
|
|
191
|
+
for (const observer of resizeObservers) {
|
|
192
|
+
observer.callback([], observer as unknown as ResizeObserver);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
expect(screen.queryByTestId("slide-scroll-hint")).toBeNull();
|
|
197
|
+
});
|
|
198
|
+
});
|
|
@@ -13,7 +13,9 @@ import useEvent from "react-use-event-hook";
|
|
|
13
13
|
import { CodeIcon, ExpandIcon, EyeOffIcon } from "lucide-react";
|
|
14
14
|
import { Deck, Fragment, Slide, Stack } from "@revealjs/react";
|
|
15
15
|
import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
|
|
16
|
+
import { cellDomProps } from "@/components/editor/common";
|
|
16
17
|
import { Slide as CellOutputSlide } from "@/components/slides/slide";
|
|
18
|
+
import { SlideScrollContainer } from "@/components/slides/slide-scroll-hint";
|
|
17
19
|
import { Button } from "@/components/ui/button";
|
|
18
20
|
import { useFullScreenElement } from "@/components/ui/fullscreen";
|
|
19
21
|
import { Tooltip } from "@/components/ui/tooltip";
|
|
@@ -303,6 +305,25 @@ function resolveSlideContentStyle(
|
|
|
303
305
|
}
|
|
304
306
|
}
|
|
305
307
|
|
|
308
|
+
/**
|
|
309
|
+
* Renders a cell's output wrapped in a `data-cell-id`/`data-cell-name` div
|
|
310
|
+
* (see `cellDomProps`), so it can be targeted by custom CSS in the slides
|
|
311
|
+
* view just like it can in the vertical layout. The wrapper is required
|
|
312
|
+
* because `CellOutputSlide` sets its own `id` from `CellOutputId` (a
|
|
313
|
+
* different scheme than `HTMLCellId`) and its inner `OutputArea` uses
|
|
314
|
+
* `display: contents`, which can't be targeted for background/border styling.
|
|
315
|
+
*/
|
|
316
|
+
export const CellOutputBlock = ({ cell }: { cell: RuntimeCell }) => (
|
|
317
|
+
<div className="flex flex-col" {...cellDomProps(cell.id, cell.name)}>
|
|
318
|
+
<CellOutputSlide
|
|
319
|
+
cellId={cell.id}
|
|
320
|
+
status={cell.status}
|
|
321
|
+
output={cell.output}
|
|
322
|
+
stale={outputIsStale(cell, false)}
|
|
323
|
+
/>
|
|
324
|
+
</div>
|
|
325
|
+
);
|
|
326
|
+
|
|
306
327
|
const SubslideView = ({
|
|
307
328
|
subslide,
|
|
308
329
|
resolveShowCode,
|
|
@@ -327,7 +348,7 @@ const SubslideView = ({
|
|
|
327
348
|
|
|
328
349
|
return (
|
|
329
350
|
<Slide>
|
|
330
|
-
<
|
|
351
|
+
<SlideScrollContainer>
|
|
331
352
|
<div
|
|
332
353
|
className={
|
|
333
354
|
anyCodeShown
|
|
@@ -339,15 +360,7 @@ const SubslideView = ({
|
|
|
339
360
|
{subslide.blocks.map((block, i) => {
|
|
340
361
|
const rendered = block.cells.map((cell) => {
|
|
341
362
|
if (!resolveShowCode(cell.id)) {
|
|
342
|
-
return
|
|
343
|
-
<CellOutputSlide
|
|
344
|
-
key={cell.id}
|
|
345
|
-
cellId={cell.id}
|
|
346
|
-
status={cell.status}
|
|
347
|
-
output={cell.output}
|
|
348
|
-
stale={outputIsStale(cell, false)}
|
|
349
|
-
/>
|
|
350
|
-
);
|
|
363
|
+
return <CellOutputBlock key={cell.id} cell={cell} />;
|
|
351
364
|
}
|
|
352
365
|
return isEditable ? (
|
|
353
366
|
<SlideCellView key={cell.id} cell={cell} />
|
|
@@ -367,7 +380,7 @@ const SubslideView = ({
|
|
|
367
380
|
return <ReactFragment key={i}>{rendered}</ReactFragment>;
|
|
368
381
|
})}
|
|
369
382
|
</div>
|
|
370
|
-
</
|
|
383
|
+
</SlideScrollContainer>
|
|
371
384
|
{/* Outside any `.fragment`: shown only before any fragment is revealed. */}
|
|
372
385
|
{slideLevel && <NotesAside text={slideLevel} />}
|
|
373
386
|
</Slide>
|
|
@@ -405,14 +418,7 @@ const ParkedPreviewContent = ({
|
|
|
405
418
|
<SlideCellReadOnlyView cell={cell} />
|
|
406
419
|
);
|
|
407
420
|
}
|
|
408
|
-
return
|
|
409
|
-
<CellOutputSlide
|
|
410
|
-
cellId={cell.id}
|
|
411
|
-
status={cell.status}
|
|
412
|
-
output={cell.output}
|
|
413
|
-
stale={outputIsStale(cell, false)}
|
|
414
|
-
/>
|
|
415
|
-
);
|
|
421
|
+
return <CellOutputBlock cell={cell} />;
|
|
416
422
|
};
|
|
417
423
|
|
|
418
424
|
// There is an upstream react bug in dev mode (https://github.com/facebook/react/issues/34840)
|
|
@@ -202,7 +202,7 @@ export const SlideCellReadOnlyView = ({ cell }: { cell: RuntimeCell }) => {
|
|
|
202
202
|
);
|
|
203
203
|
|
|
204
204
|
const editor = (
|
|
205
|
-
<div className="marimo-cell">
|
|
205
|
+
<div className="marimo-cell" {...cellDomProps(cell.id, cell.name)}>
|
|
206
206
|
<ReadonlyCode
|
|
207
207
|
code={display.code}
|
|
208
208
|
language={display.language}
|