@marimo-team/frontend 0.16.1 → 0.16.3

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 (310) hide show
  1. package/dist/assets/{ConnectedDataExplorerComponent-2wVcyvDj.js → ConnectedDataExplorerComponent-Brtw1DxF.js} +1 -1
  2. package/dist/assets/{ImageComparisonComponent-D2j6i0hv.js → ImageComparisonComponent-Dxl-PbZX.js} +1 -1
  3. package/dist/assets/{VegaLite-BckFaf2D.js → VegaLite-BXQF0Cx_.js} +1 -1
  4. package/dist/assets/_baseEach-BjSm9ht3.js +1 -0
  5. package/dist/assets/_baseMap-CV4Ezmtf.js +1 -0
  6. package/dist/assets/_baseUniq-Ci9yZGxz.js +1 -0
  7. package/dist/assets/{_createAggregator-C5CVY-0t.js → _createAggregator-VFK9K2d9.js} +1 -1
  8. package/dist/assets/{agent-panel-RGLNjkYe.js → agent-panel-BoscVLCT.js} +7 -7
  9. package/dist/assets/{any-language-editor-DjuXwGCA.js → any-language-editor-ChaY_VUU.js} +1 -1
  10. package/dist/assets/{architectureDiagram-W76B3OCA-Dyj4ds_R.js → architectureDiagram-W76B3OCA-CueUUFYd.js} +1 -1
  11. package/dist/assets/{between-horizontal-start-Dt2aKpPf.js → between-horizontal-start-DAHqmLYT.js} +1 -1
  12. package/dist/assets/{blockDiagram-QIGZ2CNN-o-i7DDvN.js → blockDiagram-QIGZ2CNN-BYYygyWn.js} +1 -1
  13. package/dist/assets/{c4Diagram-FPNF74CW-DGHEwWrx.js → c4Diagram-FPNF74CW-DAz3xEh1.js} +1 -1
  14. package/dist/assets/channel-6SqQ2U_X.js +1 -0
  15. package/dist/assets/chat-panel-DJkOLrw9.js +3 -0
  16. package/dist/assets/{chunk-4BX2VUAB-BJecb-Ri.js → chunk-4BX2VUAB-8g-RyHdt.js} +1 -1
  17. package/dist/assets/{chunk-55IACEB6-CAATkc4w.js → chunk-55IACEB6-iWZZ8Mt6.js} +1 -1
  18. package/dist/assets/{chunk-FMBD7UC4-DPuNbQ-f.js → chunk-FMBD7UC4-knjss4wk.js} +1 -1
  19. package/dist/assets/{chunk-K7UQS3LO-C8TWVLiH.js → chunk-K7UQS3LO-DVIwPBgZ.js} +1 -1
  20. package/dist/assets/{chunk-QN33PNHL-DiZZ09q4.js → chunk-QN33PNHL-CBU8pN6I.js} +1 -1
  21. package/dist/assets/{chunk-QZHKN3VN-BIUM7usu.js → chunk-QZHKN3VN-5ljElUF4.js} +1 -1
  22. package/dist/assets/{chunk-TVAH2DTR-vGTArPBG.js → chunk-TVAH2DTR-DkIdGINc.js} +1 -1
  23. package/dist/assets/{chunk-TZMSLE5B-D2KRqp_x.js → chunk-TZMSLE5B-CIFOSTqh.js} +1 -1
  24. package/dist/assets/{circle-play-cjeNez0N.js → circle-play-BOdsbq5u.js} +1 -1
  25. package/dist/assets/classDiagram-KNZD7YFC-DVqXcTYf.js +1 -0
  26. package/dist/assets/classDiagram-v2-RKCZMP56-DVqXcTYf.js +1 -0
  27. package/dist/assets/{clear-button-C97JtAez.js → clear-button-GAjXl0CQ.js} +1 -1
  28. package/dist/assets/clone-DSDb0xen.js +1 -0
  29. package/dist/assets/command-palette-BUXkqoLh.js +1 -0
  30. package/dist/assets/{common-Du9rSOwD.js → common-DahoYqdi.js} +1 -1
  31. package/dist/assets/{compile-CZXqyOxa.js → compile-Bg8uJ7vm.js} +1 -1
  32. package/dist/assets/{cose-bilkent-S5V4N54A-CqUN5Y9b.js → cose-bilkent-S5V4N54A-z_0gqD9K.js} +1 -1
  33. package/dist/assets/{dagre-5GWH7T2D-RJqTI9DM.js → dagre-5GWH7T2D-BMt7CNXL.js} +1 -1
  34. package/dist/assets/{data-grid-overlay-editor-DZN0q1LV.js → data-grid-overlay-editor-Ctn4XtXx.js} +1 -1
  35. package/dist/assets/datasources-panel-C7sqRIHs.js +1 -0
  36. package/dist/assets/{dependency-graph-panel-CEog_O7V.js → dependency-graph-panel-DNajptzv.js} +4 -4
  37. package/dist/assets/{diagram-N5W7TBWH-D-l4zZ9d.js → diagram-N5W7TBWH-BzwvLvAy.js} +1 -1
  38. package/dist/assets/{diagram-QEK2KX5R-CCOmBUt-.js → diagram-QEK2KX5R-DRLJ56FS.js} +1 -1
  39. package/dist/assets/{diagram-S2PKOQOG-C_I_9jnZ.js → diagram-S2PKOQOG-Bf8x4KTU.js} +1 -1
  40. package/dist/assets/{documentation-panel-C1BtMZ3M.js → documentation-panel-Dm6Ozl67.js} +1 -1
  41. package/dist/assets/{edit-page-B-oevUZ9.js → edit-page-CGc9EjuG.js} +53 -42
  42. package/dist/assets/{ellipsis-vertical-BEb-J8z6.js → ellipsis-vertical-Bj1YXvZe.js} +1 -1
  43. package/dist/assets/{empty-state-C99UyDE3.js → empty-state-CYev-D31.js} +1 -1
  44. package/dist/assets/{erDiagram-AWTI2OKA-BePOLi5M.js → erDiagram-AWTI2OKA-DmgzgN_I.js} +1 -1
  45. package/dist/assets/{error-panel-Bs34jXFh.js → error-panel-BYG4twCa.js} +1 -1
  46. package/dist/assets/{file-explorer-panel-Ck6UL861.js → file-explorer-panel-BSMiOApi.js} +1 -1
  47. package/dist/assets/{flowDiagram-PVAE7QVJ-BgjFu5l7.js → flowDiagram-PVAE7QVJ-BdRKkajr.js} +1 -1
  48. package/dist/assets/{ganttDiagram-OWAHRB6G-YOPb3XSV.js → ganttDiagram-OWAHRB6G-lfRAMnq_.js} +5 -5
  49. package/dist/assets/{gitGraphDiagram-NY62KEGX-CGhqaDTy.js → gitGraphDiagram-NY62KEGX-CQVTIrHF.js} +1 -1
  50. package/dist/assets/{glide-data-editor-9QUH6iso.js → glide-data-editor-D5A4pou7.js} +4 -4
  51. package/dist/assets/{graph-DQQFGrho.js → graph-CBNo279v.js} +1 -1
  52. package/dist/assets/{home-page-DRKpPCrF.js → home-page-CmdznBJR.js} +2 -2
  53. package/dist/assets/{index-SGLNXrGP.js → index-0dfGh-Gj.js} +1 -1
  54. package/dist/assets/{index-aE43R74q.js → index-BDYVSSzB.js} +1 -1
  55. package/dist/assets/{index-BJNCMUmG.js → index-B_KyDZ94.js} +1 -1
  56. package/dist/assets/{index-BjgnbONl.js → index-Bfy-I_lW.js} +1 -1
  57. package/dist/assets/{index-CUFv_thQ.js → index-Bh98Tp-z.js} +1 -1
  58. package/dist/assets/{index-C2MD0vgD.js → index-BhroIwBL.js} +1 -1
  59. package/dist/assets/{index-DdnKZNxM.js → index-BtQtesaI.js} +1 -1
  60. package/dist/assets/index-C0iXCvyY.css +1 -0
  61. package/dist/assets/index-C1SHFMCp.js +581 -0
  62. package/dist/assets/{index-C_tkBKNO.js → index-C6DWtSls.js} +1 -1
  63. package/dist/assets/{index-Aeo6WiK7.js → index-C71cdkH-.js} +1 -1
  64. package/dist/assets/{index-G5QZppK2.js → index-CT_FTqvK.js} +1 -1
  65. package/dist/assets/{index-B8jXZ12t.js → index-CU5rRr66.js} +1 -1
  66. package/dist/assets/{index-BAbIIxHU.js → index-Cb6duXQm.js} +1 -1
  67. package/dist/assets/{index-BW3k9Gss.js → index-D23e9zQj.js} +1 -1
  68. package/dist/assets/index-DUGecC2Z.js +68 -0
  69. package/dist/assets/{index-CFKO7WXI.js → index-DcGIOAQi.js} +1 -1
  70. package/dist/assets/{index-ClzeQrN7.js → index-PJfa9qXY.js} +1 -1
  71. package/dist/assets/{index-C1ez98sk.js → index-SPslPC2B.js} +1 -1
  72. package/dist/assets/{index-BprjMYH5.js → index-VPQlo4Uz.js} +1 -1
  73. package/dist/assets/{index-CfaDbEdi.js → index-qbTLKWyG.js} +1 -1
  74. package/dist/assets/infoDiagram-STP46IZ2-DBu8p9gd.js +2 -0
  75. package/dist/assets/{isEmpty-D-4c7sMv.js → isEmpty-CnOLuQIv.js} +1 -1
  76. package/dist/assets/{journeyDiagram-BIP6EPQ6-C94u3Mv3.js → journeyDiagram-BIP6EPQ6-6U_vHJBH.js} +1 -1
  77. package/dist/assets/{kanban-definition-6OIFK2YF-BEXYFzz7.js → kanban-definition-6OIFK2YF-DgnR14ys.js} +1 -1
  78. package/dist/assets/{layout-Bz2BJ2ru.js → layout-RHmq4fP9.js} +1 -1
  79. package/dist/assets/{linear-D8s7K76e.js → linear-CLdOVPGV.js} +1 -1
  80. package/dist/assets/links-Dd1icsEk.js +7 -0
  81. package/dist/assets/{logs-panel-DC7wpmPz.js → logs-panel-CjbuhBLx.js} +1 -1
  82. package/dist/assets/{markdown-renderer-DRdSWR9X.js → markdown-renderer-X5YJvAZq.js} +3 -3
  83. package/dist/assets/{mermaid-Y3x4hmD0.js → mermaid-Bl2T5oEC.js} +1 -1
  84. package/dist/assets/{mermaid.core-DzthE35Y.js → mermaid.core-CfukBvGI.js} +4 -4
  85. package/dist/assets/min-BXIes1Za.js +1 -0
  86. package/dist/assets/{mindmap-definition-Q6HEUPPD-DktvuLe1.js → mindmap-definition-Q6HEUPPD-BXCjP4Lu.js} +1 -1
  87. package/dist/assets/{number-overlay-editor-BEfwI1IT.js → number-overlay-editor-BUyqkSes.js} +1 -1
  88. package/dist/assets/{outline-panel-CdsnAy2w.js → outline-panel-BvGcPKdd.js} +1 -1
  89. package/dist/assets/{packages-panel-DiTA-d_D.js → packages-panel-BichDQWG.js} +1 -1
  90. package/dist/assets/{pieDiagram-ADFJNKIX-DQDNQ-de.js → pieDiagram-ADFJNKIX-CMzJFIJM.js} +1 -1
  91. package/dist/assets/{quadrantDiagram-LMRXKWRM-0kgIXc2-.js → quadrantDiagram-LMRXKWRM-CfGssUlO.js} +1 -1
  92. package/dist/assets/{react-plotly-DJqqfM7c.js → react-plotly-DR3hV0HW.js} +1 -1
  93. package/dist/assets/{requirementDiagram-4UW4RH46-B5rb0ypd.js → requirementDiagram-4UW4RH46-CfrFolth.js} +1 -1
  94. package/dist/assets/{run-page-CFmLrv1R.js → run-page-Bqd_4ePD.js} +1 -1
  95. package/dist/assets/{sankeyDiagram-GR3RE2ED-Dom7IlnF.js → sankeyDiagram-GR3RE2ED-D_UttKU0.js} +1 -1
  96. package/dist/assets/{scratchpad-panel-CuHWpHO8.js → scratchpad-panel-D5N15ji1.js} +1 -1
  97. package/dist/assets/secrets-panel-BpbnAO4R.js +1 -0
  98. package/dist/assets/{sequenceDiagram-C3RYC4MD-PNJWXQbw.js → sequenceDiagram-C3RYC4MD-MdfQQApP.js} +1 -1
  99. package/dist/assets/{slides-component-CJgaTRZ0.js → slides-component-C0z7rXmk.js} +1 -1
  100. package/dist/assets/{snippets-panel-B2EC1txM.js → snippets-panel-wlpZ_Wzx.js} +1 -1
  101. package/dist/assets/sortBy-BW_zNHP6.js +1 -0
  102. package/dist/assets/{state-CWict9RU.js → state-CDooX-dk.js} +1 -1
  103. package/dist/assets/{stateDiagram-KXAO66HF-BE58aJnr.js → stateDiagram-KXAO66HF-H7kfw3ot.js} +1 -1
  104. package/dist/assets/stateDiagram-v2-UMBNRL4Z-YMeb9qMR.js +1 -0
  105. package/dist/assets/{storage-DRaR04wR.js → storage-b1QCapTq.js} +6 -6
  106. package/dist/assets/{terminal-BX3Su5q7.js → terminal-CPV44BXz.js} +1 -1
  107. package/dist/assets/{time-hUzZfpNE.js → time-DDy3xv5Y.js} +1 -1
  108. package/dist/assets/{timeline-definition-XQNQX7LJ-CqQP9t51.js → timeline-definition-XQNQX7LJ-J-cPRT2_.js} +1 -1
  109. package/dist/assets/{tracing-B10Q1n-L.js → tracing-3eHHRUiJ.js} +2 -2
  110. package/dist/assets/{tracing-panel-Du8WCnno.js → tracing-panel-BMgy3D7d.js} +2 -2
  111. package/dist/assets/{trash-B81GTiv6.js → trash--tonOuDe.js} +1 -1
  112. package/dist/assets/{tree-6vW2ogkh.js → tree-ouIGEsVg.js} +1 -1
  113. package/dist/assets/{treemap-75Q7IDZK-CdwDwwsz.js → treemap-75Q7IDZK-CzJTJ_3R.js} +20 -20
  114. package/dist/assets/{variable-panel-D5qgJI7k.js → variable-panel-sFTn4Oih.js} +1 -1
  115. package/dist/assets/{vega-component-DJaJWMJM.js → vega-component-BkPkzX9r.js} +1 -1
  116. package/dist/assets/{xychartDiagram-6GGTOJPD-WFtXqaM9.js → xychartDiagram-6GGTOJPD-BZ8WOb_8.js} +1 -1
  117. package/dist/index.html +10 -3
  118. package/package.json +8 -8
  119. package/src/__mocks__/common.ts +5 -3
  120. package/src/__mocks__/notebook.ts +2 -2
  121. package/src/__mocks__/requests.ts +1 -0
  122. package/src/__tests__/main.test.tsx +2 -2
  123. package/src/components/ai/ai-provider-icon.tsx +2 -0
  124. package/src/components/app-config/ai-config.tsx +32 -1
  125. package/src/components/app-config/common.tsx +2 -2
  126. package/src/components/app-config/user-config-form.tsx +26 -0
  127. package/src/components/audio/audio-recorder.tsx +0 -1
  128. package/src/components/chat/acp/blocks.tsx +2 -2
  129. package/src/components/chat/acp/thread.tsx +3 -5
  130. package/src/components/chat/acp/utils.ts +5 -5
  131. package/src/components/chat/chat-panel.tsx +1 -1
  132. package/src/components/data-table/__tests__/columns.test.tsx +38 -0
  133. package/src/components/data-table/__tests__/data-table.test.tsx +2 -2
  134. package/src/components/data-table/cell-hover-template/feature.ts +1 -1
  135. package/src/components/data-table/cell-hover-template/types.ts +1 -1
  136. package/src/components/data-table/charts/__tests__/altair-generator.test.ts +1 -1
  137. package/src/components/data-table/charts/chart-spec/tooltips.ts +3 -3
  138. package/src/components/data-table/charts/components/chart-items.tsx +1 -1
  139. package/src/components/data-table/charts/components/form-fields.tsx +2 -2
  140. package/src/components/data-table/charts/constants.ts +1 -1
  141. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
  142. package/src/components/data-table/column-summary/chart-spec-model.tsx +2 -2
  143. package/src/components/data-table/columns.tsx +22 -3
  144. package/src/components/data-table/data-table.tsx +35 -3
  145. package/src/components/data-table/date-popover.tsx +1 -1
  146. package/src/components/data-table/download-actions.tsx +1 -1
  147. package/src/components/data-table/range-focus/__tests__/utils.test.ts +5 -5
  148. package/src/components/data-table/renderers.tsx +22 -13
  149. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +1 -1
  150. package/src/components/data-table/schemas.ts +16 -0
  151. package/src/components/data-table/types.ts +4 -3
  152. package/src/components/datasources/column-preview.tsx +9 -6
  153. package/src/components/debugger/debugger-code.tsx +1 -1
  154. package/src/components/dependency-graph/custom-node.tsx +15 -6
  155. package/src/components/dependency-graph/dependency-graph-minimap.tsx +2 -2
  156. package/src/components/dependency-graph/dependency-graph-tree.tsx +2 -2
  157. package/src/components/dependency-graph/dependency-graph.tsx +1 -1
  158. package/src/components/dependency-graph/elements.ts +7 -7
  159. package/src/components/dependency-graph/utils/changes.ts +4 -4
  160. package/src/components/editor/Cell.tsx +7 -1
  161. package/src/components/editor/ai/transport/chat-transport.tsx +1 -1
  162. package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +1 -1
  163. package/src/components/editor/chrome/panels/packages-panel.tsx +1 -1
  164. package/src/components/editor/columns/storage.ts +1 -1
  165. package/src/components/editor/database/__tests__/__snapshots__/as-code.test.ts.snap +36 -0
  166. package/src/components/editor/database/__tests__/as-code.test.ts +30 -7
  167. package/src/components/editor/database/add-database-form.tsx +11 -0
  168. package/src/components/editor/database/as-code.ts +104 -5
  169. package/src/components/editor/database/schemas.ts +36 -18
  170. package/src/components/editor/errors/auto-fix.tsx +12 -2
  171. package/src/components/editor/errors/sql-validation-errors.tsx +40 -0
  172. package/src/components/editor/navigation/clipboard.ts +2 -2
  173. package/src/components/editor/output/ConsoleOutput.tsx +14 -2
  174. package/src/components/editor/output/JsonOutput.tsx +1 -1
  175. package/src/components/editor/output/MarimoErrorOutput.tsx +60 -1
  176. package/src/components/editor/output/MarimoTracebackOutput.tsx +17 -2
  177. package/src/components/editor/renderers/grid-layout/types.ts +2 -2
  178. package/src/components/editor/renderers/plugins.ts +1 -1
  179. package/src/components/editor/renderers/types.ts +1 -1
  180. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +7 -7
  181. package/src/components/forms/form.tsx +5 -5
  182. package/src/components/ui/links.tsx +1 -0
  183. package/src/core/ai/__tests__/model-registry.test.ts +0 -10
  184. package/src/core/ai/context/providers/cell-output.ts +1 -18
  185. package/src/core/ai/context/providers/error.ts +2 -2
  186. package/src/core/ai/ids/ids.ts +1 -0
  187. package/src/core/ai/model-registry.ts +2 -1
  188. package/src/core/cells/cells.ts +5 -5
  189. package/src/core/cells/logs.ts +1 -1
  190. package/src/core/cells/types.ts +1 -1
  191. package/src/core/codemirror/__tests__/format.test.ts +6 -0
  192. package/src/core/codemirror/cells/traceback-decorations.ts +1 -1
  193. package/src/core/codemirror/editing/commands.ts +2 -2
  194. package/src/core/codemirror/find-replace/navigate.ts +1 -1
  195. package/src/core/codemirror/language/__tests__/extension.test.ts +24 -0
  196. package/src/core/codemirror/language/__tests__/sql-validation.test.ts +133 -0
  197. package/src/core/codemirror/language/__tests__/sql.test.ts +764 -79
  198. package/src/core/codemirror/language/languages/markdown.ts +4 -1
  199. package/src/core/codemirror/language/languages/sql/banner-validation-errors.ts +85 -0
  200. package/src/core/codemirror/language/languages/sql/completion-builder.ts +160 -0
  201. package/src/core/codemirror/language/languages/sql/completion-sources.tsx +9 -3
  202. package/src/core/codemirror/language/languages/sql/completion-store.ts +46 -50
  203. package/src/core/codemirror/language/languages/sql/renderers.tsx +485 -0
  204. package/src/core/codemirror/language/languages/sql/sql-mode.ts +20 -0
  205. package/src/core/codemirror/language/languages/sql/sql.ts +218 -4
  206. package/src/core/codemirror/language/languages/sql/utils.ts +4 -1
  207. package/src/core/codemirror/language/panel/panel.tsx +8 -2
  208. package/src/core/codemirror/language/panel/sql.tsx +86 -4
  209. package/src/core/codemirror/language/utils/ast.ts +3 -3
  210. package/src/core/codemirror/lsp/federated-lsp.ts +4 -4
  211. package/src/core/codemirror/lsp/lens.ts +4 -4
  212. package/src/core/codemirror/lsp/notebook-lsp.ts +1 -1
  213. package/src/core/codemirror/lsp/types.ts +1 -1
  214. package/src/core/codemirror/markdown/completions.ts +1 -1
  215. package/src/core/codemirror/reactive-references/analyzer.ts +2 -2
  216. package/src/core/codemirror/rtc/loro/awareness.ts +1 -1
  217. package/src/core/config/config-schema.ts +1 -0
  218. package/src/core/config/feature-flag.tsx +6 -2
  219. package/src/core/datasets/request-registry.ts +24 -1
  220. package/src/core/dom/events.ts +1 -1
  221. package/src/core/dom/outline.ts +2 -2
  222. package/src/core/dom/uiregistry.ts +2 -8
  223. package/src/core/errors/__tests__/errors.test.ts +22 -4
  224. package/src/core/errors/errors.ts +29 -1
  225. package/src/core/errors/state.ts +1 -1
  226. package/src/core/islands/bridge.ts +1 -0
  227. package/src/core/islands/main.ts +3 -2
  228. package/src/core/islands/parse.ts +1 -3
  229. package/src/core/kernel/messages.ts +2 -1
  230. package/src/core/network/CachingRequestRegistry.ts +74 -0
  231. package/src/core/network/DeferredRequestRegistry.ts +3 -1
  232. package/src/core/network/__tests__/CachingRequestRegistry.test.ts +73 -0
  233. package/src/core/network/requests-network.ts +7 -0
  234. package/src/core/network/requests-static.ts +1 -0
  235. package/src/core/network/requests-toasting.ts +1 -0
  236. package/src/core/network/types.ts +3 -1
  237. package/src/core/variables/state.ts +2 -2
  238. package/src/core/wasm/__tests__/state.test.ts +1 -1
  239. package/src/core/wasm/bridge.ts +5 -0
  240. package/src/core/websocket/useMarimoWebSocket.tsx +9 -2
  241. package/src/custom.d.ts +1 -1
  242. package/src/hooks/useCellRenderCount.ts +1 -0
  243. package/src/hooks/useResizeHandle.ts +4 -1
  244. package/src/plugins/core/RenderHTML.tsx +1 -2
  245. package/src/plugins/core/registerReactComponent.tsx +23 -19
  246. package/src/plugins/impl/DataTablePlugin.tsx +18 -6
  247. package/src/plugins/impl/FileUploadPlugin.tsx +1 -1
  248. package/src/plugins/impl/RefreshPlugin.tsx +1 -1
  249. package/src/plugins/impl/SliderPlugin.tsx +4 -0
  250. package/src/plugins/impl/anywidget/AnyWidgetPlugin.tsx +27 -9
  251. package/src/plugins/impl/anywidget/__tests__/AnyWidgetPlugin.test.tsx +58 -2
  252. package/src/plugins/impl/anywidget/__tests__/model.test.ts +3 -4
  253. package/src/plugins/impl/anywidget/model.ts +2 -3
  254. package/src/plugins/impl/data-editor/types.ts +1 -1
  255. package/src/plugins/impl/data-explorer/components/query-form.tsx +1 -1
  256. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +17 -5
  257. package/src/plugins/impl/data-frames/types.ts +1 -1
  258. package/src/plugins/impl/panel/PanelPlugin.tsx +2 -2
  259. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +3 -3
  260. package/src/plugins/impl/vega/__tests__/loader.test.ts +2 -2
  261. package/src/plugins/impl/vega/loader.ts +1 -1
  262. package/src/plugins/impl/vega/vega-component.tsx +1 -1
  263. package/src/plugins/impl/vega/vega-loader.ts +2 -2
  264. package/src/plugins/layout/NavigationMenuPlugin.tsx +1 -1
  265. package/src/plugins/layout/RoutesPlugin.tsx +1 -2
  266. package/src/plugins/plugins.ts +2 -2
  267. package/src/stories/dataframe.stories.tsx +2 -0
  268. package/src/utils/Logger.ts +1 -1
  269. package/src/utils/__tests__/data-views.test.ts +30 -68
  270. package/src/utils/__tests__/dom.test.ts +167 -0
  271. package/src/utils/__tests__/id-tree.test.ts +49 -1
  272. package/src/utils/__tests__/storage.test.ts +1 -1
  273. package/src/utils/__tests__/traceback.test.ts +13 -2
  274. package/src/utils/arrays.ts +1 -1
  275. package/src/utils/createReducer.ts +1 -5
  276. package/src/utils/data-views.ts +6 -19
  277. package/src/utils/dom.ts +55 -0
  278. package/src/utils/edit-distance.ts +1 -1
  279. package/src/utils/fileToBase64.ts +1 -1
  280. package/src/utils/id-tree.tsx +20 -18
  281. package/src/utils/json/base64.ts +13 -0
  282. package/src/utils/json/json-parser.ts +2 -2
  283. package/src/utils/lru.ts +4 -0
  284. package/src/utils/mergeRefs.ts +1 -1
  285. package/src/utils/objects.ts +3 -3
  286. package/src/utils/pluralize.ts +1 -1
  287. package/src/utils/routes.ts +2 -2
  288. package/src/utils/sets.ts +1 -1
  289. package/src/utils/traceback.ts +45 -15
  290. package/src/utils/tracer.ts +11 -9
  291. package/dist/assets/_baseEach-CvTX9w0Y.js +0 -1
  292. package/dist/assets/_baseMap-CtlwA90f.js +0 -1
  293. package/dist/assets/_baseUniq-BKktIGQ1.js +0 -1
  294. package/dist/assets/channel-Co6iMgWq.js +0 -1
  295. package/dist/assets/chat-panel-9alr8FS4.js +0 -3
  296. package/dist/assets/classDiagram-KNZD7YFC-BbJ0rY3y.js +0 -1
  297. package/dist/assets/classDiagram-v2-RKCZMP56-BbJ0rY3y.js +0 -1
  298. package/dist/assets/clone-BMP0PsTa.js +0 -1
  299. package/dist/assets/command-palette-B93Pjcky.js +0 -1
  300. package/dist/assets/datasources-panel-v7H3cR0p.js +0 -1
  301. package/dist/assets/index-2252nrk6.js +0 -68
  302. package/dist/assets/index-C7CoaNFb.js +0 -578
  303. package/dist/assets/index-DadI618h.css +0 -1
  304. package/dist/assets/infoDiagram-STP46IZ2-CJLOpSAf.js +0 -2
  305. package/dist/assets/links-BpXlz1GG.js +0 -7
  306. package/dist/assets/min-BBO3-1Hg.js +0 -1
  307. package/dist/assets/secrets-panel-CfHc5YD0.js +0 -1
  308. package/dist/assets/sortBy-DZnlX29-.js +0 -1
  309. package/dist/assets/stateDiagram-v2-UMBNRL4Z-CdThjimL.js +0 -1
  310. package/src/__tests__/lru.test.ts +0 -74
