@marimo-team/islands 0.25.3-dev16 → 0.25.3-dev162

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.
Files changed (515) hide show
  1. package/dist/{ConnectedDataExplorerComponent-CNMliVzw.js → ConnectedDataExplorerComponent-BbDrlHvG.js} +17 -15
  2. package/dist/{ErrorBoundary-BEmYzeHb.js → ErrorBoundary-D6GPQ8dk.js} +16 -16
  3. package/dist/{abnfDiagram-VCTEODGH-D-Ez91gV.js → abnfDiagram-VCTEODGH-Dr-fo8_z.js} +2 -2
  4. package/dist/any-language-editor-3E24SnCV.js +75 -0
  5. package/dist/{architectureDiagram-5GKGNRK7-CTpcNtO8.js → architectureDiagram-5GKGNRK7-ByKIl9GG.js} +1 -1
  6. package/dist/{arrays-CN1djC4k.js → arrays-R6JsImiT.js} +8 -0
  7. package/dist/assets/__vite-browser-external-DVeFf2e7.js +1 -0
  8. package/dist/assets/worker-C1pfNBsx.js +113 -0
  9. package/dist/{button-CvjkwdSk.js → button-BQRdqQi1.js} +199 -192
  10. package/dist/{capabilities-CQ5IjhzL.js → capabilities-CI4xUPsp.js} +2 -2
  11. package/dist/{chat-ui-DaHynk8g.js → chat-ui-BsV2WH-4.js} +1143 -1142
  12. package/dist/{check-EDwSwP89.js → check-SpOMoCLP.js} +1 -1
  13. package/dist/{chunk-IMKFNOWR-DGxi-zeo.js → chunk-IMKFNOWR-IKDP18MQ.js} +1 -1
  14. package/dist/{chunk-SHT3W25Y-CV9J3rAB.js → chunk-SHT3W25Y-LkIgegwh.js} +1 -1
  15. package/dist/{chunk-SVP7TREG-BL-9Fqgg.js → chunk-SVP7TREG-DReBYtnB.js} +1 -1
  16. package/dist/{chunk-TICWLB2K-Cu_XMjDM.js → chunk-TICWLB2K-DQ0A0-1D.js} +1 -1
  17. package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
  18. package/dist/{classDiagram-ZZMXUADV-BXXV13Hq.js → classDiagram-ZZMXUADV-CwvXdCNE.js} +2 -2
  19. package/dist/{classDiagram-v2-VYDZK3BY-B7FXJ1Cp.js → classDiagram-v2-VYDZK3BY-D0XAxDsc.js} +2 -2
  20. package/dist/{code-visibility-D75HwL4W.js → code-visibility-DEIiTBMH.js} +6 -6
  21. package/dist/{common-hR234FGW.js → common-BmlT-bPP.js} +6828 -6648
  22. package/dist/{copy-icon-Ft7t9bqz.js → copy-icon-C1trdvVt.js} +3 -3
  23. package/dist/{cynefinDiagram-5FMLGOSQ-CH96rwba.js → cynefinDiagram-5FMLGOSQ-BFN68nHr.js} +1 -1
  24. package/dist/{dagre-GXQ25YYZ-BD3PmpFY.js → dagre-GXQ25YYZ-CZt4rtLq.js} +1 -1
  25. package/dist/{data-grid-overlay-editor-D-NMDtk0.js → data-grid-overlay-editor-20Ge8ID1.js} +5 -5
  26. package/dist/{data-grid-types-BH_r7g7l.js → data-grid-types-0PJ-9N5n.js} +1 -1
  27. package/dist/{diagram-S7CK7UJ4-BsSJJldB.js → diagram-S7CK7UJ4-D5cOz47_.js} +1 -1
  28. package/dist/{diagram-UQ7AKVKN-muQtNZc4.js → diagram-UQ7AKVKN-Qgdppb4a.js} +1 -1
  29. package/dist/{diagram-VX7I27RA-CdhuZAqR.js → diagram-VX7I27RA-BsDCvily.js} +1 -1
  30. package/dist/{diagram-Z3DM3KII-BD8mXjOj.js → diagram-Z3DM3KII-igTkGjKI.js} +1 -1
  31. package/dist/{dialog-CEBFZNyc.js → dialog-DgeqyrEZ.js} +3 -3
  32. package/dist/{dist-DpBpA_n1.js → dist-Lm-D-Vr6.js} +3 -3
  33. package/dist/{dropdown-menu-CP_qCYHC.js → dropdown-menu-BWnnAstC.js} +1277 -1229
  34. package/dist/{ebnfDiagram-PWID7BFC-BIN1sweE.js → ebnfDiagram-PWID7BFC-BHuZGjIr.js} +2 -2
  35. package/dist/{erDiagram-RLTQ6QDP-Ctp5cfoN.js → erDiagram-RLTQ6QDP-DKObXTVE.js} +1 -1
  36. package/dist/{error-banner-D-WCIiMt.js → error-banner-D40pmfQQ.js} +83 -83
  37. package/dist/{error-entries-Bv6bZPF3.js → error-entries-BpUJSLUZ.js} +1019 -978
  38. package/dist/{feedback-button-B3sliPJj.js → feedback-button-zWcCfXEI.js} +23 -23
  39. package/dist/{flowDiagram-HODETNUW-3EfLrlFb.js → flowDiagram-HODETNUW-DZI_kit0.js} +2 -2
  40. package/dist/{formats-27CW_UP4.js → formats-CwJHWasD.js} +3 -3
  41. package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
  42. package/dist/{glide-data-editor-Dufy2ePW.js → glide-data-editor-Dn1Ekucb.js} +370 -368
  43. package/dist/{glide-utils-DJyqh0EM.js → glide-utils-Dz_F4pAY.js} +16 -16
  44. package/dist/{globals-B02fTTAH.js → globals-D_fhTQMd.js} +3 -3
  45. package/dist/{highlighted-body-KPVGNVTW-zwjq21tf.js → highlighted-body-KPVGNVTW-3Ziwfz-V.js} +2 -2
  46. package/dist/{html-to-image-Bf8QMGi4.js → html-to-image-CQr2-IDA.js} +632 -595
  47. package/dist/{infoDiagram-27XIBGKW-DipQoHxl.js → infoDiagram-27XIBGKW-DdPl-7-n.js} +1 -1
  48. package/dist/{ishikawaDiagram-5VMMS53U-DgFMjSGz.js → ishikawaDiagram-5VMMS53U-DbyW6l59.js} +1 -1
  49. package/dist/{kanban-definition-UXKFOSKX-w1ACVjgl.js → kanban-definition-UXKFOSKX-BMX9SyBS.js} +1 -1
  50. package/dist/{label-BDKF3Afc.js → label-D9_-zSg-.js} +3 -3
  51. package/dist/{linear-Cnaq3Tfb.js → linear-DWERh7eI.js} +121 -73
  52. package/dist/{loader-BQOfjTIJ.js → loader-DOVB0Syl.js} +12 -12
  53. package/dist/main.js +7568 -7246
  54. package/dist/{mermaid-CHo49Yv-.js → mermaid-C8W8mTbA.js} +38 -38
  55. package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
  56. package/dist/{mindmap-definition-YA3MSWOX-CrT0KSfX.js → mindmap-definition-YA3MSWOX-Zd_tAxWL.js} +1 -1
  57. package/dist/{number-overlay-editor-EF8mCVoy.js → number-overlay-editor-ELtg9k3M.js} +3 -3
  58. package/dist/{objects-CzUgoMIF.js → objects-DCmMvZtn.js} +1 -3
  59. package/dist/{once-BtE-wKRL.js → once-eG8Vmvjd.js} +1 -1
  60. package/dist/{pegDiagram-XKGWAZYB-BqvywNJA.js → pegDiagram-XKGWAZYB-DjYydPdo.js} +2 -2
  61. package/dist/{pieDiagram-E7YTZNPT-BfxJ_XCc.js → pieDiagram-E7YTZNPT-R5LKjO2n.js} +1 -1
  62. package/dist/precisionRound-DhAzeRcm.js +49 -0
  63. package/dist/{process-output-BZg56CCb.js → process-output-Uw-VJE5V.js} +5 -5
  64. package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
  65. package/dist/{railroadDiagram-O6MQD6OU-8vFLVTPu.js → railroadDiagram-O6MQD6OU-C7uNKtfm.js} +2 -2
  66. package/dist/{react-vega-BED0DjiB.js → react-vega-C4T9Rb_w.js} +12284 -12270
  67. package/dist/{requirementDiagram-BXWQKSXE-a_MxGvxe.js → requirementDiagram-BXWQKSXE-CxAIzQfl.js} +1 -1
  68. package/dist/{reveal-component-Boolki8h.js → reveal-component-CduO3VgT.js} +14 -14
  69. package/dist/{select-BButFi-d.js → select-CkF_GBxO.js} +537 -458
  70. package/dist/{sequenceDiagram-WJ2MYXX4-CXFMnxGh.js → sequenceDiagram-WJ2MYXX4-B5tmlPd5.js} +1 -1
  71. package/dist/{spec-BwarBpUJ.js → spec-45FnujvG.js} +41 -11
  72. package/dist/{stateDiagram-D77RDMKH-DQeA_CwI.js → stateDiagram-D77RDMKH-C1hc5H7Y.js} +2 -2
  73. package/dist/{stateDiagram-v2-MP3YSRHH-BxxQucm1.js → stateDiagram-v2-MP3YSRHH-DRWeqQTn.js} +2 -2
  74. package/dist/style.css +1 -1
  75. package/dist/{swimlanes-42K2YHIH-Do6L-cYg.js → swimlanes-42K2YHIH-NTLas--s.js} +1 -1
  76. package/dist/{swimlanesDiagram-VR7AAH4N-DUzPvSVU.js → swimlanesDiagram-VR7AAH4N-ChPggljD.js} +2 -2
  77. package/dist/{swiper-component-DKntyn8p.js → swiper-component-BkCm-kLg.js} +2 -2
  78. package/dist/{time-BieKwdYS.js → time-BaMbJs4z.js} +18 -18
  79. package/dist/{timeline-definition-24CTP7MA-D3c46WM5.js → timeline-definition-24CTP7MA-B4CZ9srJ.js} +1 -1
  80. package/dist/{toDate-UtiwmnH2.js → toDate-rySyYxqk.js} +19 -18
  81. package/dist/{toast-B9UMEi8u.js → toast-Btbve3Lm.js} +231 -213
  82. package/dist/{tooltip-BO1REbqs.js → tooltip-CJ4Rqasp.js} +327 -303
  83. package/dist/{use-restore-focus-BEM7sFWl.js → use-restore-focus-CmGwRNId.js} +1482 -1433
  84. package/dist/{useAsyncData-Deh5kszT.js → useAsyncData-B7MiltyV.js} +15 -14
  85. package/dist/{useDateFormatter-D8XruNGG.js → useDateFormatter-eCL_SdeG.js} +2 -2
  86. package/dist/{useDeepCompareMemoize-DXwzRINI.js → useDeepCompareMemoize-DZmHBD_1.js} +1 -1
  87. package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-CSdWn6NP.js} +1 -1
  88. package/dist/{useLifecycle-j7D9uD1o.js → useLifecycle-DRbRhzxg.js} +3 -3
  89. package/dist/{useTheme-CRnjkku0.js → useTheme-TLkqJsvo.js} +57 -54
  90. package/dist/{vega-component-BeF9dfyO.js → vega-component-DC6P127L.js} +148 -148
  91. package/dist/{vega-embed-container-BNHE18G9.js → vega-embed-container--LYZqguO.js} +2 -2
  92. package/dist/{vega-loader.browser-DNST6uVf.js → vega-loader.browser-B9Pz0EGP.js} +298 -507
  93. package/dist/{vennDiagram-4TSXK5OY-BSZD8JcZ.js → vennDiagram-4TSXK5OY-DJIvMt44.js} +1 -1
  94. package/dist/{wardleyDiagram-VM6X3IG4-48cUWkfA.js → wardleyDiagram-VM6X3IG4-45H0zg0u.js} +1 -1
  95. package/dist/{xychartDiagram-S5SC5T6Z-CswYgYeu.js → xychartDiagram-S5SC5T6Z-ZT-XzcPN.js} +2 -2
  96. package/package.json +16 -16
  97. package/src/__tests__/module-entry.test.ts +44 -0
  98. package/src/__tests__/mount.test.ts +1 -21
  99. package/src/__tests__/{host-imports.test.ts → replica-imports.test.ts} +12 -11
  100. package/src/components/ai/__tests__/ai-model-dropdown.test.tsx +63 -0
  101. package/src/components/ai/ai-model-dropdown.tsx +11 -6
  102. package/src/components/app-config/ai-config.tsx +7 -2
  103. package/src/components/app-config/user-config-form.tsx +35 -0
  104. package/src/components/chat/__tests__/message-queue.test.tsx +17 -0
  105. package/src/components/chat/acp/__tests__/session-tabs.test.tsx +43 -0
  106. package/src/components/chat/acp/__tests__/state.test.ts +2 -2
  107. package/src/components/chat/acp/blocks.tsx +3 -2
  108. package/src/components/chat/acp/session-tabs.tsx +8 -3
  109. package/src/components/chat/chat-components.tsx +2 -0
  110. package/src/components/chat/chat-panel.tsx +9 -8
  111. package/src/components/chat/chat-utils.ts +4 -8
  112. package/src/components/data-table/TableTopBar.tsx +2 -0
  113. package/src/components/data-table/__tests__/chart-spec-model.test.ts +195 -195
  114. package/src/components/data-table/__tests__/column-explorer.test.tsx +27 -1
  115. package/src/components/data-table/__tests__/columns.test.tsx +105 -0
  116. package/src/components/data-table/__tests__/context-menu-interaction.test.tsx +130 -0
  117. package/src/components/data-table/__tests__/data-table.test.tsx +1 -0
  118. package/src/components/data-table/__tests__/date-popover.test.tsx +72 -0
  119. package/src/components/data-table/__tests__/export-actions.test.tsx +105 -0
  120. package/src/components/data-table/__tests__/keyboard-selection.test.tsx +188 -0
  121. package/src/components/data-table/__tests__/search-highlight.test.tsx +109 -0
  122. package/src/components/data-table/__tests__/url-detector.test.tsx +74 -0
  123. package/src/components/data-table/cell-selection/feature.ts +2 -2
  124. package/src/components/data-table/cell-selection/types.ts +2 -2
  125. package/src/components/data-table/charts/__tests__/chart-panel.test.tsx +74 -1
  126. package/src/components/data-table/charts/__tests__/spec-snapshot.test.ts +20 -20
  127. package/src/components/data-table/charts/__tests__/spec.test.ts +78 -52
  128. package/src/components/data-table/charts/__tests__/storage.test.ts +4 -1
  129. package/src/components/data-table/charts/chart-spec/spec.ts +68 -43
  130. package/src/components/data-table/charts/charts.tsx +40 -30
  131. package/src/components/data-table/charts/storage.ts +16 -5
  132. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
  133. package/src/components/data-table/column-summary/chart-spec-model.tsx +23 -16
  134. package/src/components/data-table/column-summary/column-summary.tsx +2 -4
  135. package/src/components/data-table/column-visibility-dropdown.tsx +8 -13
  136. package/src/components/data-table/columns.tsx +45 -46
  137. package/src/components/data-table/context-menu.tsx +36 -20
  138. package/src/components/data-table/data-table.tsx +13 -1
  139. package/src/components/data-table/date-popover.tsx +6 -4
  140. package/src/components/data-table/export-actions.tsx +76 -48
  141. package/src/components/data-table/range-focus/atoms.ts +4 -6
  142. package/src/components/data-table/range-focus/use-cell-range-selection.ts +65 -38
  143. package/src/components/data-table/range-focus/use-scroll-into-view.ts +21 -2
  144. package/src/components/data-table/renderers.tsx +16 -7
  145. package/src/components/data-table/row-viewer-panel/__tests__/row-viewer.test.tsx +24 -1
  146. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +4 -4
  147. package/src/components/data-table/search-highlight.tsx +79 -0
  148. package/src/components/data-table/types.ts +1 -0
  149. package/src/components/data-table/url-detector.tsx +49 -9
  150. package/src/components/datasources/__tests__/column-actions.test.tsx +97 -0
  151. package/src/components/datasources/__tests__/column-preview.test.tsx +98 -5
  152. package/src/components/datasources/__tests__/datasources-interactions.test.tsx +181 -0
  153. package/src/components/datasources/__tests__/table-list.test.tsx +118 -0
  154. package/src/components/datasources/__tests__/utils.test.ts +57 -6
  155. package/src/components/datasources/column-preview.tsx +13 -4
  156. package/src/components/datasources/datasources.tsx +51 -39
  157. package/src/components/datasources/utils.ts +32 -23
  158. package/src/components/debugger/debugger-code.tsx +5 -0
  159. package/src/components/dependency-graph/dependency-graph-tree.tsx +8 -8
  160. package/src/components/dependency-graph/elements.ts +24 -21
  161. package/src/components/dependency-graph/panels.tsx +2 -1
  162. package/src/components/dependency-graph/utils/__tests__/layout.test.ts +18 -11
  163. package/src/components/editor/SortableCell.tsx +1 -3
  164. package/src/{core/attachments/__tests__/toast.test.tsx → components/editor/__tests__/agent-toast.test.tsx} +1 -1
  165. package/src/components/editor/__tests__/data-attributes.test.tsx +6 -2
  166. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +111 -18
  167. package/src/components/editor/__tests__/package-alert.test.tsx +22 -1
  168. package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +24 -0
  169. package/src/components/editor/actions/pair-with-agent-modal.tsx +18 -15
  170. package/src/components/editor/actions/useRestartKernel.tsx +1 -1
  171. package/src/components/editor/ai/add-cell-with-ai.tsx +3 -3
  172. package/src/components/editor/ai/ai-completion-editor.tsx +1 -0
  173. package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +1 -1
  174. package/src/components/editor/alerts/connection-notice.tsx +1 -1
  175. package/src/components/editor/alerts/startup-logs-alert.tsx +1 -0
  176. package/src/components/editor/app-container.tsx +1 -1
  177. package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +1 -1
  178. package/src/components/editor/cell/CreateCellButton.tsx +10 -12
  179. package/src/components/editor/cell/DeleteButton.tsx +3 -2
  180. package/src/components/editor/cell/RunButton.tsx +2 -2
  181. package/src/components/editor/cell/StopButton.tsx +2 -2
  182. package/src/components/editor/cell/__tests__/useShouldShowInterrupt.test.ts +39 -0
  183. package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +54 -0
  184. package/src/components/editor/cell/code/cell-editor.tsx +2 -2
  185. package/src/components/editor/cell/code/language-toggle.tsx +8 -7
  186. package/src/components/editor/cell/collapse.tsx +5 -3
  187. package/src/components/editor/cell/useShouldShowInterrupt.ts +2 -12
  188. package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +1 -1
  189. package/src/components/editor/chrome/components/feedback-button.tsx +1 -1
  190. package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +31 -2
  191. package/src/components/editor/chrome/panels/__tests__/runtime-details.test.tsx +1 -1
  192. package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +1 -1
  193. package/src/components/editor/chrome/panels/cache-panel.tsx +1 -0
  194. package/src/components/editor/chrome/panels/outline/__tests__/outline-keyboard.test.tsx +84 -0
  195. package/src/components/editor/chrome/panels/outline/floating-outline.tsx +39 -14
  196. package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +3 -2
  197. package/src/components/editor/chrome/panels/packages-panel.tsx +4 -7
  198. package/src/components/editor/chrome/panels/secrets-panel.tsx +1 -0
  199. package/src/components/editor/chrome/panels/snippets-panel.tsx +5 -1
  200. package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +9 -18
  201. package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +58 -1
  202. package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +4 -4
  203. package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +1 -1
  204. package/src/components/editor/chrome/wrapper/footer-items/lsp-status.tsx +1 -1
  205. package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +1 -1
  206. package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +1 -7
  207. package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +12 -2
  208. package/src/components/editor/chrome/wrapper/storage.ts +1 -1
  209. package/src/components/editor/connections/components.tsx +1 -1
  210. package/src/components/editor/controls/Controls.tsx +2 -2
  211. package/src/components/editor/controls/__tests__/command-palette.test.tsx +53 -0
  212. package/src/components/editor/controls/__tests__/keyboard-shortcuts.test.tsx +61 -0
  213. package/src/components/editor/controls/__tests__/notebook-menu-dropdown.test.tsx +1 -1
  214. package/src/components/editor/controls/command-palette.tsx +22 -10
  215. package/src/components/editor/controls/keyboard-shortcuts.tsx +14 -5
  216. package/src/components/editor/dynamic-favicon.tsx +21 -40
  217. package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +9 -23
  218. package/src/components/editor/errors/send-error-report-button.tsx +3 -6
  219. package/src/components/editor/file-tree/__tests__/file-explorer-interactions.test.tsx +6 -0
  220. package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +47 -0
  221. package/src/components/editor/file-tree/__tests__/use-file-search.test.tsx +91 -0
  222. package/src/components/editor/file-tree/file-explorer.tsx +45 -8
  223. package/src/components/editor/file-tree/file-name-input.tsx +1 -0
  224. package/src/components/editor/file-tree/file-viewer.tsx +4 -2
  225. package/src/components/editor/file-tree/use-file-search.ts +35 -21
  226. package/src/components/editor/header/__tests__/status.test.tsx +5 -3
  227. package/src/components/editor/header/app-header.tsx +1 -1
  228. package/src/components/editor/header/status.tsx +40 -20
  229. package/src/components/editor/links/__tests__/cell-link.test.tsx +146 -0
  230. package/src/components/editor/links/cell-link.tsx +14 -5
  231. package/src/components/editor/navigation/focus-utils.ts +4 -4
  232. package/src/components/editor/notebook-banner.tsx +1 -0
  233. package/src/components/editor/notebook-cell.tsx +12 -3
  234. package/src/components/editor/output/MarimoErrorOutput.tsx +2 -1
  235. package/src/components/editor/output/MarimoTracebackOutput.tsx +19 -17
  236. package/src/components/editor/output/Outputs.css +8 -0
  237. package/src/components/editor/output/__tests__/traceback.test.tsx +27 -1
  238. package/src/components/editor/output/ansi-reduce.ts +33 -20
  239. package/src/components/editor/output/console/ConsoleOutput.tsx +19 -25
  240. package/src/components/editor/package-alert.tsx +14 -7
  241. package/src/components/editor/renderers/grid-layout/grid-layout.tsx +12 -6
  242. package/src/components/editor/renderers/vertical-layout/sidebar/toggle.tsx +7 -1
  243. package/src/components/home/components.tsx +17 -31
  244. package/src/components/icons/__tests__/large-spinner.test.tsx +39 -0
  245. package/src/components/icons/large-spinner.tsx +3 -14
  246. package/src/components/icons/spinner.tsx +1 -1
  247. package/src/components/mcp/mcp-status-indicator.tsx +1 -1
  248. package/src/components/pages/__tests__/home-page.test.tsx +116 -0
  249. package/src/components/pages/home-page.tsx +164 -91
  250. package/src/components/scratchpad/scratchpad.test.tsx +95 -0
  251. package/src/components/scratchpad/scratchpad.tsx +16 -3
  252. package/src/components/slides/reveal-component.tsx +4 -2
  253. package/src/components/slides/slide-cell-view.tsx +1 -1
  254. package/src/components/slides/slide-form.tsx +1 -0
  255. package/src/components/tracing/tracing-keyboard.test.tsx +85 -0
  256. package/src/components/tracing/tracing.tsx +45 -41
  257. package/src/components/ui/__tests__/draggable-popover.test.tsx +24 -0
  258. package/src/components/ui/__tests__/range-slider.test.tsx +165 -0
  259. package/src/components/ui/alert-dialog.tsx +1 -1
  260. package/src/components/ui/draggable-popover.tsx +24 -2
  261. package/src/components/ui/range-slider.tsx +22 -9
  262. package/src/core/ai/context/providers/datasource.ts +6 -2
  263. package/src/core/ai/tools/base.ts +16 -7
  264. package/src/core/ai/tools/edit-notebook-tool.ts +47 -45
  265. package/src/core/ai/tools/registry.ts +13 -8
  266. package/src/core/ai/tools/sample-tool.ts +6 -7
  267. package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +4 -0
  268. package/src/core/cells/__tests__/cell.test.ts +39 -0
  269. package/src/core/cells/__tests__/cells.test.ts +3 -1
  270. package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
  271. package/src/core/cells/__tests__/notebook-outline.test.ts +113 -0
  272. package/src/core/cells/__tests__/session.test.ts +117 -36
  273. package/src/core/cells/cell.ts +14 -3
  274. package/src/core/cells/cells.ts +3 -1
  275. package/src/core/cells/pending-delete-service.ts +2 -6
  276. package/src/core/cells/session.ts +1 -1
  277. package/src/core/cells/types.ts +10 -1
  278. package/src/core/codemirror/__tests__/setup.test.ts +29 -29
  279. package/src/core/codemirror/ai/__tests__/resources.test.ts +117 -0
  280. package/src/core/codemirror/ai/resources.ts +1 -1
  281. package/src/core/codemirror/cells/__tests__/extensions.test.ts +15 -0
  282. package/src/core/codemirror/cells/extensions.ts +7 -3
  283. package/src/core/codemirror/keymaps/vim.ts +2 -6
  284. package/src/core/codemirror/language/__tests__/sql.test.ts +22 -20
  285. package/src/core/codemirror/language/extension.ts +8 -8
  286. package/src/core/codemirror/language/languages/markdown.ts +8 -6
  287. package/src/core/codemirror/language/languages/python.ts +16 -10
  288. package/src/core/codemirror/language/languages/sql/sql.ts +9 -7
  289. package/src/core/codemirror/language/panel/panel.tsx +1 -0
  290. package/src/core/codemirror/language/types.ts +7 -7
  291. package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
  292. package/src/core/codemirror/readonly/extension.ts +2 -2
  293. package/src/core/codemirror/rtc/extension.ts +24 -12
  294. package/src/core/codemirror/rtc/loro/awareness.ts +34 -19
  295. package/src/core/codemirror/rtc/loro/sync.ts +1 -0
  296. package/src/core/codemirror/utils.ts +1 -0
  297. package/src/core/config/__tests__/config-schema.test.ts +5 -3
  298. package/src/core/config/config-schema.ts +3 -0
  299. package/src/core/datasets/__tests__/data-source-discovery.test.ts +5 -5
  300. package/src/core/datasets/data-source-discovery.ts +4 -6
  301. package/src/core/edit-app.tsx +2 -2
  302. package/src/core/errors/error-entries.ts +3 -0
  303. package/src/core/export/hooks.ts +1 -1
  304. package/src/core/hotkeys/actions.ts +2 -4
  305. package/src/core/islands/__tests__/bootstrap.test.ts +16 -42
  306. package/src/core/islands/__tests__/bridge.test.ts +31 -26
  307. package/src/core/islands/bootstrap.ts +22 -52
  308. package/src/core/islands/bridge.ts +31 -20
  309. package/src/core/islands/components/__tests__/IslandControls.test.tsx +7 -5
  310. package/src/core/islands/worker/__tests__/controller.test.ts +62 -4
  311. package/src/core/islands/worker/controller.ts +4 -10
  312. package/src/core/islands/worker/worker.tsx +33 -33
  313. package/src/core/kernel/__tests__/RuntimeState.test.ts +1 -1
  314. package/src/core/network/__tests__/connection.test.ts +1 -1
  315. package/src/core/network/connection-notice.ts +1 -1
  316. package/src/core/network/connection.ts +5 -3
  317. package/src/core/network/requests-lazy.ts +1 -1
  318. package/src/core/network/useConnectionNotice.ts +8 -2
  319. package/src/core/notebook/attachments.ts +38 -0
  320. package/src/core/notebook/document/__tests__/codemirror.test.ts +485 -0
  321. package/src/core/notebook/document/__tests__/draft.test.ts +322 -0
  322. package/src/core/notebook/document/__tests__/fixtures.ts +92 -0
  323. package/src/core/notebook/document/__tests__/hooks.test.tsx +391 -0
  324. package/src/core/notebook/document/__tests__/lifecycle-scenarios.test.ts +61 -0
  325. package/src/core/notebook/document/__tests__/model.test.ts +191 -0
  326. package/src/core/notebook/document/__tests__/protocol-fixtures.ts +38 -0
  327. package/src/core/notebook/document/__tests__/recovery-scenarios.test.ts +230 -0
  328. package/src/core/notebook/document/__tests__/scenario-fixture.ts +43 -0
  329. package/src/core/notebook/document/__tests__/scenarios.test.ts +205 -0
  330. package/src/core/notebook/document/__tests__/state.test.ts +438 -0
  331. package/src/core/notebook/document/__tests__/submission.test.ts +203 -0
  332. package/src/core/notebook/document/__tests__/test-host.test.ts +92 -0
  333. package/src/core/notebook/document/__tests__/test-host.ts +247 -0
  334. package/src/core/notebook/document/__tests__/test-notebook.ts +149 -0
  335. package/src/core/notebook/document/__tests__/user.ts +61 -0
  336. package/src/core/notebook/document/codemirror.ts +311 -0
  337. package/src/core/notebook/document/draft.ts +472 -0
  338. package/src/core/notebook/document/hooks.tsx +118 -0
  339. package/src/core/notebook/document/index.ts +15 -0
  340. package/src/core/notebook/document/model.ts +55 -0
  341. package/src/core/notebook/document/select.ts +41 -0
  342. package/src/core/notebook/document/state.ts +374 -0
  343. package/src/core/notebook/document/sync.ts +369 -0
  344. package/src/core/notebook/index.ts +18 -0
  345. package/src/core/notebook/replica/AGENTS.md +11 -0
  346. package/src/core/notebook/replica/__tests__/attachments.test.ts +56 -0
  347. package/src/core/notebook/replica/__tests__/document.test.ts +126 -0
  348. package/src/core/notebook/replica/__tests__/fixtures.ts +79 -0
  349. package/src/core/notebook/replica/__tests__/replica.test.ts +550 -0
  350. package/src/core/notebook/replica/backend.ts +19 -0
  351. package/src/core/notebook/replica/connection.ts +42 -0
  352. package/src/core/notebook/replica/index.ts +13 -0
  353. package/src/core/notebook/replica/replica.ts +286 -0
  354. package/src/core/notebook/replica/resources/attachments.ts +22 -0
  355. package/src/core/notebook/replica/resources/document.ts +101 -0
  356. package/src/core/packages/__tests__/useSandboxController.test.tsx +1 -1
  357. package/src/core/packages/useSandboxController.ts +1 -1
  358. package/src/core/run-app.tsx +3 -3
  359. package/src/core/runtime/__tests__/adapter.test.ts +1 -1
  360. package/src/core/runtime/__tests__/createWsUrl.test.ts +77 -7
  361. package/src/core/runtime/__tests__/runtime.test.ts +32 -58
  362. package/src/core/runtime/adapter.ts +1 -1
  363. package/src/core/runtime/config.ts +2 -2
  364. package/src/core/runtime/runtime.ts +38 -42
  365. package/src/core/runtime/types.ts +0 -2
  366. package/src/core/saving/filename.ts +1 -1
  367. package/src/core/saving/save-component.tsx +13 -4
  368. package/src/core/saving/useAutoSave.ts +1 -1
  369. package/src/core/session/__tests__/backend.test.ts +235 -0
  370. package/src/core/session/__tests__/useNotebookReplica.hook.test.tsx +183 -0
  371. package/src/core/session/__tests__/useNotebookSession.hook.test.tsx +609 -0
  372. package/src/core/session/active-notebook.ts +7 -0
  373. package/src/core/session/backend.ts +125 -0
  374. package/src/core/{websocket → session}/types.ts +2 -2
  375. package/src/core/session/useNotebookReplica.ts +72 -0
  376. package/src/core/{websocket → session}/useNotebookSession.tsx +18 -25
  377. package/src/core/state/__tests__/jotai.test.tsx +108 -0
  378. package/src/core/state/jotai.ts +1 -1
  379. package/src/core/static/__tests__/files.test.ts +38 -10
  380. package/src/core/static/files.ts +2 -0
  381. package/src/core/{websocket → transports}/__tests__/connection-state.test.ts +1 -13
  382. package/src/core/transports/__tests__/server.test.ts +408 -0
  383. package/src/core/transports/__tests__/static.test.ts +175 -0
  384. package/src/core/transports/__tests__/wasm.test.ts +166 -0
  385. package/src/core/{websocket → transports}/connection-state.ts +9 -16
  386. package/src/core/transports/server.ts +152 -0
  387. package/src/core/transports/static.ts +84 -0
  388. package/src/core/transports/wasm.ts +97 -0
  389. package/src/core/wasm/__tests__/bridge.test.ts +213 -50
  390. package/src/core/wasm/__tests__/worker.test.ts +187 -0
  391. package/src/core/wasm/bridge.ts +81 -52
  392. package/src/core/wasm/rpc.ts +15 -3
  393. package/src/core/wasm/store.ts +3 -3
  394. package/src/core/wasm/worker/bootstrap.ts +55 -51
  395. package/src/core/wasm/worker/getMarimoWheel.ts +1 -1
  396. package/src/core/wasm/worker/save-worker.ts +9 -10
  397. package/src/core/wasm/worker/types.ts +29 -18
  398. package/src/core/wasm/worker/worker.ts +97 -44
  399. package/src/css/globals.css +10 -0
  400. package/src/hooks/__tests__/useAsyncData.test.tsx +148 -0
  401. package/src/hooks/__tests__/useDebounce.test.tsx +51 -0
  402. package/src/hooks/__tests__/useDeepCompareMemoize.test.tsx +39 -0
  403. package/src/hooks/__tests__/useDelayElapsed.test.tsx +28 -0
  404. package/src/hooks/__tests__/useInternalStateWithSync.test.tsx +20 -0
  405. package/src/hooks/__tests__/useScript.test.tsx +77 -0
  406. package/src/hooks/__tests__/useStateForKey.test.tsx +257 -0
  407. package/src/hooks/useAsyncData.ts +3 -3
  408. package/src/hooks/useDataSourceDiscovery.ts +6 -4
  409. package/src/hooks/useDebounce.ts +6 -10
  410. package/src/hooks/useDeepCompareMemoize.ts +1 -1
  411. package/src/hooks/useDelayElapsed.ts +14 -10
  412. package/src/hooks/useElapsedTime.ts +3 -3
  413. package/src/hooks/useEventListener.ts +1 -2
  414. package/src/hooks/useInputHistory.ts +4 -7
  415. package/src/hooks/useInternalStateWithSync.ts +6 -6
  416. package/src/hooks/useResizeObserver.ts +4 -7
  417. package/src/hooks/useScript.ts +67 -70
  418. package/src/hooks/useStateForKey.ts +93 -0
  419. package/src/mount.tsx +1 -5
  420. package/src/plugins/__tests__/plugin-object-schemas.test.ts +104 -0
  421. package/src/plugins/core/registerReactComponent.tsx +1 -1
  422. package/src/plugins/impl/CodeEditorPlugin.tsx +1 -1
  423. package/src/plugins/impl/DataEditorPlugin.tsx +1 -1
  424. package/src/plugins/impl/DataTablePlugin.tsx +29 -33
  425. package/src/plugins/impl/DropdownPlugin.tsx +2 -6
  426. package/src/plugins/impl/FileBrowserPlugin.tsx +4 -16
  427. package/src/plugins/impl/FormPlugin.tsx +1 -1
  428. package/src/plugins/impl/RangeSliderPlugin.tsx +16 -2
  429. package/src/plugins/impl/RefreshPlugin.tsx +1 -0
  430. package/src/plugins/impl/SliderPlugin.tsx +6 -8
  431. package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +117 -1
  432. package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +45 -0
  433. package/src/plugins/impl/__tests__/RangeSliderPlugin.test.tsx +109 -0
  434. package/src/plugins/impl/__tests__/SliderPlugin.test.tsx +24 -3
  435. package/src/plugins/impl/anywidget/__tests__/registry.test.ts +153 -0
  436. package/src/plugins/impl/anywidget/__tests__/widget-binding.test.ts +241 -2
  437. package/src/plugins/impl/anywidget/model.ts +3 -1
  438. package/src/plugins/impl/anywidget/registry.ts +18 -14
  439. package/src/plugins/impl/anywidget/runtime.ts +21 -9
  440. package/src/plugins/impl/anywidget/widget-binding.ts +160 -82
  441. package/src/plugins/impl/chat/__tests__/chat-prompts.test.tsx +93 -0
  442. package/src/plugins/impl/chat/chat-ui.tsx +14 -11
  443. package/src/plugins/impl/code/any-language-editor.tsx +2 -2
  444. package/src/plugins/impl/data-editor/glide-data-editor.tsx +8 -5
  445. package/src/plugins/impl/data-editor/glide-utils.ts +3 -1
  446. package/src/plugins/impl/data-explorer/ConnectedDataExplorerComponent.tsx +1 -1
  447. package/src/plugins/impl/data-explorer/components/column-summary.tsx +4 -2
  448. package/src/plugins/impl/data-explorer/state/reducer.ts +1 -1
  449. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +1 -2
  450. package/src/plugins/impl/data-frames/__tests__/sidebar.test.tsx +160 -0
  451. package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +66 -66
  452. package/src/plugins/impl/data-frames/panel.tsx +43 -16
  453. package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +5 -3
  454. package/src/plugins/impl/panel/PanelPlugin.tsx +16 -17
  455. package/src/plugins/impl/panel/__tests__/utils.test.ts +39 -1
  456. package/src/plugins/impl/panel/utils.ts +17 -0
  457. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +2 -5
  458. package/src/plugins/impl/plotly/selection.ts +25 -19
  459. package/src/plugins/impl/vega/VegaPlugin.tsx +2 -3
  460. package/src/plugins/impl/vega/make-selectable.ts +4 -7
  461. package/src/plugins/layout/RoutesPlugin.tsx +1 -1
  462. package/src/stories/__tests__/editor-story.test.tsx +33 -0
  463. package/src/stories/button.stories.tsx +1 -0
  464. package/src/stories/cell.stories.tsx +1 -1
  465. package/src/stories/editor.stories.tsx +24 -17
  466. package/src/stories/form-wrapper.stories.tsx +2 -2
  467. package/src/stories/layout/vertical/one-column.stories.tsx +1 -1
  468. package/src/stories/runtime-story.tsx +1 -1
  469. package/src/stories/select.stories.tsx +2 -2
  470. package/src/stories/switchable-multi-select.stories.tsx +1 -1
  471. package/src/utils/__tests__/arrays.test.ts +35 -0
  472. package/src/utils/__tests__/batch-requests.test.ts +3 -3
  473. package/src/utils/__tests__/createReducer.test.ts +1 -0
  474. package/src/utils/__tests__/numbers.test.ts +105 -1
  475. package/src/utils/__tests__/objects.test.ts +21 -0
  476. package/src/utils/arrays.ts +11 -2
  477. package/src/utils/blob.ts +1 -1
  478. package/src/utils/createReducer.ts +11 -5
  479. package/src/utils/maps.ts +0 -3
  480. package/src/utils/numbers.ts +79 -18
  481. package/src/utils/objects.ts +4 -9
  482. package/src/utils/once.ts +19 -19
  483. package/src/utils/tracer.ts +9 -5
  484. package/src/utils/zod-utils.ts +1 -3
  485. package/dist/any-language-editor-DZ_YTVus.js +0 -76
  486. package/dist/assets/__vite-browser-external-BXYkiFsk.js +0 -1
  487. package/dist/assets/worker-HPY9fbhz.js +0 -114
  488. package/dist/mermaid-HWGCJPDP-ByCsZnYF.js +0 -2
  489. package/dist/precisionRound-DMIVQrt2.js +0 -97
  490. package/src/core/attachments/state.ts +0 -21
  491. package/src/core/host/AGENTS.md +0 -6
  492. package/src/core/host/__tests__/events.test.ts +0 -46
  493. package/src/core/host/__tests__/notebook-client.test.ts +0 -191
  494. package/src/core/host/__tests__/protocol.test.ts +0 -214
  495. package/src/core/host/connection.ts +0 -81
  496. package/src/core/host/events.ts +0 -60
  497. package/src/core/host/notebook-client.ts +0 -226
  498. package/src/core/host/protocol.ts +0 -1943
  499. package/src/core/state/__tests__/jotai.test.ts +0 -25
  500. package/src/core/wasm/worker/message-buffer.ts +0 -33
  501. package/src/core/websocket/__tests__/createConnectionTransport.test.ts +0 -49
  502. package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +0 -140
  503. package/src/core/websocket/__tests__/useNotebookSession.hook.test.tsx +0 -883
  504. package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
  505. package/src/core/websocket/transports/__tests__/sse.test.ts +0 -335
  506. package/src/core/websocket/transports/__tests__/transport.test.ts +0 -308
  507. package/src/core/websocket/transports/__tests__/ws.test.ts +0 -125
  508. package/src/core/websocket/transports/basic.ts +0 -102
  509. package/src/core/websocket/transports/create.ts +0 -31
  510. package/src/core/websocket/transports/sse.ts +0 -308
  511. package/src/core/websocket/transports/transport.ts +0 -50
  512. package/src/core/websocket/transports/ws.ts +0 -98
  513. package/src/core/websocket/useNotebookClient.ts +0 -80
  514. /package/src/{core/attachments/toast.ts → components/editor/agent-toast.ts} +0 -0
  515. /package/src/core/{websocket → session}/connection-utils.ts +0 -0
