@marimo-team/frontend 0.23.12-dev7 → 0.23.12-dev9
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-6opTJjMX.js → CellStatus-BGSEw-sx.js} +1 -1
- package/dist/assets/{ConnectedDataExplorerComponent-i1kaFF7n.js → ConnectedDataExplorerComponent-swQQzg5v.js} +1 -1
- package/dist/assets/{DeferredRequestRegistry-RuL7NV1n.js → DeferredRequestRegistry-EP9ZArpv.js} +1 -1
- package/dist/assets/{ImperativeModal-B62Q6S9l.js → ImperativeModal-MQnbMIO2.js} +1 -1
- package/dist/assets/{JsonOutput-CWVuEz6C.js → JsonOutput-CxKHBYIA.js} +3 -3
- package/dist/assets/{LazyAnyLanguageCodeMirror-CsAMDSIw.js → LazyAnyLanguageCodeMirror-CUQODgGJ.js} +2 -2
- package/dist/assets/{MarimoErrorOutput-dYrcxVwq.js → MarimoErrorOutput-G8Q8ZYoi.js} +1 -1
- package/dist/assets/{RSPContexts-VzcTZjG1.js → RSPContexts-CXueMbRb.js} +1 -1
- package/dist/assets/{RenderHTML-ohul2q99.js → RenderHTML-DXJCvdz4.js} +1 -1
- package/dist/assets/{RunButton-BMpP08P_.js → RunButton-B0ruC_FE.js} +1 -1
- package/dist/assets/{add-cell-with-ai-5tJjrFh0.js → add-cell-with-ai-DWNUMbns.js} +1 -1
- package/dist/assets/{add-connection-dialog-pVExi7gB.js → add-connection-dialog-CZ2UuO8f.js} +3 -3
- package/dist/assets/{agent-panel-By97CFFK.js → agent-panel-B-_gvxz2.js} +1 -1
- package/dist/assets/{ai-model-dropdown-Dvmxl0HU.js → ai-model-dropdown-BW60s6ul.js} +1 -1
- package/dist/assets/{any-language-editor-F2HBwXr3.js → any-language-editor-ChWsxHdv.js} +1 -1
- package/dist/assets/{app-config-button-BB5z7_FE.js → app-config-button-DJaefZBz.js} +1 -1
- package/dist/assets/{architectureDiagram-VXUJARFQ-DkQVwQl-.js → architectureDiagram-VXUJARFQ-BTCyBm7a.js} +1 -1
- package/dist/assets/{blockDiagram-VD42YOAC-CACq6Mqn.js → blockDiagram-VD42YOAC-mvbUAzY4.js} +1 -1
- package/dist/assets/{c4Diagram-YG6GDRKO-COoIP9fI.js → c4Diagram-YG6GDRKO-qKF4yNR5.js} +1 -1
- package/dist/assets/{cache-panel-BlIrcwlT.js → cache-panel-Ds3GhmDF.js} +1 -1
- package/dist/assets/{cell-editor-DQKaGrC9.js → cell-editor-CvLW6KK3.js} +1 -1
- package/dist/assets/{cell-link-DBKqdVgo.js → cell-link-BWqpbaiv.js} +1 -1
- package/dist/assets/{cells-DiASVTIh.js → cells-BidbgSuB.js} +3 -3
- package/dist/assets/channel-Bvgym58O.js +1 -0
- package/dist/assets/{chat-display-D8X6vz7W.js → chat-display-BRCFntOw.js} +1 -1
- package/dist/assets/{chat-panel-B9l3ukjX.js → chat-panel-BGCbxSQx.js} +1 -1
- package/dist/assets/{chat-ui-BwH7dd6n.js → chat-ui-CceYGzB9.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-Cr4aqhf3.js → chunk-55IACEB6-BZgGh8Op.js} +1 -1
- package/dist/assets/{chunk-5FQGJX7Z-DTLanAkx.js → chunk-5FQGJX7Z-C6VN0dQj.js} +3 -3
- package/dist/assets/{chunk-ABZYJK2D-BWwBJaW4.js → chunk-ABZYJK2D-DntHwfwl.js} +1 -1
- package/dist/assets/{chunk-ATLVNIR6-ZywQjHDL.js → chunk-ATLVNIR6-CZy1WXhH.js} +1 -1
- package/dist/assets/{chunk-B4BG7PRW-Q6rM60b0.js → chunk-B4BG7PRW-CifnFMMD.js} +1 -1
- package/dist/assets/{chunk-DI55MBZ5-DkUFRB44.js → chunk-DI55MBZ5-BKMnvFi2.js} +1 -1
- package/dist/assets/{chunk-EXTU4WIE-A9IRvoap.js → chunk-EXTU4WIE-CYseDwky.js} +1 -1
- package/dist/assets/{chunk-JA3XYJ7Z-BC57JRLK.js → chunk-JA3XYJ7Z-Bj396ovX.js} +1 -1
- package/dist/assets/{chunk-JZLCHNYA-CmPEo2OR.js → chunk-JZLCHNYA-QttzWzFq.js} +1 -1
- package/dist/assets/{chunk-N4CR4FBY-qcFzulsJ.js → chunk-N4CR4FBY-DgrFkHXi.js} +2 -2
- package/dist/assets/{chunk-QN33PNHL-CfKFSQ8y.js → chunk-QN33PNHL-shgGaZ1X.js} +1 -1
- package/dist/assets/{chunk-QXUST7PY-DiH4MyLq.js → chunk-QXUST7PY-EJQ74OiC.js} +1 -1
- package/dist/assets/{chunk-S3R3BYOJ-C7n0Esov.js → chunk-S3R3BYOJ-DHLCcICg.js} +1 -1
- package/dist/assets/{chunk-TZMSLE5B-Yl1gB5ep.js → chunk-TZMSLE5B-BgJLE0Za.js} +1 -1
- package/dist/assets/classDiagram-2ON5EDUG-DrqS8d9F.js +1 -0
- package/dist/assets/classDiagram-v2-WZHVMYZB-DchP-T46.js +1 -0
- package/dist/assets/{code-block-37QAKDTI-BJ9X4ytb.js → code-block-37QAKDTI--cy-8SOv.js} +1 -1
- package/dist/assets/{column-preview-B3CdpsbL.js → column-preview-BbgM2h8n.js} +1 -1
- package/dist/assets/{command-DRHbYHUP.js → command-CsbsBLBw.js} +1 -1
- package/dist/assets/{command-palette-D2BHtSuk.js → command-palette-Mqu8KKo1.js} +1 -1
- package/dist/assets/{common-CvUUt55g.js → common-B94MReIe.js} +1 -1
- package/dist/assets/{components-CimBDpZ8.js → components-DoRr7Hf1.js} +1 -1
- package/dist/assets/{config-3clPIEB9.js → config-BE150fVL.js} +1 -1
- package/dist/assets/{context-C2Ie4tn_.js → context-DE_5rdOV.js} +1 -1
- package/dist/assets/{copy-icon-EHMT-qlr.js → copy-icon-BCIGtBo0.js} +1 -1
- package/dist/assets/{cose-bilkent-S5V4N54A-CQqSLzd1.js → cose-bilkent-S5V4N54A-DhxFsKpJ.js} +1 -1
- package/dist/assets/{dagre-6UL2VRFP-C8k8cWk0.js → dagre-6UL2VRFP-B6hk_Bns.js} +1 -1
- package/dist/assets/{data-grid-overlay-editor-BrFXEIvf.js → data-grid-overlay-editor-CTUPMnar.js} +1 -1
- package/dist/assets/{datasource-Da-qoi34.js → datasource-DI-YUWev.js} +1 -1
- package/dist/assets/{dates-D8uxHHPL.js → dates-CnrjjcMO.js} +1 -1
- package/dist/assets/{dependency-graph-panel-CMjZH8W-.js → dependency-graph-panel-B7_LMfP4.js} +1 -1
- package/dist/assets/{diagram-PSM6KHXK-CyHuNpNq.js → diagram-PSM6KHXK-mo2Enmtf.js} +1 -1
- package/dist/assets/{diagram-QEK2KX5R-XfuQrtcF.js → diagram-QEK2KX5R-BmkxV10c.js} +1 -1
- package/dist/assets/{diagram-S2PKOQOG-bJWzui-7.js → diagram-S2PKOQOG-FgQ9g-FW.js} +1 -1
- package/dist/assets/dist-B1NchzZ7.js +1 -0
- package/dist/assets/{dist-CyK0ePPW.js → dist-B3BjoKW1.js} +1 -1
- package/dist/assets/dist-Bc19bAck.js +1 -0
- package/dist/assets/{dist-D-2yWcX9.js → dist-Bj9Iedc0.js} +1 -1
- package/dist/assets/{dist-BHCGBHnf.js → dist-BygSqKXd.js} +1 -1
- package/dist/assets/{dist-77VmTZjj.js → dist-CBFremCY.js} +1 -1
- package/dist/assets/dist-CGfx7GOn.js +1 -0
- package/dist/assets/{dist-CABwQOV5.js → dist-CKZJyGZk.js} +1 -1
- package/dist/assets/{dist-CIQQgRzz.js → dist-CKjd2mnC.js} +1 -1
- package/dist/assets/dist-CKlHe_tO.js +1 -0
- package/dist/assets/{dist-C4-ruy-b.js → dist-CPAr7_4H.js} +1 -1
- package/dist/assets/{dist-FYUcqnI2.js → dist-CmjkyMZS.js} +1 -1
- package/dist/assets/{dist-sJHUucQ8.js → dist-Cq98Ix9k.js} +1 -1
- package/dist/assets/{dist-XexmIjM8.js → dist-CwSi3e6S.js} +1 -1
- package/dist/assets/{dist-Cqrb9QGk.js → dist-D6TmDEVn.js} +1 -1
- package/dist/assets/{dist-DblYTes5.js → dist-DHMtQYxT.js} +1 -1
- package/dist/assets/{dist-BP6Oj7vU.js → dist-DU6-XN1L.js} +1 -1
- package/dist/assets/{dist-CruUwJkI.js → dist-DZJfnBKu.js} +1 -1
- package/dist/assets/dist-D_FHXQyQ.js +1 -0
- package/dist/assets/{dist-CKVgRUgH.js → dist-Ds-fJX2L.js} +1 -1
- package/dist/assets/{dist-DyuwOQr-.js → dist-d_9Qt_7_.js} +1 -1
- package/dist/assets/dist-znptp4sC.js +1 -0
- package/dist/assets/{documentation-panel-BS_uG8hW.js → documentation-panel-BGXFZYSy.js} +1 -1
- package/dist/assets/{download-CdS_EveB.js → download-DgEarSps.js} +1 -1
- package/dist/assets/{edit-page-DanoliKk.js → edit-page-DExCsBoE.js} +4 -4
- package/dist/assets/{erDiagram-Q2GNP2WA-Db-GMQLy.js → erDiagram-Q2GNP2WA-DZx9RiLu.js} +1 -1
- package/dist/assets/{error-banner-BSQVN46J.js → error-banner-C4DZksWV.js} +1 -1
- package/dist/assets/{error-panel-Csh1BgrG.js → error-panel-Bd98g_JW.js} +1 -1
- package/dist/assets/{es-EItoYvXh.js → es-Cy7KBUrF.js} +1 -1
- package/dist/assets/{esm-DwJBDgEq.js → esm-BqXnk7X6.js} +1 -1
- package/dist/assets/{esm-X3Tr2pur.js → esm-DSv-aO_T.js} +1 -1
- package/dist/assets/{field-DlNY-dDH.js → field-CA9HCE2Y.js} +1 -1
- package/dist/assets/{file-explorer-panel--h0xwnRB.js → file-explorer-panel-5GiP_o58.js} +1 -1
- package/dist/assets/{file-icons-D6BjDFSV.js → file-icons-BwFX01F6.js} +1 -1
- package/dist/assets/{file-name-input-CsUxNFtr.js → file-name-input-C_iFa52z.js} +1 -1
- package/dist/assets/{fileToBase64-BSOFR3RV.js → fileToBase64-Doh9J-g6.js} +1 -1
- package/dist/assets/{floating-outline-D2cwxR8Z.js → floating-outline-BDx00oB1.js} +1 -1
- package/dist/assets/{flowDiagram-NV44I4VS-DSxxTDOm.js → flowDiagram-NV44I4VS-BaCfA1PD.js} +1 -1
- package/dist/assets/{focus-BvvRVcVF.js → focus-CocfMydm.js} +1 -1
- package/dist/assets/{form-CO925gWV.js → form-DgnBiuvP.js} +1 -1
- package/dist/assets/{formats-ZGU43GQU.js → formats-Dkhsq416.js} +1 -1
- package/dist/assets/{formatting-DhA_x3cD.js → formatting-Bjzx5J8_.js} +1 -1
- package/dist/assets/{gallery-page-CNPcxPCI.js → gallery-page-Cwx-CV9Q.js} +1 -1
- package/dist/assets/{ganttDiagram-JELNMOA3-Boeh8Xec.js → ganttDiagram-JELNMOA3-D76yMCwq.js} +1 -1
- package/dist/assets/{gitGraphDiagram-V2S2FVAM-Ww-CAbr5.js → gitGraphDiagram-V2S2FVAM-xaQk-fkD.js} +1 -1
- package/dist/assets/github-BQ8If5nZ.js +1 -0
- package/dist/assets/{glide-data-editor-Bmm8OMxa.js → glide-data-editor-DtDJGBDZ.js} +4 -4
- package/dist/assets/{globals-Bx8Km3LH.js → globals-BDWM3c_z.js} +1 -1
- package/dist/assets/home-page-BuVWyEpt.js +4 -0
- package/dist/assets/{hooks-7dyPrQQS.js → hooks-dPm1h9aq.js} +1 -1
- package/dist/assets/{html-to-image-BWhkUSek.js → html-to-image-TCtIotr9.js} +1 -1
- package/dist/assets/{index-C65kCpI9.css → index-Bj8QWDiJ.css} +1 -1
- package/dist/assets/index-CrgYGp5w.js +38 -0
- package/dist/assets/{infoDiagram-HS3SLOUP-emf5Oa26.js → infoDiagram-HS3SLOUP-CaCHYq-C.js} +1 -1
- package/dist/assets/{input-DB2LiTiQ.js → input-b2KTOk0X.js} +1 -1
- package/dist/assets/{journeyDiagram-XKPGCS4Q-BM5cpMVY.js → journeyDiagram-XKPGCS4Q-9j5RE995.js} +1 -1
- package/dist/assets/{kanban-definition-3W4ZIXB7-BAIfwDqR.js → kanban-definition-3W4ZIXB7-KTZNPjVQ.js} +1 -1
- package/dist/assets/{kiosk-mode-D0mAc3Fr.js → kiosk-mode-sfaqwl5N.js} +1 -1
- package/dist/assets/{layout-C0MKkswN.js → layout-CVg460UU.js} +3 -3
- package/dist/assets/{linear-BWkmpE3J.js → linear-BWk6x-Bf.js} +1 -1
- package/dist/assets/{links-BN8FYTyp.js → links-BL4SaTJe.js} +1 -1
- package/dist/assets/{logs-panel-BaGDTq_5.js → logs-panel-Bs7u1Wfd.js} +1 -1
- package/dist/assets/{markdown-renderer-CyLjgnQY.js → markdown-renderer-CGZTB2Dx.js} +3 -3
- package/dist/assets/{mermaid-4DMBBIKO-DX6ZCeSi.js → mermaid-4DMBBIKO-1vt0_Bql.js} +1 -1
- package/dist/assets/{mermaid-yhDJCmk2.js → mermaid-BC06IzvM.js} +3 -3
- package/dist/assets/{mermaid-parser.core-CEw6EtVC.js → mermaid-parser.core-UC5-TA69.js} +1 -1
- package/dist/assets/{mindmap-definition-VGOIOE7T-DAiNJDIe.js → mindmap-definition-VGOIOE7T-DwhzT05K.js} +1 -1
- package/dist/assets/{name-cell-input-DBkW5PZU.js → name-cell-input-D4k4IMJD.js} +1 -1
- package/dist/assets/{number-overlay-editor-4rrKClOH.js → number-overlay-editor-DU72uJyj.js} +1 -1
- package/dist/assets/{outline-panel-xLeB4sTR.js → outline-panel-5sRz-QR2.js} +1 -1
- package/dist/assets/{packages-panel-BbWGOWIZ.js → packages-panel-DhXpwKjz.js} +1 -1
- package/dist/assets/{pair-with-agent-modal-Q9Od23Rh.js → pair-with-agent-modal-BONZmBdh.js} +1 -1
- package/dist/assets/{panels-id0eyz64.js → panels-C3XyfWZa.js} +1 -1
- package/dist/assets/{pathUtils-BXCjaLHB.js → pathUtils-ANiMIEDI.js} +1 -1
- package/dist/assets/{pieDiagram-ADFJNKIX-KdHVGtb7.js → pieDiagram-ADFJNKIX-Ddohs4pt.js} +1 -1
- package/dist/assets/{precisionRound-BOmLQIKI.js → precisionRound-CCOoIlcP.js} +1 -1
- package/dist/assets/{process-output-BcuY_Us9.js → process-output-CRIsE74Q.js} +1 -1
- package/dist/assets/{quadrantDiagram-AYHSOK5B-B9NNSzQG.js → quadrantDiagram-AYHSOK5B-DXHmstFN.js} +1 -1
- package/dist/assets/{radio-group-XouISBp9.js → radio-group-Czn6pjhm.js} +1 -1
- package/dist/assets/react-vega-DrvGjEhj.js +1 -0
- package/dist/assets/{react-vega-BfOzG-mm.js → react-vega-IsGFjh4e.js} +1 -1
- package/dist/assets/{readonly-python-code-BK3Xk2qY.js → readonly-python-code-DtUWOxnZ.js} +1 -1
- package/dist/assets/{renderShortcut-LpVarhnQ.js → renderShortcut-CKbqJyj4.js} +1 -1
- package/dist/assets/{request-registry-K6vbazWs.js → request-registry-unC7eRnq.js} +1 -1
- package/dist/assets/{requirementDiagram-UZGBJVZJ-B5pxFnOe.js → requirementDiagram-UZGBJVZJ-FZxRqc8c.js} +1 -1
- package/dist/assets/{reveal-component-Do91RUH9.js → reveal-component-DDZ2IxNS.js} +1 -1
- package/dist/assets/{run-page-CYnMjVum.js → run-page-K4C80Bqk.js} +1 -1
- package/dist/assets/{sankeyDiagram-TZEHDZUN-w55_GOPb.js → sankeyDiagram-TZEHDZUN-BVzsFJnF.js} +1 -1
- package/dist/assets/{scratchpad-panel-DH3KlUbZ.js → scratchpad-panel-Cwl5E8lN.js} +1 -1
- package/dist/assets/{secrets-panel-CgahHnqr.js → secrets-panel-BUtOtnIM.js} +1 -1
- package/dist/assets/{sequenceDiagram-WL72ISMW-CW_L_PJr.js → sequenceDiagram-WL72ISMW-DdzNFBtb.js} +1 -1
- package/dist/assets/{session-panel-BJP2lKfE.js → session-panel-DGjSy-dF.js} +1 -1
- package/dist/assets/{share-DQjChRJG.js → share-vrPro738.js} +1 -1
- package/dist/assets/{snippets-panel-DKenTNmv.js → snippets-panel-94zH2JCj.js} +1 -1
- package/dist/assets/{spec-CDgWI0fT.js → spec-BzxoPflZ.js} +1 -1
- package/dist/assets/{src-CvyFXpBy.js → src-CyeQdfB6.js} +1 -1
- package/dist/assets/{state-DwAS0kE4.js → state-ClDZE-YW.js} +1 -1
- package/dist/assets/{state-Cy10NkuA.js → state-CzwQl1aE.js} +1 -1
- package/dist/assets/{state-DjrxAf9W.js → state-RnIztwr-.js} +1 -1
- package/dist/assets/{state-MC8-jN2e.js → state-WA3j91X9.js} +1 -1
- package/dist/assets/{stateDiagram-FKZM4ZOC-BOX6WbbZ.js → stateDiagram-FKZM4ZOC-DCOZ5EVk.js} +1 -1
- package/dist/assets/stateDiagram-v2-4FDKWEC3-D_uhE9WV.js +1 -0
- package/dist/assets/stex-CruVQx-P.js +1 -0
- package/dist/assets/{swiper-component-BwPCQTdo.js → swiper-component-B3QJ6Yx5.js} +1 -1
- package/dist/assets/{switch-DvDNxcZP.js → switch-DHhZkGEv.js} +1 -1
- package/dist/assets/{terminal-BXH7Uaqi.js → terminal-C0JxB62q.js} +1 -1
- package/dist/assets/{textarea-BBpaAGpK.js → textarea-Dz09niIv.js} +1 -1
- package/dist/assets/{time-SPyfucy1.js → time-BsAzPDU3.js} +1 -1
- package/dist/assets/{timeline-definition-IT6M3QCI-Lad2-H_k.js → timeline-definition-IT6M3QCI-BJT2fHGH.js} +1 -1
- package/dist/assets/{tracing-Bz68-Fa1.js → tracing-C_GaBGFx.js} +1 -1
- package/dist/assets/tracing-panel-BkzzwM_5.js +2 -0
- package/dist/assets/{tree-actions-C729o8TG.js → tree-actions-CesD4Rcl.js} +1 -1
- package/dist/assets/{useBoolean-BMzj74q1.js → useBoolean-48bgGoSa.js} +1 -1
- package/dist/assets/{useCellActionButton-VGB6-gGh.js → useCellActionButton-DNYd1sgZ.js} +1 -1
- package/dist/assets/{useDateFormatter-CAlTJ8HV.js → useDateFormatter-CANi6nSX.js} +1 -1
- package/dist/assets/{useDeleteCell-D_p8uMly.js → useDeleteCell-CCCMHD2a.js} +1 -1
- package/dist/assets/{useDependencyPanelTab-v8fQPE_U.js → useDependencyPanelTab-P57LIkal.js} +1 -1
- package/dist/assets/{useInstallPackage-C1Dd0aIZ.js → useInstallPackage-DEHK-C20.js} +1 -1
- package/dist/assets/{useNotebookActions-Hdu82BAI.js → useNotebookActions-B8xsvWwy.js} +1 -1
- package/dist/assets/{useNumberFormatter-CuxZh3Bq.js → useNumberFormatter-DCM-63YT.js} +1 -1
- package/dist/assets/{usePress-BSFUeqnS.js → usePress-mjvipKvz.js} +1 -1
- package/dist/assets/{useRunCells-DXtOL4UR.js → useRunCells-DFXV3Rm5.js} +1 -1
- package/dist/assets/{useSplitCell-CzaZEqwj.js → useSplitCell-R-0wFhnd.js} +1 -1
- package/dist/assets/{utils-DPvpQ891.js → utils-BIlJBJIu.js} +1 -1
- package/dist/assets/{vega-component-Ch7x9hsC.js → vega-component-wGZOy7qv.js} +1 -1
- package/dist/assets/{vega-loader.browser-CZV6_g2i.js → vega-loader.browser-BJ9oKrvH.js} +1 -1
- package/dist/assets/{write-secret-modal-K2n79wHj.js → write-secret-modal-qfcjtCvk.js} +1 -1
- package/dist/assets/{xychartDiagram-PRI3JC2R-f8MNNXWc.js → xychartDiagram-PRI3JC2R-BtC1koqJ.js} +1 -1
- package/dist/assets/youtube-NfBeYlaL.js +1 -0
- package/dist/index.html +112 -112
- package/package.json +1 -1
- package/src/components/editor/actions/useNotebookActions.tsx +4 -4
- package/src/components/home/components.tsx +4 -4
- package/src/components/icons/github.tsx +21 -0
- package/src/components/icons/youtube.tsx +21 -0
- package/src/components/storage/components.tsx +3 -7
- package/src/plugins/impl/FileBrowserPlugin.tsx +165 -74
- package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +314 -0
- package/dist/assets/channel-CpOVhGq6.js +0 -1
- package/dist/assets/classDiagram-2ON5EDUG-Bxr8oM_y.js +0 -1
- package/dist/assets/classDiagram-v2-WZHVMYZB-CY-gITpZ.js +0 -1
- package/dist/assets/dist-Bm-o3knM.js +0 -1
- package/dist/assets/dist-C0zWDt4u.js +0 -1
- package/dist/assets/dist-C2qq2Q11.js +0 -1
- package/dist/assets/dist-CI-LXQQ2.js +0 -1
- package/dist/assets/dist-DThLGT6I.js +0 -1
- package/dist/assets/dist-VVk6z_gh.js +0 -1
- package/dist/assets/github-CyzgLJDA.js +0 -1
- package/dist/assets/home-page-CPt4LGp0.js +0 -4
- package/dist/assets/index-awbrczCl.js +0 -38
- package/dist/assets/react-vega-4x9RLMqT.js +0 -1
- package/dist/assets/stateDiagram-v2-4FDKWEC3-JHjNwkbq.js +0 -1
- package/dist/assets/stex-BBWVYm-R.js +0 -1
- package/dist/assets/tracing-panel-BfgGYFNi.js +0 -2
- package/dist/assets/youtube-BEAtppjN.js +0 -1
- /package/dist/assets/{Deferred-BMfCOLaw.js → Deferred-CfyqLOPG.js} +0 -0
- /package/dist/assets/{SSRProvider-DX2edArU.js → SSRProvider-DrpctNAg.js} +0 -0
- /package/dist/assets/{alert-1y_DnRWn.js → alert-Bjh7v4lb.js} +0 -0
- /package/dist/assets/{azure-DBVzcmvx.js → azure-B42ls0Ui.js} +0 -0
- /package/dist/assets/{badge-6yGCqY1Z.js → badge-CFAaMy0O.js} +0 -0
- /package/dist/assets/{blob-BiK5xmlC.js → blob-dGUJ3Bw8.js} +0 -0
- /package/dist/assets/{bundle.esm-D544r2Sr.js → bundle.esm-BULc9l6b.js} +0 -0
- /package/dist/assets/{card-s1ZaQ9ub.js → card-DrIItWkf.js} +0 -0
- /package/dist/assets/{copy-D8MtpXgN.js → copy-CyasABTK.js} +0 -0
- /package/dist/assets/{defaultLocale-DK1MWd7f.js → defaultLocale-CGfP-Ye3.js} +0 -0
- /package/dist/assets/{defaultLocale-OkOxlkkM.js → defaultLocale-CuYNS33t.js} +0 -0
- /package/dist/assets/{dialog-DkJmIrsG.js → dialog-Dr_Y1zNi.js} +0 -0
- /package/dist/assets/{dist-UghNT0W0.js → dist-BM-OLiKa.js} +0 -0
- /package/dist/assets/{dist-ZjSH4Z6x.js → dist-BZhJ1bTM.js} +0 -0
- /package/dist/assets/{dist-CNKFZCiw.js → dist-D-o1OXc9.js} +0 -0
- /package/dist/assets/{dist-BtrqKtvn.js → dist-DnIl7RU-.js} +0 -0
- /package/dist/assets/{emotion-is-prop-valid.esm-CK2zY6a8.js → emotion-is-prop-valid.esm-DiQGBfwj.js} +0 -0
- /package/dist/assets/{empty-state-QmmE2oN4.js → empty-state-vKu4k0Y4.js} +0 -0
- /package/dist/assets/{en-US-BXNio91F.js → en-US-DZwIjHwu.js} +0 -0
- /package/dist/assets/{errors-9jMmWHd9.js → errors-48KFPvCp.js} +0 -0
- /package/dist/assets/{events-XR_LpvHc.js → events-BRbNg7Li.js} +0 -0
- /package/dist/assets/{extends-CeSFM22p.js → extends-2LbFKIQQ.js} +0 -0
- /package/dist/assets/{house-DHu4JLi3.js → house-DkdBWh44.js} +0 -0
- /package/dist/assets/{icons-avFV3lBF.js → icons-D3YFXNmD.js} +0 -0
- /package/dist/assets/{image-BzUcK6ho.js → image-jhXeQEgs.js} +0 -0
- /package/dist/assets/{isValid-DKyiOp4U.js → isValid-Cgon0fXK.js} +0 -0
- /package/dist/assets/{kbd-UVzWBHfi.js → kbd-BCXa3Ocm.js} +0 -0
- /package/dist/assets/{link-e5mRDDOC.js → link-My4Pey3q.js} +0 -0
- /package/dist/assets/{links-CCkJpphF.js → links-DK7te6sJ.js} +0 -0
- /package/dist/assets/{message-circle-RkIzfQEi.js → message-circle-D_YIPPZo.js} +0 -0
- /package/dist/assets/{micromark-factory-space-BUQpMdx2.js → micromark-factory-space-P--XWZhg.js} +0 -0
- /package/dist/assets/{multi-icon-CTvmuLdL.js → multi-icon-CGXdgpE4.js} +0 -0
- /package/dist/assets/{numbers-_ry1Nlla.js → numbers-BKZTJMZ6.js} +0 -0
- /package/dist/assets/{objectWithoutPropertiesLoose-BkUn3I0-.js → objectWithoutPropertiesLoose-Msf1n32r.js} +0 -0
- /package/dist/assets/{ordinal-Cn9sg_-a.js → ordinal-CIZb_ice.js} +0 -0
- /package/dist/assets/{package-BTIV9-Dk.js → package-BoMcg6sy.js} +0 -0
- /package/dist/assets/{panel-context-DC1vAeB3.js → panel-context-RKllh8pM.js} +0 -0
- /package/dist/assets/{paths-DhuNSnZ_.js → paths-kNeJ8nbe.js} +0 -0
- /package/dist/assets/{plus-ZXRHY1up.js → plus-CExKUszm.js} +0 -0
- /package/dist/assets/{preload-helper-BW0IMuFq.js → preload-helper-y72bE5iF.js} +0 -0
- /package/dist/assets/{prop-types-B6Y2e__V.js → prop-types-D_pYuT11.js} +0 -0
- /package/dist/assets/{purify.es-DfJp_of2.js → purify.es-DdxMtdqK.js} +0 -0
- /package/dist/assets/{range-DNqFcYmr.js → range-ClqUI25v.js} +0 -0
- /package/dist/assets/{react-icons.esm-DCqqMD4w.js → react-icons.esm-C2u-_EAQ.js} +0 -0
- /package/dist/assets/{react-resizable-panels.browser.esm-Ce2ksurd.js → react-resizable-panels.browser.esm-CgWOEYeG.js} +0 -0
- /package/dist/assets/{refresh-ccw-Bee7JLOl.js → refresh-ccw-CUkO1Vlo.js} +0 -0
- /package/dist/assets/{refresh-cw-C9FftltI.js → refresh-cw-DcEasnos.js} +0 -0
- /package/dist/assets/{requests-DqJEWJ-Q.js → requests-Bm3bohzL.js} +0 -0
- /package/dist/assets/{rotate-ccw-ZsOWbQCw.js → rotate-ccw-CBXqO1Fd.js} +0 -0
- /package/dist/assets/{save-BNNMzGly.js → save-CGxzAyve.js} +0 -0
- /package/dist/assets/{semaphore-X3ApuO41.js → semaphore-FlZezxaf.js} +0 -0
- /package/dist/assets/{session-CsT5Gg9j.js → session-B6_8umQX.js} +0 -0
- /package/dist/assets/{settings-1WkYMLdR.js → settings-Cn43l_vx.js} +0 -0
- /package/dist/assets/{sparkles-COaEc8Qn.js → sparkles-DctOjjEz.js} +0 -0
- /package/dist/assets/{spinner-BbI9qk88.js → spinner-DTBVbtl-.js} +0 -0
- /package/dist/assets/{square-35tXIgiR.js → square-DPWHdF_-.js} +0 -0
- /package/dist/assets/{square-function-Dx0pKHko.js → square-function-CPbVtjKW.js} +0 -0
- /package/dist/assets/{stex-0ac7Aukl.js → stex-C6JeW1YI.js} +0 -0
- /package/dist/assets/{table-CnW850Wt.js → table-Fk_msRcD.js} +0 -0
- /package/dist/assets/{timer-B6DpdVnC.js → timer-BgiWPhV9.js} +0 -0
- /package/dist/assets/{trash-2-CqTUwVuU.js → trash-2-CjPoUZCP.js} +0 -0
- /package/dist/assets/{trash-BW_KaFjz.js → trash-Icq8_IVf.js} +0 -0
- /package/dist/assets/{triangle-alert-D8Ft17xk.js → triangle-alert-CV7pqa1o.js} +0 -0
- /package/dist/assets/{types-BnrgJ4Gh.js → types-xF5uWODg.js} +0 -0
- /package/dist/assets/{use-toast-kCNiuc-_.js → use-toast-BH8bU9Xf.js} +0 -0
- /package/dist/assets/{useAsyncData-DAQcLiyE.js → useAsyncData-CT1LpOBD.js} +0 -0
- /package/dist/assets/{useDebounce-CpLI2dsc.js → useDebounce-BlBSYv0n.js} +0 -0
- /package/dist/assets/{useDeepCompareMemoize-CWcgQCbT.js → useDeepCompareMemoize-zUHU--0D.js} +0 -0
- /package/dist/assets/{useHotkey-CJo8iX8v.js → useHotkey-C-blZ3Z8.js} +0 -0
- /package/dist/assets/{useIframeCapabilities-B0dNZiKK.js → useIframeCapabilities-DuGyzPVb.js} +0 -0
- /package/dist/assets/{useTheme-D_ZbTTJw.js → useTheme-CWoNQwFz.js} +0 -0
- /package/dist/assets/{uuid-ClFZlR7U.js → uuid-BukULOeS.js} +0 -0
- /package/dist/assets/{workflow-f8flhcJ1.js → workflow-ClrYl5m7.js} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
3
|
import { type LucideIcon, CornerLeftUp } from "lucide-react";
|
|
4
|
-
import { type JSX, useEffect, useState } from "react";
|
|
4
|
+
import { type JSX, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import {
|
|
7
7
|
FILE_ICON as FILE_TYPE_ICONS,
|
|
@@ -129,6 +129,7 @@ interface FileBrowserProps extends Data, PluginFunctions {
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
interface CheckboxOrIconProps {
|
|
132
|
+
name: string;
|
|
132
133
|
isSelected: boolean;
|
|
133
134
|
canSelect: boolean;
|
|
134
135
|
Icon: LucideIcon;
|
|
@@ -136,6 +137,7 @@ interface CheckboxOrIconProps {
|
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
function CheckboxOrIcon({
|
|
140
|
+
name,
|
|
139
141
|
isSelected,
|
|
140
142
|
canSelect,
|
|
141
143
|
Icon,
|
|
@@ -146,17 +148,21 @@ function CheckboxOrIcon({
|
|
|
146
148
|
<>
|
|
147
149
|
<Checkbox
|
|
148
150
|
checked={isSelected}
|
|
151
|
+
aria-label={`Select ${name}`}
|
|
152
|
+
tabIndex={-1}
|
|
149
153
|
onClick={(e) => {
|
|
150
154
|
onSelect();
|
|
151
155
|
e.stopPropagation();
|
|
152
156
|
}}
|
|
153
|
-
className={cn({
|
|
157
|
+
className={cn({
|
|
158
|
+
"hidden group-hover:flex group-focus:flex": !isSelected,
|
|
159
|
+
})}
|
|
154
160
|
/>
|
|
155
161
|
<Icon
|
|
156
162
|
size={16}
|
|
157
163
|
className={cn("mr-2", {
|
|
158
164
|
hidden: isSelected,
|
|
159
|
-
"group-hover:hidden": !isSelected,
|
|
165
|
+
"group-hover:hidden group-focus:hidden": !isSelected,
|
|
160
166
|
})}
|
|
161
167
|
/>
|
|
162
168
|
</>
|
|
@@ -165,6 +171,18 @@ function CheckboxOrIcon({
|
|
|
165
171
|
return <Icon size={16} className="mr-2" />;
|
|
166
172
|
}
|
|
167
173
|
|
|
174
|
+
interface RowModel {
|
|
175
|
+
key: string;
|
|
176
|
+
name: string;
|
|
177
|
+
Icon: LucideIcon;
|
|
178
|
+
isSelected: boolean;
|
|
179
|
+
canSelect: boolean;
|
|
180
|
+
/** Enter and mouse-click action. */
|
|
181
|
+
onPrimary: () => void;
|
|
182
|
+
/** Space action; null when the row has nothing to toggle. */
|
|
183
|
+
onToggleSelect: (() => void) | null;
|
|
184
|
+
}
|
|
185
|
+
|
|
168
186
|
/**
|
|
169
187
|
* File browser component.
|
|
170
188
|
*
|
|
@@ -184,6 +202,13 @@ export const FileBrowser = ({
|
|
|
184
202
|
const [path, setPath] = useInternalStateWithSync(initialPath);
|
|
185
203
|
const [isUpdatingPath, setIsUpdatingPath] = useState(false);
|
|
186
204
|
const [showLoadingOverlay, setShowLoadingOverlay] = useState(false);
|
|
205
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
206
|
+
const rowRefs = useRef<(HTMLTableRowElement | null)[]>([]);
|
|
207
|
+
const gridRef = useRef<HTMLTableElement | null>(null);
|
|
208
|
+
// Set when navigation is triggered from within the grid, so focus can follow
|
|
209
|
+
// to the parent row after the new listing renders instead of falling to the
|
|
210
|
+
// body when the previously focused row unmounts.
|
|
211
|
+
const refocusParentRef = useRef(false);
|
|
187
212
|
|
|
188
213
|
// HACK: use the random-id of the host element to force a re-render
|
|
189
214
|
// when the random-id changes, this means the cell was re-rendered
|
|
@@ -210,6 +235,22 @@ export const FileBrowser = ({
|
|
|
210
235
|
};
|
|
211
236
|
}, [isPending]);
|
|
212
237
|
|
|
238
|
+
// Reset the roving tabindex whenever the listing reloads (a new path or a
|
|
239
|
+
// same-path refresh) so activeIndex never points past the current rows.
|
|
240
|
+
const listingKey = `${path}::${randomId}`;
|
|
241
|
+
const [prevListingKey, setPrevListingKey] = useState(listingKey);
|
|
242
|
+
if (prevListingKey !== listingKey) {
|
|
243
|
+
setPrevListingKey(listingKey);
|
|
244
|
+
setActiveIndex(0);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
useLayoutEffect(() => {
|
|
248
|
+
if (refocusParentRef.current) {
|
|
249
|
+
refocusParentRef.current = false;
|
|
250
|
+
rowRefs.current[0]?.focus();
|
|
251
|
+
}
|
|
252
|
+
}, [listingKey]);
|
|
253
|
+
|
|
213
254
|
const files = data?.files ?? [];
|
|
214
255
|
const selectedPaths = new Set(value.map((x) => x.path));
|
|
215
256
|
const canSelectDirectories =
|
|
@@ -269,6 +310,8 @@ export const FileBrowser = ({
|
|
|
269
310
|
return;
|
|
270
311
|
}
|
|
271
312
|
|
|
313
|
+
refocusParentRef.current =
|
|
314
|
+
gridRef.current?.contains(document.activeElement) ?? false;
|
|
272
315
|
setPath(newPath);
|
|
273
316
|
setIsUpdatingPath(false);
|
|
274
317
|
}
|
|
@@ -333,78 +376,90 @@ export const FileBrowser = ({
|
|
|
333
376
|
setValue([...value, ...filesInView]);
|
|
334
377
|
}
|
|
335
378
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
);
|
|
379
|
+
const rowModels: RowModel[] = [
|
|
380
|
+
{
|
|
381
|
+
key: "parent",
|
|
382
|
+
name: PARENT_DIRECTORY,
|
|
383
|
+
Icon: CornerLeftUp,
|
|
384
|
+
isSelected: false,
|
|
385
|
+
canSelect: false,
|
|
386
|
+
onPrimary: () => setNewPath(PARENT_DIRECTORY),
|
|
387
|
+
onToggleSelect: null,
|
|
388
|
+
},
|
|
389
|
+
...files.map((file): RowModel => {
|
|
390
|
+
let filePath = file.path;
|
|
391
|
+
if (filePath.startsWith("//")) {
|
|
392
|
+
filePath = filePath.slice(1) as FilePath;
|
|
393
|
+
}
|
|
352
394
|
|
|
353
|
-
|
|
354
|
-
|
|
395
|
+
const canSelect =
|
|
396
|
+
(canSelectDirectories && file.is_directory) ||
|
|
397
|
+
(canSelectFiles && !file.is_directory);
|
|
398
|
+
const isSelected = selectedPaths.has(filePath);
|
|
399
|
+
const fileType: FileType = file.is_directory
|
|
400
|
+
? "directory"
|
|
401
|
+
: guessFileType(file.name);
|
|
402
|
+
|
|
403
|
+
const toggle = () =>
|
|
404
|
+
handleSelection({
|
|
405
|
+
path: filePath,
|
|
406
|
+
name: file.name,
|
|
407
|
+
isDirectory: file.is_directory,
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
return {
|
|
411
|
+
key: file.id,
|
|
412
|
+
name: file.name,
|
|
413
|
+
Icon: FILE_TYPE_ICONS[fileType],
|
|
414
|
+
isSelected,
|
|
415
|
+
canSelect,
|
|
416
|
+
onPrimary: file.is_directory
|
|
417
|
+
? () => setNewPath(filePath)
|
|
418
|
+
: canSelect
|
|
419
|
+
? toggle
|
|
420
|
+
: () => {},
|
|
421
|
+
onToggleSelect: canSelect ? toggle : null,
|
|
422
|
+
};
|
|
423
|
+
}),
|
|
424
|
+
];
|
|
355
425
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
426
|
+
function focusRow(index: number) {
|
|
427
|
+
setActiveIndex(index);
|
|
428
|
+
rowRefs.current[index]?.focus();
|
|
429
|
+
}
|
|
359
430
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
(canSelectDirectories && file.is_directory) ||
|
|
393
|
-
(canSelectFiles && !file.is_directory)
|
|
394
|
-
}
|
|
395
|
-
Icon={Icon}
|
|
396
|
-
onSelect={() =>
|
|
397
|
-
handleSelection({
|
|
398
|
-
path: filePath,
|
|
399
|
-
name: file.name,
|
|
400
|
-
isDirectory: file.is_directory,
|
|
401
|
-
})
|
|
402
|
-
}
|
|
403
|
-
/>
|
|
404
|
-
</TableCell>
|
|
405
|
-
<TableCell>{file.name}</TableCell>
|
|
406
|
-
</TableRow>,
|
|
407
|
-
);
|
|
431
|
+
function handleRowKeyDown(
|
|
432
|
+
e: React.KeyboardEvent<HTMLTableRowElement>,
|
|
433
|
+
index: number,
|
|
434
|
+
) {
|
|
435
|
+
const lastIndex = rowModels.length - 1;
|
|
436
|
+
switch (e.key) {
|
|
437
|
+
case "ArrowDown":
|
|
438
|
+
e.preventDefault();
|
|
439
|
+
focusRow(Math.min(index + 1, lastIndex));
|
|
440
|
+
break;
|
|
441
|
+
case "ArrowUp":
|
|
442
|
+
e.preventDefault();
|
|
443
|
+
focusRow(Math.max(index - 1, 0));
|
|
444
|
+
break;
|
|
445
|
+
case "Home":
|
|
446
|
+
e.preventDefault();
|
|
447
|
+
focusRow(0);
|
|
448
|
+
break;
|
|
449
|
+
case "End":
|
|
450
|
+
e.preventDefault();
|
|
451
|
+
focusRow(lastIndex);
|
|
452
|
+
break;
|
|
453
|
+
case "Enter":
|
|
454
|
+
e.preventDefault();
|
|
455
|
+
rowModels[index].onPrimary();
|
|
456
|
+
break;
|
|
457
|
+
// Space is select-only; preventDefault stops the list from scrolling.
|
|
458
|
+
case " ":
|
|
459
|
+
e.preventDefault();
|
|
460
|
+
rowModels[index].onToggleSelect?.();
|
|
461
|
+
break;
|
|
462
|
+
}
|
|
408
463
|
}
|
|
409
464
|
|
|
410
465
|
// Get list of parent directories.
|
|
@@ -490,8 +545,44 @@ export const FileBrowser = ({
|
|
|
490
545
|
<span>Listing files...</span>
|
|
491
546
|
</div>
|
|
492
547
|
)}
|
|
493
|
-
<Table
|
|
494
|
-
|
|
548
|
+
<Table
|
|
549
|
+
ref={gridRef}
|
|
550
|
+
className="cursor-pointer table-fixed"
|
|
551
|
+
role="grid"
|
|
552
|
+
aria-label="File browser"
|
|
553
|
+
aria-multiselectable={multiple}
|
|
554
|
+
>
|
|
555
|
+
<TableBody>
|
|
556
|
+
{rowModels.map((row, index) => (
|
|
557
|
+
<TableRow
|
|
558
|
+
key={row.key}
|
|
559
|
+
role="row"
|
|
560
|
+
ref={(el) => {
|
|
561
|
+
rowRefs.current[index] = el;
|
|
562
|
+
}}
|
|
563
|
+
tabIndex={index === activeIndex ? 0 : -1}
|
|
564
|
+
onFocus={() => setActiveIndex(index)}
|
|
565
|
+
onKeyDown={(e) => handleRowKeyDown(e, index)}
|
|
566
|
+
className={cn(
|
|
567
|
+
"hover:bg-accent group select-none focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-inset",
|
|
568
|
+
{ "bg-primary/25 hover:bg-primary/35": row.isSelected },
|
|
569
|
+
)}
|
|
570
|
+
aria-selected={row.canSelect ? row.isSelected : undefined}
|
|
571
|
+
onClick={row.onPrimary}
|
|
572
|
+
>
|
|
573
|
+
<TableCell role="gridcell" className="w-[50px] pl-4">
|
|
574
|
+
<CheckboxOrIcon
|
|
575
|
+
name={row.name}
|
|
576
|
+
isSelected={row.isSelected}
|
|
577
|
+
canSelect={row.canSelect}
|
|
578
|
+
Icon={row.Icon}
|
|
579
|
+
onSelect={() => row.onToggleSelect?.()}
|
|
580
|
+
/>
|
|
581
|
+
</TableCell>
|
|
582
|
+
<TableCell role="gridcell">{row.name}</TableCell>
|
|
583
|
+
</TableRow>
|
|
584
|
+
))}
|
|
585
|
+
</TableBody>
|
|
495
586
|
</Table>
|
|
496
587
|
</div>
|
|
497
588
|
<div className="mt-4">
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
4
|
+
import { beforeAll, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import { SetupMocks } from "@/__mocks__/common";
|
|
6
|
+
import { initialModeAtom } from "@/core/mode";
|
|
7
|
+
import { store } from "@/core/state/jotai";
|
|
8
|
+
import type { IPluginProps } from "../../types";
|
|
9
|
+
import { FileBrowserPlugin } from "../FileBrowserPlugin";
|
|
10
|
+
|
|
11
|
+
interface MockFile {
|
|
12
|
+
id: string;
|
|
13
|
+
path: string;
|
|
14
|
+
name: string;
|
|
15
|
+
is_directory: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const FILES: MockFile[] = [
|
|
19
|
+
{ id: "1", path: "/home/user/docs", name: "docs", is_directory: true },
|
|
20
|
+
{ id: "2", path: "/home/user/a.txt", name: "a.txt", is_directory: false },
|
|
21
|
+
{ id: "3", path: "/home/user/b.txt", name: "b.txt", is_directory: false },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
type Value = MockFile[];
|
|
25
|
+
|
|
26
|
+
function mockListDirectory(files: MockFile[]) {
|
|
27
|
+
return vi.fn().mockResolvedValue({
|
|
28
|
+
files,
|
|
29
|
+
total_count: files.length,
|
|
30
|
+
is_truncated: false,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function makeProps(
|
|
35
|
+
overrides: {
|
|
36
|
+
selectionMode?: string;
|
|
37
|
+
multiple?: boolean;
|
|
38
|
+
value?: Value;
|
|
39
|
+
setValue?: (v: Value) => void;
|
|
40
|
+
files?: MockFile[];
|
|
41
|
+
list_directory?: ReturnType<typeof vi.fn>;
|
|
42
|
+
host?: HTMLElement;
|
|
43
|
+
} = {},
|
|
44
|
+
): IPluginProps<Value, Record<string, unknown>> {
|
|
45
|
+
const files = overrides.files ?? FILES;
|
|
46
|
+
const list_directory = overrides.list_directory ?? mockListDirectory(files);
|
|
47
|
+
return {
|
|
48
|
+
data: {
|
|
49
|
+
initialPath: "/home/user",
|
|
50
|
+
filetypes: [],
|
|
51
|
+
selectionMode: overrides.selectionMode ?? "all",
|
|
52
|
+
multiple: overrides.multiple ?? true,
|
|
53
|
+
label: null,
|
|
54
|
+
restrictNavigation: false,
|
|
55
|
+
},
|
|
56
|
+
value: overrides.value ?? [],
|
|
57
|
+
setValue: overrides.setValue ?? vi.fn(),
|
|
58
|
+
host: overrides.host ?? document.createElement("div"),
|
|
59
|
+
functions: {
|
|
60
|
+
list_directory,
|
|
61
|
+
},
|
|
62
|
+
} as unknown as IPluginProps<Value, Record<string, unknown>>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function renderBrowser(overrides: Parameters<typeof makeProps>[0] = {}) {
|
|
66
|
+
const listDirectory =
|
|
67
|
+
overrides.list_directory ?? mockListDirectory(overrides.files ?? FILES);
|
|
68
|
+
const result = render(
|
|
69
|
+
FileBrowserPlugin.render(
|
|
70
|
+
makeProps({ ...overrides, list_directory: listDirectory }) as Parameters<
|
|
71
|
+
typeof FileBrowserPlugin.render
|
|
72
|
+
>[0],
|
|
73
|
+
),
|
|
74
|
+
);
|
|
75
|
+
return { ...result, listDirectory };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
beforeAll(() => {
|
|
79
|
+
SetupMocks.resizeObserver();
|
|
80
|
+
store.set(initialModeAtom, "edit");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe("FileBrowserPlugin keyboard accessibility", () => {
|
|
84
|
+
it("renders a row per file plus the parent row", async () => {
|
|
85
|
+
renderBrowser();
|
|
86
|
+
expect(await screen.findByText("docs")).toBeInTheDocument();
|
|
87
|
+
// parent "..", docs, a.txt, b.txt
|
|
88
|
+
expect(screen.getAllByRole("row")).toHaveLength(4);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("marks the list as a multiselectable grid", async () => {
|
|
92
|
+
renderBrowser({ multiple: true });
|
|
93
|
+
await screen.findByText("docs");
|
|
94
|
+
const grid = screen.getByRole("grid");
|
|
95
|
+
expect(grid).toHaveAttribute("aria-multiselectable", "true");
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("does not select a non-selectable file on click (mode=directory)", async () => {
|
|
99
|
+
const setValue = vi.fn();
|
|
100
|
+
renderBrowser({ selectionMode: "directory", setValue });
|
|
101
|
+
const fileCell = await screen.findByText("a.txt");
|
|
102
|
+
fireEvent.click(fileCell.closest('[role="row"]')!);
|
|
103
|
+
expect(setValue).not.toHaveBeenCalled();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("labels each selectable checkbox with the file name", async () => {
|
|
107
|
+
renderBrowser({ selectionMode: "all" });
|
|
108
|
+
await screen.findByText("docs");
|
|
109
|
+
expect(
|
|
110
|
+
screen.getByRole("checkbox", { name: "Select a.txt" }),
|
|
111
|
+
).toBeInTheDocument();
|
|
112
|
+
expect(
|
|
113
|
+
screen.getByRole("checkbox", { name: "Select docs" }),
|
|
114
|
+
).toBeInTheDocument();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("keeps checkboxes out of the tab order", async () => {
|
|
118
|
+
renderBrowser({ selectionMode: "all" });
|
|
119
|
+
await screen.findByText("docs");
|
|
120
|
+
expect(
|
|
121
|
+
screen.getByRole("checkbox", { name: "Select a.txt" }),
|
|
122
|
+
).toHaveAttribute("tabindex", "-1");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("places exactly one row in the tab order", async () => {
|
|
126
|
+
renderBrowser();
|
|
127
|
+
await screen.findByText("docs");
|
|
128
|
+
const rows = screen.getAllByRole("row");
|
|
129
|
+
const tabbable = rows.filter((r) => r.getAttribute("tabindex") === "0");
|
|
130
|
+
expect(tabbable).toHaveLength(1);
|
|
131
|
+
// the parent row is first and starts active
|
|
132
|
+
expect(rows[0]).toHaveAttribute("tabindex", "0");
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("resets the active row to the parent row after navigating", async () => {
|
|
136
|
+
renderBrowser({ selectionMode: "all" });
|
|
137
|
+
const docs = await screen.findByText("docs");
|
|
138
|
+
const docsRow = docs.closest('[role="row"]')!;
|
|
139
|
+
fireEvent.keyDown(docsRow, { key: "ArrowDown" }); // move active off the parent
|
|
140
|
+
fireEvent.click(docs); // navigate into "docs"
|
|
141
|
+
await screen.findByText("docs"); // listing reloads (mock returns same files)
|
|
142
|
+
const rows = screen.getAllByRole("row");
|
|
143
|
+
expect(rows[0]).toHaveAttribute("tabindex", "0");
|
|
144
|
+
// the focused row must match the only tabbable row
|
|
145
|
+
expect(rows[0]).toHaveFocus();
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("resets the active row when the listing refreshes in place", async () => {
|
|
149
|
+
// The cell's random-id changes when the cell re-renders, refetching the
|
|
150
|
+
// same path. A shrinking listing must not leave activeIndex out of bounds.
|
|
151
|
+
const parent = document.createElement("div");
|
|
152
|
+
parent.setAttribute("random-id", "a");
|
|
153
|
+
const host = document.createElement("div");
|
|
154
|
+
parent.append(host);
|
|
155
|
+
document.body.append(parent);
|
|
156
|
+
|
|
157
|
+
const list_directory = vi
|
|
158
|
+
.fn()
|
|
159
|
+
.mockResolvedValueOnce({
|
|
160
|
+
files: FILES,
|
|
161
|
+
total_count: FILES.length,
|
|
162
|
+
is_truncated: false,
|
|
163
|
+
})
|
|
164
|
+
.mockResolvedValue({
|
|
165
|
+
files: [FILES[0]],
|
|
166
|
+
total_count: 1,
|
|
167
|
+
is_truncated: false,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const props = () =>
|
|
171
|
+
FileBrowserPlugin.render(
|
|
172
|
+
makeProps({ host, list_directory }) as Parameters<
|
|
173
|
+
typeof FileBrowserPlugin.render
|
|
174
|
+
>[0],
|
|
175
|
+
);
|
|
176
|
+
const { rerender } = render(props());
|
|
177
|
+
await screen.findByText("a.txt");
|
|
178
|
+
|
|
179
|
+
// Move the active row to the last row, then trigger a same-path refresh.
|
|
180
|
+
fireEvent.keyDown(screen.getAllByRole("row")[0], { key: "End" });
|
|
181
|
+
expect(screen.getAllByRole("row").at(-1)).toHaveAttribute("tabindex", "0");
|
|
182
|
+
|
|
183
|
+
parent.setAttribute("random-id", "b");
|
|
184
|
+
rerender(props());
|
|
185
|
+
|
|
186
|
+
await waitFor(() =>
|
|
187
|
+
// parent ".." plus the single remaining file
|
|
188
|
+
expect(screen.getAllByRole("row")).toHaveLength(2),
|
|
189
|
+
);
|
|
190
|
+
const rows = screen.getAllByRole("row");
|
|
191
|
+
const tabbable = rows.filter((r) => r.getAttribute("tabindex") === "0");
|
|
192
|
+
expect(tabbable).toHaveLength(1);
|
|
193
|
+
expect(rows[0]).toHaveAttribute("tabindex", "0");
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("syncs the tabbable row to whichever row gains focus", async () => {
|
|
197
|
+
renderBrowser();
|
|
198
|
+
await screen.findByText("docs");
|
|
199
|
+
const rows = screen.getAllByRole("row"); // [.., docs, a.txt, b.txt]
|
|
200
|
+
expect(rows[0]).toHaveAttribute("tabindex", "0");
|
|
201
|
+
|
|
202
|
+
fireEvent.focus(rows[2]); // e.g. focus from a mouse click, not arrow keys
|
|
203
|
+
expect(rows[2]).toHaveAttribute("tabindex", "0");
|
|
204
|
+
expect(rows[0]).toHaveAttribute("tabindex", "-1");
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("moves focus to the parent row after navigating from within the grid", async () => {
|
|
208
|
+
// Navigating into a directory unmounts the focused row; focus must follow
|
|
209
|
+
// to the parent row instead of falling back to the document body.
|
|
210
|
+
const list_directory = vi
|
|
211
|
+
.fn()
|
|
212
|
+
.mockResolvedValueOnce({
|
|
213
|
+
files: FILES,
|
|
214
|
+
total_count: FILES.length,
|
|
215
|
+
is_truncated: false,
|
|
216
|
+
})
|
|
217
|
+
.mockResolvedValue({
|
|
218
|
+
files: [
|
|
219
|
+
{
|
|
220
|
+
id: "99",
|
|
221
|
+
path: "/home/user/docs/inner.txt",
|
|
222
|
+
name: "inner.txt",
|
|
223
|
+
is_directory: false,
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
total_count: 1,
|
|
227
|
+
is_truncated: false,
|
|
228
|
+
});
|
|
229
|
+
renderBrowser({ selectionMode: "all", list_directory });
|
|
230
|
+
await screen.findByText("docs");
|
|
231
|
+
|
|
232
|
+
const rows = screen.getAllByRole("row"); // [.., docs, a.txt, b.txt]
|
|
233
|
+
fireEvent.keyDown(rows[0], { key: "ArrowDown" }); // focus the docs row
|
|
234
|
+
expect(rows[1]).toHaveFocus();
|
|
235
|
+
fireEvent.keyDown(rows[1], { key: "Enter" }); // navigate into docs
|
|
236
|
+
|
|
237
|
+
await screen.findByText("inner.txt");
|
|
238
|
+
expect(screen.getAllByRole("row")[0]).toHaveFocus();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("moves focus with arrows and clamps at the ends", async () => {
|
|
242
|
+
renderBrowser();
|
|
243
|
+
await screen.findByText("docs");
|
|
244
|
+
const rows = screen.getAllByRole("row"); // [.., docs, a.txt, b.txt]
|
|
245
|
+
|
|
246
|
+
fireEvent.keyDown(rows[0], { key: "ArrowDown" });
|
|
247
|
+
expect(rows[1]).toHaveFocus();
|
|
248
|
+
expect(rows[1]).toHaveAttribute("tabindex", "0");
|
|
249
|
+
|
|
250
|
+
fireEvent.keyDown(rows[1], { key: "ArrowUp" });
|
|
251
|
+
expect(rows[0]).toHaveFocus();
|
|
252
|
+
|
|
253
|
+
fireEvent.keyDown(rows[0], { key: "ArrowUp" }); // clamp at top
|
|
254
|
+
expect(rows[0]).toHaveFocus();
|
|
255
|
+
|
|
256
|
+
fireEvent.keyDown(rows[0], { key: "End" });
|
|
257
|
+
expect(rows[3]).toHaveFocus();
|
|
258
|
+
|
|
259
|
+
fireEvent.keyDown(rows[3], { key: "ArrowDown" }); // clamp at bottom
|
|
260
|
+
expect(rows[3]).toHaveFocus();
|
|
261
|
+
|
|
262
|
+
fireEvent.keyDown(rows[3], { key: "Home" });
|
|
263
|
+
expect(rows[0]).toHaveFocus();
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it("Enter navigates into a directory", async () => {
|
|
267
|
+
const setValue = vi.fn();
|
|
268
|
+
const { listDirectory } = renderBrowser({
|
|
269
|
+
selectionMode: "all",
|
|
270
|
+
setValue,
|
|
271
|
+
});
|
|
272
|
+
await screen.findByText("docs");
|
|
273
|
+
fireEvent.keyDown(rowFor("docs"), { key: "Enter" });
|
|
274
|
+
await waitFor(() =>
|
|
275
|
+
expect(listDirectory).toHaveBeenCalledWith({ path: "/home/user/docs" }),
|
|
276
|
+
);
|
|
277
|
+
// navigation does not mutate value
|
|
278
|
+
expect(setValue).not.toHaveBeenCalled();
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it("Enter toggles selection on a selectable file", async () => {
|
|
282
|
+
const setValue = vi.fn();
|
|
283
|
+
renderBrowser({ selectionMode: "all", multiple: true, setValue });
|
|
284
|
+
await screen.findByText("a.txt");
|
|
285
|
+
fireEvent.keyDown(rowFor("a.txt"), { key: "Enter" });
|
|
286
|
+
expect(setValue).toHaveBeenCalledWith([
|
|
287
|
+
expect.objectContaining({ path: "/home/user/a.txt" }),
|
|
288
|
+
]);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it("Space toggles selection and never navigates", async () => {
|
|
292
|
+
const setValue = vi.fn();
|
|
293
|
+
renderBrowser({ selectionMode: "all", multiple: true, setValue });
|
|
294
|
+
await screen.findByText("docs");
|
|
295
|
+
// Space on a selectable directory selects it (does not navigate)
|
|
296
|
+
fireEvent.keyDown(rowFor("docs"), { key: " " });
|
|
297
|
+
expect(setValue).toHaveBeenCalledWith([
|
|
298
|
+
expect.objectContaining({ path: "/home/user/docs" }),
|
|
299
|
+
]);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("Space on the parent row is a no-op", async () => {
|
|
303
|
+
const setValue = vi.fn();
|
|
304
|
+
renderBrowser({ selectionMode: "all", setValue });
|
|
305
|
+
await screen.findByText("docs");
|
|
306
|
+
const parentRow = screen.getAllByRole("row")[0];
|
|
307
|
+
fireEvent.keyDown(parentRow, { key: " " });
|
|
308
|
+
expect(setValue).not.toHaveBeenCalled();
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
function rowFor(name: string): HTMLElement {
|
|
313
|
+
return screen.getByText(name).closest('[role="row"]') as HTMLElement;
|
|
314
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{et as r,tt as e}from"./chunk-ABZYJK2D-BWwBJaW4.js";var o=(t,a)=>e.lang.round(r.parse(t)[a]);export{o as t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./purify.es-DfJp_of2.js";import"./src-CvyFXpBy.js";import"./chunk-S3R3BYOJ-C7n0Esov.js";import{n as t}from"./src-BnrQkOKh.js";import"./chunk-ABZYJK2D-BWwBJaW4.js";import"./chunk-HN2XXSSU-Bcaj5fRB.js";import"./chunk-CVBHYZKI-C-NWvPQL.js";import"./chunk-ATLVNIR6-ZywQjHDL.js";import"./dist-BXRWfNwi.js";import"./chunk-JA3XYJ7Z-BC57JRLK.js";import"./chunk-JZLCHNYA-CmPEo2OR.js";import"./chunk-QXUST7PY-DiH4MyLq.js";import"./chunk-N4CR4FBY-qcFzulsJ.js";import"./chunk-FMBD7UC4-DlnzxSkO.js";import"./chunk-55IACEB6-Cr4aqhf3.js";import"./chunk-QN33PNHL-CfKFSQ8y.js";import{i,n as o,r as m,t as p}from"./chunk-B4BG7PRW-Q6rM60b0.js";var a={parser:o,get db(){return new p},renderer:m,styles:i,init:t(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{a as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./purify.es-DfJp_of2.js";import"./src-CvyFXpBy.js";import"./chunk-S3R3BYOJ-C7n0Esov.js";import{n as t}from"./src-BnrQkOKh.js";import"./chunk-ABZYJK2D-BWwBJaW4.js";import"./chunk-HN2XXSSU-Bcaj5fRB.js";import"./chunk-CVBHYZKI-C-NWvPQL.js";import"./chunk-ATLVNIR6-ZywQjHDL.js";import"./dist-BXRWfNwi.js";import"./chunk-JA3XYJ7Z-BC57JRLK.js";import"./chunk-JZLCHNYA-CmPEo2OR.js";import"./chunk-QXUST7PY-DiH4MyLq.js";import"./chunk-N4CR4FBY-qcFzulsJ.js";import"./chunk-FMBD7UC4-DlnzxSkO.js";import"./chunk-55IACEB6-Cr4aqhf3.js";import"./chunk-QN33PNHL-CfKFSQ8y.js";import{i,n as o,r as m,t as p}from"./chunk-B4BG7PRW-Q6rM60b0.js";var a={parser:o,get db(){return new p},renderer:m,styles:i,init:t(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{a as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./dist-Dez1I5M9.js";import"./dist-D-2yWcX9.js";import"./dist-CNKFZCiw.js";import"./dist-ZjSH4Z6x.js";import{i,n as r,r as a,t as o}from"./dist-FYUcqnI2.js";export{o as closePercentBrace,r as liquid,a as liquidCompletionSource,i as liquidLanguage};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./dist-Dez1I5M9.js";import"./dist-D-2yWcX9.js";import"./dist-CNKFZCiw.js";import"./dist-ZjSH4Z6x.js";import{n as o,t as r}from"./dist-BHCGBHnf.js";export{r as vue,o as vueLanguage};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./dist-Dez1I5M9.js";import"./dist-CNKFZCiw.js";import{n as s,r as a,t as o}from"./dist-sJHUucQ8.js";export{o as sass,s as sassCompletionSource,a as sassLanguage};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./dist-Dez1I5M9.js";import"./dist-D-2yWcX9.js";import"./dist-CNKFZCiw.js";import"./dist-ZjSH4Z6x.js";import{n as p,t as o}from"./dist-DyuwOQr-.js";export{o as php,p as phpLanguage};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./dist-Dez1I5M9.js";import"./dist-D-2yWcX9.js";import"./dist-CNKFZCiw.js";import"./dist-ZjSH4Z6x.js";import{i as a,n as r,r as o,t as i}from"./dist-Cqrb9QGk.js";export{i as closePercentBrace,r as jinja,o as jinjaCompletionSource,a as jinjaLanguage};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./dist-Dez1I5M9.js";import"./dist-CNKFZCiw.js";import{n as s,r as a,t as e}from"./dist-77VmTZjj.js";export{e as less,s as lessCompletionSource,a as lessLanguage};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{t}from"./createLucideIcon-BTp1tQDO.js";var a=t("github",[["path",{d:"M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4",key:"tonef"}],["path",{d:"M9 18c-4.51 2-5-2-7-2",key:"9comsn"}]]);export{a as t};
|