@marimo-team/frontend 0.22.1-dev34 → 0.22.1-dev39

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 (239) hide show
  1. package/dist/assets/{CellStatus-DKyVv7Zj.js → CellStatus-Cf0Jlrcs.js} +1 -1
  2. package/dist/assets/{ConnectedDataExplorerComponent-BUc9LHJJ.js → ConnectedDataExplorerComponent-DUxaLoL7.js} +1 -1
  3. package/dist/assets/{JsonOutput-D1i8P1dG.js → JsonOutput-IpD2GLtO.js} +2 -2
  4. package/dist/assets/{MarimoErrorOutput-RmM7djc-.js → MarimoErrorOutput-dTNCLY-Q.js} +1 -1
  5. package/dist/assets/{Plot-C7NE7pEx.js → Plot-BAM1jEAz.js} +72 -72
  6. package/dist/assets/{RenderHTML-Bmn77an6.js → RenderHTML-C5GEp4ca.js} +1 -1
  7. package/dist/assets/{add-cell-with-ai-RyZ9Xe2b.js → add-cell-with-ai-C0J3LyiV.js} +1 -1
  8. package/dist/assets/{add-connection-dialog-ogwy8tvS.js → add-connection-dialog-C42PDYI7.js} +1 -1
  9. package/dist/assets/{agent-panel-BHLkHj7k.js → agent-panel-CH-jHjEl.js} +1 -1
  10. package/dist/assets/{ai-model-dropdown-Dnf-CxbP.js → ai-model-dropdown-D14GiszF.js} +1 -1
  11. package/dist/assets/{app-config-button-D1Z_xsvC.js → app-config-button-v-557oRb.js} +1 -1
  12. package/dist/assets/{cell-editor-_GDTh-4a.js → cell-editor-Dd6UaL1A.js} +2 -2
  13. package/dist/assets/{cell-link-D4UrIH9w.js → cell-link-Cimoe3Fv.js} +1 -1
  14. package/dist/assets/{cells-ArUhhHls.js → cells-CcsG9Aum.js} +1 -1
  15. package/dist/assets/{chat-display-YmFjOXkV.js → chat-display-hfpeXiYe.js} +1 -1
  16. package/dist/assets/{chat-panel-B76rxYTh.js → chat-panel-DxT370nA.js} +1 -1
  17. package/dist/assets/{chat-ui-BitNq1z6.js → chat-ui-Dv4y0-td.js} +1 -1
  18. package/dist/assets/{column-preview-NDhbeu0E.js → column-preview-ZSErTRFA.js} +1 -1
  19. package/dist/assets/{command-palette-uJxkhle4.js → command-palette-CjF_cblG.js} +1 -1
  20. package/dist/assets/{common-CRBlPqv5.js → common-BZK7spst.js} +1 -1
  21. package/dist/assets/{components-DwGcJvMB.js → components-D2OlyENc.js} +1 -1
  22. package/dist/assets/{components-BfHGr__b.js → components-DpxyscxU.js} +1 -1
  23. package/dist/assets/{datasource-D9e37ifa.js → datasource-D9nfSxKS.js} +1 -1
  24. package/dist/assets/{dependency-graph-panel-BBmN-Vc7.js → dependency-graph-panel-5MbMtFss.js} +1 -1
  25. package/dist/assets/{documentation-panel-Dm2xtsTq.js → documentation-panel-DPdXS3YO.js} +1 -1
  26. package/dist/assets/{download-7EtMZf2Y.js → download-BFQaUFKI.js} +1 -1
  27. package/dist/assets/{edit-page-Cr_DnrkM.js → edit-page-CMd8_Psc.js} +4 -4
  28. package/dist/assets/{error-panel-C3-vTzaH.js → error-panel-DV8jpRsf.js} +1 -1
  29. package/dist/assets/{file-explorer-panel-g9KppC7Y.js → file-explorer-panel-Dr_ZNDk3.js} +1 -1
  30. package/dist/assets/{file-icons-JXAG6vK-.js → file-icons-DSJsG_mI.js} +1 -1
  31. package/dist/assets/{floating-outline-B6Qyid7Q.js → floating-outline-Cfa1ESSb.js} +1 -1
  32. package/dist/assets/{focus-DCN0oEe0.js → focus-C5u0JQUq.js} +1 -1
  33. package/dist/assets/{form-BVnQnVQ2.js → form-3ZUGKch9.js} +1 -1
  34. package/dist/assets/glide-data-editor-a3qLDl-r.js +132 -0
  35. package/dist/assets/{home-page-Bg02jazh.js → home-page-BrqppCUS.js} +1 -1
  36. package/dist/assets/{hooks-zQJ9iU_R.js → hooks-CHE17GG1.js} +1 -1
  37. package/dist/assets/{html-to-image-C5XSE7QT.js → html-to-image-BRbQwG7G.js} +1 -1
  38. package/dist/assets/{index-BaQAJwyb.css → index-BkdonYlq.css} +1 -1
  39. package/dist/assets/index-Bt8G6SSE.js +42 -0
  40. package/dist/assets/{kiosk-mode-CriCUOI1.js → kiosk-mode-Cu86-jaD.js} +1 -1
  41. package/dist/assets/{layout-Cudicm29.js → layout-B-lTkLKA.js} +1 -1
  42. package/dist/assets/{logs-panel-CoWO9c8s.js → logs-panel-CNVgwoHO.js} +1 -1
  43. package/dist/assets/{markdown-renderer-CyUc0f8D.js → markdown-renderer-B91NzmVT.js} +1 -1
  44. package/dist/assets/{name-cell-input-DeM6upjB.js → name-cell-input-hsV_b1Op.js} +1 -1
  45. package/dist/assets/{outline-panel-C4P3wA7Z.js → outline-panel-C3jvSnZF.js} +1 -1
  46. package/dist/assets/{packages-panel-DnrjjQDF.js → packages-panel-0_Z5vM7i.js} +1 -1
  47. package/dist/assets/{panels-BCRqI88j.js → panels-uc8QhzpO.js} +1 -1
  48. package/dist/assets/{process-output-e_aMblRk.js → process-output-CsvKn_Mr.js} +1 -1
  49. package/dist/assets/{readonly-python-code-CVgh88Tn.js → readonly-python-code-oFCRG7Wt.js} +1 -1
  50. package/dist/assets/{run-page-C-ySBXLo.js → run-page-DKCqiq_f.js} +1 -1
  51. package/dist/assets/{scratchpad-panel-C5Pogi1P.js → scratchpad-panel-ChHLgDv_.js} +1 -1
  52. package/dist/assets/{session-panel-DEsnZWks.js → session-panel-CPKKt31q.js} +1 -1
  53. package/dist/assets/{snippets-panel-DQgE3W8I.js → snippets-panel-CDqEDwpY.js} +1 -1
  54. package/dist/assets/{spec-CBbUxOvL.js → spec-CFx2bitO.js} +1 -1
  55. package/dist/assets/{state-pGNeffyB.js → state-BBVlYaRC.js} +1 -1
  56. package/dist/assets/{state-CV8Wy3e4.js → state-C93JW11U.js} +1 -1
  57. package/dist/assets/{textarea-DqzNK0s9.js → textarea-DJEKmYtw.js} +1 -1
  58. package/dist/assets/{tracing-BUFVOmZw.js → tracing-CLWi5jD3.js} +1 -1
  59. package/dist/assets/{tracing-panel-BsLloPWd.js → tracing-panel-ksnvVrMH.js} +2 -2
  60. package/dist/assets/{useAddCell-cC7JUC0q.js → useAddCell-mJ1PkF-E.js} +1 -1
  61. package/dist/assets/{useCellActionButton-BiYBXHfb.js → useCellActionButton-4HWj1rt3.js} +1 -1
  62. package/dist/assets/{useDeleteCell-D2p4Dz0U.js → useDeleteCell-B0OAS0ly.js} +1 -1
  63. package/dist/assets/{useDependencyPanelTab-c5-eXlcr.js → useDependencyPanelTab-BuZ0fgAR.js} +1 -1
  64. package/dist/assets/useLifecycle-N3bfh_O1.js +1 -0
  65. package/dist/assets/useNotebookActions-DuHUqtII.js +1 -0
  66. package/dist/assets/{useRunCells-DgBY-vh9.js → useRunCells-Du76UV1R.js} +1 -1
  67. package/dist/assets/{useSplitCell-SS0kKwVk.js → useSplitCell-CeL7eJq1.js} +1 -1
  68. package/dist/index.html +25 -25
  69. package/package.json +1 -1
  70. package/src/__mocks__/common.ts +4 -4
  71. package/src/components/chat/acp/agent-panel.tsx +2 -2
  72. package/src/components/data-table/__tests__/columns.test.tsx +7 -7
  73. package/src/components/data-table/cell-hover-template/types.ts +1 -1
  74. package/src/components/data-table/cell-hover-text/types.ts +1 -1
  75. package/src/components/data-table/cell-selection/__tests__/feature.test.ts +1 -1
  76. package/src/components/data-table/cell-selection/types.ts +1 -1
  77. package/src/components/data-table/cell-styling/types.ts +1 -1
  78. package/src/components/data-table/charts/chart-spec/altair-generator.ts +2 -2
  79. package/src/components/data-table/column-formatting/types.ts +2 -2
  80. package/src/components/data-table/column-summary/legacy-chart-spec.ts +1 -1
  81. package/src/components/data-table/column-wrapping/types.ts +1 -1
  82. package/src/components/data-table/copy-column/types.ts +1 -1
  83. package/src/components/data-table/data-table.tsx +12 -12
  84. package/src/components/data-table/focus-row/types.ts +1 -1
  85. package/src/components/data-table/loading-table.tsx +1 -1
  86. package/src/components/data-table/range-focus/__tests__/atoms.test.ts +2 -2
  87. package/src/components/data-table/range-focus/atoms.ts +2 -2
  88. package/src/components/dependency-graph/dependency-graph-tree.tsx +1 -1
  89. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +1 -1
  90. package/src/components/editor/actions/pair-with-agent-modal.tsx +142 -0
  91. package/src/components/editor/actions/useNotebookActions.tsx +10 -0
  92. package/src/components/editor/ai/ai-completion-editor.tsx +1 -1
  93. package/src/components/editor/app-container.tsx +1 -1
  94. package/src/components/editor/chrome/panels/empty-state.tsx +1 -0
  95. package/src/components/editor/controls/keyboard-shortcuts.tsx +1 -1
  96. package/src/components/editor/navigation/__tests__/navigation.test.ts +1 -1
  97. package/src/components/editor/navigation/navigation.ts +1 -1
  98. package/src/components/editor/notebook-cell.tsx +1 -1
  99. package/src/components/editor/output/JsonOutput.tsx +4 -4
  100. package/src/components/editor/output/ansi-reduce.ts +2 -2
  101. package/src/components/editor/output/console/ConsoleOutput.tsx +1 -1
  102. package/src/components/editor/renderers/cells-renderer.tsx +1 -1
  103. package/src/components/editor/renderers/grid-layout/grid-layout.tsx +1 -1
  104. package/src/components/editor/renderers/plugins.ts +1 -1
  105. package/src/components/editor/renderers/slides-layout/types.ts +2 -2
  106. package/src/components/editor/renderers/vertical-layout/__tests__/useFocusFirstEditor.test.ts +2 -2
  107. package/src/components/editor/renderers/vertical-layout/__tests__/vertical-layout.test.ts +1 -1
  108. package/src/components/find-replace/find-replace.tsx +3 -1
  109. package/src/components/forms/form.tsx +1 -1
  110. package/src/components/forms/options.ts +1 -1
  111. package/src/components/static-html/static-banner.tsx +2 -2
  112. package/src/components/terminal/terminal.tsx +4 -4
  113. package/src/components/ui/button.tsx +1 -1
  114. package/src/components/ui/command.tsx +1 -1
  115. package/src/core/ai/context/providers/__tests__/datasource.test.ts +1 -1
  116. package/src/core/ai/context/providers/__tests__/error.test.ts +1 -1
  117. package/src/core/ai/context/providers/__tests__/variable.test.ts +1 -1
  118. package/src/core/ai/context/registry.ts +2 -2
  119. package/src/core/ai/tools/registry.ts +1 -1
  120. package/src/core/cells/__tests__/cells.test.ts +2 -2
  121. package/src/core/cells/__tests__/scrollCellIntoView.test.ts +1 -1
  122. package/src/core/cells/__tests__/session.test.ts +1 -1
  123. package/src/core/cells/__tests__/utils.test.ts +1 -1
  124. package/src/core/cells/cells.ts +1 -1
  125. package/src/core/cells/ids.ts +1 -1
  126. package/src/core/codemirror/ai/request.ts +1 -1
  127. package/src/core/codemirror/copilot/__tests__/language-server.test.ts +1 -1
  128. package/src/core/codemirror/copilot/__tests__/transport.test.ts +1 -1
  129. package/src/core/codemirror/copilot/language-server.ts +1 -1
  130. package/src/core/codemirror/copilot/types.ts +1 -1
  131. package/src/core/codemirror/facet.ts +1 -1
  132. package/src/core/codemirror/language/__tests__/sql.test.ts +4 -4
  133. package/src/core/codemirror/language/languages/sql/completion-builder.ts +1 -1
  134. package/src/core/codemirror/language/metadata.ts +1 -1
  135. package/src/core/codemirror/language/types.ts +1 -1
  136. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +1 -1
  137. package/src/core/codemirror/lsp/notebook-lsp.ts +1 -1
  138. package/src/core/codemirror/misc/__tests__/dnd.test.ts +1 -1
  139. package/src/core/codemirror/rtc/loro/awareness.ts +1 -1
  140. package/src/core/config/feature-flag.tsx +1 -1
  141. package/src/core/dom/outline.ts +1 -1
  142. package/src/core/export/__tests__/hooks.test.ts +1 -1
  143. package/src/core/hotkeys/__tests__/hotkeys.test.ts +1 -1
  144. package/src/core/hotkeys/shortcuts.ts +1 -1
  145. package/src/core/islands/__tests__/bridge.test.ts +2 -2
  146. package/src/core/islands/bridge.ts +2 -2
  147. package/src/core/islands/components/output-wrapper.tsx +1 -1
  148. package/src/core/islands/parse.ts +1 -1
  149. package/src/core/lsp/__tests__/transport.test.ts +1 -1
  150. package/src/core/network/DeferredRequestRegistry.ts +1 -1
  151. package/src/core/network/__tests__/requests-network.test.ts +1 -1
  152. package/src/core/network/api.ts +2 -2
  153. package/src/core/network/requests-lazy.ts +1 -1
  154. package/src/core/network/requests-toasting.tsx +1 -1
  155. package/src/core/static/files.ts +1 -1
  156. package/src/core/vscode/vscode-bindings.ts +1 -1
  157. package/src/core/wasm/bridge.ts +3 -3
  158. package/src/core/wasm/worker/tracer.ts +1 -1
  159. package/src/core/websocket/useWebSocket.tsx +2 -2
  160. package/src/css/globals.css +37 -61
  161. package/src/custom.d.ts +1 -1
  162. package/src/hooks/__tests__/useDuplicateShortcuts.test.ts +2 -2
  163. package/src/hooks/debug.ts +3 -3
  164. package/src/hooks/useDebounce.ts +1 -1
  165. package/src/hooks/useEventListener.ts +1 -1
  166. package/src/hooks/useHotkey.ts +1 -1
  167. package/src/hooks/useLifecycle.ts +2 -2
  168. package/src/hooks/useNonce.ts +1 -1
  169. package/src/hooks/useResizeObserver.ts +2 -2
  170. package/src/main.tsx +1 -1
  171. package/src/plugins/core/RenderHTML.tsx +3 -3
  172. package/src/plugins/core/__test__/registerReactComponent.test.ts +1 -1
  173. package/src/plugins/core/registerReactComponent.tsx +4 -4
  174. package/src/plugins/core/rpc.ts +1 -1
  175. package/src/plugins/impl/DataTablePlugin.tsx +1 -1
  176. package/src/plugins/impl/FileBrowserPlugin.tsx +1 -1
  177. package/src/plugins/impl/FormPlugin.tsx +1 -1
  178. package/src/plugins/impl/__tests__/MatrixPlugin.test.tsx +1 -1
  179. package/src/plugins/impl/anywidget/AnyWidgetPlugin.tsx +1 -1
  180. package/src/plugins/impl/anywidget/model.ts +1 -1
  181. package/src/plugins/impl/anywidget/types.ts +2 -2
  182. package/src/plugins/impl/anywidget/widget-binding.ts +1 -1
  183. package/src/plugins/impl/chat/ChatPlugin.tsx +1 -1
  184. package/src/plugins/impl/chat/chat-ui.tsx +1 -1
  185. package/src/plugins/impl/data-editor/glide-data-editor.tsx +1 -1
  186. package/src/plugins/impl/data-explorer/ConnectedDataExplorerComponent.tsx +2 -2
  187. package/src/plugins/impl/data-explorer/components/query-form.tsx +1 -1
  188. package/src/plugins/impl/data-explorer/functions/function.ts +1 -1
  189. package/src/plugins/impl/data-explorer/queries/types.ts +1 -1
  190. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +1 -1
  191. package/src/plugins/impl/data-frames/forms/renderers.tsx +1 -1
  192. package/src/plugins/impl/data-frames/utils/operators.ts +1 -1
  193. package/src/plugins/impl/matplotlib/MatplotlibPlugin.tsx +1 -1
  194. package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +1 -1
  195. package/src/plugins/impl/panel/PanelPlugin.tsx +2 -2
  196. package/src/plugins/impl/plotly/Plot.tsx +3 -3
  197. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +62 -44
  198. package/src/plugins/impl/plotly/__tests__/PlotlyPlugin.test.tsx +114 -0
  199. package/src/plugins/impl/plotly/__tests__/selection.test.ts +158 -196
  200. package/src/plugins/impl/plotly/selection.ts +274 -56
  201. package/src/plugins/impl/vega/batched.ts +1 -1
  202. package/src/plugins/impl/vega/make-selectable.ts +1 -1
  203. package/src/plugins/impl/vega/types.ts +1 -1
  204. package/src/plugins/layout/DownloadPlugin.tsx +1 -1
  205. package/src/plugins/layout/LazyPlugin.tsx +1 -1
  206. package/src/plugins/layout/RoutesPlugin.tsx +1 -1
  207. package/src/plugins/layout/mermaid/mermaid.tsx +1 -1
  208. package/src/plugins/plugins.ts +1 -1
  209. package/src/stories/data-explorer.stories.tsx +1 -1
  210. package/src/stories/dataframe.stories.tsx +1 -1
  211. package/src/stories/editor.stories.tsx +1 -1
  212. package/src/stories/select.stories.tsx +1 -1
  213. package/src/stories/switchable-multi-select.stories.tsx +1 -1
  214. package/src/utils/Logger.ts +1 -1
  215. package/src/utils/__tests__/arrays.test.ts +1 -1
  216. package/src/utils/__tests__/blob.test.ts +1 -1
  217. package/src/utils/__tests__/dates.test.ts +1 -1
  218. package/src/utils/__tests__/errors.test.ts +1 -1
  219. package/src/utils/__tests__/objects.test.ts +3 -3
  220. package/src/utils/__tests__/waitForWs.test.ts +1 -1
  221. package/src/utils/arrays.ts +1 -1
  222. package/src/utils/assertNever.ts +1 -1
  223. package/src/utils/batch-requests.ts +2 -2
  224. package/src/utils/createReducer.ts +2 -2
  225. package/src/utils/id-tree.tsx +2 -2
  226. package/src/utils/idle.ts +1 -1
  227. package/src/utils/invariant.ts +1 -2
  228. package/src/utils/maps.ts +1 -1
  229. package/src/utils/math.ts +0 -1
  230. package/src/utils/multi-map.ts +1 -1
  231. package/src/utils/objects.ts +1 -1
  232. package/src/utils/once.ts +2 -2
  233. package/src/utils/staticImplements.ts +1 -1
  234. package/src/utils/storage/jotai.ts +1 -1
  235. package/src/utils/tracer.ts +2 -2
  236. package/dist/assets/glide-data-editor-CDqunAkw.js +0 -132
  237. package/dist/assets/index-KI45dku7.js +0 -35
  238. package/dist/assets/useLifecycle-D202VvPd.js +0 -1
  239. package/dist/assets/useNotebookActions-Bb4xxjuJ.js +0 -1