@@ -5,7 +5,10 @@ import { type JSX, useEffect, useId, useState } from "react";
5
5
  import { useLocale } from "react-aria";
6
6
  import { z } from "zod";
7
7
  import { cn } from "@/utils/cn";
8
- import { prettyScientificNumber } from "@/utils/numbers";
8
+ import {
9
+ fractionDigitsForSlider,
10
+ prettyScientificNumber,
11
+ } from "@/utils/numbers";
9
12
  import { RangeSlider } from "../../components/ui/range-slider";
10
13
  import type { IPlugin, IPluginProps, Setter } from "../types";
11
14
  import { Labeled } from "./common/labeled";
@@ -87,6 +90,12 @@ const RangeSliderComponent = ({
87
90
 
88
91
  // Hold internal value
89
92
  const [internalValue, setInternalValue] = useState(value);
93
+ const fractionDigits = fractionDigitsForSlider(
94
+ step,
95
+ steps,
96
+ start,
97
+ internalValue.map(valueMap),
98
+ );
90
99
 
91
100
  // Update internal value on prop change
92
101
  useEffect(() => {
@@ -122,6 +131,7 @@ const RangeSliderComponent = ({
122
131
  min={start}
123
132
  max={stop}
124
133
  step={step}
134
+ steps={steps ?? undefined}
125
135
  orientation={orientation}
126
136
  disabled={disabled}
127
137
  // Triggered on all value changes
@@ -155,8 +165,12 @@ const RangeSliderComponent = ({
155
165
  {showValue && (
156
166
  <div className="text-xs text-muted-foreground min-w-[16px]">
157
167
  {`${prettyScientificNumber(valueMap(internalValue[0]), {
168
+ maximumFractionDigits: fractionDigits,
169
+ locale,
170
+ })}, ${prettyScientificNumber(valueMap(internalValue[1]), {
171
+ maximumFractionDigits: fractionDigits,
158
172
  locale,
159
- })}, ${prettyScientificNumber(valueMap(internalValue[1]), { locale })}`}
173
+ })}`}
160
174
  </div>
161
175
  )}
162
176
  </div>
@@ -119,6 +119,7 @@ const RefreshComponent = ({ setValue, data }: IPluginProps<Value, Data>) => {
119
119
  <Labeled label={data.label}>
120
120
  <span className="inline-flex items-center text-secondary-foreground rounded shadow-sm-solid">
121
121
  <Button
122
+ aria-label="Refresh"
122
123
  data-testid="marimo-plugin-refresh-button"
123
124
  variant="secondary"
124
125
  size="icon"
@@ -1,8 +1,9 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- import { type JSX, useEffect, useId, useMemo, useState } from "react";
2
+ import { type JSX, useId, useMemo } from "react";
3
3
  import { useLocale } from "react-aria";
4
4
  import { z } from "zod";
5
5
  import { NumberField } from "@/components/ui/number-field";
6
+ import { useInternalStateWithSync } from "@/hooks/useInternalStateWithSync";
6
7
  import { cn } from "@/utils/cn";
7
8
  import { clamp } from "@/utils/math";
8
9
  import {
@@ -156,13 +157,10 @@ const SliderComponent = ({
156
157
  const { locale } = useLocale();
157
158
 
158
159
  // Hold internal value
159
- const [internalValue, setInternalValue] = useState(value);
160
- // Update internal value on prop change
161
- useEffect(() => {
162
- // TODO: Replace this synchronization with a controlled-state primitive.
163
- // oxlint-disable-next-line react/no-deriving-state-in-effects -- Synchronize the editable buffer when the controlled value changes.
164
- setInternalValue(value);
165
- }, [value]);
160
+ const [internalValue, setInternalValue] = useInternalStateWithSync(
161
+ value,
162
+ Object.is,
163
+ );
166
164
 
167
165
  const stepsConfig = useMemo(() => computeStepsConfig(steps), [steps]);
168
166
 
@@ -12,11 +12,13 @@ import {
12
12
  waitFor,
13
13
  } from "@testing-library/react";
14
14
  import { Provider } from "jotai";
15
+ import { useState } from "react";
15
16
  import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
16
17
  import { SetupMocks } from "@/__mocks__/common";
17
18
  import type { DownloadAsFunction } from "@/components/data-table/schemas";
18
19
  import type { FieldTypesWithExternalType } from "@/components/data-table/types";
19
20
  import { store } from "@/core/state/jotai";
21
+ import { Deferred } from "@/utils/Deferred";
20
22
  import {
21
23
  type GetDataUrl,
22
24
  type GetRowIds,
@@ -463,7 +465,7 @@ describe("LoadingDataTableComponent", () => {
463
465
  });
464
466
  });
465
467
 
466
- describe("static notebook control suppression", () => {
468
+ describe("table pagination and static notebook control suppression", () => {
467
469
  const fieldTypes: FieldTypesWithExternalType = [
468
470
  ["id", ["integer", "integer"]],
469
471
  ["name", ["string", "string"]],
@@ -538,6 +540,120 @@ describe("static notebook control suppression", () => {
538
540
  mockIsStatic.mockReturnValue(false);
539
541
  });
540
542
 
543
+ it("requests only the first page with the new configured page size", async () => {
544
+ const props = makeProps();
545
+ const view = (pageSize: number) => (
546
+ <Wrapper>
547
+ <LoadingDataTableComponent {...props} pageSize={pageSize} />
548
+ </Wrapper>
549
+ );
550
+ const { rerender } = render(view(PAGE_SIZE));
551
+ await waitFor(() =>
552
+ expect(screen.getByTestId("next-page-button")).toBeEnabled(),
553
+ );
554
+ fireEvent.click(screen.getByTestId("next-page-button"));
555
+ await waitFor(() =>
556
+ expect(props.search).toHaveBeenLastCalledWith(
557
+ expect.objectContaining({ page_number: 1, page_size: PAGE_SIZE }),
558
+ ),
559
+ );
560
+ await waitFor(() =>
561
+ expect(screen.getByTestId("next-page-button")).toBeEnabled(),
562
+ );
563
+ props.search.mockClear();
564
+
565
+ rerender(view(5));
566
+ await waitFor(() => expect(props.search).toHaveBeenCalled());
567
+ expect(
568
+ props.search.mock.calls.every(
569
+ ([request]) => request.page_number === 0 && request.page_size === 5,
570
+ ),
571
+ ).toBe(true);
572
+ });
573
+
574
+ it("preserves a new page size when a pending response changes the row count in the same batch", async () => {
575
+ const props = makeProps();
576
+ const Harness = () => {
577
+ const [pageSize, setPageSize] = useState(PAGE_SIZE);
578
+ return (
579
+ <Wrapper>
580
+ <button type="button" onClick={() => setPageSize(5)}>
581
+ Change configured page size
582
+ </button>
583
+ <LoadingDataTableComponent {...props} pageSize={pageSize} />
584
+ </Wrapper>
585
+ );
586
+ };
587
+ render(<Harness />);
588
+ await waitFor(() =>
589
+ expect(screen.getByTestId("next-page-button")).toBeEnabled(),
590
+ );
591
+ const response = {
592
+ data: firstPage,
593
+ total_rows: 25,
594
+ cell_styles: null,
595
+ cell_hover_texts: null,
596
+ };
597
+ const pendingPage = new Deferred<typeof response>();
598
+ props.search.mockReturnValueOnce(pendingPage.promise);
599
+ fireEvent.click(screen.getByTestId("next-page-button"));
600
+ await waitFor(() =>
601
+ expect(props.search).toHaveBeenLastCalledWith(
602
+ expect.objectContaining({ page_number: 1, page_size: PAGE_SIZE }),
603
+ ),
604
+ );
605
+ props.search.mockClear();
606
+
607
+ await act(async () => {
608
+ pendingPage.resolve(response);
609
+ // Settle the table-loading promises without committing the queued render.
610
+ await new Promise((resolve) => setTimeout(resolve, 0));
611
+ fireEvent.click(
612
+ screen.getByRole("button", { name: "Change configured page size" }),
613
+ );
614
+ });
615
+
616
+ await waitFor(() => expect(props.search).toHaveBeenCalled());
617
+ expect(props.search).toHaveBeenLastCalledWith(
618
+ expect.objectContaining({ page_number: 0, page_size: 5 }),
619
+ );
620
+ });
621
+
622
+ it("returns to the first page when a refreshed result changes the row count", async () => {
623
+ const props = makeProps();
624
+ const view = () => (
625
+ <Wrapper>
626
+ <LoadingDataTableComponent {...props} />
627
+ </Wrapper>
628
+ );
629
+ const { rerender } = render(view());
630
+ await waitFor(() =>
631
+ expect(screen.getByTestId("next-page-button")).toBeEnabled(),
632
+ );
633
+ fireEvent.click(screen.getByTestId("next-page-button"));
634
+ await waitFor(() =>
635
+ expect(props.search).toHaveBeenLastCalledWith(
636
+ expect.objectContaining({ page_number: 1 }),
637
+ ),
638
+ );
639
+ await waitFor(() =>
640
+ expect(screen.getByTestId("next-page-button")).toBeEnabled(),
641
+ );
642
+ props.search = vi.fn().mockResolvedValue({
643
+ data: firstPage,
644
+ total_rows: 25,
645
+ cell_styles: null,
646
+ cell_hover_texts: null,
647
+ });
648
+
649
+ rerender(view());
650
+ await waitFor(() =>
651
+ expect(props.search).toHaveBeenLastCalledWith(
652
+ expect.objectContaining({ page_number: 0, page_size: PAGE_SIZE }),
653
+ ),
654
+ );
655
+ });
656
+
541
657
  it("renders kernel-dependent controls in normal mode", async () => {
542
658
  const props = makeProps();
543
659
  render(
@@ -1,6 +1,7 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
3
  import {
4
+ act,
4
5
  fireEvent,
5
6
  render,
6
7
  screen,
@@ -88,6 +89,50 @@ beforeAll(() => {
88
89
  });
89
90
 
90
91
  describe("FileBrowserPlugin session cache recovery", () => {
92
+ it("delays the initial loading overlay and hides it when listing completes", async () => {
93
+ vi.useFakeTimers();
94
+ try {
95
+ let resolveListing: (value: {
96
+ files: MockFile[];
97
+ total_count: number;
98
+ is_truncated: boolean;
99
+ }) => void = () => undefined;
100
+ const listDirectory = vi.fn(
101
+ () =>
102
+ new Promise((resolve) => {
103
+ resolveListing = resolve;
104
+ }),
105
+ );
106
+ const { unmount } = renderBrowser({ list_directory: listDirectory });
107
+
108
+ await act(async () => {
109
+ vi.advanceTimersByTime(199);
110
+ });
111
+ expect(screen.queryByText("Listing files...")).not.toBeInTheDocument();
112
+ await act(async () => {
113
+ vi.advanceTimersByTime(1);
114
+ });
115
+ expect(screen.getByText("Listing files...")).toBeInTheDocument();
116
+
117
+ await act(async () => {
118
+ resolveListing({
119
+ files: FILES,
120
+ total_count: FILES.length,
121
+ is_truncated: false,
122
+ });
123
+ });
124
+ expect(screen.queryByText("Listing files...")).not.toBeInTheDocument();
125
+ expect(screen.getByText("docs")).toBeInTheDocument();
126
+ await act(async () => {
127
+ vi.advanceTimersByTime(200);
128
+ });
129
+ expect(screen.queryByText("Listing files...")).not.toBeInTheDocument();
130
+ unmount();
131
+ } finally {
132
+ vi.useRealTimers();
133
+ }
134
+ });
135
+
91
136
  it("retries a failed cached listing when the plugin resets", async () => {
92
137
  const host = document.createElement("marimo-file-browser");
93
138
  const wrapper = document.createElement("marimo-ui-element");
@@ -0,0 +1,109 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { render } from "@testing-library/react";
4
+ import { describe, expect, it, vi } from "vitest";
5
+ import type { z } from "zod";
6
+ import type { IPluginProps } from "../../types";
7
+ import { RangeSliderPlugin } from "../RangeSliderPlugin";
8
+
9
+ vi.mock("@/components/ui/range-slider", () => ({
10
+ RangeSlider: () => <div data-testid="range-slider" />,
11
+ }));
12
+
13
+ vi.mock("react-aria", () => ({
14
+ useLocale: () => ({ locale: "en-US" }),
15
+ }));
16
+
17
+ describe("RangeSliderPlugin", () => {
18
+ type PluginProps = IPluginProps<
19
+ number[],
20
+ z.infer<typeof RangeSliderPlugin.prototype.validator>
21
+ >;
22
+
23
+ const createProps = (
24
+ value: number[],
25
+ data: Partial<PluginProps["data"]> = {},
26
+ ): PluginProps => ({
27
+ host: document.createElement("div"),
28
+ value,
29
+ setValue: vi.fn(),
30
+ data: {
31
+ initialValue: value,
32
+ label: null,
33
+ start: 0,
34
+ stop: 10,
35
+ step: 0.01,
36
+ steps: null,
37
+ debounce: false,
38
+ orientation: "horizontal",
39
+ showValue: true,
40
+ fullWidth: true,
41
+ disabled: false,
42
+ ...data,
43
+ },
44
+ functions: {},
45
+ });
46
+
47
+ it("rounds floating-point artifacts in the displayed range", () => {
48
+ const plugin = new RangeSliderPlugin();
49
+ const props = createProps([1.2, 1.500000000000001]);
50
+
51
+ const { getByText } = render(plugin.render(props));
52
+
53
+ expect(getByText("1.2, 1.5")).toBeDefined();
54
+ });
55
+
56
+ it("preserves precision from finer-grained steps", () => {
57
+ const plugin = new RangeSliderPlugin();
58
+ const props = createProps([1.234, 1.235000000000001], { step: 0.001 });
59
+
60
+ const { getByText } = render(plugin.render(props));
61
+
62
+ expect(getByText("1.234, 1.235")).toBeDefined();
63
+ });
64
+
65
+ it("retains value precision when no step is supplied", () => {
66
+ const plugin = new RangeSliderPlugin();
67
+ const props = createProps([1.2345, 1.500000000000001], {
68
+ step: undefined,
69
+ });
70
+
71
+ const { getByText } = render(plugin.render(props));
72
+
73
+ expect(getByText("1.2345, 1.5")).toBeDefined();
74
+ });
75
+
76
+ it("preserves precision for small displayed values", () => {
77
+ const plugin = new RangeSliderPlugin();
78
+ const props = createProps([0.00123, 0.0012400000000000002], {
79
+ stop: 0.01,
80
+ step: 0.00001,
81
+ });
82
+
83
+ const { getByText } = render(plugin.render(props));
84
+
85
+ expect(getByText("1.23e-3, 1.24e-3")).toBeDefined();
86
+ });
87
+
88
+ it("infers precision from custom steps", () => {
89
+ const plugin = new RangeSliderPlugin();
90
+ const props = createProps([0, 1], {
91
+ stop: 2,
92
+ step: undefined,
93
+ steps: [1, 1.234, 2],
94
+ });
95
+
96
+ const { getByText } = render(plugin.render(props));
97
+
98
+ expect(getByText("1, 1.234")).toBeDefined();
99
+ });
100
+
101
+ it("preserves decimals from the slider origin", () => {
102
+ const plugin = new RangeSliderPlugin();
103
+ const props = createProps([0.5, 1.5], { start: 0.5, stop: 10, step: 1 });
104
+
105
+ const { getByText } = render(plugin.render(props));
106
+
107
+ expect(getByText("0.5, 1.5")).toBeDefined();
108
+ });
109
+ });
@@ -212,6 +212,28 @@ describe("SliderPlugin", () => {
212
212
  expect(setValue).toHaveBeenCalledWith(9);
213
213
  });
214
214
 
215
+ it("preserves an uncommitted drag until the controlled value changes", () => {
216
+ const plugin = new SliderPlugin();
217
+ const setValue = vi.fn();
218
+ const props = createProps({
219
+ debounce: true,
220
+ includeInput: false,
221
+ setValue,
222
+ });
223
+ const { getByRole, rerender } = render(plugin.render(props));
224
+
225
+ fireEvent.click(getByRole("button", { name: "Slider change" }));
226
+ rerender(
227
+ plugin.render({ ...props, data: { ...props.data, label: "Updated" } }),
228
+ );
229
+ fireEvent.click(getByRole("button", { name: "Slider commit" }));
230
+ expect(setValue).toHaveBeenLastCalledWith(6);
231
+
232
+ rerender(plugin.render({ ...props, value: 2 }));
233
+ fireEvent.click(getByRole("button", { name: "Slider commit" }));
234
+ expect(setValue).toHaveBeenLastCalledWith(2);
235
+ });
236
+
215
237
  describe("editable input with steps (regression for #9850)", () => {
216
238
  it("displays the actual step value, not the index", () => {
217
239
  const plugin = new SliderPlugin();
@@ -381,9 +403,8 @@ describe("SliderPlugin", () => {
381
403
  vi.advanceTimersByTime(0);
382
404
  });
383
405
 
384
- // Shrink `steps` so the held index (4) is now out of range. The index
385
- // syncs in an effect after this render, so the render must not throw on
386
- // the stale, out-of-range index.
406
+ // Shrink `steps` so the held index (4) is now out of range. Updating
407
+ // the controlled index must render the new valid step without throwing.
387
408
  const shrunkProps = createStepsProps({
388
409
  steps: [10, 20],
389
410
  valueIndex: 1,
@@ -8,6 +8,8 @@ import {
8
8
  type MockInstance,
9
9
  vi,
10
10
  } from "vitest";
11
+ import { Deferred } from "@/utils/Deferred";
12
+ import { Logger } from "@/utils/Logger";
11
13
  import { getMarimoInternal, Model } from "../model";
12
14
  import { handleWidgetMessage, WidgetRegistry } from "../registry";
13
15
  import type { EsmSpec, ModelState, WidgetModelId } from "../types";
@@ -155,6 +157,155 @@ describe("WidgetRegistry models", () => {
155
157
  );
156
158
  });
157
159
 
160
+ describe("outgoing messages", () => {
161
+ async function openModel(id = testId) {
162
+ await handleWidgetMessage(registry, {
163
+ model_id: id,
164
+ message: {
165
+ method: "open",
166
+ state: {},
167
+ buffer_paths: [],
168
+ buffers: [],
169
+ },
170
+ });
171
+ return registry.getModel(id);
172
+ }
173
+
174
+ afterEach(() => {
175
+ mockSendModelValue.mockReset().mockResolvedValue(null);
176
+ vi.restoreAllMocks();
177
+ });
178
+
179
+ it("waits for each acknowledgement before sending the next update", async () => {
180
+ const model = await openModel();
181
+ const responses = [new Deferred<null>(), new Deferred<null>()];
182
+ for (const response of responses) {
183
+ mockSendModelValue.mockReturnValueOnce(response.promise);
184
+ }
185
+ const states = [
186
+ { card: "A", seq: 5 },
187
+ { card: "", seq: 6 },
188
+ { card: "B", seq: 7 },
189
+ ];
190
+ for (const state of states) {
191
+ model.set("selection", state);
192
+ model.save_changes();
193
+ }
194
+
195
+ await vi.waitFor(() =>
196
+ expect(mockSendModelValue).toHaveBeenCalledTimes(1),
197
+ );
198
+ for (const [index, response] of responses.entries()) {
199
+ response.resolve(null);
200
+ await vi.waitFor(() =>
201
+ expect(mockSendModelValue).toHaveBeenCalledTimes(index + 2),
202
+ );
203
+ }
204
+ expect(mockSendModelValue.mock.calls).toEqual(
205
+ states.map((selection) => [
206
+ {
207
+ modelId: testId,
208
+ message: {
209
+ method: "update",
210
+ state: { selection },
211
+ bufferPaths: [],
212
+ },
213
+ buffers: [],
214
+ },
215
+ ]),
216
+ );
217
+ });
218
+
219
+ it("orders custom messages with updates and waits before calling callbacks", async () => {
220
+ const model = await openModel();
221
+ const response = new Deferred<null>();
222
+ mockSendModelValue.mockReturnValueOnce(response.promise);
223
+ const callback = vi.fn();
224
+ const sent = model.send({ action: "first" }, callback);
225
+ model.set("count", 1);
226
+ model.save_changes();
227
+ const last = model.send({ action: "last" });
228
+
229
+ await vi.waitFor(() =>
230
+ expect(mockSendModelValue).toHaveBeenCalledTimes(1),
231
+ );
232
+ expect(callback).not.toHaveBeenCalled();
233
+ response.resolve(null);
234
+ await Promise.all([sent, last]);
235
+ expect(callback).toHaveBeenCalledExactlyOnceWith();
236
+ expect(
237
+ mockSendModelValue.mock.calls.map(([request]) => request.message),
238
+ ).toEqual([
239
+ { method: "custom", content: { action: "first" } },
240
+ { method: "update", state: { count: 1 }, bufferPaths: [] },
241
+ { method: "custom", content: { action: "last" } },
242
+ ]);
243
+ });
244
+
245
+ it("continues sending after a failed update", async () => {
246
+ const model = await openModel();
247
+ const response = new Deferred<null>();
248
+ mockSendModelValue.mockReturnValueOnce(response.promise);
249
+ const logError = vi
250
+ .spyOn(Logger, "error")
251
+ .mockImplementation(() => undefined);
252
+ model.set("count", 1);
253
+ model.save_changes();
254
+ model.set("count", 2);
255
+ model.save_changes();
256
+ const last = model.send({ action: "done" });
257
+
258
+ await vi.waitFor(() =>
259
+ expect(mockSendModelValue).toHaveBeenCalledTimes(1),
260
+ );
261
+ const error = new Error("Network failure");
262
+ response.reject(error);
263
+ await last;
264
+ expect(mockSendModelValue).toHaveBeenCalledTimes(3);
265
+ expect(logError).toHaveBeenCalledWith(
266
+ "[anywidget] Failed to save model changes",
267
+ error,
268
+ );
269
+ });
270
+
271
+ it("allows different models to send independently", async () => {
272
+ const first = await openModel();
273
+ const secondId = asModelId("second-model");
274
+ const second = await openModel(secondId);
275
+ const response = new Deferred<null>();
276
+ mockSendModelValue.mockReturnValueOnce(response.promise);
277
+
278
+ const firstSend = first.send({ value: 1 });
279
+ await second.send({ value: 2 });
280
+ expect(
281
+ mockSendModelValue.mock.calls.map(([request]) => request.modelId),
282
+ ).toEqual([testId, secondId]);
283
+ response.resolve(null);
284
+ await firstSend;
285
+ });
286
+
287
+ it("drops queued messages when the model closes", async () => {
288
+ const model = await openModel();
289
+ const response = new Deferred<null>();
290
+ mockSendModelValue.mockReturnValueOnce(response.promise);
291
+ const first = model.send({ value: 1 });
292
+ model.set("count", 2);
293
+ model.save_changes();
294
+ const last = model.send({ value: 3 });
295
+
296
+ await vi.waitFor(() =>
297
+ expect(mockSendModelValue).toHaveBeenCalledTimes(1),
298
+ );
299
+ await handleWidgetMessage(registry, {
300
+ model_id: testId,
301
+ message: { method: "close" },
302
+ });
303
+ response.resolve(null);
304
+ await Promise.all([first, last]);
305
+ expect(mockSendModelValue).toHaveBeenCalledTimes(1);
306
+ });
307
+ });
308
+
158
309
  describe("static mode", () => {
159
310
  beforeEach(() => {
160
311
  mockIsStatic.mockReturnValue(true);
@@ -238,6 +389,7 @@ describe("WidgetRegistry.getWidget", () => {
238
389
  jsUrl: SPEC.url,
239
390
  jsHash: SPEC.hash,
240
391
  kernelAuthored: true,
392
+ lifetime: expect.any(AbortSignal),
241
393
  });
242
394
  expect(widgetDef.initialize).toHaveBeenCalledTimes(1);
243
395
  expect(widget.exports).toBe(exports);
@@ -263,6 +415,7 @@ describe("WidgetRegistry.getWidget", () => {
263
415
  jsUrl: SPEC.url,
264
416
  jsHash: SPEC.hash,
265
417
  kernelAuthored: true,
418
+ lifetime: expect.any(AbortSignal),
266
419
  });
267
420
  });
268
421