@@ -29,7 +29,7 @@ interface GetTooltipParams {
29
29
 
30
30
  export function getTooltips(
31
31
  params: GetTooltipParams,
32
- ): Array<StringFieldDef<string>> | undefined {
32
+ ): StringFieldDef<string>[] | undefined {
33
33
  const { formValues, xEncoding, yEncoding, colorByEncoding } = params;
34
34
 
35
35
  if (!formValues.tooltips) {
@@ -73,7 +73,7 @@ export function getTooltips(
73
73
 
74
74
  // If autoTooltips is enabled, we manually add the x, y, and color columns to the tooltips
75
75
  if (formValues.tooltips.auto) {
76
- const tooltips: Array<StringFieldDef<string>> = [];
76
+ const tooltips: StringFieldDef<string>[] = [];
77
77
  const xTooltip = addTooltip(
78
78
  xEncoding,
79
79
  formValues.general?.xColumn?.type || "string",
@@ -105,7 +105,7 @@ export function getTooltips(
105
105
 
106
106
  // Selected tooltips from the form.
107
107
  const selectedTooltips = formValues.tooltips.fields ?? [];
108
- const tooltips: Array<StringFieldDef<string>> = [];
108
+ const tooltips: StringFieldDef<string>[] = [];
109
109
 
110
110
  // We need to find the matching columns for the selected tooltips if they exist
111
111
  // Otherwise, we can add them without other parameters
@@ -103,7 +103,7 @@ const ColumnSelectorWithAggregation: React.FC<{
103
103
  selectedDataType?: SelectedDataType;
104
104
  };
105
105
  defaultAggregation?: AggregationFn;
106
- columns: Array<{ name: string; type: DataType }>;
106
+ columns: { name: string; type: DataType }[];
107
107
  binFieldName: FieldName;
108
108
  }> = ({
109
109
  columnFieldName,
@@ -86,7 +86,7 @@ export const ColumnSelector = ({
86
86
  includeCountField = true,
87
87
  }: {
88
88
  fieldName: FieldName;
89
- columns: Array<{ name: string; type: DataType }>;
89
+ columns: { name: string; type: DataType }[];
90
90
  onValueChange?: (fieldName: string, type: DataType | undefined) => void;
91
91
  includeCountField?: boolean;
92
92
  }) => {
@@ -197,7 +197,7 @@ export const SelectField = ({
197
197
  }: {
198
198
  fieldName: FieldName;
199
199
  label: string;
200
- options: Array<{ display: React.ReactNode; value: string }>;
200
+ options: { display: React.ReactNode; value: string }[];
201
201
  defaultValue: string;
202
202
  }) => {
203
203
  const form = useFormContext();
@@ -79,7 +79,7 @@ export const AGGREGATION_TYPE_DESCRIPTIONS: Record<AggregationFn, string> = {
79
79
  bin: "Group values into bins",
80
80
  };
81
81
 
82
- export const COLOR_SCHEMES: Array<ColorScheme | typeof DEFAULT_COLOR_SCHEME> = [
82
+ export const COLOR_SCHEMES: (ColorScheme | typeof DEFAULT_COLOR_SCHEME)[] = [
83
83
  DEFAULT_COLOR_SCHEME,
84
84
  // Categorical schemes
85
85
  "accent",
@@ -211,7 +211,7 @@ const ColumnPreview = ({
211
211
  refetchPreview,
212
212
  });
213
213
 
214
- const previewStats = stats && renderStats(stats, dataType, locale);
214
+ const previewStats = stats && renderStats({ stats, dataType, locale });
215
215
 
216
216
  const chart = chart_spec && renderChart(chart_spec, theme);
217
217
 
@@ -778,14 +778,14 @@ export class ColumnChartSpecModel<T> {
778
778
  const yField = "value";
779
779
 
780
780
  // Calculate xStart and xEnd for each value count
781
- const newValueCounts: Array<{
781
+ const newValueCounts: {
782
782
  count: number;
783
783
  value: string;
784
784
  xStart: number;
785
785
  xEnd: number;
786
786
  xMid: number;
787
787
  proportion: number;
788
- }> = [];
788
+ }[] = [];
789
789
  let xStart = 0;
790
790
  for (const valueCount of valueCounts) {
791
791
  const xEnd = xStart + valueCount.count;
@@ -17,6 +17,7 @@ import { JsonOutput } from "../editor/output/JsonOutput";
17
17
  import { Button } from "../ui/button";
18
18
  import { Checkbox } from "../ui/checkbox";
19
19
  import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
20
+ import { Tooltip } from "../ui/tooltip";
20
21
  import { DataTableColumnHeader } from "./column-header";
21
22
  import type { ColumnChartSpecModel } from "./column-summary/chart-spec-model";
22
23
  import { TableColumnSummary } from "./column-summary/column-summary";
@@ -103,6 +104,7 @@ export function generateColumns<T>({
103
104
  chartSpecModel,
104
105
  textJustifyColumns,
105
106
  wrappedColumns,
107
+ headerTooltip,
106
108
  showDataTypes,
107
109
  calculateTopKRows,
108
110
  }: {
@@ -112,9 +114,10 @@ export function generateColumns<T>({
112
114
  chartSpecModel?: ColumnChartSpecModel<unknown>;
113
115
  textJustifyColumns?: Record<string, "left" | "center" | "right">;
114
116
  wrappedColumns?: string[];
117
+ headerTooltip?: Record<string, string>;
115
118
  showDataTypes?: boolean;
116
119
  calculateTopKRows?: CalculateTopKRows;
117
- }): Array<ColumnDef<T>> {
120
+ }): ColumnDef<T>[] {
118
121
  // Row-headers are typically index columns
119
122
  const rowHeadersSet = new Set(rowHeaders.map(([columnName]) => columnName));
120
123
 
@@ -165,6 +168,7 @@ export function generateColumns<T>({
165
168
  header: ({ column }) => {
166
169
  const stats = chartSpecModel?.getColumnStats(key);
167
170
  const dtype = column.columnDef.meta?.dtype;
171
+ const headerTitle = headerTooltip?.[key];
168
172
  const dtypeHeader =
169
173
  showDataTypes && dtype ? (
170
174
  <div className="flex flex-row gap-1">
@@ -179,14 +183,29 @@ export function generateColumns<T>({
179
183
 
180
184
  const headerWithType = (
181
185
  <div className="flex flex-col">
182
- <span className="font-bold">{key === "" ? " " : key}</span>
186
+ <span
187
+ className={cn(
188
+ "font-bold",
189
+ headerTitle && "underline decoration-dotted",
190
+ )}
191
+ >
192
+ {key === "" ? " " : key}
193
+ </span>
183
194
  {dtypeHeader}
184
195
  </div>
185
196
  );
186
197
 
198
+ const headerWithTooltip = headerTitle ? (
199
+ <Tooltip content={headerTitle} delayDuration={300}>
200
+ {headerWithType}
201
+ </Tooltip>
202
+ ) : (
203
+ headerWithType
204
+ );
205
+
187
206
  const dataTableColumnHeader = (
188
207
  <DataTableColumnHeader
189
- header={headerWithType}
208
+ header={headerWithTooltip}
190
209
  column={column}
191
210
  calculateTopKRows={calculateTopKRows}
192
211
  />
@@ -47,7 +47,8 @@ import { getStableRowId } from "./utils";
47
47
  interface DataTableProps<TData> extends Partial<DownloadActionProps> {
48
48
  wrapperClassName?: string;
49
49
  className?: string;
50
- columns: Array<ColumnDef<TData>>;
50
+ maxHeight?: number;
51
+ columns: ColumnDef<TData>[];
51
52
  data: TData[];
52
53
  // Sorting
53
54
  manualSorting?: boolean; // server-side sorting
@@ -95,6 +96,7 @@ interface DataTableProps<TData> extends Partial<DownloadActionProps> {
95
96
  const DataTableInternal = <TData,>({
96
97
  wrapperClassName,
97
98
  className,
99
+ maxHeight,
98
100
  columns,
99
101
  data,
100
102
  selection,
@@ -250,6 +252,36 @@ const DataTableInternal = <TData,>({
250
252
 
251
253
  const rowViewerPanelOpen = isPanelOpen?.("row-viewer") ?? false;
252
254
 
255
+ const tableRef = React.useRef<HTMLTableElement | null>(null);
256
+
257
+ // Why use a ref to set max-height on the wrapper?
258
+ // - position: sticky only works when the sticky element's nearest scrollable
259
+ // ancestor is its immediate container. If max-height/overflow are applied
260
+ // on a grandparent, sticky table headers (th) will not stick.
261
+ // - We keep the scroll wrapper colocated with the base Table component, but
262
+ // derive the scroll boundary from maxHeight here to avoid coupling UI base
263
+ // components to data-table specifics or expanding their API surface.
264
+ // - Setting styles on the table's direct wrapper ensures the header sticks
265
+ // reliably across browsers without changing upstream components.
266
+ React.useEffect(() => {
267
+ if (!tableRef.current) {
268
+ return;
269
+ }
270
+ const wrapper = tableRef.current.parentElement as HTMLDivElement | null;
271
+ if (!wrapper) {
272
+ return;
273
+ }
274
+ if (maxHeight) {
275
+ wrapper.style.maxHeight = `${maxHeight}px`;
276
+ // Ensure wrapper scrolls
277
+ if (!wrapper.style.overflow) {
278
+ wrapper.style.overflow = "auto";
279
+ }
280
+ } else {
281
+ wrapper.style.removeProperty("max-height");
282
+ }
283
+ }, [maxHeight]);
284
+
253
285
  return (
254
286
  <div className={cn(wrapperClassName, "flex flex-col space-y-1")}>
255
287
  <FilterPills filters={filters} table={table} />
@@ -263,11 +295,11 @@ const DataTableInternal = <TData,>({
263
295
  reloading={reloading}
264
296
  />
265
297
  )}
266
- <Table className="relative">
298
+ <Table className="relative" ref={tableRef}>
267
299
  {showLoadingBar && (
268
300
  <div className="absolute top-0 left-0 h-[3px] w-1/2 bg-primary animate-slide" />
269
301
  )}
270
- {renderTableHeader(table)}
302
+ {renderTableHeader(table, Boolean(maxHeight))}
271
303
  <CellSelectionProvider>
272
304
  <DataTableBody
273
305
  table={table}
@@ -124,7 +124,7 @@ const RelativeTime = ({ date }: { date: Date }) => {
124
124
  const differenceInSeconds = (currentTime.getTime() - date.getTime()) / 1000;
125
125
 
126
126
  // Define time units with their thresholds and conversion factors
127
- const timeUnits: Array<[number, number, string]> = [
127
+ const timeUnits: [number, number, string][] = [
128
128
  [60, 1, "second"], // Less than 60 seconds
129
129
  [60, 60, "minute"], // Less than 60 minutes
130
130
  [24, 3600, "hour"], // Less than 24 hours
@@ -167,7 +167,7 @@ export const DownloadAs: React.FC<DownloadActionProps> = (props) => {
167
167
  );
168
168
  };
169
169
 
170
- function fetchJson(url: string): Promise<Array<Record<string, unknown>>> {
170
+ function fetchJson(url: string): Promise<Record<string, unknown>[]> {
171
171
  return fetch(url).then((res) => {
172
172
  if (!res.ok) {
173
173
  throw new Error(res.statusText);
@@ -20,17 +20,17 @@ function createMockCell(id: string, value: unknown): Cell<unknown, unknown> {
20
20
  function createMockColumn(id: string): Column<unknown> {
21
21
  return {
22
22
  id: id,
23
- getIndex: () => Number.parseInt(id),
23
+ getIndex: () => Number.parseInt(id, 10),
24
24
  } as unknown as Column<unknown>;
25
25
  }
26
26
 
27
27
  function createMockRow(
28
28
  id: string,
29
- cells: Array<Cell<unknown, unknown>>,
29
+ cells: Cell<unknown, unknown>[],
30
30
  ): Row<unknown> {
31
31
  return {
32
32
  id,
33
- index: Number.parseInt(id),
33
+ index: Number.parseInt(id, 10),
34
34
  getAllCells: () => cells,
35
35
  original: {},
36
36
  depth: 0,
@@ -43,8 +43,8 @@ function createMockRow(
43
43
  }
44
44
 
45
45
  function createMockTable(
46
- rows: Array<Row<unknown>>,
47
- columns: Array<Column<unknown>>,
46
+ rows: Row<unknown>[],
47
+ columns: Column<unknown>[],
48
48
  ): Table<unknown> {
49
49
  return {
50
50
  getRow: (id: string) => rows.find((row) => row.id === id),
@@ -26,12 +26,13 @@ import { useScrollIntoViewOnFocus } from "./range-focus/use-scroll-into-view";
26
26
 
27
27
  export function renderTableHeader<TData>(
28
28
  table: Table<TData>,
29
+ isSticky?: boolean,
29
30
  ): JSX.Element | null {
30
31
  if (!table.getRowModel().rows?.length) {
31
32
  return null;
32
33
  }
33
34
 
34
- const renderHeaderGroup = (headerGroups: Array<HeaderGroup<TData>>) => {
35
+ const renderHeaderGroup = (headerGroups: HeaderGroup<TData>[]) => {
35
36
  return headerGroups.map((headerGroup) =>
36
37
  headerGroup.headers.map((header) => {
37
38
  const { className, style } = getPinningStyles(header.column);
@@ -57,7 +58,7 @@ export function renderTableHeader<TData>(
57
58
  };
58
59
 
59
60
  return (
60
- <TableHeader>
61
+ <TableHeader className={cn(isSticky && "sticky top-0 z-10")}>
61
62
  <TableRow>
62
63
  {renderHeaderGroup(table.getLeftHeaderGroups())}
63
64
  {renderHeaderGroup(table.getCenterHeaderGroups())}
@@ -69,7 +70,7 @@ export function renderTableHeader<TData>(
69
70
 
70
71
  interface DataTableBodyProps<TData> {
71
72
  table: Table<TData>;
72
- columns: Array<ColumnDef<TData>>;
73
+ columns: ColumnDef<TData>[];
73
74
  rowViewerPanelOpen: boolean;
74
75
  getRowIndex?: (row: TData, idx: number) => number;
75
76
  viewedRowIdx?: number;
@@ -95,7 +96,7 @@ export const DataTableBody = <TData,>({
95
96
 
96
97
  function applyHoverTemplate(
97
98
  template: string,
98
- cells: Array<Cell<TData, unknown>>,
99
+ cells: Cell<TData, unknown>[],
99
100
  ): string {
100
101
  const variableRegex = /{{(\w+)}}/g;
101
102
  // Map column id -> stringified value
@@ -106,13 +107,13 @@ export const DataTableBody = <TData,>({
106
107
  const s = renderUnknownValue({ value: v, nullAsEmptyString: true });
107
108
  idToValue.set(c.column.id, s);
108
109
  }
109
- return template.replace(variableRegex, (_substr, varName: string) => {
110
+ return template.replaceAll(variableRegex, (_substr, varName: string) => {
110
111
  const val = idToValue.get(varName);
111
- return val !== undefined ? val : `{{${varName}}}`;
112
+ return val === undefined ? `{{${varName}}}` : val;
112
113
  });
113
114
  }
114
115
 
115
- const renderCells = (cells: Array<Cell<TData, unknown>>) => {
116
+ const renderCells = (cells: Cell<TData, unknown>[]) => {
116
117
  return cells.map((cell) => {
117
118
  const { className, style: pinningstyle } = getPinningStyles(cell.column);
118
119
  const style = Object.assign(
@@ -154,6 +155,8 @@ export const DataTableBody = <TData,>({
154
155
  }
155
156
  };
156
157
 
158
+ const hoverTemplate = table.getState().cellHoverTemplate || null;
159
+
157
160
  return (
158
161
  <TableBody onKeyDown={handleCellsKeyDown} ref={tableRef}>
159
162
  {table.getRowModel().rows?.length ? (
@@ -165,12 +168,18 @@ export const DataTableBody = <TData,>({
165
168
  const isRowViewedInPanel =
166
169
  rowViewerPanelOpen && viewedRowIdx === rowIndex;
167
170
 
168
- // Compute hover title once per row using this row's cells (visible or hidden)
169
- const hoverTemplate = table.getState().cellHoverTemplate || null;
170
- const rowCells = row.getAllCells();
171
- const rowTitle = hoverTemplate
172
- ? applyHoverTemplate(hoverTemplate, rowCells)
173
- : undefined;
171
+ // Compute hover title once per row using all visible cells
172
+ let rowTitle: string | undefined;
173
+ if (hoverTemplate) {
174
+ const visibleCells = row.getVisibleCells?.() ?? [
175
+ ...row.getLeftVisibleCells(),
176
+ ...row.getCenterVisibleCells(),
177
+ ...row.getRightVisibleCells(),
178
+ ];
179
+ rowTitle = hoverTemplate
180
+ ? applyHoverTemplate(hoverTemplate, visibleCells)
181
+ : undefined;
182
+ }
174
183
 
175
184
  return (
176
185
  <TableRow
@@ -188,7 +188,7 @@ export const RowViewerPanel: React.FC<RowViewerPanelProps> = ({
188
188
  </TableRow>
189
189
  </TableHeader>
190
190
  <TableBody>
191
- {fieldTypes?.map(([columnName, [dataType, externalType]]) => {
191
+ {fieldTypes?.map(([columnName, [dataType, _externalType]]) => {
192
192
  const columnValue = rowValues[columnName];
193
193
 
194
194
  if (!inSearchQuery({ columnName, columnValue, searchQuery })) {
@@ -0,0 +1,16 @@
1
+ /* Copyright 2024 Marimo. All rights reserved. */
2
+
3
+ import z from "zod";
4
+ import { rpc } from "@/plugins/core/rpc";
5
+
6
+ export type DownloadAsArgs = (req: {
7
+ format: "csv" | "json" | "parquet";
8
+ }) => Promise<string>;
9
+
10
+ export const DownloadAsSchema = rpc
11
+ .input(
12
+ z.object({
13
+ format: z.enum(["csv", "json", "parquet"]),
14
+ }),
15
+ )
16
+ .output(z.string());
@@ -27,9 +27,10 @@ export type ColumnHeaderStats = Record<
27
27
  number | string | null
28
28
  >;
29
29
 
30
- export type FieldTypesWithExternalType = Array<
31
- [columnName: string, [dataType: DataType, externalType: string]]
32
- >;
30
+ export type FieldTypesWithExternalType = [
31
+ columnName: string,
32
+ [dataType: DataType, externalType: string],
33
+ ][];
33
34
  export type FieldTypes = Record<string, DataType>;
34
35
 
35
36
  export function toFieldTypes(
@@ -110,7 +110,8 @@ export const DatasetColumnPreview: React.FC<{
110
110
  });
111
111
 
112
112
  const stats =
113
- preview.stats && renderStats(preview.stats, column.type, locale);
113
+ preview.stats &&
114
+ renderStats({ stats: preview.stats, dataType: column.type, locale });
114
115
 
115
116
  const chart = preview.chart_spec && renderChart(preview.chart_spec, theme);
116
117
 
@@ -175,11 +176,13 @@ export function renderPreviewError({
175
176
  );
176
177
  }
177
178
 
178
- export function renderStats(
179
- stats: Partial<Record<ColumnHeaderStatsKey, unknown>>,
180
- dataType: DataType,
181
- locale: string,
182
- ) {
179
+ interface RenderStatsProps {
180
+ stats: Partial<Record<ColumnHeaderStatsKey, unknown>>;
181
+ dataType: DataType;
182
+ locale: string;
183
+ }
184
+
185
+ export function renderStats({ stats, dataType, locale }: RenderStatsProps) {
183
186
  return (
184
187
  <div className="gap-x-16 gap-y-1 grid grid-cols-2-fit border rounded p-2 empty:hidden">
185
188
  {Object.entries(stats).map(([key, value]) => {
@@ -106,7 +106,7 @@ const DebuggerInput: React.FC<{
106
106
  key: "Enter",
107
107
  preventDefault: true,
108
108
  stopPropagation: true,
109
- run: (view: EditorView) => {
109
+ run: () => {
110
110
  const v = value.trim().replaceAll("\n", "\\n");
111
111
  if (!v) {
112
112
  return true;
@@ -1,7 +1,7 @@
1
1
  /* Copyright 2024 Marimo. All rights reserved. */
2
2
 
3
3
  import { useAtomValue } from "jotai";
4
- import React, { memo, use } from "react";
4
+ import React, { memo, use, useId } from "react";
5
5
  import { Handle, Position, useStore } from "reactflow";
6
6
  import { TinyCode } from "@/components/editor/cell/TinyCode";
7
7
  import { useCellIds } from "@/core/cells/cells";
@@ -23,7 +23,7 @@ const EQUALITY_CHECK = (
23
23
  prevProps: CustomNodeProps,
24
24
  nextProps: CustomNodeProps,
25
25
  ) => {
26
- const keys: Array<keyof CustomNodeProps> = ["data", "selected", "id"];
26
+ const keys: (keyof CustomNodeProps)[] = ["data", "selected", "id"];
27
27
  return keys.every((key) => prevProps[key] === nextProps[key]);
28
28
  };
29
29
 
@@ -37,18 +37,25 @@ export const CustomNode = memo((props: CustomNodeProps) => {
37
37
  const reactFlowWidth = useStore(({ width }) => width);
38
38
  const edgeMarkers = use(EdgeMarkerContext);
39
39
 
40
+ const inputOneId = useId();
41
+ const inputTwoId = useId();
42
+ const outputOneId = useId();
43
+ const outputTwoId = useId();
44
+
40
45
  const linesOfCode = cell.code.split("\n").length;
41
46
  return (
42
47
  <div>
43
48
  <Handle
44
49
  type="target"
45
- id="inputs"
50
+ id={inputOneId}
51
+ data-testid="input-one"
46
52
  position={edgeMarkers === "LR" ? Position.Left : Position.Top}
47
53
  style={{ background: color }}
48
54
  />
49
55
  <Handle
50
56
  type="source"
51
- id="inputs"
57
+ id={inputTwoId}
58
+ data-testid="input-two"
52
59
  position={edgeMarkers === "LR" ? Position.Left : Position.Top}
53
60
  style={{ background: color }}
54
61
  />
@@ -69,13 +76,15 @@ export const CustomNode = memo((props: CustomNodeProps) => {
69
76
  </div>
70
77
  <Handle
71
78
  type="source"
72
- id="outputs"
79
+ id={outputOneId}
80
+ data-testid="output-one"
73
81
  position={edgeMarkers === "LR" ? Position.Right : Position.Bottom}
74
82
  style={{ background: color }}
75
83
  />
76
84
  <Handle
77
85
  type="target"
78
- id="outputs"
86
+ id={outputTwoId}
87
+ data-testid="output-two"
79
88
  position={edgeMarkers === "LR" ? Position.Right : Position.Bottom}
80
89
  style={{ background: color }}
81
90
  />
@@ -31,7 +31,7 @@ import { useFitToViewOnDimensionChange } from "./utils/useFitToViewOnDimensionCh
31
31
  interface Props {
32
32
  cellIds: CellId[];
33
33
  variables: Variables;
34
- cellAtoms: Array<Atom<CellData>>;
34
+ cellAtoms: Atom<CellData>[];
35
35
  }
36
36
 
37
37
  const elementsBuilder = new VerticalElementsBuilder();
@@ -57,7 +57,7 @@ export const DependencyGraphMinimap: React.FC<PropsWithChildren<Props>> = ({
57
57
 
58
58
  // If the cellIds change, update the nodes.
59
59
  const syncChanges = useEvent(
60
- (elements: { nodes: Array<Node<NodeData>>; edges: Edge[] }) => {
60
+ (elements: { nodes: Node<NodeData>[]; edges: Edge[] }) => {
61
61
  setNodes(elements.nodes);
62
62
  setEdges([]);
63
63
  },
@@ -36,7 +36,7 @@ import { useFitToViewOnDimensionChange } from "./utils/useFitToViewOnDimensionCh
36
36
  interface Props {
37
37
  cellIds: CellId[];
38
38
  variables: Variables;
39
- cellAtoms: Array<Atom<CellData>>;
39
+ cellAtoms: Atom<CellData>[];
40
40
  layoutDirection: LayoutDirection;
41
41
  settings: GraphSettings;
42
42
  }
@@ -74,7 +74,7 @@ export const DependencyGraphTree: React.FC<PropsWithChildren<Props>> = ({
74
74
  const api = useReactFlow();
75
75
 
76
76
  const syncChanges = useEvent(
77
- (elements: { nodes: Array<Node<NodeData>>; edges: Edge[] }) => {
77
+ (elements: { nodes: Node<NodeData>[]; edges: Edge[] }) => {
78
78
  // Layout the elements
79
79
  const result = layoutElements({
80
80
  nodes: elements.nodes,
@@ -18,7 +18,7 @@ import "./dependency-graph.css";
18
18
  interface Props {
19
19
  cellIds: CellId[];
20
20
  variables: Variables;
21
- cellAtoms: Array<Atom<CellData>>;
21
+ cellAtoms: Atom<CellData>[];
22
22
  children?: React.ReactNode;
23
23
  }
24
24
 
@@ -22,10 +22,10 @@ export function getNodeHeight(linesOfCode: number) {
22
22
  interface ElementsBuilder {
23
23
  createElements: (
24
24
  cellIds: CellId[],
25
- cellAtoms: Array<Atom<CellData>>,
25
+ cellAtoms: Atom<CellData>[],
26
26
  variables: Variables,
27
27
  hidePureMarkdown: boolean,
28
- ) => { nodes: Array<Node<NodeData>>; edges: Edge[] };
28
+ ) => { nodes: Node<NodeData>[]; edges: Edge[] };
29
29
  }
30
30
 
31
31
  export class VerticalElementsBuilder implements ElementsBuilder {
@@ -69,12 +69,12 @@ export class VerticalElementsBuilder implements ElementsBuilder {
69
69
 
70
70
  createElements(
71
71
  cellIds: CellId[],
72
- cellAtoms: Array<Atom<CellData>>,
72
+ cellAtoms: Atom<CellData>[],
73
73
  variables: Variables,
74
- hidePureMarkdown: boolean,
74
+ _hidePureMarkdown: boolean,
75
75
  ) {
76
76
  let prevY = 0;
77
- const nodes: Array<Node<NodeData>> = [];
77
+ const nodes: Node<NodeData>[] = [];
78
78
  const edges: Edge[] = [];
79
79
  for (const [cellId, cellAtom] of Arrays.zip(cellIds, cellAtoms)) {
80
80
  const node = this.createNode(cellId, cellAtom, prevY);
@@ -135,11 +135,11 @@ export class TreeElementsBuilder implements ElementsBuilder {
135
135
 
136
136
  createElements(
137
137
  cellIds: CellId[],
138
- cellAtoms: Array<Atom<CellData>>,
138
+ cellAtoms: Atom<CellData>[],
139
139
  variables: Variables,
140
140
  hidePureMarkdown: boolean,
141
141
  ) {
142
- const nodes: Array<Node<NodeData>> = [];
142
+ const nodes: Node<NodeData>[] = [];
143
143
  const edges: Edge[] = [];
144
144
 
145
145
  const nodesWithEdges = new Set<CellId>();
@@ -11,8 +11,8 @@ import type {
11
11
  export function getNodeChanges(
12
12
  prevNodes: Node[],
13
13
  nextNodes: Node[],
14
- ): Array<NodeAddChange | NodeRemoveChange> {
15
- const changes: Array<NodeAddChange | NodeRemoveChange> = [];
14
+ ): (NodeAddChange | NodeRemoveChange)[] {
15
+ const changes: (NodeAddChange | NodeRemoveChange)[] = [];
16
16
  const prevNodeIds = new Set(prevNodes.map((node) => node.id));
17
17
  const nextNodeIds = new Set(nextNodes.map((node) => node.id));
18
18
 
@@ -33,8 +33,8 @@ export function getNodeChanges(
33
33
  export function getEdgeChanges(
34
34
  prevEdges: Edge[],
35
35
  nextEdges: Edge[],
36
- ): Array<EdgeAddChange | EdgeRemoveChange> {
37
- const changes: Array<EdgeAddChange | EdgeRemoveChange> = [];
36
+ ): (EdgeAddChange | EdgeRemoveChange)[] {
37
+ const changes: (EdgeAddChange | EdgeRemoveChange)[] = [];
38
38
  const prevEdgeIds = new Set(prevEdges.map((edge) => edge.id));
39
39
  const nextEdgeIds = new Set(nextEdges.map((edge) => edge.id));
40
40