@@ -58,7 +58,7 @@ describe("isCustomMarimoElement", () => {
58
58
  });
59
59
 
60
60
  describe("connectedCallback - light DOM nesting detection", () => {
61
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
+ // oxlint-disable-next-line typescript/no-explicit-any
62
62
  let createRootSpy: any;
63
63
  const mockRoot = {
64
64
  render: vi.fn(),
@@ -1,6 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
- /* eslint-disable unicorn/prefer-spread */
3
+ /* oxlint-disable unicorn/prefer-spread */
4
4
  /**
5
5
  * WebComponent Factory for React Components
6
6
  *
@@ -88,7 +88,7 @@ interface PluginSlotProps<T> {
88
88
 
89
89
  /* Handles synchronization of value on behalf of the component */
90
90
 
91
- // eslint-disable-next-line react/function-component-definition
91
+ // oxlint-disable-next-line react/function-component-definition
92
92
  function PluginSlotInternal<T>(
93
93
  { hostElement, plugin, children, getInitialValue }: PluginSlotProps<T>,
94
94
  ref: React.Ref<PluginSlotHandle>,
@@ -231,7 +231,7 @@ function PluginSlotInternal<T>(
231
231
  }
232
232
 
233
233
  return methods;
234
- // eslint-disable-next-line react-hooks/exhaustive-deps
234
+ // oxlint-disable-next-line react-hooks/exhaustive-deps
235
235
  }, [plugin.functions, hostElement, resetNonce]);
236
236
 
237
237
  // If we failed to parse the initial value, render an error
@@ -265,7 +265,7 @@ function PluginSlotInternal<T>(
265
265
  }
266
266
 
267
267
  const PluginSlot: React.ForwardRefExoticComponent<
268
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
268
+ // oxlint-disable-next-line typescript/no-explicit-any
269
269
  PluginSlotProps<any> & React.RefAttributes<PluginSlotHandle>
270
270
  > = React.forwardRef(PluginSlotInternal);
271
271
 
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* oxlint-disable typescript/no-explicit-any */
3
3
 
4
4
  import type { ZodType } from "zod";
5
5
 
@@ -205,7 +205,7 @@ interface Data<T> {
205
205
  cellHoverTexts?: Record<string, Record<string, string | null>> | null;
206
206
  }
207
207
 
208
- // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
208
+ // oxlint-disable-next-line typescript/consistent-type-definitions
209
209
  type DataTableFunctions = {
210
210
  download_as: DownloadAsArgs;
211
211
  get_column_summaries: <T>(opts: {}) => Promise<ColumnSummaries<T>>;
@@ -62,7 +62,7 @@ interface FileInfo {
62
62
  is_directory: boolean;
63
63
  }
64
64
 
65
- // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
65
+ // oxlint-disable-next-line typescript/consistent-type-definitions
66
66
  type PluginFunctions = {
67
67
  list_directory: (req: { path: string }) => Promise<{
68
68
  files: FileInfo[];
@@ -44,7 +44,7 @@ interface Data {
44
44
  * is clicked, this plugin assumes the value of the associated plugin.
45
45
  */
46
46
 
47
- // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
47
+ // oxlint-disable-next-line typescript/consistent-type-definitions
48
48
  type Functions = {
49
49
  validate: (req: { value?: unknown }) => Promise<string | undefined | null>;
50
50
  };
@@ -52,7 +52,7 @@ beforeEach(() => {
52
52
 
53
53
  // jsdom's PointerEvent doesn't properly inherit MouseEvent properties
54
54
  // like clientX. Polyfill it so fireEvent.pointerDown/Move/Up work.
55
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
+ // oxlint-disable-next-line typescript/no-explicit-any
56
56
  (globalThis as any).PointerEvent = class PointerEvent extends MouseEvent {
57
57
  readonly pointerId: number;
58
58
  constructor(type: string, init: PointerEventInit = {}) {
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* oxlint-disable typescript/no-explicit-any */
3
3
 
4
4
  import type { AnyWidget } from "@anywidget/types";
5
5
  import { useEffect, useRef } from "react";
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* oxlint-disable typescript/no-explicit-any */
3
3
 
4
4
  import type { AnyModel } from "@anywidget/types";
5
5
  import { debounce } from "lodash-es";
@@ -2,7 +2,7 @@
2
2
  import type { Base64String } from "@/utils/json/base64";
3
3
  import type { TypedString } from "@/utils/typed";
4
4
 
5
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
+ // oxlint-disable-next-line typescript/no-explicit-any
6
6
  export type EventHandler = (...args: any[]) => void;
7
7
 
8
8
  /**
@@ -13,7 +13,7 @@ export type WidgetModelId = TypedString<"WidgetModelId">;
13
13
  /**
14
14
  * AnyWidget model state with buffers.
15
15
  */
16
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ // oxlint-disable-next-line typescript/no-explicit-any
17
17
  export type ModelState = Record<string | number, any>;
18
18
 
19
19
  /**
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* oxlint-disable typescript/no-explicit-any */
3
3
 
4
4
  import type { AnyWidget, Experimental } from "@anywidget/types";
5
5
  import { asRemoteURL } from "@/core/runtime/config";
@@ -13,7 +13,7 @@ const LazyChatbot = React.lazy(() =>
13
13
  import("./chat-ui").then((m) => ({ default: m.Chatbot })),
14
14
  );
15
15
 
16
- // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
16
+ // oxlint-disable-next-line typescript/consistent-type-definitions
17
17
  export type PluginFunctions = {
18
18
  get_chat_history: (req: {}) => Promise<{ messages: UIMessage[] }>;
19
19
  delete_chat_history: (req: {}) => Promise<null>;
@@ -469,7 +469,7 @@ export const Chatbot: React.FC<Props> = (props) => {
469
469
  resetInput();
470
470
  }}
471
471
  ref={formRef}
472
- // biome-ignore lint/a11y/useSemanticElements: inert is used to disable the entire form
472
+ // oxlint-ignore-next-line -- inert is used to disable the entire form
473
473
  inert={props.disabled || undefined}
474
474
  className={cn(
475
475
  "flex w-full border-t border-(--slate-6) px-2 py-1 items-center",
@@ -227,7 +227,7 @@ export const GlideDataEditor = <T,>({
227
227
 
228
228
  // Force re-render to update the total rows
229
229
  rerender();
230
- // eslint-disable-next-line react-hooks/exhaustive-deps
230
+ // oxlint-disable-next-line react-hooks/exhaustive-deps
231
231
  }, [data.length]);
232
232
 
233
233
  const getCellContent = useCallback(
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-base-to-string */
2
+ /* oxlint-disable typescript/no-base-to-string */
3
3
  import * as cql from "compassql/build/src";
4
4
  import { createStore, Provider, useAtomValue } from "jotai";
5
5
  import { ListFilterIcon } from "lucide-react";
@@ -268,7 +268,7 @@ const HorizontalCarouselItem = ({
268
268
  );
269
269
  };
270
270
  // Make the plot responsive
271
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
271
+ // oxlint-disable-next-line typescript/no-explicit-any
272
272
  function makeResponsive(spec: any) {
273
273
  // NOTE: for row/column, this applies to the inner plot
274
274
  // so we tend to overflow due to the legends,
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-base-to-string */
2
+ /* oxlint-disable typescript/no-base-to-string */
3
3
 
4
4
  import { ExpandedType } from "compassql/build/src/query/expandedtype";
5
5
  import { PrimitiveType, type Schema } from "compassql/build/src/schema";
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-base-to-string */
2
+ /* oxlint-disable typescript/no-base-to-string */
3
3
  import type { FieldQuery } from "compassql/build/src/query/encoding";
4
4
  import { type FieldFunction, isAggregateOp, type TimeUnitOp } from "./types";
5
5
 
@@ -28,7 +28,7 @@ export interface Result {
28
28
  limit: number;
29
29
  }
30
30
 
31
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-redundant-type-constituents
31
+ // oxlint-disable-next-line typescript/no-explicit-any, typescript/no-redundant-type-constituents
32
32
  export type TopLevelFacetedUnitSpec = TopLevel<FacetedUnitSpec<any, any>> & {
33
33
  data: NamedData;
34
34
  };
@@ -54,7 +54,7 @@ interface Data {
54
54
  lazy: boolean;
55
55
  }
56
56
 
57
- // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
57
+ // oxlint-disable-next-line typescript/consistent-type-definitions
58
58
  type PluginFunctions = {
59
59
  get_dataframe: (req: {}) => Promise<{
60
60
  url: string;
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* oxlint-disable typescript/no-explicit-any */
3
3
 
4
4
  import React, { useEffect } from "react";
5
5
  import {
@@ -194,7 +194,7 @@ export function isConditionValueValid(operator: string, value: unknown) {
194
194
  return possibleSchemas.some((schema) => schema.safeParse(value).success);
195
195
  }
196
196
 
197
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
197
+ // oxlint-disable-next-line typescript/no-explicit-any
198
198
  const safeGet = (obj: any, key: string): [z.ZodType] | [] => {
199
199
  if (obj[key]) {
200
200
  return obj[key];
@@ -57,7 +57,7 @@ const MatplotlibComponent = (props: MatplotlibState) => {
57
57
  controller.abort();
58
58
  instance.current = null;
59
59
  };
60
- // eslint-disable-next-line react-hooks/exhaustive-deps
60
+ // oxlint-disable-next-line react-hooks/exhaustive-deps
61
61
  }, []);
62
62
 
63
63
  // No dependency array: intentionally syncs all props into the imperative
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* oxlint-disable typescript/no-explicit-any */
3
3
 
4
4
  import { useCallback, useEffect, useRef } from "react";
5
5
  import { z } from "zod";
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* oxlint-disable typescript/no-explicit-any */
3
3
 
4
4
  import { useCallback, useEffect, useRef, useState } from "react";
5
5
  import { z } from "zod";
@@ -74,7 +74,7 @@ interface PanelData {
74
74
 
75
75
  type T = Record<string, unknown>;
76
76
 
77
- // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
77
+ // oxlint-disable-next-line typescript/consistent-type-definitions
78
78
  type PluginFunctions = {
79
79
  send_to_widget: <T>(req: {
80
80
  message?: unknown;
@@ -4,7 +4,7 @@ import type * as PlotlyTypes from "plotly.js";
4
4
  // Import the pre-built dist bundle, not the source entry point.
5
5
  // The source entry point requires Node.js polyfills (e.g. `buffer/`)
6
6
  // that are unavailable in the browser/bundler environment.
7
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
7
+ // oxlint-disable-next-line typescript/ban-ts-comment
8
8
  // @ts-expect-error — no type declarations for dist path, we use PlotlyTypes above
9
9
  import Plotly from "plotly.js/dist/plotly";
10
10
  import { useEffect, useRef } from "react";
@@ -107,7 +107,7 @@ export const Plot = (props: PlotProps) => {
107
107
 
108
108
  const plotlyEl = el as unknown as PlotlyElement;
109
109
 
110
- // eslint-disable-next-line @typescript-eslint/ban-types -- Plotly's event API uses generic function references
110
+ // oxlint-disable-next-line typescript/ban-types -- Plotly's event API uses generic function references
111
111
  const attached: {
112
112
  plotlyName: string;
113
113
  handler: (...args: never[]) => void;
@@ -131,7 +131,7 @@ export const Plot = (props: PlotProps) => {
131
131
  }
132
132
  };
133
133
  // Re-sync whenever any event handler prop changes
134
- // eslint-disable-next-line react-hooks/exhaustive-deps
134
+ // oxlint-disable-next-line react-hooks/exhaustive-deps
135
135
  },
136
136
  EVENT_NAMES.map((name) => props[propName(name)]),
137
137
  );
@@ -14,11 +14,16 @@ import useEvent from "react-use-event-hook";
14
14
  import { useDeepCompareMemoize } from "@/hooks/useDeepCompareMemoize";
15
15
  import { useScript } from "@/hooks/useScript";
16
16
  import { Arrays } from "@/utils/arrays";
17
- import { Objects } from "@/utils/objects";
18
17
  import {
19
- extractClickSelection,
20
18
  extractIndices,
21
19
  extractPoints,
20
+ extractSunburstPoints,
21
+ extractTreemapPoints,
22
+ hasPureLineTrace,
23
+ lineSelectionButtons,
24
+ type ModeBarButton,
25
+ mergeModeBarButtonsToAdd,
26
+ shouldHandleClickSelection,
22
27
  } from "./selection";
23
28
  import { usePlotlyLayout } from "./usePlotlyLayout";
24
29
 
@@ -35,6 +40,10 @@ type T =
35
40
  x?: number[];
36
41
  y?: number[];
37
42
  };
43
+ lasso?: {
44
+ x?: unknown[];
45
+ y?: unknown[];
46
+ };
38
47
  // These are kept in the state to persist selections across re-renders
39
48
  // on the frontend, but likely not used in the backend.
40
49
  selections?: unknown[];
@@ -77,23 +86,6 @@ const LazyPlot = lazy(() =>
77
86
  import("./Plot").then((mod) => ({ default: mod.Plot })),
78
87
  );
79
88
 
80
- const SUNBURST_DATA_KEYS: (keyof Plotly.SunburstPlotDatum)[] = [
81
- "color",
82
- "curveNumber",
83
- "entry",
84
- "hovertext",
85
- "id",
86
- "label",
87
- "parent",
88
- "percentEntry",
89
- "percentParent",
90
- "percentRoot",
91
- "pointNumber",
92
- "root",
93
- "value",
94
- ] as const;
95
- const TREE_MAP_DATA_KEYS = SUNBURST_DATA_KEYS;
96
-
97
89
  export const PlotlyComponent = memo(
98
90
  ({ figure: originalFigure, value, setValue, config }: PlotlyPluginProps) => {
99
91
  // Used for rendering LaTeX. TODO: Serve this library from Marimo
@@ -102,7 +94,7 @@ export const PlotlyComponent = memo(
102
94
  );
103
95
  const isScriptLoaded = scriptStatus === "ready";
104
96
 
105
- const { figure, layout, handleReset } = usePlotlyLayout({
97
+ const { figure, layout, setLayout, handleReset } = usePlotlyLayout({
106
98
  originalFigure,
107
99
  initialValue: value,
108
100
  isScriptLoaded,
@@ -112,31 +104,48 @@ export const PlotlyComponent = memo(
112
104
  handleReset();
113
105
  setValue({});
114
106
  });
107
+ const handleSetDragmode = useEvent(
108
+ (dragmode: Plotly.Layout["dragmode"]) => {
109
+ setLayout((prev) => ({ ...prev, dragmode }));
110
+ setValue((prev) => ({ ...prev, dragmode }));
111
+ },
112
+ );
115
113
 
116
114
  const configMemo = useDeepCompareMemoize(config);
117
115
  const plotlyConfig = useMemo((): Partial<Plotly.Config> => {
118
- return {
119
- displaylogo: false,
120
- modeBarButtonsToAdd: [
121
- // Custom button to reset the state
122
- {
123
- name: "reset",
124
- title: "Reset state",
125
- icon: {
126
- svg: `
116
+ const hasPureLine = hasPureLineTrace(figure.data);
117
+ const defaultButtons: ModeBarButton[] = [
118
+ // Custom button to reset the state
119
+ {
120
+ name: "reset",
121
+ title: "Reset state",
122
+ icon: {
123
+ svg: `
127
124
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
128
125
  stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-rotate-ccw">
129
126
  <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
130
127
  <path d="M3 3v5h5" />
131
128
  </svg>`,
132
- },
133
- click: handleResetWithClear,
134
129
  },
135
- ],
130
+ click: handleResetWithClear,
131
+ },
132
+ ];
133
+ if (hasPureLine) {
134
+ defaultButtons.push(...lineSelectionButtons(handleSetDragmode));
135
+ }
136
+
137
+ return {
138
+ displaylogo: false,
136
139
  // Prioritize user's config
137
140
  ...configMemo,
141
+ modeBarButtonsToAdd: mergeModeBarButtonsToAdd(
142
+ defaultButtons,
143
+ configMemo.modeBarButtonsToAdd as
144
+ | readonly ModeBarButton[]
145
+ | undefined,
146
+ ),
138
147
  };
139
- }, [handleResetWithClear, configMemo]);
148
+ }, [handleResetWithClear, handleSetDragmode, configMemo, figure.data]);
140
149
 
141
150
  return (
142
151
  <LazyPlot
@@ -171,6 +180,7 @@ export const PlotlyComponent = memo(
171
180
  points: Arrays.EMPTY,
172
181
  indices: Arrays.EMPTY,
173
182
  range: undefined,
183
+ lasso: undefined,
174
184
  };
175
185
  });
176
186
  })}
@@ -181,9 +191,7 @@ export const PlotlyComponent = memo(
181
191
 
182
192
  setValue((prev) => ({
183
193
  ...prev,
184
- points: evt.points.map((point) =>
185
- Objects.pick(point, TREE_MAP_DATA_KEYS),
186
- ),
194
+ points: extractTreemapPoints(evt.points),
187
195
  }));
188
196
  })}
189
197
  onSunburstClick={useEvent((evt: Readonly<Plotly.PlotMouseEvent>) => {
@@ -193,9 +201,7 @@ export const PlotlyComponent = memo(
193
201
 
194
202
  setValue((prev) => ({
195
203
  ...prev,
196
- points: evt.points.map((point) =>
197
- Objects.pick(point, SUNBURST_DATA_KEYS),
198
- ),
204
+ points: extractSunburstPoints(evt.points),
199
205
  }));
200
206
  })}
201
207
  config={plotlyConfig}
@@ -203,13 +209,21 @@ export const PlotlyComponent = memo(
203
209
  if (!evt) {
204
210
  return;
205
211
  }
206
-
207
- const clickSelection = extractClickSelection(evt);
208
- if (!clickSelection) {
212
+ // Handle clicks for chart types where box/lasso selection
213
+ // is limited or unavailable (e.g. bar, heatmaps, histograms, pure line traces).
214
+ if (!shouldHandleClickSelection(evt.points)) {
209
215
  return;
210
216
  }
211
-
212
- setValue((prev) => ({ ...prev, ...clickSelection }));
217
+ const extractedPoints = extractPoints(evt.points);
218
+ const extractedIndices = extractIndices(evt.points);
219
+ setValue((prev) => ({
220
+ ...prev,
221
+ selections: Arrays.EMPTY,
222
+ range: undefined,
223
+ lasso: undefined,
224
+ points: extractedPoints,
225
+ indices: extractedIndices,
226
+ }));
213
227
  })}
214
228
  onSelected={useEvent((evt: Readonly<Plotly.PlotSelectionEvent>) => {
215
229
  if (!evt) {
@@ -223,6 +237,10 @@ export const PlotlyComponent = memo(
223
237
  points: extractPoints(evt.points),
224
238
  indices: extractIndices(evt.points),
225
239
  range: evt.range,
240
+ lasso:
241
+ "lassoPoints" in evt
242
+ ? (evt.lassoPoints as { x?: unknown[]; y?: unknown[] })
243
+ : undefined,
226
244
  }));
227
245
  })}
228
246
  className="w-full"
@@ -0,0 +1,114 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { act, render, waitFor } from "@testing-library/react";
4
+ import { Suspense } from "react";
5
+ import { describe, expect, it, vi } from "vitest";
6
+ import { SetupMocks } from "@/__mocks__/common";
7
+ import type { Setter } from "@/plugins/types";
8
+ import { PlotlyComponent } from "../PlotlyPlugin";
9
+
10
+ SetupMocks.resizeObserver();
11
+
12
+ type CapturedPlotProps = {
13
+ onClick?: (event: {
14
+ points: {
15
+ data?: { type?: string };
16
+ x?: string | number;
17
+ y?: string | number;
18
+ pointIndex?: number;
19
+ pointNumber?: number;
20
+ curveNumber?: number;
21
+ }[];
22
+ }) => void;
23
+ } | null;
24
+
25
+ let capturedPlotProps: CapturedPlotProps = null;
26
+
27
+ vi.mock("../Plot", () => ({
28
+ Plot: (props: CapturedPlotProps) => {
29
+ capturedPlotProps = props;
30
+ return <div data-testid="plotly-mock" />;
31
+ },
32
+ }));
33
+
34
+ vi.mock("../usePlotlyLayout", () => ({
35
+ usePlotlyLayout: ({
36
+ originalFigure,
37
+ }: {
38
+ originalFigure: {
39
+ data: unknown[];
40
+ layout: Record<string, unknown>;
41
+ frames: unknown[] | null;
42
+ };
43
+ }) => ({
44
+ figure: originalFigure,
45
+ layout: originalFigure.layout,
46
+ handleReset: vi.fn(),
47
+ }),
48
+ }));
49
+
50
+ vi.mock("@/hooks/useScript", () => ({
51
+ useScript: () => "ready",
52
+ }));
53
+
54
+ vi.mock("react-use-event-hook", () => ({
55
+ default: <T,>(callback: T) => callback,
56
+ }));
57
+
58
+ describe("PlotlyPlugin", () => {
59
+ it("clicking a bar selects that bar", async () => {
60
+ const setValue = vi.fn<Setter<unknown>>();
61
+
62
+ render(
63
+ <Suspense fallback={null}>
64
+ <PlotlyComponent
65
+ figure={{
66
+ data: [{ type: "bar" }],
67
+ layout: {},
68
+ frames: null,
69
+ }}
70
+ value={undefined}
71
+ setValue={setValue}
72
+ host={document.createElement("div")}
73
+ config={{}}
74
+ />
75
+ </Suspense>,
76
+ );
77
+
78
+ await waitFor(() => {
79
+ expect(capturedPlotProps).not.toBeNull();
80
+ });
81
+
82
+ act(() => {
83
+ capturedPlotProps?.onClick?.({
84
+ points: [
85
+ {
86
+ data: { type: "bar" },
87
+ x: "Feb",
88
+ y: 18,
89
+ pointIndex: 1,
90
+ pointNumber: 1,
91
+ curveNumber: 0,
92
+ },
93
+ ],
94
+ });
95
+ });
96
+
97
+ expect(setValue).toHaveBeenCalledTimes(1);
98
+ const updater = setValue.mock.calls[0][0] as (value: unknown) => unknown;
99
+ expect(updater({})).toEqual({
100
+ selections: [],
101
+ points: [
102
+ {
103
+ x: "Feb",
104
+ y: 18,
105
+ curveNumber: 0,
106
+ pointNumber: 1,
107
+ pointIndex: 1,
108
+ },
109
+ ],
110
+ indices: [1],
111
+ range: undefined,
112
+ });
113
+ });
114
+ });