@marimo-team/frontend 0.23.17-dev5 → 0.23.17-dev50
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-DIW20_Z8.js → CellStatus-XlxL4ctu.js} +1 -1
- package/dist/assets/{ConnectedDataExplorerComponent-C4zEgCZh.js → ConnectedDataExplorerComponent-BF5CJvB2.js} +1 -1
- package/dist/assets/{ErrorBoundary-DzTD8LVq.js → ErrorBoundary-BfMsWVQU.js} +1 -1
- package/dist/assets/ImageComparisonComponent-CukPDP1p.js +1 -0
- package/dist/assets/{ImperativeModal-fY-ZfT0b.js → ImperativeModal-Ci0icDPt.js} +1 -1
- package/dist/assets/{JsonOutput-Bk2exFh0.js → JsonOutput-W3f6H6VQ.js} +13 -13
- package/dist/assets/{LazyAnyLanguageCodeMirror-A-Ant1Ad.js → LazyAnyLanguageCodeMirror-Dcvy_p3-.js} +2 -2
- package/dist/assets/{MarimoErrorOutput-L_o2Knzo.js → MarimoErrorOutput-COZo8cfk.js} +5 -5
- package/dist/assets/{RSPContexts-WiCgGm__.js → RSPContexts-IrDQoFki.js} +1 -1
- package/dist/assets/{RenderHTML-BTDLQMKg.js → RenderHTML-CQC8I348.js} +1 -1
- package/dist/assets/{RunButton-DiHX9YjB.js → RunButton-DRxV8u_T.js} +1 -1
- package/dist/assets/add-cell-with-ai-CuLILhtV.js +107 -0
- package/dist/assets/{add-connection-dialog-BZaJAQCM.js → add-connection-dialog-Dld_PDdZ.js} +31 -31
- package/dist/assets/{agent-panel-CRxiqCgP.js → agent-panel-3Ta5EPgw.js} +6 -6
- package/dist/assets/ai-model-dropdown-CIqhiHxf.js +5 -0
- package/dist/assets/{alert-dialog-Bb8Lz8ko.js → alert-dialog-DMh8_LWc.js} +1 -1
- package/dist/assets/{any-language-editor-BIeaxtdD.js → any-language-editor-DUQN91an.js} +1 -1
- package/dist/assets/{app-config-button-BS4LSo1l.js → app-config-button-EyzXs1Nt.js} +1 -1
- package/dist/assets/{blob-B9eg-RfN.js → blob-BzgGkt3B.js} +1 -1
- package/dist/assets/{button-DDGiD1NW.js → button-BB1AV4Rb.js} +1 -1
- package/dist/assets/{cache-panel-B2B1ePao.js → cache-panel-hpL5o4Y7.js} +1 -1
- package/dist/assets/{capabilities-DoEg0XwL.js → capabilities-LI6_PoMn.js} +1 -1
- package/dist/assets/{cell-editor-OC7h_nZ3.js → cell-editor-C5qD14SG.js} +11 -11
- package/dist/assets/{cell-link-D0aELsL_.js → cell-link-uPmFMRTh.js} +1 -1
- package/dist/assets/cells-BE1kpmPF.css +2 -0
- package/dist/assets/{cells-DLYs3NiJ.js → cells-DxL32Atg.js} +60 -60
- package/dist/assets/chat-display-CBpsXLHT.js +1 -0
- package/dist/assets/chat-panel-Dzq-QTrj.js +4 -0
- package/dist/assets/chat-ui-BcI4PAQ1.js +4 -0
- package/dist/assets/{column-preview-CnqeJb-x.js → column-preview-Dxxs9Brz.js} +1 -1
- package/dist/assets/{command-Dqxie4gq.js → command-CPFHYoYk.js} +1 -1
- package/dist/assets/command-palette-B1EO8oVR.js +1 -0
- package/dist/assets/{common-D_beLbpm.js → common-aHaDUD0-.js} +1 -1
- package/dist/assets/components-Bm1d4vm9.js +1 -0
- package/dist/assets/{components-CxEGXaTB.js → components-RV25kGIW.js} +1 -1
- package/dist/assets/config-BVfo0E1-.js +1 -0
- package/dist/assets/config-Bm5B9wGP.js +1 -0
- package/dist/assets/{copy-Bxb1_Gtw.js → copy-B-LLR1Yy.js} +1 -1
- package/dist/assets/{copy-icon-neDQUo4Q.js → copy-icon-DWG8Y-xW.js} +1 -1
- package/dist/assets/{createReducer-DGx5Af-C.js → createReducer-DNehfY0t.js} +1 -1
- package/dist/assets/{datasource-Bfg8PKXp.js → datasource-D0eBPOXe.js} +2 -2
- package/dist/assets/{dates-C2LWzsCZ.js → dates-BzOh4kS_.js} +1 -1
- package/dist/assets/defaultLocale-t77eoiwF.js +1 -0
- package/dist/assets/{dependency-graph-panel-CB5ie0zu.js → dependency-graph-panel-BKWUzXHX.js} +2 -2
- package/dist/assets/{diagram-PSM6KHXK-DIXxW5au.js → diagram-PSM6KHXK-CrTUa1Xy.js} +1 -1
- package/dist/assets/{dialog-BCVepWLJ.js → dialog-88bLE398.js} +1 -1
- package/dist/assets/{dist-CPjTeT8p.js → dist-6qzebh8f.js} +1 -1
- package/dist/assets/dist-BLqRx0W-.js +1 -0
- package/dist/assets/{dist-BP4hpPAE.js → dist-BVr4HQPR.js} +1 -1
- package/dist/assets/{dist-DnjsPBRJ.js → dist-BWXIz8tq.js} +1 -1
- package/dist/assets/{dist-Cros4IAo.js → dist-BWbS__vR.js} +1 -1
- package/dist/assets/dist-BZehnCk2.js +1 -0
- package/dist/assets/dist-BaRgF7DU.js +1 -0
- package/dist/assets/{dist-DYEuVkEX.js → dist-BblMEWTQ.js} +1 -1
- package/dist/assets/dist-BlMeFaGB.js +1 -0
- package/dist/assets/{dist-CrKffqgx.js → dist-BmYa2llD.js} +1 -1
- package/dist/assets/{dist-9o0Xjd5v.js → dist-Btp8vRFr.js} +1 -1
- package/dist/assets/{dist-C-3FVUQA.js → dist-BvMWjDxm.js} +1 -1
- package/dist/assets/{dist-DeJBvhAc.js → dist-ByfZ_2N7.js} +1 -1
- package/dist/assets/dist-C-g2AKOo.js +1 -0
- package/dist/assets/{dist-DQl27SFq.js → dist-C52BqSeO.js} +1 -1
- package/dist/assets/{dist-CiVShZKM.js → dist-C7rDfTPJ.js} +1 -1
- package/dist/assets/{dist-BKgHjzML.js → dist-C830fIIj.js} +1 -1
- package/dist/assets/{dist-fLBYOt9R.js → dist-CHN_sQZw.js} +1 -1
- package/dist/assets/dist-CLFhXj8x.js +1 -0
- package/dist/assets/{dist-D47O3FBX.js → dist-CLQWOmD7.js} +1 -1
- package/dist/assets/dist-CO4dulTL.js +1 -0
- package/dist/assets/dist-CPw3iq_l.js +1 -0
- package/dist/assets/dist-CQtN-vVI.js +1 -0
- package/dist/assets/dist-CZE9FE_5.js +1 -0
- package/dist/assets/dist-CexuM4NA.js +1 -0
- package/dist/assets/{dist-DJuRuTXr.js → dist-CfiLpZZj.js} +1 -1
- package/dist/assets/dist-CjSt6gRp.js +1 -0
- package/dist/assets/dist-Cr4q2U0d.js +1 -0
- package/dist/assets/{dist-C6_DArtj.js → dist-CxaoIFrU.js} +1 -1
- package/dist/assets/{dist-aRc_dRed.js → dist-D5nYeU7Q.js} +1 -1
- package/dist/assets/{dist-BJZAIIze.js → dist-DX04AOlt.js} +1 -1
- package/dist/assets/dist-DkZos4_s.js +1 -0
- package/dist/assets/{dist-DI1-Z60I.js → dist-DmCNk9gq.js} +1 -1
- package/dist/assets/{dist-kLs0VbW_.js → dist-DmjT6iaH.js} +1 -1
- package/dist/assets/{dist-CvWC93qL.js → dist-DrY8fZeD.js} +1 -1
- package/dist/assets/{dist-l4RTzHX-.js → dist-Drexw1Ir.js} +1 -1
- package/dist/assets/{dist-DrBqBDHF.js → dist-DtNSqHzW.js} +1 -1
- package/dist/assets/dist-DxQA7Dn1.js +1 -0
- package/dist/assets/{dist-BLN8PNJV.js → dist-Dza6FJtV.js} +1 -1
- package/dist/assets/{dist-8SH6SWEG.js → dist-HrXjBuXP.js} +1 -1
- package/dist/assets/dist-J00F7mRY.js +1 -0
- package/dist/assets/{dist-DcwTQG1A.js → dist-Jbd9zUbK.js} +1 -1
- package/dist/assets/{dist-CZvbHnyT.js → dist-bvfx5OQE.js} +1 -1
- package/dist/assets/{dist-12S8I4CH.js → dist-gUHullA_.js} +11 -11
- package/dist/assets/dist-nYKCNtEX.js +1 -0
- package/dist/assets/dist-oK8dffBy.js +1 -0
- package/dist/assets/{documentation-panel-Dii7ouzj.js → documentation-panel-DotG4o5W.js} +1 -1
- package/dist/assets/{download-DenADH0w.js → download-Tklnz6pn.js} +3 -3
- package/dist/assets/{dropdown-menu-dHmZR8bI.js → dropdown-menu-BGBlPKNz.js} +1 -1
- package/dist/assets/{edit-page-B0EhuiM-.js → edit-page-HdLqqfXC.js} +6 -6
- package/dist/assets/{error-banner-BSxEOIn2.js → error-banner-BkIr-0dH.js} +1 -1
- package/dist/assets/{error-entries-4XYBryls.js → error-entries-BvUR_22-.js} +3 -3
- package/dist/assets/{error-panel-xYZ4lX0A.js → error-panel-v0YdlA0h.js} +1 -1
- package/dist/assets/{errors-PgHhDa-M.js → errors-DCPV979Q.js} +1 -1
- package/dist/assets/{es-gYgfF8y5.js → es-Dl2xAwTv.js} +1 -1
- package/dist/assets/{esm-B30N1GS0.js → esm-Bmzgrl_5.js} +1 -1
- package/dist/assets/{esm-BDGraAqp.js → esm-Nb9m4lqg.js} +1 -1
- package/dist/assets/{field-BsxD35VE.js → field-BFgvUZyh.js} +1 -1
- package/dist/assets/file-explorer-panel-DSZY0Q7h.js +37 -0
- package/dist/assets/{file-icons-mgXTzM1c.js → file-icons-NkObNkr_.js} +1 -1
- package/dist/assets/{file-name-input-Dq7Z_QmU.js → file-name-input-BQJ9U9lU.js} +1 -1
- package/dist/assets/{floating-outline-ypOHt2wD.js → floating-outline-BHmregl1.js} +1 -1
- package/dist/assets/{focus-0L1nX7M9.js → focus-BBiJct2G.js} +1 -1
- package/dist/assets/{form-oz4Z280Z.js → form-BGoLLcgk.js} +1 -1
- package/dist/assets/{form-BsW7zr4t.js → form-BIUQB1NI.js} +1 -1
- package/dist/assets/{formats-DzmLpc9A.js → formats-DNYtnQk7.js} +1 -1
- package/dist/assets/{formatting-COz4XEaB.js → formatting-qNOrQYRN.js} +1 -1
- package/dist/assets/{fullscreen-CTDqNQr6.js → fullscreen-B51geQ_6.js} +1 -1
- package/dist/assets/{gallery-page-DbuxknAw.js → gallery-page-DBHHOraF.js} +1 -1
- package/dist/assets/{ganttDiagram-JELNMOA3-DaS60lKW.js → ganttDiagram-JELNMOA3-C9KBLmAA.js} +1 -1
- package/dist/assets/{glide-data-editor-CejKKgnN.js → glide-data-editor-CHN4-xUu.js} +1 -1
- package/dist/assets/{home-page-BOP1dDcM.js → home-page-DLeE6pH_.js} +2 -2
- package/dist/assets/{html-to-image-D_C-hjtC.js → html-to-image-ChNWEUlR.js} +1 -1
- package/dist/assets/index-BxVymcMs.js +38 -0
- package/dist/assets/index-WoaGtlKd.css +2 -0
- package/dist/assets/{input-JxFwu-3G.js → input-_AaMXWgD.js} +1 -1
- package/dist/assets/{kiosk-mode-BvKMuigM.js → kiosk-mode-RTwj6XH4.js} +1 -1
- package/dist/assets/{label-CqjrpwRC.js → label-DUD3SZnk.js} +1 -1
- package/dist/assets/{layout-yfmf2ZBx.js → layout-QkEddeXT.js} +4 -4
- package/dist/assets/{linear-BPv4krGt.js → linear-B1ROUUtm.js} +1 -1
- package/dist/assets/{links-ClNQSIal.js → links-DBc28bsl.js} +1 -1
- package/dist/assets/{logs-panel-OMd1Z9CL.js → logs-panel-Cdcjc_fq.js} +1 -1
- package/dist/assets/markdown-export-CNu5ZTPR.js +1 -0
- package/dist/assets/{markdown-renderer-BfLNJGNj.js → markdown-renderer-DpskAUxO.js} +1 -1
- package/dist/assets/{menu-items-CCi6aOPm.js → menu-items-Db-bgz92.js} +1 -1
- package/dist/assets/{mermaid-B8gNHyGy.js → mermaid-OU2hLna0.js} +3 -3
- package/dist/assets/{name-cell-input-COtjRghz.js → name-cell-input-DoxL2EXI.js} +1 -1
- package/dist/assets/{numbers-rmawRqQP.js → numbers-D9g2ArIv.js} +1 -1
- package/dist/assets/{outline-panel-CIGf4SLb.js → outline-panel-BxjI-YSj.js} +1 -1
- package/dist/assets/{packages-panel-DLuMuNuG.js → packages-panel-CiKYP9Ij.js} +1 -1
- package/dist/assets/{pair-with-agent-modal-C5OhJ8rX.js → pair-with-agent-modal-1b5Eh8Xo.js} +1 -1
- package/dist/assets/{panel-accordion-state-D1UP17Lk.js → panel-accordion-state-BkWYwckU.js} +1 -1
- package/dist/assets/{panels-B0w23XJS.js → panels-Swk0l08v.js} +2 -2
- package/dist/assets/{popover-Bcz1Zikb.js → popover-DHbixh3D.js} +1 -1
- package/dist/assets/{precisionRound-i2ImZxgc.js → precisionRound-DORAUfVY.js} +1 -1
- package/dist/assets/process-output-DJonUYp2.js +1 -0
- package/dist/assets/{quadrantDiagram-AYHSOK5B-DJuGB95-.js → quadrantDiagram-AYHSOK5B-Duf8sGaa.js} +1 -1
- package/dist/assets/{radio-group-BGXYy3u5.js → radio-group-ByLzIKjm.js} +1 -1
- package/dist/assets/react-vega-J-J2akIt.js +191 -0
- package/dist/assets/{readonly-code-display-DdABj8tH.js → readonly-code-display-B_ZHScA7.js} +1 -1
- package/dist/assets/{readonly-python-code-DUjqXwhi.js → readonly-python-code-C4GeGU7O.js} +1 -1
- package/dist/assets/{renderShortcut-Bl8_FVn8.js → renderShortcut-DnqsU4zj.js} +1 -1
- package/dist/assets/{reveal-component-BjgfnO81.js → reveal-component-De_cjq3p.js} +2 -2
- package/dist/assets/{run-page-DDty5GvQ.js → run-page-DmXT_-MQ.js} +1 -1
- package/dist/assets/{runs-s9t2f_Tg.js → runs-C6avq6Gi.js} +1 -1
- package/dist/assets/scratchpad-panel-BtGHIRdJ.js +1 -0
- package/dist/assets/{scroll-to-bottom-button-C8yfT4wq.js → scroll-to-bottom-button-CRMPUjYZ.js} +1 -1
- package/dist/assets/{secrets-panel-Cz17_MLf.js → secrets-panel-DmAwH7vI.js} +1 -1
- package/dist/assets/{select-BP75_5jJ.js → select-Clmc8Hw2.js} +1 -1
- package/dist/assets/{session-BmukRjSi.js → session-BtBr2zr3.js} +1 -1
- package/dist/assets/{session-panel-aMoQPTCB.js → session-panel-kBLydN0h.js} +1 -1
- package/dist/assets/{share-852X_cqy.js → share-DSOv_SvY.js} +1 -1
- package/dist/assets/{skeleton-CPuDx7yn.js → skeleton-CJymG2v3.js} +1 -1
- package/dist/assets/{snippets-panel-DBDXr-XP.js → snippets-panel-l_HnIWUj.js} +1 -1
- package/dist/assets/{spec-C7opZZRp.js → spec-CdDzA5ef.js} +1 -1
- package/dist/assets/{state-DCtLlFJq.js → state-B4lC29et.js} +1 -1
- package/dist/assets/{state-C4kiwedg.js → state-BkoVfBqt.js} +1 -1
- package/dist/assets/{state-hlEqpZfH.js → state-D9xpDCxa.js} +2 -2
- package/dist/assets/state-DDimGh2o.js +1 -0
- package/dist/assets/{strings--BknHX9C.js → strings-DMKwTex-.js} +1 -1
- package/dist/assets/{swiper-component-DXW8snlt.js → swiper-component-pSAP3cRf.js} +1 -1
- package/dist/assets/switch-8FxRs-OU.js +1 -0
- package/dist/assets/{terminal-CaHTVNrz.js → terminal-DPQJ6hNg.js} +1 -1
- package/dist/assets/{textarea-DtCcemo9.js → textarea-BzWvGIrJ.js} +1 -1
- package/dist/assets/{time-p47i6wvp.js → time-BO-naW1O.js} +1 -1
- package/dist/assets/tooltip-BMi4WFDl.js +61 -0
- package/dist/assets/{tooltip-4bZlU7jl.js → tooltip-BcgbFR7q.js} +1 -1
- package/dist/assets/{tracing-CStM7RGI.js → tracing-DCuWLKnk.js} +1 -1
- package/dist/assets/{tracing-panel-BTLzu8L-.js → tracing-panel-dVtThkzL.js} +2 -2
- package/dist/assets/{tree-actions-BwwVyp3l.js → tree-actions-o2iyMmKN.js} +1 -1
- package/dist/assets/{useBoolean-DIi7jQLa.js → useBoolean-sASJEpGA.js} +1 -1
- package/dist/assets/{useCellActionButton-uxVyv3JK.js → useCellActionButton-n2-2xb-5.js} +1 -1
- package/dist/assets/{useDeleteCell-Cy23OP4e.js → useDeleteCell-DH0weyin.js} +1 -1
- package/dist/assets/{useDependencyPanelTab-DNfjp_-X.js → useDependencyPanelTab-DQZmbkd-.js} +1 -1
- package/dist/assets/{useEventListener-C0195JsF.js → useEventListener-B_wSLgFR.js} +1 -1
- package/dist/assets/{useHotkey-DLZvrRZT.js → useHotkey-DJyYmk5P.js} +1 -1
- package/dist/assets/{useIframeCapabilities-j6fR_dBA.js → useIframeCapabilities-D_6fB_8O.js} +1 -1
- package/dist/assets/{useInstallPackage-WiYBwhUO.js → useInstallPackage-DyNrAhrx.js} +1 -1
- package/dist/assets/{useInterval-CnQfyMa9.js → useInterval-CjGsg4ie.js} +1 -1
- package/dist/assets/useNotebookActions-BUQta3nX.js +12 -0
- package/dist/assets/useRunCells-8xYRh7wH.js +1 -0
- package/dist/assets/{useSplitCell-BK5mnkkL.js → useSplitCell-BvgvIZaz.js} +1 -1
- package/dist/assets/{useTheme-Bxv9B31g.js → useTheme-BR31Gjbc.js} +1 -1
- package/dist/assets/utils-C5VWChv9.js +1 -0
- package/dist/assets/{vega-component-BGiCExka.js → vega-component-DG9G1qk2.js} +1 -1
- package/dist/assets/{vega-embed-container-DxSqUOCK.js → vega-embed-container-BJRQVehC.js} +1 -1
- package/dist/assets/vega-loader.browser-CAfmqKEc.js +6 -0
- package/dist/assets/{write-secret-modal-Dtm66yVf.js → write-secret-modal-DwCUuNRy.js} +1 -1
- package/dist/assets/{xychartDiagram-PRI3JC2R-B8A0hi-Q.js → xychartDiagram-PRI3JC2R-ClPpSFDI.js} +1 -1
- package/dist/assets/{zod-H_cgTO0M.js → zod-CIOjj3iA.js} +5 -5
- package/dist/index.html +87 -87
- package/package.json +7 -7
- package/src/__mocks__/requests.ts +5 -0
- package/src/components/ai/ai-model-dropdown.tsx +2 -2
- package/src/components/app-config/user-config-form.tsx +26 -0
- package/src/components/chat/__tests__/capabilities-popover.test.tsx +38 -0
- package/src/components/chat/__tests__/chat-abort.test.ts +51 -0
- package/src/components/chat/__tests__/use-chat-controller-id.test.tsx +39 -0
- package/src/components/chat/capabilities-popover.tsx +68 -0
- package/src/components/chat/chat-abort.ts +44 -0
- package/src/components/chat/chat-display.tsx +17 -0
- package/src/components/chat/chat-panel.tsx +107 -50
- package/src/components/chat/chat-utils.ts +1 -1
- package/src/components/chat/use-chat-controller-id.ts +24 -0
- package/src/components/data-table/charts/__tests__/schemas.test.ts +35 -0
- package/src/components/data-table/charts/schemas.ts +5 -2
- package/src/components/databases/icons/huggingface.svg +8 -0
- package/src/components/datasets/__tests__/icons.test.ts +21 -0
- package/src/components/datasets/icons.tsx +10 -0
- package/src/components/datasources/__tests__/components.test.tsx +29 -0
- package/src/components/datasources/components.tsx +8 -3
- package/src/components/editor/actions/export-dialog/__tests__/export-dialog.test.tsx +35 -0
- package/src/components/editor/actions/export-dialog/__tests__/state.test.ts +61 -0
- package/src/components/editor/actions/export-dialog/export-command.ts +4 -9
- package/src/components/editor/actions/export-dialog/export-dialog.tsx +27 -23
- package/src/components/editor/actions/export-dialog/format-notice.tsx +28 -0
- package/src/components/editor/actions/export-dialog/state.ts +23 -5
- package/src/components/editor/actions/export-dialog/use-export-dialog.ts +7 -15
- package/src/components/editor/actions/useConfigActions.tsx +24 -0
- package/src/components/editor/ai/add-cell-with-ai.tsx +2 -2
- package/src/components/editor/ai/ai-completion-editor.tsx +2 -2
- package/src/components/editor/chrome/panels/outline/__tests__/useActiveOutline.test.ts +26 -0
- package/src/components/editor/chrome/wrapper/useOpenAiAssistant.ts +2 -2
- package/src/components/editor/code/__tests__/readonly-python-code.test.tsx +114 -2
- package/src/components/editor/connections/storage/__tests__/__snapshots__/as-code.test.ts.snap +14 -0
- package/src/components/editor/connections/storage/__tests__/as-code.test.ts +20 -0
- package/src/components/editor/connections/storage/add-storage-form.tsx +10 -0
- package/src/components/editor/connections/storage/as-code.ts +19 -1
- package/src/components/editor/connections/storage/schemas.ts +19 -0
- package/src/components/storage/__tests__/storage-snippets.test.ts +88 -0
- package/src/components/storage/components.tsx +2 -0
- package/src/components/storage/storage-snippets.ts +58 -0
- package/src/core/__tests__/mode.test.ts +85 -0
- package/src/core/ai/__tests__/config.test.tsx +96 -0
- package/src/core/ai/config.ts +16 -22
- package/src/core/ai/constants.ts +7 -0
- package/src/core/ai/staged-cells.ts +3 -0
- package/src/core/ai/state.ts +10 -0
- package/src/core/codemirror/__tests__/setup.test.ts +1 -1
- package/src/core/codemirror/cm.ts +2 -2
- package/src/core/codemirror/code-lens/__tests__/extension.test.ts +4 -5
- package/src/core/codemirror/code-lens/extension.ts +3 -3
- package/src/core/codemirror/find-replace/search-highlight.ts +8 -3
- package/src/core/codemirror/language/languages/sql/__tests__/renderers.test.tsx +44 -0
- package/src/core/codemirror/language/languages/sql/renderers.tsx +3 -3
- package/src/core/codemirror/theme/__tests__/light.test.ts +59 -123
- package/src/core/codemirror/theme/dark.ts +6 -5
- package/src/core/codemirror/theme/light.ts +6 -4
- package/src/core/config/__tests__/config-schema.test.ts +2 -0
- package/src/core/config/config-schema.ts +1 -0
- package/src/core/config/feature-flag.tsx +0 -2
- package/src/core/dom/outline.ts +25 -2
- package/src/core/hotkeys/hotkeys.ts +2 -0
- package/src/core/mode.ts +11 -9
- package/src/core/network/__tests__/api.test.ts +132 -17
- package/src/core/network/__tests__/export-filename.test.ts +43 -0
- package/src/core/network/__tests__/requests-lazy.test.ts +1 -0
- package/src/core/network/api.ts +47 -12
- package/src/core/network/export-filename.ts +37 -0
- package/src/core/network/markdown-export.ts +19 -0
- package/src/core/network/requests-network.ts +29 -5
- package/src/core/network/types.ts +4 -0
- package/src/core/storage/types.ts +1 -0
- package/src/css/app/codemirror.css +11 -7
- package/src/css/globals.css +8 -0
- package/src/plugins/impl/DataEditorPlugin.tsx +2 -9
- package/src/plugins/impl/__tests__/DataEditorPlugin.test.ts +18 -0
- package/src/plugins/impl/chat/chat-ui.tsx +51 -3
- package/src/plugins/impl/data-frames/__tests__/schema.test.ts +30 -0
- package/src/plugins/impl/data-frames/schema.ts +4 -1
- package/src/plugins/impl/image-comparison/ImageComparisonComponent.tsx +20 -1
- package/src/plugins/impl/image-comparison/__tests__/ImageComparisonComponent.test.tsx +58 -0
- package/src/stories/theme.stories.tsx +71 -1
- package/dist/assets/ImageComparisonComponent-COvcNAUu.js +0 -1
- package/dist/assets/add-cell-with-ai-BU5EDuHt.js +0 -107
- package/dist/assets/ai-model-dropdown-CLCa-gsg.js +0 -5
- package/dist/assets/cells-BVzo2MHf.css +0 -2
- package/dist/assets/chat-display-7CzBSZRm.js +0 -1
- package/dist/assets/chat-panel-Dd5WiR1a.js +0 -4
- package/dist/assets/chat-ui-CYqqqoSC.js +0 -4
- package/dist/assets/command-palette-BBlSC8AZ.js +0 -1
- package/dist/assets/components-K_Mi0vdC.js +0 -1
- package/dist/assets/config-BJVx3eBW.js +0 -1
- package/dist/assets/config-DAL-jiRM.js +0 -1
- package/dist/assets/defaultLocale-DOVIEEPN.js +0 -1
- package/dist/assets/dist-B99-E4qp.js +0 -1
- package/dist/assets/dist-Bfm9U3vp.js +0 -1
- package/dist/assets/dist-BiwuSVkx.js +0 -1
- package/dist/assets/dist-BrZjJXDA.js +0 -1
- package/dist/assets/dist-CaZf6AoY.js +0 -1
- package/dist/assets/dist-Cgoy5550.js +0 -1
- package/dist/assets/dist-Csf5i4KY.js +0 -1
- package/dist/assets/dist-D6Iobl3P.js +0 -1
- package/dist/assets/dist-D6WgndTj.js +0 -1
- package/dist/assets/dist-DcXy-1eJ.js +0 -1
- package/dist/assets/dist-DsfPGbgk.js +0 -1
- package/dist/assets/dist-DtbtRAqz.js +0 -1
- package/dist/assets/dist-I3qeQWuP.js +0 -1
- package/dist/assets/dist-aeKlrIMv.js +0 -1
- package/dist/assets/dist-gDi2I7IJ.js +0 -1
- package/dist/assets/dist-miDa4-cz.js +0 -1
- package/dist/assets/dist-nDEBxpL6.js +0 -1
- package/dist/assets/dist-oUL4XFdB.js +0 -1
- package/dist/assets/file-explorer-panel-4h-BKKaM.js +0 -26
- package/dist/assets/house-DS0r7dNZ.js +0 -1
- package/dist/assets/index-BXlfeAku.js +0 -38
- package/dist/assets/index-DYycoCjG.css +0 -2
- package/dist/assets/process-output-Cm_vuKBw.js +0 -1
- package/dist/assets/react-vega-BLc5RhC7.js +0 -188
- package/dist/assets/scratchpad-panel-DJkO5OrI.js +0 -1
- package/dist/assets/state-Brswj8bD.js +0 -1
- package/dist/assets/switch-CONP-vq2.js +0 -1
- package/dist/assets/tooltip-B7U4xkIN.js +0 -61
- package/dist/assets/useNotebookActions-BHaEvPEM.js +0 -12
- package/dist/assets/useRunCells-kmbsc2R5.js +0 -1
- package/dist/assets/utils-BWBBpCkT.js +0 -1
- package/dist/assets/vega-loader.browser-Dun7Qe4B.js +0 -6
- /package/dist/assets/{bundle.esm-D0TWQ6iT.js → bundle.esm-CvMga-X6.js} +0 -0
- /package/dist/assets/{icons-CIPE8AIY.js → icons-NFYKylj6.js} +0 -0
- /package/dist/assets/{useDeepCompareMemoize-CSMoa-ga.js → useDeepCompareMemoize-BLRnan2Y.js} +0 -0
|
@@ -140,11 +140,16 @@ export const searchHighlighter = ViewPlugin.fromClass(
|
|
|
140
140
|
);
|
|
141
141
|
|
|
142
142
|
export const highlightTheme = EditorView.baseTheme({
|
|
143
|
-
"&light .cm-searchMatch": {
|
|
144
|
-
|
|
143
|
+
"&light .cm-searchMatch": {
|
|
144
|
+
backgroundColor: "var(--cm-search-match-background-light)",
|
|
145
|
+
},
|
|
146
|
+
"&dark .cm-searchMatch": {
|
|
147
|
+
backgroundColor: "var(--cm-search-match-background-dark)",
|
|
148
|
+
},
|
|
145
149
|
|
|
146
150
|
"&light .cm-searchMatch-selected": { backgroundColor: "transparent" },
|
|
147
151
|
"&dark .cm-searchMatch.cm-searchMatch-selected": {
|
|
148
|
-
backgroundColor:
|
|
152
|
+
backgroundColor:
|
|
153
|
+
"var(--cm-search-match-selected-background-dark) !important",
|
|
149
154
|
},
|
|
150
155
|
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { render } from "@testing-library/react";
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import type {
|
|
6
|
+
DataTable,
|
|
7
|
+
DataTableColumn,
|
|
8
|
+
DataType,
|
|
9
|
+
} from "@/core/kernel/messages";
|
|
10
|
+
import { renderColumnInfo, renderTableInfo } from "../renderers";
|
|
11
|
+
|
|
12
|
+
const geometryColumn = {
|
|
13
|
+
name: "geom",
|
|
14
|
+
type: "geometry" as DataType,
|
|
15
|
+
external_type: "geometry",
|
|
16
|
+
sample_values: [],
|
|
17
|
+
} as DataTableColumn;
|
|
18
|
+
|
|
19
|
+
describe("SQL renderers", () => {
|
|
20
|
+
it("renders table information with an unrecognized column type", () => {
|
|
21
|
+
const table: DataTable = {
|
|
22
|
+
name: "shapes",
|
|
23
|
+
type: "table",
|
|
24
|
+
source: "local",
|
|
25
|
+
source_type: "local",
|
|
26
|
+
num_rows: null,
|
|
27
|
+
num_columns: 1,
|
|
28
|
+
variable_name: null,
|
|
29
|
+
columns: [geometryColumn],
|
|
30
|
+
primary_keys: [],
|
|
31
|
+
indexes: [],
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const result = render(renderTableInfo(table));
|
|
35
|
+
|
|
36
|
+
expect(result.container.querySelector("svg")).not.toBeNull();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("renders column information with an unrecognized column type", () => {
|
|
40
|
+
const result = render(renderColumnInfo(geometryColumn));
|
|
41
|
+
|
|
42
|
+
expect(result.container.querySelector("svg")).not.toBeNull();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
TableIcon,
|
|
14
14
|
ViewIcon,
|
|
15
15
|
} from "@/components/databases/namespace-icons";
|
|
16
|
-
import { DATA_TYPE_ICON } from "@/components/datasets/icons";
|
|
16
|
+
import { DATA_TYPE_ICON, resolveDataType } from "@/components/datasets/icons";
|
|
17
17
|
import { Badge } from "@/components/ui/badge";
|
|
18
18
|
import {
|
|
19
19
|
type ConnectionName,
|
|
@@ -149,7 +149,7 @@ export const renderTableInfo = (table: DataTable): React.ReactNode => {
|
|
|
149
149
|
);
|
|
150
150
|
|
|
151
151
|
const columnItems = table.columns.map((column) => {
|
|
152
|
-
const TypeIcon = DATA_TYPE_ICON[column.type];
|
|
152
|
+
const TypeIcon = DATA_TYPE_ICON[resolveDataType(column.type)];
|
|
153
153
|
return (
|
|
154
154
|
<div
|
|
155
155
|
key={column.name}
|
|
@@ -288,7 +288,7 @@ export const renderTableInfo = (table: DataTable): React.ReactNode => {
|
|
|
288
288
|
};
|
|
289
289
|
|
|
290
290
|
export const renderColumnInfo = (column: DataTableColumn): React.ReactNode => {
|
|
291
|
-
const TypeIcon = DATA_TYPE_ICON[column.type];
|
|
291
|
+
const TypeIcon = DATA_TYPE_ICON[resolveDataType(column.type)];
|
|
292
292
|
|
|
293
293
|
const typeBadge = (
|
|
294
294
|
<Badge
|
|
@@ -1,136 +1,72 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
3
|
+
import type { Extension } from "@codemirror/state";
|
|
4
|
+
import { EditorView } from "@codemirror/view";
|
|
5
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
6
|
+
import { darkTheme } from "../dark";
|
|
5
7
|
import { lightTheme } from "../light";
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
const getThemeConfig = () => ({
|
|
9
|
-
variant: "light",
|
|
10
|
-
settings: {
|
|
11
|
-
background: "#ffffff",
|
|
12
|
-
foreground: "#000000",
|
|
13
|
-
caret: "#000000",
|
|
14
|
-
selection: "#d7d4f0",
|
|
15
|
-
lineHighlight: "#cceeff44",
|
|
16
|
-
gutterBackground: "var(--color-background)",
|
|
17
|
-
gutterForeground: "var(--gray-10)",
|
|
18
|
-
},
|
|
19
|
-
styles: [
|
|
20
|
-
{ tag: t.comment, color: "#708090" },
|
|
21
|
-
{ tag: t.variableName, color: "#000000" },
|
|
22
|
-
{ tag: [t.string, t.special(t.brace)], color: "#a11" },
|
|
23
|
-
{ tag: t.number, color: "#164" },
|
|
24
|
-
{ tag: t.bool, color: "#219" },
|
|
25
|
-
{ tag: t.null, color: "#219" },
|
|
26
|
-
{ tag: t.keyword, color: "#708", fontWeight: 500 },
|
|
27
|
-
{ tag: t.className, color: "#00f" },
|
|
28
|
-
{ tag: t.definition(t.typeName), color: "#00f" },
|
|
29
|
-
{ tag: t.typeName, color: "#085" },
|
|
30
|
-
{ tag: t.angleBracket, color: "#000000" },
|
|
31
|
-
{ tag: t.tagName, color: "#170" },
|
|
32
|
-
{ tag: t.attributeName, color: "#00c" },
|
|
33
|
-
{ tag: t.operator, color: "#a2f", fontWeight: 500 },
|
|
34
|
-
{ tag: [t.function(t.variableName)], color: "#00c" },
|
|
35
|
-
{ tag: [t.propertyName], color: "#05a" },
|
|
36
|
-
],
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
describe("lightTheme", () => {
|
|
40
|
-
it("should export a theme", () => {
|
|
41
|
-
expect(lightTheme).toBeDefined();
|
|
42
|
-
expect(typeof lightTheme).toBe("object");
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
describe("theme configuration", () => {
|
|
46
|
-
const config = getThemeConfig();
|
|
47
|
-
|
|
48
|
-
it("should have correct basic settings", () => {
|
|
49
|
-
expect(config.variant).toBe("light");
|
|
50
|
-
expect(config.settings).toEqual({
|
|
51
|
-
background: "#ffffff",
|
|
52
|
-
foreground: "#000000",
|
|
53
|
-
caret: "#000000",
|
|
54
|
-
selection: "#d7d4f0",
|
|
55
|
-
lineHighlight: "#cceeff44",
|
|
56
|
-
gutterBackground: "var(--color-background)",
|
|
57
|
-
gutterForeground: "var(--gray-10)",
|
|
58
|
-
});
|
|
59
|
-
});
|
|
9
|
+
const mounted: Array<{ host: HTMLDivElement; view: EditorView }> = [];
|
|
60
10
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
11
|
+
function mountTheme(extension: Extension) {
|
|
12
|
+
const host = document.createElement("div");
|
|
13
|
+
document.body.append(host);
|
|
14
|
+
const root = host.attachShadow({ mode: "open" });
|
|
15
|
+
const parent = document.createElement("div");
|
|
16
|
+
root.append(parent);
|
|
17
|
+
const view = new EditorView({ extensions: extension, parent, root });
|
|
18
|
+
mounted.push({ host, view });
|
|
66
19
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
20
|
+
const style = root.querySelector("style");
|
|
21
|
+
if (!style) {
|
|
22
|
+
throw new Error("CodeMirror did not mount its theme styles");
|
|
23
|
+
}
|
|
24
|
+
return { css: style.textContent ?? "", view };
|
|
25
|
+
}
|
|
73
26
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
expect(style?.tag).toContain(t.special(t.brace));
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it("should style numbers and boolean values", () => {
|
|
84
|
-
expect(findStyle(t.number)).toEqual({
|
|
85
|
-
tag: t.number,
|
|
86
|
-
color: "#164",
|
|
87
|
-
});
|
|
88
|
-
expect(findStyle(t.bool)).toEqual({
|
|
89
|
-
tag: t.bool,
|
|
90
|
-
color: "#219",
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it("should style keywords with emphasis", () => {
|
|
95
|
-
expect(findStyle(t.keyword)).toEqual({
|
|
96
|
-
tag: t.keyword,
|
|
97
|
-
color: "#708",
|
|
98
|
-
fontWeight: 500,
|
|
99
|
-
});
|
|
100
|
-
});
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
for (const { host, view } of mounted.splice(0)) {
|
|
29
|
+
view.destroy();
|
|
30
|
+
host.remove();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
101
33
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
34
|
+
const themeCases = [
|
|
35
|
+
{
|
|
36
|
+
name: "light",
|
|
37
|
+
extension: lightTheme,
|
|
38
|
+
dark: false,
|
|
39
|
+
selectionAlias: "var(--cm-selection-background-light)",
|
|
40
|
+
reactiveColor: "var(--cm-reactive-reference-color-light)",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "dark",
|
|
44
|
+
extension: darkTheme,
|
|
45
|
+
dark: true,
|
|
46
|
+
selectionAlias: "var(--cm-selection-background-dark)",
|
|
47
|
+
reactiveColor: "var(--cm-reactive-reference-color-dark)",
|
|
48
|
+
},
|
|
49
|
+
] as const;
|
|
109
50
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
color: "#00f",
|
|
114
|
-
});
|
|
115
|
-
expect(findStyle(t.typeName)).toEqual({
|
|
116
|
-
tag: t.typeName,
|
|
117
|
-
color: "#085",
|
|
118
|
-
});
|
|
119
|
-
});
|
|
51
|
+
describe.each(themeCases)("$name theme", (theme) => {
|
|
52
|
+
it("uses the production theme tokens", () => {
|
|
53
|
+
const { css, view } = mountTheme(theme.extension);
|
|
120
54
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
55
|
+
expect(view.state.facet(EditorView.darkTheme)).toBe(theme.dark);
|
|
56
|
+
expect(css).toContain(
|
|
57
|
+
`--cm-selection-background: ${theme.selectionAlias};`,
|
|
58
|
+
);
|
|
59
|
+
expect(css).toContain("background-color: var(--cm-selection-background);");
|
|
60
|
+
expect(css).toContain(`color: ${theme.reactiveColor};`);
|
|
61
|
+
expect(css).toContain(
|
|
62
|
+
"border-bottom: 2px solid var(--cm-reactive-reference-border-color);",
|
|
63
|
+
);
|
|
127
64
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
});
|
|
65
|
+
const hoverRule = css
|
|
66
|
+
.split("\n")
|
|
67
|
+
.find((rule) => rule.includes(".mo-cm-reactive-reference-hover"));
|
|
68
|
+
expect(hoverRule).toBeDefined();
|
|
69
|
+
expect(hoverRule).toContain("cursor: pointer;");
|
|
70
|
+
expect(hoverRule).not.toContain("border-bottom");
|
|
135
71
|
});
|
|
136
72
|
});
|
|
@@ -11,7 +11,7 @@ export const darkTheme = [
|
|
|
11
11
|
background: "var(--cm-background)",
|
|
12
12
|
foreground: "#abb2bf",
|
|
13
13
|
caret: "#528bff",
|
|
14
|
-
selection: "
|
|
14
|
+
selection: "var(--cm-selection-background)",
|
|
15
15
|
lineHighlight: "#2c313c",
|
|
16
16
|
gutterBackground: "var(--color-background)",
|
|
17
17
|
gutterForeground: "var(--gray-10)",
|
|
@@ -36,15 +36,16 @@ export const darkTheme = [
|
|
|
36
36
|
],
|
|
37
37
|
}),
|
|
38
38
|
EditorView.theme({
|
|
39
|
+
"&": {
|
|
40
|
+
"--cm-selection-background": "var(--cm-selection-background-dark)",
|
|
41
|
+
},
|
|
39
42
|
".mo-cm-reactive-reference": {
|
|
40
43
|
fontWeight: "400",
|
|
41
|
-
color: "
|
|
42
|
-
borderBottom: "2px solid
|
|
44
|
+
color: "var(--cm-reactive-reference-color-dark)",
|
|
45
|
+
borderBottom: "2px solid var(--cm-reactive-reference-border-color)",
|
|
43
46
|
},
|
|
44
47
|
".mo-cm-reactive-reference-hover": {
|
|
45
48
|
cursor: "pointer",
|
|
46
|
-
borderBottomWidth: "3px",
|
|
47
|
-
borderBottomColor: "#4a90a5",
|
|
48
49
|
},
|
|
49
50
|
}),
|
|
50
51
|
];
|
|
@@ -11,7 +11,7 @@ export const lightTheme = [
|
|
|
11
11
|
background: "#ffffff",
|
|
12
12
|
foreground: "#000000",
|
|
13
13
|
caret: "#000000",
|
|
14
|
-
selection: "
|
|
14
|
+
selection: "var(--cm-selection-background)",
|
|
15
15
|
lineHighlight: "#cceeff44",
|
|
16
16
|
gutterBackground: "var(--color-background)",
|
|
17
17
|
gutterForeground: "var(--gray-10)",
|
|
@@ -45,14 +45,16 @@ export const lightTheme = [
|
|
|
45
45
|
],
|
|
46
46
|
}),
|
|
47
47
|
EditorView.theme({
|
|
48
|
+
"&": {
|
|
49
|
+
"--cm-selection-background": "var(--cm-selection-background-light)",
|
|
50
|
+
},
|
|
48
51
|
".mo-cm-reactive-reference": {
|
|
49
52
|
fontWeight: "400",
|
|
50
|
-
color: "
|
|
51
|
-
borderBottom: "2px solid
|
|
53
|
+
color: "var(--cm-reactive-reference-color-light)",
|
|
54
|
+
borderBottom: "2px solid var(--cm-reactive-reference-border-color)",
|
|
52
55
|
},
|
|
53
56
|
".mo-cm-reactive-reference-hover": {
|
|
54
57
|
cursor: "pointer",
|
|
55
|
-
borderBottomWidth: "3px",
|
|
56
58
|
},
|
|
57
59
|
}),
|
|
58
60
|
];
|
|
@@ -66,6 +66,7 @@ test("default UserConfig - empty", () => {
|
|
|
66
66
|
"display": {
|
|
67
67
|
"cell_output": "below",
|
|
68
68
|
"code_editor_font_size": 14,
|
|
69
|
+
"code_lens": true,
|
|
69
70
|
"dataframes": "rich",
|
|
70
71
|
"default_table_max_columns": 50,
|
|
71
72
|
"default_table_page_size": 10,
|
|
@@ -139,6 +140,7 @@ test("default UserConfig - one level", () => {
|
|
|
139
140
|
"display": {
|
|
140
141
|
"cell_output": "below",
|
|
141
142
|
"code_editor_font_size": 14,
|
|
143
|
+
"code_lens": true,
|
|
142
144
|
"dataframes": "rich",
|
|
143
145
|
"default_table_max_columns": 50,
|
|
144
146
|
"default_table_page_size": 10,
|
|
@@ -13,7 +13,6 @@ export interface ExperimentalFeatures {
|
|
|
13
13
|
external_agents: boolean;
|
|
14
14
|
debugger: boolean; // Live frame-watching debugger (gutter breakpoints + pdb)
|
|
15
15
|
line_timing: boolean; // Green active-line highlight + per-line elapsed timer
|
|
16
|
-
editor_code_lens: boolean; // Inline icons in cell editors linking datasources/buckets/caches to their panels
|
|
17
16
|
// Add new feature flags here
|
|
18
17
|
}
|
|
19
18
|
|
|
@@ -25,7 +24,6 @@ const defaultValues: ExperimentalFeatures = {
|
|
|
25
24
|
external_agents: import.meta.env.DEV,
|
|
26
25
|
debugger: false,
|
|
27
26
|
line_timing: false,
|
|
28
|
-
editor_code_lens: import.meta.env.DEV,
|
|
29
27
|
};
|
|
30
28
|
|
|
31
29
|
export function getFeatureFlag<T extends keyof ExperimentalFeatures>(
|
package/src/core/dom/outline.ts
CHANGED
|
@@ -63,13 +63,36 @@ function getOutline(html: string): Outline | null {
|
|
|
63
63
|
return { items };
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
function toXPathStringLiteral(value: string): string {
|
|
67
|
+
if (!value.includes('"')) {
|
|
68
|
+
return `"${value}"`;
|
|
69
|
+
}
|
|
70
|
+
if (!value.includes("'")) {
|
|
71
|
+
return `'${value}'`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const segments = value.split('"');
|
|
75
|
+
const literals: string[] = [];
|
|
76
|
+
for (const [index, segment] of segments.entries()) {
|
|
77
|
+
if (segment) {
|
|
78
|
+
literals.push(`"${segment}"`);
|
|
79
|
+
}
|
|
80
|
+
if (index < segments.length - 1) {
|
|
81
|
+
literals.push(`'"'`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return `concat(${literals.join(", ")})`;
|
|
85
|
+
}
|
|
86
|
+
|
|
66
87
|
export function headingToIdentifier(heading: Element): OutlineItem["by"] {
|
|
67
88
|
const id = heading.id;
|
|
68
89
|
if (id) {
|
|
69
90
|
return { id };
|
|
70
91
|
}
|
|
71
|
-
const name = heading.textContent;
|
|
72
|
-
return {
|
|
92
|
+
const name = heading.textContent ?? "";
|
|
93
|
+
return {
|
|
94
|
+
path: `//${heading.tagName}[contains(., ${toXPathStringLiteral(name)})]`,
|
|
95
|
+
};
|
|
73
96
|
}
|
|
74
97
|
|
|
75
98
|
export function mergeOutlines(outlines: (Outline | null)[]): Outline {
|
|
@@ -393,11 +393,13 @@ const DEFAULT_HOT_KEY = {
|
|
|
393
393
|
name: "Collapse all sections",
|
|
394
394
|
group: "Editing",
|
|
395
395
|
key: "Mod-Shift-\\",
|
|
396
|
+
additionalKeywords: ["fold", "headers"],
|
|
396
397
|
},
|
|
397
398
|
"global.expandAllSections": {
|
|
398
399
|
name: "Expand all sections",
|
|
399
400
|
group: "Editing",
|
|
400
401
|
key: "Mod-Shift-/",
|
|
402
|
+
additionalKeywords: ["unfold", "headers"],
|
|
401
403
|
},
|
|
402
404
|
"global.toggleMinimap": {
|
|
403
405
|
name: "Toggle Minimap",
|
package/src/core/mode.ts
CHANGED
|
@@ -55,20 +55,22 @@ export async function runDuringPresentMode(
|
|
|
55
55
|
fn: () => void | Promise<void>,
|
|
56
56
|
): Promise<void> {
|
|
57
57
|
const state = store.get(viewStateAtom);
|
|
58
|
-
if (state.mode
|
|
58
|
+
if (state.mode !== "edit") {
|
|
59
59
|
await fn();
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
store.set(viewStateAtom, { ...state, mode: "present" });
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
try {
|
|
65
|
+
// Wait 100ms to allow the page to render
|
|
66
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
67
|
+
// Wait 2 frames
|
|
68
|
+
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
69
|
+
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
70
|
+
await fn();
|
|
71
|
+
} finally {
|
|
72
|
+
store.set(viewStateAtom, state);
|
|
73
|
+
}
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
export const viewStateAtom = atom<ViewState>({
|
|
@@ -105,7 +105,10 @@ describe("API", () => {
|
|
|
105
105
|
});
|
|
106
106
|
|
|
107
107
|
await expect(
|
|
108
|
-
API.handleExportResponse(
|
|
108
|
+
API.handleExportResponse(
|
|
109
|
+
{ data: "markdown", response },
|
|
110
|
+
{ defaultFilename: "download.md" },
|
|
111
|
+
),
|
|
109
112
|
).resolves.toEqual({
|
|
110
113
|
contents: "markdown",
|
|
111
114
|
filename: "résumé.qmd",
|
|
@@ -113,27 +116,139 @@ describe("API", () => {
|
|
|
113
116
|
});
|
|
114
117
|
});
|
|
115
118
|
|
|
116
|
-
it("
|
|
119
|
+
it("parses quoted Content-Disposition filenames", async () => {
|
|
120
|
+
const response = new Response("html", {
|
|
121
|
+
headers: {
|
|
122
|
+
"Content-Disposition": 'inline; filename="notebook.html"',
|
|
123
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
|
|
117
127
|
await expect(
|
|
118
|
-
API.handleExportResponse(
|
|
119
|
-
data: "
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
128
|
+
API.handleExportResponse(
|
|
129
|
+
{ data: "html", response },
|
|
130
|
+
{ defaultFilename: "download.html" },
|
|
131
|
+
),
|
|
132
|
+
).resolves.toEqual({
|
|
133
|
+
contents: "html",
|
|
134
|
+
filename: "notebook.html",
|
|
135
|
+
mediaType: "text/html; charset=utf-8",
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("parses unquoted Content-Disposition filenames", async () => {
|
|
140
|
+
const response = new Response("pdf", {
|
|
141
|
+
headers: {
|
|
142
|
+
"Content-Disposition": "attachment; filename=notebook.pdf",
|
|
143
|
+
"Content-Type": "application/pdf",
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
await expect(
|
|
148
|
+
API.handleExportResponse(
|
|
149
|
+
{ data: "pdf", response },
|
|
150
|
+
{ defaultFilename: "download.pdf" },
|
|
151
|
+
),
|
|
152
|
+
).resolves.toEqual({
|
|
153
|
+
contents: "pdf",
|
|
154
|
+
filename: "notebook.pdf",
|
|
155
|
+
mediaType: "application/pdf",
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("prefers RFC 5987 filenames over quoted fallbacks", async () => {
|
|
160
|
+
const response = new Response("markdown", {
|
|
161
|
+
headers: {
|
|
162
|
+
"Content-Disposition":
|
|
163
|
+
"attachment; filename=\"wrong.md\"; filename*=UTF-8''notebook.md",
|
|
164
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
await expect(
|
|
169
|
+
API.handleExportResponse(
|
|
170
|
+
{ data: "markdown", response },
|
|
171
|
+
{ defaultFilename: "download.md" },
|
|
172
|
+
),
|
|
173
|
+
).resolves.toEqual({
|
|
174
|
+
contents: "markdown",
|
|
175
|
+
filename: "notebook.md",
|
|
176
|
+
mediaType: "text/plain; charset=utf-8",
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("falls back to a default filename when headers are missing", async () => {
|
|
181
|
+
const response = new Response("markdown", {
|
|
182
|
+
headers: {
|
|
183
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
await expect(
|
|
188
|
+
API.handleExportResponse(
|
|
189
|
+
{ data: "markdown", response },
|
|
190
|
+
{ defaultFilename: "download.md" },
|
|
191
|
+
),
|
|
192
|
+
).resolves.toEqual({
|
|
193
|
+
contents: "markdown",
|
|
194
|
+
filename: "download.md",
|
|
195
|
+
mediaType: "text/plain; charset=utf-8",
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("falls back to a default filename when Content-Disposition is unparsable", async () => {
|
|
200
|
+
const response = new Response("markdown", {
|
|
201
|
+
headers: {
|
|
202
|
+
"Content-Disposition": "attachment",
|
|
203
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
await expect(
|
|
208
|
+
API.handleExportResponse(
|
|
209
|
+
{ data: "markdown", response },
|
|
210
|
+
{ defaultFilename: "download.md" },
|
|
211
|
+
),
|
|
212
|
+
).resolves.toEqual({
|
|
213
|
+
contents: "markdown",
|
|
214
|
+
filename: "download.md",
|
|
215
|
+
mediaType: "text/plain; charset=utf-8",
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("falls back to a default filename when RFC 5987 encoding is malformed", async () => {
|
|
220
|
+
const response = new Response("markdown", {
|
|
221
|
+
headers: {
|
|
222
|
+
"Content-Disposition": "attachment; filename*=UTF-8''%E0%A4%A",
|
|
223
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
await expect(
|
|
228
|
+
API.handleExportResponse(
|
|
229
|
+
{ data: "markdown", response },
|
|
230
|
+
{ defaultFilename: "download.md" },
|
|
231
|
+
),
|
|
232
|
+
).resolves.toEqual({
|
|
233
|
+
contents: "markdown",
|
|
234
|
+
filename: "download.md",
|
|
235
|
+
mediaType: "text/plain; charset=utf-8",
|
|
236
|
+
});
|
|
125
237
|
});
|
|
126
238
|
|
|
127
239
|
it("rejects export responses without a media type", async () => {
|
|
128
240
|
await expect(
|
|
129
|
-
API.handleExportResponse(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
241
|
+
API.handleExportResponse(
|
|
242
|
+
{
|
|
243
|
+
data: "markdown",
|
|
244
|
+
response: new Response(null, {
|
|
245
|
+
headers: {
|
|
246
|
+
"Content-Disposition": "attachment; filename*=UTF-8''notebook.md",
|
|
247
|
+
},
|
|
248
|
+
}),
|
|
249
|
+
},
|
|
250
|
+
{ defaultFilename: "download.md" },
|
|
251
|
+
),
|
|
137
252
|
).rejects.toThrow("Export response is missing a media type");
|
|
138
253
|
});
|
|
139
254
|
});
|