@marimo-team/frontend 0.24.1-dev99 → 0.24.2-dev129

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 (304) hide show
  1. package/dist/assets/{CellStatus-wvvZkEPY.js → CellStatus-LoTwk7fR.js} +1 -1
  2. package/dist/assets/{ConnectedDataExplorerComponent-Dkqk66Mv.js → ConnectedDataExplorerComponent-DW6cJ-Lr.js} +1 -1
  3. package/dist/assets/{ErrorBoundary-npvnLp9x.js → ErrorBoundary-CDVGFYfr.js} +1 -1
  4. package/dist/assets/JsonOutput-CzIGPEZQ.js +50 -0
  5. package/dist/assets/{LazyAnyLanguageCodeMirror-zSwE3dvU.js → LazyAnyLanguageCodeMirror-LboTfNDv.js} +2 -2
  6. package/dist/assets/{MarimoErrorOutput-CeUo5oka.js → MarimoErrorOutput-DqpoYOvw.js} +1 -1
  7. package/dist/assets/RenderHTML-DwhMAd9l.js +1 -0
  8. package/dist/assets/{RunButton-BaV8A-z4.js → RunButton-BlpbweyH.js} +1 -1
  9. package/dist/assets/{VisuallyHidden-SChAyKIQ.js → VisuallyHidden-CBMDmozt.js} +1 -1
  10. package/dist/assets/{add-cell-with-ai-DoLkfzYn.js → add-cell-with-ai-R-3DS79K.js} +1 -1
  11. package/dist/assets/{add-connection-dialog-C1IF1nR0.js → add-connection-dialog-BGfpw5lC.js} +1 -1
  12. package/dist/assets/{agent-panel-CG154QrU.js → agent-panel-Cgt_K0tD.js} +1 -1
  13. package/dist/assets/ai-model-dropdown-DCmiuk7x.js +3 -0
  14. package/dist/assets/alert-dialog-CA-2mBs3.js +11 -0
  15. package/dist/assets/any-language-editor-DflLjPSQ.js +1 -0
  16. package/dist/assets/{app-config-button-ktBH1pEB.js → app-config-button-DUJC6b6x.js} +1 -1
  17. package/dist/assets/badge-BSgtkC2e.js +1 -0
  18. package/dist/assets/{blob-DVtvZmWH.js → blob-B2d_dHwI.js} +1 -1
  19. package/dist/assets/button-Dh8EwhsF.js +1 -0
  20. package/dist/assets/{cache-panel-C7jsiqCa.js → cache-panel-DqgtC98s.js} +1 -1
  21. package/dist/assets/{capabilities-LWzb3E3M.js → capabilities-D8kPgMKr.js} +1 -1
  22. package/dist/assets/{cell-editor-DoDqaCZp.js → cell-editor-Dw09J9yD.js} +6 -6
  23. package/dist/assets/{cell-link-Dqqt6Rgs.js → cell-link-6burT2XF.js} +1 -1
  24. package/dist/assets/{cells-D4RwofRx.js → cells-Cp-G34Rz.js} +56 -56
  25. package/dist/assets/{chat-display-COmzHgx5.js → chat-display-Bu405iyc.js} +1 -1
  26. package/dist/assets/{chat-panel-B2tyEfGW.js → chat-panel-BlUwNY5j.js} +1 -1
  27. package/dist/assets/{chat-ui-B5bsr-7V.js → chat-ui-DGiVDzNh.js} +1 -1
  28. package/dist/assets/{circle--ysFeW9z.js → circle-ByJdIf5p.js} +1 -1
  29. package/dist/assets/{column-preview-CW5DPFvy.js → column-preview-riSXbYe_.js} +1 -1
  30. package/dist/assets/{command-palette-B9dyvMvJ.js → command-palette-CCVzJcyf.js} +1 -1
  31. package/dist/assets/{common-CC3tuCpi.js → common-CHR7w7aQ.js} +1 -1
  32. package/dist/assets/{components-D02ZZZMP.js → components-C7mWrmXr.js} +1 -1
  33. package/dist/assets/{components-CBlGIIAX.js → components-DUYCXngU.js} +1 -1
  34. package/dist/assets/config-B-r81uZ6.js +1 -0
  35. package/dist/assets/{config-D4frVGQ4.js → config-BlNM0caL.js} +1 -1
  36. package/dist/assets/{copy-Cg05mM3C.js → copy-DlEomWzI.js} +1 -1
  37. package/dist/assets/{copy-icon-CRxVZTJ9.js → copy-icon-z8fuTE3w.js} +1 -1
  38. package/dist/assets/{createReducer-Bq-nQJiK.js → createReducer-B_XmHROl.js} +1 -1
  39. package/dist/assets/{datasource-Do8f2hFf.js → datasource-DrODSIs0.js} +1 -1
  40. package/dist/assets/{dates-DK5JikJo.js → dates-B58T85Jq.js} +1 -1
  41. package/dist/assets/dependency-graph-panel-AY5BEVH2.js +5 -0
  42. package/dist/assets/{dist-7qdHLg-L.js → dist-B0RXffUm.js} +1 -1
  43. package/dist/assets/dist-B0qYy1Ye.js +1 -0
  44. package/dist/assets/{dist-B97dKQGP.js → dist-B8pdsUrS.js} +1 -1
  45. package/dist/assets/{dist-BcfF-rkl.js → dist-BF7Lrekv.js} +1 -1
  46. package/dist/assets/dist-BL8RjfvI.js +1 -0
  47. package/dist/assets/dist-BVZxge7j.js +1 -0
  48. package/dist/assets/{dist-fxnYzq-R.js → dist-BaRNSaca.js} +1 -1
  49. package/dist/assets/dist-Bk2yQtw4.js +1 -0
  50. package/dist/assets/dist-BsfiiKoy.js +1 -0
  51. package/dist/assets/dist-BskmVd3B.js +1 -0
  52. package/dist/assets/{dist-DL1Thauf.js → dist-Bsu3h9O7.js} +1 -1
  53. package/dist/assets/{dist-PIe1xcZo.js → dist-BtC9ym6k.js} +7 -7
  54. package/dist/assets/{dist-DeuWxYVk.js → dist-Bv0S1RlZ.js} +1 -1
  55. package/dist/assets/{dist-CidBzUqR.js → dist-C--ZICxQ.js} +1 -1
  56. package/dist/assets/dist-C-2fD3XY.js +1 -0
  57. package/dist/assets/{dist-DzAWvPVK.js → dist-CKUpxYGQ.js} +1 -1
  58. package/dist/assets/dist-CMFMfBm1.js +1 -0
  59. package/dist/assets/dist-CZNULd6Z.js +2 -0
  60. package/dist/assets/dist-CjFduPiC.js +1 -0
  61. package/dist/assets/{dist-DoAjHgMj.js → dist-CmImLjus.js} +1 -1
  62. package/dist/assets/{dist-BKx0MLbb.js → dist-Cq8NOszX.js} +1 -1
  63. package/dist/assets/{dist-DCc0VfiO.js → dist-Cx4BE7jC.js} +3 -3
  64. package/dist/assets/dist-D45ScydS.js +1 -0
  65. package/dist/assets/dist-D6dg87r7.js +1 -0
  66. package/dist/assets/dist-DEjfQLz0.js +1 -0
  67. package/dist/assets/{dist-BcYW-EJk.js → dist-DJOWOALB.js} +1 -1
  68. package/dist/assets/{dist-CxxZaSme.js → dist-DPoYlxSC.js} +1 -1
  69. package/dist/assets/dist-DR-Y-nl3.js +1 -0
  70. package/dist/assets/dist-Dahlp9JQ.js +1 -0
  71. package/dist/assets/{dist-DIkuvChK.js → dist-Db-HC93w.js} +1 -1
  72. package/dist/assets/{dist-DTM7BAUu.js → dist-DdOlZ6mj.js} +1 -1
  73. package/dist/assets/{dist-Dz_04liz.js → dist-DiYjQAhI.js} +1 -1
  74. package/dist/assets/{dist-BO5c5n_b.js → dist-DkPPv0FB.js} +1 -1
  75. package/dist/assets/{dist-DkCO0b-0.js → dist-DmGtPaVM.js} +1 -1
  76. package/dist/assets/{dist-CXmhxecl.js → dist-DnxYYyU7.js} +1 -1
  77. package/dist/assets/{dist-CO1Hfv5H.js → dist-Dw9YRsCU.js} +1 -1
  78. package/dist/assets/dist-Dwx3KdUP.js +1 -0
  79. package/dist/assets/{dist-BgL43w5r.js → dist-DzCQtGkt.js} +1 -1
  80. package/dist/assets/dist-JweaDt6P.js +1 -0
  81. package/dist/assets/{dist-Dbu5sPgR.js → dist-gELFCfHH.js} +1 -1
  82. package/dist/assets/dist-kGDJ0AWF.js +1 -0
  83. package/dist/assets/{dist-Cqm1W-Zm.js → dist-kaLvV_d4.js} +1 -1
  84. package/dist/assets/{dist-CEeRVpMD.js → dist-qvk3g06H.js} +1 -1
  85. package/dist/assets/dist-wCw2twuB.js +1 -0
  86. package/dist/assets/dist-wF42tUcr.js +1 -0
  87. package/dist/assets/dist-wY2yia-1.js +3 -0
  88. package/dist/assets/{documentation-panel-DvHjxlli.js → documentation-panel-CaJF7e-j.js} +1 -1
  89. package/dist/assets/{download-BP8MrprC.js → download-DMxOzI7b.js} +1 -1
  90. package/dist/assets/dropdown-menu-C40jM9o4.js +1 -0
  91. package/dist/assets/{edit-page-71cK-Nhe.js → edit-page-Vqd9NedM.js} +6 -6
  92. package/dist/assets/{error-banner-BYN8YUMe.js → error-banner-Dw5YY9wq.js} +1 -1
  93. package/dist/assets/{error-entries-DOZ1u97X.js → error-entries-Cv2m1yhc.js} +1 -1
  94. package/dist/assets/{error-panel-CINcf76Z.js → error-panel-Bhlvt6_H.js} +1 -1
  95. package/dist/assets/{es-BuMFDpR4.js → es-CrFhA96G.js} +1 -1
  96. package/dist/assets/{esm-Dw0vvSg2.js → esm-BHMOvJzM.js} +1 -1
  97. package/dist/assets/{esm-BGpfQNhD.js → esm-DmqQGMel.js} +1 -1
  98. package/dist/assets/file-explorer-panel-6HvNfCrJ.js +1 -0
  99. package/dist/assets/{file-icons-DgKj9mrV.js → file-icons-DdGYuADJ.js} +1 -1
  100. package/dist/assets/file-name-input-K4MKESI_.js +3 -0
  101. package/dist/assets/{floating-outline-CRXIsrPm.js → floating-outline-DaUHnl_e.js} +1 -1
  102. package/dist/assets/{formats-DSzGCKeO.js → formats-C6s96nu2.js} +1 -1
  103. package/dist/assets/{formatting-BJlT1s_3.js → formatting-BWZH2nBg.js} +1 -1
  104. package/dist/assets/{fullscreen-0EEPR7uc.js → fullscreen-BH2jz-F4.js} +5 -5
  105. package/dist/assets/{gallery-page-TqnFYECu.js → gallery-page-C3pBpHlY.js} +1 -1
  106. package/dist/assets/{glide-data-editor-DcY3nXI8.js → glide-data-editor-sICUMEhk.js} +1 -1
  107. package/dist/assets/{glide-utils-CR1sWLZU.js → glide-utils-UGsrRHYj.js} +1 -1
  108. package/dist/assets/home-page-BLd6rnbk.js +4 -0
  109. package/dist/assets/{html-to-image-DMn_7CCA.js → html-to-image-D6GUC5q6.js} +1 -1
  110. package/dist/assets/index-BGT7have.css +2 -0
  111. package/dist/assets/index-ipFYAeCF.js +29 -0
  112. package/dist/assets/{input-Daz6sk8l.js → input-DEbY281O.js} +2 -2
  113. package/dist/assets/{kiosk-mode-CzGt3mc2.js → kiosk-mode-mxgb5lWf.js} +1 -1
  114. package/dist/assets/{layout-KJMQADEj.js → layout-DWnrxIo2.js} +5 -5
  115. package/dist/assets/links-DLvOXyO_.js +1 -0
  116. package/dist/assets/{logs-panel-DFibPeCT.js → logs-panel-BGS2v3ba.js} +1 -1
  117. package/dist/assets/lua-1tNpM92n.js +1 -0
  118. package/dist/assets/{lua-CRIS5afH.js → lua-DXBxhmso.js} +1 -1
  119. package/dist/assets/{markdown-renderer-CdZX2MvM.js → markdown-renderer-BZKlbm2Q.js} +1 -1
  120. package/dist/assets/menu-items-BSRA2YI9.js +1 -0
  121. package/dist/assets/{mermaid-CeseGGnS.js → mermaid-l6lQkCib.js} +1 -1
  122. package/dist/assets/{name-cell-input-B-d5Jwh4.js → name-cell-input-BMCdK-el.js} +1 -1
  123. package/dist/assets/{numbers-DKurV_vq.js → numbers-Bc-r3jsC.js} +1 -1
  124. package/dist/assets/{outline-panel-D2Wk10hY.js → outline-panel-Dr5u73V6.js} +1 -1
  125. package/dist/assets/{packages-panel-CQsbxIlG.js → packages-panel-BdpRg9tX.js} +1 -1
  126. package/dist/assets/{pair-with-agent-modal-CNxmIMFM.js → pair-with-agent-modal-CbUFKJHP.js} +1 -1
  127. package/dist/assets/{panel-accordion-state-D6-FMXE2.js → panel-accordion-state-DjUTN7i5.js} +1 -1
  128. package/dist/assets/{panels-BgcK_4M7.js → panels-CWn0Yh1D.js} +1 -1
  129. package/dist/assets/process-output-Ck7-P_xp.js +1 -0
  130. package/dist/assets/{readonly-code-display-BvqLeUsJ.js → readonly-code-display--S2daDa6.js} +1 -1
  131. package/dist/assets/{readonly-python-code-GSN4D4sb.js → readonly-python-code-DpIyjHqY.js} +1 -1
  132. package/dist/assets/{renderShortcut-DK_OucLT.js → renderShortcut-X-CJUSM8.js} +1 -1
  133. package/dist/assets/{reveal-component-u9ED2diI.js → reveal-component-nZIAapoD.js} +1 -1
  134. package/dist/assets/{run-page-U5iuhyz8.js → run-page-9pl8qhQR.js} +1 -1
  135. package/dist/assets/{runs-BQTlv6Ja.js → runs-euHSzlw_.js} +1 -1
  136. package/dist/assets/{scratchpad-panel--YOR0kUB.js → scratchpad-panel-BleGt2KM.js} +1 -1
  137. package/dist/assets/{scroll-to-bottom-button-xua0e9rA.js → scroll-to-bottom-button-DufiYUD7.js} +1 -1
  138. package/dist/assets/{secrets-panel-CZPbFAZH.js → secrets-panel-D3BpDIgg.js} +1 -1
  139. package/dist/assets/select-nLt2y0Sw.js +1 -0
  140. package/dist/assets/{session-CEdta5_Q.js → session-Sz5nSFku.js} +1 -1
  141. package/dist/assets/session-panel-DRGPlL5J.js +1 -0
  142. package/dist/assets/{share-C2MPy_VX.js → share-CPtBiNgr.js} +1 -1
  143. package/dist/assets/{skeleton-CsceCAjw.js → skeleton-BKeh8hf3.js} +1 -1
  144. package/dist/assets/{snippets-panel-BxwHsPmW.js → snippets-panel-D5yy7kj0.js} +1 -1
  145. package/dist/assets/{spec-CUFquO6R.js → spec-DKsAmLTi.js} +1 -1
  146. package/dist/assets/{state-BqrF--O0.js → state-B6AklCzD.js} +1 -1
  147. package/dist/assets/{state-C2c3_VuY.js → state-B8XRqyFg.js} +1 -1
  148. package/dist/assets/{state-CHplO0zn.js → state-Di9TbuV9.js} +1 -1
  149. package/dist/assets/{strings-CpYReX2Q.js → strings-CReV1AYG.js} +1 -1
  150. package/dist/assets/{swiper-component-Bot7ehYH.js → swiper-component-5Kdi1-Gn.js} +1 -1
  151. package/dist/assets/{switch-CtH5Ct94.js → switch-DjXr9Y9D.js} +1 -1
  152. package/dist/assets/{tabs-c6mpccpH.js → tabs-Cy1qXLzH.js} +1 -1
  153. package/dist/assets/{terminal-C73iz1fU.js → terminal-CQAFGBfN.js} +1 -1
  154. package/dist/assets/{tooltip-Cwltdez8.js → tooltip-BG35uS_N.js} +1 -1
  155. package/dist/assets/{tooltip-D7dq6bnc.js → tooltip-BUtPzKB4.js} +1 -1
  156. package/dist/assets/{tracing-Dhq121dR.js → tracing-DNk3gmWv.js} +1 -1
  157. package/dist/assets/{tracing-panel-IKt1933_.js → tracing-panel-Yqazr6w_.js} +2 -2
  158. package/dist/assets/{tree-actions-DIfWonCA.js → tree-actions-CG5g7aUQ.js} +1 -1
  159. package/dist/assets/{useAddCell-BYrVaYfZ.js → useAddCell-DdB_uBif.js} +1 -1
  160. package/dist/assets/{useBoolean-ZU5StAbr.js → useBoolean-BXC4CItZ.js} +1 -1
  161. package/dist/assets/{useCellActionButton-DbXDs0MA.js → useCellActionButton-B31neI3m.js} +1 -1
  162. package/dist/assets/{useDebounce-Dulm61-t.js → useDebounce-DgpSQhrP.js} +1 -1
  163. package/dist/assets/{useDeleteCell-Wgcl3CRG.js → useDeleteCell-Bz49_cFj.js} +1 -1
  164. package/dist/assets/{useDependencyPanelTab-C5AU8GKL.js → useDependencyPanelTab-C_ps0r--.js} +1 -1
  165. package/dist/assets/{useEventListener-D27Dii_l.js → useEventListener-92uWqz-P.js} +1 -1
  166. package/dist/assets/{useIframeCapabilities-DEpTCh1Q.js → useIframeCapabilities-C7Di8f2y.js} +1 -1
  167. package/dist/assets/{useInstallPackage-u7d0wo79.js → useInstallPackage-DsD08SLK.js} +1 -1
  168. package/dist/assets/{useInterval-B1_J4wdT.js → useInterval-B4v7_zd0.js} +1 -1
  169. package/dist/assets/{useNotebookActions-FuMERtHq.js → useNotebookActions-CQtbk9CB.js} +2 -2
  170. package/dist/assets/{useRunCells-DTdMRbkE.js → useRunCells-CX7oW5zy.js} +1 -1
  171. package/dist/assets/{useSplitCell-2z0zEB8X.js → useSplitCell-Dy2_DmJR.js} +1 -1
  172. package/dist/assets/{useTheme-CF-zG9YH.js → useTheme-C-ri8BtY.js} +1 -1
  173. package/dist/assets/utils-D5Ywm7-q.js +1 -0
  174. package/dist/assets/{vega-component-BSXJcTJb.js → vega-component-C7TCzyaU.js} +1 -1
  175. package/dist/assets/write-secret-modal-D6zoZgLY.js +2 -0
  176. package/dist/index.html +73 -73
  177. package/package.json +26 -26
  178. package/src/components/ai/ai-provider-icon.tsx +2 -2
  179. package/src/components/ai/ai-utils.ts +1 -1
  180. package/src/components/app-config/ai-config.tsx +33 -37
  181. package/src/components/app-config/user-config-form.tsx +1 -1
  182. package/src/components/data-table/__tests__/column-explorer.test.tsx +64 -4
  183. package/src/components/data-table/__tests__/column-visibility-dropdown.test.tsx +137 -4
  184. package/src/components/data-table/__tests__/url-detector.test.tsx +1 -1
  185. package/src/components/data-table/__tests__/useColumnVisibility.test.ts +153 -1
  186. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +54 -25
  187. package/src/components/data-table/column-visibility-dropdown.tsx +62 -14
  188. package/src/components/data-table/date-popover.tsx +2 -1
  189. package/src/components/data-table/hooks/use-column-visibility.ts +76 -0
  190. package/src/components/data-table/renderers.tsx +4 -8
  191. package/src/components/data-table/show-only-column-button.tsx +58 -0
  192. package/src/components/dependency-graph/__tests__/elements.test.ts +151 -0
  193. package/src/components/dependency-graph/custom-edge.tsx +68 -0
  194. package/src/components/dependency-graph/custom-node.tsx +54 -26
  195. package/src/components/dependency-graph/dependency-graph-tree.tsx +110 -21
  196. package/src/components/dependency-graph/elements.ts +225 -31
  197. package/src/components/dependency-graph/panels.tsx +23 -2
  198. package/src/components/dependency-graph/utils/__tests__/layout.test.ts +78 -0
  199. package/src/components/dependency-graph/utils/layout.ts +108 -18
  200. package/src/components/editor/Output.tsx +40 -0
  201. package/src/components/editor/__tests__/Output.test.tsx +85 -2
  202. package/src/components/editor/connections/secret-combobox.tsx +3 -1
  203. package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +832 -0
  204. package/src/components/editor/file-tree/__tests__/file-viewer.test.tsx +27 -0
  205. package/src/components/editor/file-tree/__tests__/requesting-tree.test.ts +130 -0
  206. package/src/components/editor/file-tree/file-browser-row.tsx +82 -0
  207. package/src/components/editor/file-tree/file-explorer.tsx +377 -159
  208. package/src/components/editor/file-tree/file-operations.tsx +1 -1
  209. package/src/components/editor/file-tree/file-search-results.tsx +142 -0
  210. package/src/components/editor/file-tree/file-tree-row.tsx +40 -0
  211. package/src/components/editor/file-tree/file-viewer.tsx +2 -1
  212. package/src/components/editor/file-tree/renderers.tsx +4 -2
  213. package/src/components/editor/file-tree/requesting-tree.tsx +162 -32
  214. package/src/components/editor/file-tree/use-file-search.ts +142 -0
  215. package/src/components/editor/file-tree/use-hover-expand.ts +34 -0
  216. package/src/components/editor/navigation/__tests__/navigation.test.ts +30 -0
  217. package/src/components/editor/navigation/navigation.ts +20 -0
  218. package/src/components/forms/form.tsx +6 -4
  219. package/src/components/home/components.tsx +1 -0
  220. package/src/components/static-html/share-modal.tsx +3 -2
  221. package/src/components/ui/__tests__/badge.test.ts +63 -0
  222. package/src/components/ui/__tests__/button.test.ts +19 -0
  223. package/src/components/ui/__tests__/fullscreen.test.tsx +88 -0
  224. package/src/components/ui/__tests__/menu-items.test.ts +31 -0
  225. package/src/components/ui/badge.tsx +9 -7
  226. package/src/components/ui/button.tsx +1 -0
  227. package/src/components/ui/combobox.tsx +1 -1
  228. package/src/components/ui/date-input.tsx +1 -1
  229. package/src/components/ui/dialog.tsx +3 -1
  230. package/src/components/ui/fullscreen.tsx +43 -1
  231. package/src/components/ui/input.tsx +5 -1
  232. package/src/components/ui/links.tsx +2 -1
  233. package/src/components/ui/menu-items.tsx +9 -9
  234. package/src/components/ui/native-select.tsx +2 -2
  235. package/src/components/ui/navigation.tsx +1 -1
  236. package/src/components/ui/range-slider.tsx +5 -3
  237. package/src/components/ui/select.tsx +1 -1
  238. package/src/components/ui/sheet.tsx +1 -1
  239. package/src/components/ui/toast.tsx +8 -5
  240. package/src/components/ui/toaster.tsx +2 -2
  241. package/src/core/ai/ids/__tests__/ids.test.ts +0 -8
  242. package/src/core/ai/ids/ids.ts +1 -1
  243. package/src/core/cells/__tests__/add-missing-import.test.ts +20 -0
  244. package/src/core/codemirror/language/__tests__/utils.test.ts +1 -1
  245. package/src/core/config/config-schema.ts +1 -0
  246. package/src/core/hotkeys/hotkeys.ts +5 -0
  247. package/src/core/network/__tests__/requests-toasting.test.tsx +14 -0
  248. package/src/core/network/requests-toasting.tsx +1 -1
  249. package/src/css/globals.css +28 -0
  250. package/src/hooks/useEventListener.ts +1 -1
  251. package/src/plugins/core/RenderHTML.tsx +6 -4
  252. package/src/plugins/impl/MatrixPlugin.tsx +1 -1
  253. package/src/plugins/impl/code/any-language-editor.tsx +7 -4
  254. package/src/plugins/impl/data-frames/__tests__/schema.test.ts +34 -1
  255. package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +25 -25
  256. package/src/plugins/impl/data-frames/schema.ts +5 -11
  257. package/src/plugins/impl/panel/__tests__/utils.test.ts +4 -4
  258. package/src/plugins/impl/vega/__tests__/vega.test.ts +1 -1
  259. package/src/stories/cell.stories.tsx +15 -11
  260. package/src/utils/__tests__/events.test.ts +1 -1
  261. package/dist/assets/JsonOutput-CRLQQVKf.js +0 -50
  262. package/dist/assets/RenderHTML-YkwVPe9V.js +0 -1
  263. package/dist/assets/ai-model-dropdown-CrSrb8Zz.js +0 -3
  264. package/dist/assets/alert-dialog-BVi_GyOB.js +0 -11
  265. package/dist/assets/any-language-editor-BL8H-DwB.js +0 -1
  266. package/dist/assets/badge-D_-uqy2N.js +0 -1
  267. package/dist/assets/button-Btj6GXNy.js +0 -1
  268. package/dist/assets/config-ycxJQP2b.js +0 -1
  269. package/dist/assets/dependency-graph-panel-Dg-tUB9T.js +0 -5
  270. package/dist/assets/dist-2oRmY-BC.js +0 -1
  271. package/dist/assets/dist-8lhGoJ54.js +0 -3
  272. package/dist/assets/dist-B4QaGCvF.js +0 -1
  273. package/dist/assets/dist-B_ABJVTW.js +0 -1
  274. package/dist/assets/dist-Bke0Ybxy.js +0 -1
  275. package/dist/assets/dist-Bw8CAY5i.js +0 -1
  276. package/dist/assets/dist-BwmO3SSk.js +0 -1
  277. package/dist/assets/dist-C3KxgR0m.js +0 -1
  278. package/dist/assets/dist-CLE562nZ.js +0 -1
  279. package/dist/assets/dist-CLi0j3bw.js +0 -1
  280. package/dist/assets/dist-CMIyXejt.js +0 -1
  281. package/dist/assets/dist-CbQrIaPV.js +0 -2
  282. package/dist/assets/dist-CpgfIIzU.js +0 -1
  283. package/dist/assets/dist-D7aYPqs9.js +0 -1
  284. package/dist/assets/dist-DKCF5R0T.js +0 -1
  285. package/dist/assets/dist-DbFa9cik.js +0 -1
  286. package/dist/assets/dist-DdPuhs_-.js +0 -1
  287. package/dist/assets/dist-DkfdZExz.js +0 -1
  288. package/dist/assets/dist-hOh6JBwi.js +0 -1
  289. package/dist/assets/dist-mY1j_5eA.js +0 -1
  290. package/dist/assets/dist-tg3aVnpD.js +0 -1
  291. package/dist/assets/dropdown-menu-CqNabM1f.js +0 -1
  292. package/dist/assets/file-explorer-panel-cflxW8a7.js +0 -1
  293. package/dist/assets/file-name-input-CQF4Ovwx.js +0 -3
  294. package/dist/assets/home-page-DPRHPAQM.js +0 -4
  295. package/dist/assets/index-BkIXRAbi.css +0 -2
  296. package/dist/assets/index-p49fbIlR.js +0 -29
  297. package/dist/assets/links-DPh7yoP-.js +0 -1
  298. package/dist/assets/lua-_4wuYo1j.js +0 -1
  299. package/dist/assets/menu-items-BSVrMleU.js +0 -1
  300. package/dist/assets/process-output-DvTtgoMs.js +0 -1
  301. package/dist/assets/select-czJLm6jf.js +0 -1
  302. package/dist/assets/session-panel-C_N3WGWQ.js +0 -1
  303. package/dist/assets/utils-CWSZQEjr.js +0 -1
  304. package/dist/assets/write-secret-modal-lNU_7c2x.js +0 -2
@@ -7,6 +7,7 @@ import {
7
7
  } from "@tanstack/react-table";
8
8
  import { fireEvent, render, screen } from "@testing-library/react";
9
9
  import { beforeAll, describe, expect, it } from "vitest";
10
+ import { TooltipProvider } from "@/components/ui/tooltip";
10
11
  import { ColumnVisibilityDropdown } from "../column-visibility-dropdown";
11
12
  import { INDEX_COLUMN_NAME, SELECT_COLUMN_ID } from "../types";
12
13
 
@@ -20,6 +21,7 @@ beforeAll(() => {
20
21
  });
21
22
 
22
23
  type Row = Record<string, unknown>;
24
+ const EMPTY_COLUMN_IDS: readonly string[] = [];
23
25
 
24
26
  // Select, index, and nameless columns are non-hideable in production
25
27
  // (see columns.tsx), so the harness mirrors that to keep visibility counts
@@ -46,11 +48,14 @@ const TEST_COLUMNS: ColumnDef<Row>[] = [
46
48
  ];
47
49
 
48
50
  interface HarnessProps {
49
- initiallyHidden?: string[];
50
- nonHideable?: string[];
51
+ initiallyHidden?: readonly string[];
52
+ nonHideable?: readonly string[];
51
53
  }
52
54
 
53
- function Harness({ initiallyHidden = [], nonHideable = [] }: HarnessProps) {
55
+ function Harness({
56
+ initiallyHidden = EMPTY_COLUMN_IDS,
57
+ nonHideable = EMPTY_COLUMN_IDS,
58
+ }: HarnessProps) {
54
59
  const table = useReactTable<Row>({
55
60
  data: [],
56
61
  columns: TEST_COLUMNS.map((column) =>
@@ -70,11 +75,25 @@ function Harness({ initiallyHidden = [], nonHideable = [] }: HarnessProps) {
70
75
  }
71
76
 
72
77
  function renderAndOpen(props?: HarnessProps) {
73
- const result = render(<Harness {...(props ?? {})} />);
78
+ const result = render(
79
+ <TooltipProvider>
80
+ <Harness {...(props ?? {})} />
81
+ </TooltipProvider>,
82
+ );
74
83
  fireEvent.click(screen.getByTestId("column-visibility-trigger"));
75
84
  return result;
76
85
  }
77
86
 
87
+ function getShowOnlyButton(columnName: string): HTMLElement {
88
+ const button = getColumnOption(columnName).querySelector(
89
+ '[aria-label="Show only this column"]',
90
+ );
91
+ if (!button) {
92
+ throw new Error(`No show-only button for column ${columnName}`);
93
+ }
94
+ return button as HTMLElement;
95
+ }
96
+
78
97
  function getOptionTexts(): string[] {
79
98
  return screen.getAllByRole("option").map((el) => el.textContent ?? "");
80
99
  }
@@ -270,10 +289,124 @@ describe("ColumnVisibilityDropdown", () => {
270
289
  it("offers both bulk actions when matches are mixed", () => {
271
290
  renderAndOpen({ initiallyHidden: ["cust_age"] });
272
291
  fireEvent.change(getSearchInput(), { target: { value: "cust" } });
292
+ expect(screen.getByText(/Show only 2 matching/)).toBeInTheDocument();
273
293
  expect(screen.getByText(/Hide 1 matching/)).toBeInTheDocument();
274
294
  expect(screen.getByText(/Show 1 matching/)).toBeInTheDocument();
275
295
  });
276
296
 
297
+ it("lists show-only before hide and show bulk actions while searching", () => {
298
+ renderAndOpen({ initiallyHidden: ["cust_age"] });
299
+ fireEvent.change(getSearchInput(), { target: { value: "cust" } });
300
+ expect(getOptionTexts().slice(0, 3)).toEqual([
301
+ "Show only 2 matching",
302
+ "Hide 1 matching",
303
+ "Show 1 matching",
304
+ ]);
305
+ });
306
+
307
+ it("'Show only N matching' isolates matching columns", () => {
308
+ renderAndOpen({ initiallyHidden: ["cust_age"] });
309
+ fireEvent.change(getSearchInput(), { target: { value: "cust" } });
310
+ fireEvent.click(getColumnOption("Show only 2 matching"));
311
+ fireEvent.change(getSearchInput(), { target: { value: "" } });
312
+
313
+ expect(
314
+ getColumnOption("customer_name").querySelector(".lucide-eye-off"),
315
+ ).toBeNull();
316
+ expect(
317
+ getColumnOption("cust_age").querySelector(".lucide-eye-off"),
318
+ ).toBeNull();
319
+ expect(
320
+ getColumnOption("order_total").querySelector(".lucide-eye-off"),
321
+ ).not.toBeNull();
322
+ fireEvent.change(getSearchInput(), { target: { value: "cust" } });
323
+ expect(getColumnOption("Show only 2 matching")).toHaveAttribute(
324
+ "aria-disabled",
325
+ "true",
326
+ );
327
+ });
328
+
329
+ it("disables 'Show only N matching' when already showing only matches", () => {
330
+ renderAndOpen({
331
+ initiallyHidden: ["order_total"],
332
+ });
333
+ fireEvent.change(getSearchInput(), { target: { value: "cust" } });
334
+ expect(getColumnOption("Show only 2 matching")).toHaveAttribute(
335
+ "aria-disabled",
336
+ "true",
337
+ );
338
+ });
339
+
340
+ it("omits 'Show only N matching' without search text", () => {
341
+ renderAndOpen();
342
+ expect(
343
+ screen.queryByText(/Show only \d+ matching/),
344
+ ).not.toBeInTheDocument();
345
+ });
346
+
347
+ it("omits search bulk actions when only non-hideable columns match", () => {
348
+ renderAndOpen({ nonHideable: ["customer_name"] });
349
+ fireEvent.change(getSearchInput(), { target: { value: "customer" } });
350
+ expect(screen.getByText("customer_name")).toBeInTheDocument();
351
+ expect(
352
+ screen.queryByText(/Show only \d+ matching/),
353
+ ).not.toBeInTheDocument();
354
+ expect(screen.queryByText(/Hide \d+ matching/)).not.toBeInTheDocument();
355
+ expect(screen.queryByText(/Show \d+ matching/)).not.toBeInTheDocument();
356
+ });
357
+
358
+ it("show-only icon isolates one column without clearing search", () => {
359
+ renderAndOpen();
360
+ fireEvent.change(getSearchInput(), { target: { value: "cust" } });
361
+ fireEvent.click(getShowOnlyButton("customer_name"));
362
+ expect(getSearchInput()).toHaveValue("cust");
363
+ fireEvent.change(getSearchInput(), { target: { value: "" } });
364
+
365
+ expect(
366
+ getColumnOption("customer_name").querySelector(".lucide-eye-off"),
367
+ ).toBeNull();
368
+ expect(
369
+ getColumnOption("cust_age").querySelector(".lucide-eye-off"),
370
+ ).not.toBeNull();
371
+ expect(
372
+ getColumnOption("order_total").querySelector(".lucide-eye-off"),
373
+ ).not.toBeNull();
374
+ });
375
+
376
+ it("show-only icon does not toggle the row visibility", () => {
377
+ renderAndOpen();
378
+ fireEvent.click(getShowOnlyButton("customer_name"));
379
+
380
+ expect(
381
+ getColumnOption("customer_name").querySelector(".lucide-eye-off"),
382
+ ).toBeNull();
383
+ });
384
+
385
+ it("disables show-only icon when the column is already alone", () => {
386
+ renderAndOpen({
387
+ initiallyHidden: ["cust_age", "order_total"],
388
+ });
389
+ expect(getShowOnlyButton("customer_name")).toHaveAttribute(
390
+ "aria-disabled",
391
+ "true",
392
+ );
393
+ });
394
+
395
+ it("disabled show-only icon blocks pointer activation of the row", () => {
396
+ renderAndOpen({
397
+ initiallyHidden: ["cust_age", "order_total"],
398
+ });
399
+ const button = getShowOnlyButton("customer_name");
400
+ expect(button).toHaveAttribute("aria-disabled", "true");
401
+
402
+ fireEvent.pointerDown(button, { pointerId: 1, bubbles: true });
403
+ fireEvent.click(button, { bubbles: true });
404
+
405
+ expect(
406
+ getColumnOption("customer_name").querySelector(".lucide-eye-off"),
407
+ ).toBeNull();
408
+ });
409
+
277
410
  it("renders non-hideable columns disabled and without an eye toggle", () => {
278
411
  renderAndOpen({ nonHideable: ["customer_name"] });
279
412
  const option = getColumnOption("customer_name");
@@ -98,7 +98,7 @@ describe("UrlDetector", () => {
98
98
  expect(img).toHaveAttribute("src", dataUri);
99
99
  });
100
100
 
101
- it.skip("prevents event propagation on link clicks", () => {
101
+ it.fails("prevents event propagation on link clicks", () => {
102
102
  const mockStopPropagation = vi.fn();
103
103
  render(<UrlDetector parts={parseContent("Check https://marimo.io")} />);
104
104
  const link = screen.getByRole("link");
@@ -1,8 +1,62 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
+ import {
4
+ type ColumnDef,
5
+ getCoreRowModel,
6
+ useReactTable,
7
+ } from "@tanstack/react-table";
3
8
  import { act, renderHook } from "@testing-library/react";
4
9
  import { describe, expect, it } from "vitest";
5
- import { useColumnVisibility } from "../hooks/use-column-visibility";
10
+ import {
11
+ applyShowOnlyColumns,
12
+ getShowOnlyColumnState,
13
+ getShowOnlyVisibility,
14
+ isShowingOnly,
15
+ isShowingOnlyColumns,
16
+ useColumnVisibility,
17
+ } from "../hooks/use-column-visibility";
18
+ import { INDEX_COLUMN_NAME, SELECT_COLUMN_ID } from "../types";
19
+
20
+ type Row = Record<string, unknown>;
21
+
22
+ const TEST_COLUMNS: ColumnDef<Row>[] = [
23
+ { id: SELECT_COLUMN_ID, accessorKey: SELECT_COLUMN_ID, enableHiding: false },
24
+ {
25
+ id: INDEX_COLUMN_NAME,
26
+ accessorKey: INDEX_COLUMN_NAME,
27
+ enableHiding: false,
28
+ },
29
+ { id: "customer_name", accessorKey: "customer_name" },
30
+ { id: "cust_age", accessorKey: "cust_age" },
31
+ { id: "order_total", accessorKey: "order_total" },
32
+ ];
33
+
34
+ function createTestTable({
35
+ initiallyHidden = [],
36
+ nonHideable = [],
37
+ }: {
38
+ initiallyHidden?: string[];
39
+ nonHideable?: string[];
40
+ } = {}) {
41
+ const { result } = renderHook(() =>
42
+ useReactTable<Row>({
43
+ data: [],
44
+ columns: TEST_COLUMNS.map((column) =>
45
+ nonHideable.includes(column.id as string)
46
+ ? { ...column, enableHiding: false }
47
+ : column,
48
+ ),
49
+ getCoreRowModel: getCoreRowModel(),
50
+ locale: "en-US",
51
+ initialState: {
52
+ columnVisibility: Object.fromEntries(
53
+ initiallyHidden.map((id) => [id, false]),
54
+ ),
55
+ },
56
+ }),
57
+ );
58
+ return result.current;
59
+ }
6
60
 
7
61
  describe("useColumnVisibility", () => {
8
62
  it("should initialize with correct default values", () => {
@@ -40,3 +94,101 @@ describe("useColumnVisibility", () => {
40
94
  expect(result.current.columnVisibility).toEqual({ a: false, c: false });
41
95
  });
42
96
  });
97
+
98
+ describe("getShowOnlyVisibility", () => {
99
+ it("shows matching hideable columns and hides the rest", () => {
100
+ const table = createTestTable({ initiallyHidden: ["cust_age"] });
101
+
102
+ expect(
103
+ getShowOnlyVisibility(table, ["customer_name", "order_total"]),
104
+ ).toEqual({
105
+ customer_name: true,
106
+ cust_age: false,
107
+ order_total: true,
108
+ });
109
+ });
110
+
111
+ it("ignores non-hideable columns in the input", () => {
112
+ const table = createTestTable({ nonHideable: ["customer_name"] });
113
+
114
+ expect(
115
+ getShowOnlyVisibility(table, [
116
+ SELECT_COLUMN_ID,
117
+ "customer_name",
118
+ "cust_age",
119
+ ]),
120
+ ).toEqual({
121
+ cust_age: true,
122
+ order_total: false,
123
+ });
124
+ });
125
+
126
+ it("hides every hideable column when the input is empty", () => {
127
+ const table = createTestTable();
128
+
129
+ expect(getShowOnlyVisibility(table, [])).toEqual({
130
+ customer_name: false,
131
+ cust_age: false,
132
+ order_total: false,
133
+ });
134
+ });
135
+ });
136
+
137
+ describe("isShowingOnly", () => {
138
+ it("returns true when visible hideable columns match the input", () => {
139
+ const table = createTestTable({
140
+ initiallyHidden: ["cust_age", "order_total"],
141
+ });
142
+
143
+ expect(isShowingOnly(table, ["customer_name"])).toBe(true);
144
+ });
145
+
146
+ it("returns false when extra hideable columns remain visible", () => {
147
+ const table = createTestTable();
148
+
149
+ expect(isShowingOnly(table, ["customer_name"])).toBe(false);
150
+ });
151
+
152
+ it("ignores non-hideable columns in the input", () => {
153
+ const table = createTestTable({
154
+ initiallyHidden: ["cust_age", "order_total"],
155
+ nonHideable: ["customer_name"],
156
+ });
157
+
158
+ expect(isShowingOnly(table, [SELECT_COLUMN_ID, "customer_name"])).toBe(
159
+ true,
160
+ );
161
+ });
162
+
163
+ it("returns true when every hideable column is hidden and the input is empty", () => {
164
+ const table = createTestTable({
165
+ initiallyHidden: ["customer_name", "cust_age", "order_total"],
166
+ });
167
+
168
+ expect(isShowingOnly(table, [])).toBe(true);
169
+ });
170
+ });
171
+
172
+ describe("isShowingOnlyColumns", () => {
173
+ it("reuses precomputed visible hideable columns", () => {
174
+ const table = createTestTable({
175
+ initiallyHidden: ["cust_age", "order_total"],
176
+ });
177
+ const state = getShowOnlyColumnState(table);
178
+
179
+ expect(isShowingOnlyColumns(state, ["customer_name"])).toBe(true);
180
+ expect(isShowingOnly(table, ["customer_name"])).toBe(true);
181
+ });
182
+ });
183
+
184
+ describe("applyShowOnlyColumns", () => {
185
+ it("shows only the requested hideable columns", () => {
186
+ const table = createTestTable({ initiallyHidden: ["cust_age"] });
187
+
188
+ act(() => {
189
+ applyShowOnlyColumns(table, ["customer_name", "order_total"]);
190
+ });
191
+
192
+ expect(isShowingOnly(table, ["customer_name", "order_total"])).toBe(true);
193
+ });
194
+ });
@@ -10,7 +10,7 @@ import {
10
10
  EyeIcon,
11
11
  EyeOffIcon,
12
12
  } from "lucide-react";
13
- import { useState } from "react";
13
+ import { useMemo, useState } from "react";
14
14
  import { useLocale } from "react-aria";
15
15
  import {
16
16
  AddDataframeChart,
@@ -52,8 +52,12 @@ import type { Column, Table } from "@tanstack/react-table";
52
52
  import { cn } from "@/utils/cn";
53
53
  import {
54
54
  getColumnCountForDisplay,
55
+ getShowOnlyColumnState,
55
56
  getUserColumnVisibilityCounts,
57
+ isShowingOnlyColumns,
58
+ type ShowOnlyColumnState,
56
59
  } from "../hooks/use-column-visibility";
60
+ import { ShowOnlyColumnButton } from "../show-only-column-button";
57
61
 
58
62
  interface ColumnExplorerPanelProps<TData> {
59
63
  previewColumn: PreviewColumn;
@@ -94,6 +98,11 @@ export function ColumnExplorerPanel<TData>({
94
98
  hiddenColumns: hiddenColumnCount,
95
99
  } = getColumnCountForDisplay(table, totalColumns);
96
100
  const { visible: visibleColumnCount } = getUserColumnVisibilityCounts(table);
101
+ const columnVisibility = table.getState().columnVisibility;
102
+ const showOnlyColumnState = useMemo(
103
+ () => getShowOnlyColumnState(table),
104
+ [table, columnVisibility],
105
+ );
97
106
 
98
107
  const { rowsAndColumns, hiddenSuffix } = prettifyRowColumnCount({
99
108
  numRows: totalRows,
@@ -162,6 +171,8 @@ export function ColumnExplorerPanel<TData>({
162
171
  dataType={dataType}
163
172
  externalType={externalType}
164
173
  previewColumn={previewColumn}
174
+ table={table}
175
+ showOnlyColumnState={showOnlyColumnState}
165
176
  defaultExpanded={index === 0}
166
177
  />
167
178
  );
@@ -179,6 +190,8 @@ function ColumnItem<TData>({
179
190
  dataType,
180
191
  externalType,
181
192
  previewColumn,
193
+ table,
194
+ showOnlyColumnState,
182
195
  defaultExpanded = false,
183
196
  }: {
184
197
  columnName: string;
@@ -186,6 +199,8 @@ function ColumnItem<TData>({
186
199
  dataType: DataType;
187
200
  externalType: string;
188
201
  previewColumn: PreviewColumn;
202
+ table: Table<TData>;
203
+ showOnlyColumnState: ShowOnlyColumnState;
189
204
  defaultExpanded?: boolean;
190
205
  }) {
191
206
  const [isExpanded, setIsExpanded] = useState(defaultExpanded);
@@ -218,36 +233,50 @@ function ColumnItem<TData>({
218
233
  )}
219
234
  />
220
235
  {column?.getCanHide() && (
221
- <Tooltip
222
- content={column.getIsVisible() ? "Hide column" : "Show column"}
223
- delayDuration={400}
224
- >
225
- <Button
226
- type="button"
227
- variant="text"
228
- size="icon"
229
- aria-label={
230
- column.getIsVisible() ? "Hide column" : "Show column"
231
- }
236
+ <>
237
+ <ShowOnlyColumnButton
238
+ table={table}
239
+ columnIds={[columnName]}
240
+ disabled={isShowingOnlyColumns(showOnlyColumnState, [
241
+ columnName,
242
+ ])}
232
243
  className={cn(
233
- "hover:bg-muted text-muted-foreground hover:text-primary",
234
244
  column.getIsVisible()
235
245
  ? "group-hover:opacity-100 opacity-0"
236
246
  : "opacity-100",
237
247
  )}
238
- onClick={(e) => {
239
- e.preventDefault();
240
- e.stopPropagation();
241
- column.toggleVisibility(!column.getIsVisible());
242
- }}
248
+ />
249
+ <Tooltip
250
+ content={column.getIsVisible() ? "Hide column" : "Show column"}
251
+ delayDuration={400}
243
252
  >
244
- {column.getIsVisible() ? (
245
- <EyeIcon className="h-3 w-3" strokeWidth={2.5} />
246
- ) : (
247
- <EyeOffIcon className="h-3 w-3" strokeWidth={2.5} />
248
- )}
249
- </Button>
250
- </Tooltip>
253
+ <Button
254
+ type="button"
255
+ variant="text"
256
+ size="icon"
257
+ aria-label={
258
+ column.getIsVisible() ? "Hide column" : "Show column"
259
+ }
260
+ className={cn(
261
+ "hover:bg-muted text-muted-foreground hover:text-primary",
262
+ column.getIsVisible()
263
+ ? "group-hover:opacity-100 opacity-0"
264
+ : "opacity-100",
265
+ )}
266
+ onClick={(e) => {
267
+ e.preventDefault();
268
+ e.stopPropagation();
269
+ column.toggleVisibility(!column.getIsVisible());
270
+ }}
271
+ >
272
+ {column.getIsVisible() ? (
273
+ <EyeIcon className="h-3 w-3" strokeWidth={2.5} />
274
+ ) : (
275
+ <EyeOffIcon className="h-3 w-3" strokeWidth={2.5} />
276
+ )}
277
+ </Button>
278
+ </Tooltip>
279
+ </>
251
280
  )}
252
281
  <span className="text-xs text-muted-foreground">{externalType}</span>
253
282
  </div>
@@ -5,8 +5,8 @@
5
5
  // https://github.com/TanStack/table/issues/5567
6
6
 
7
7
  import type { Table } from "@tanstack/react-table";
8
- import { Columns3Icon, EyeIcon, EyeOffIcon } from "lucide-react";
9
- import React from "react";
8
+ import { Columns3Icon, EyeIcon, EyeOffIcon, ScanEyeIcon } from "lucide-react";
9
+ import React, { useMemo } from "react";
10
10
  import { ColumnName } from "@/components/datasources/components";
11
11
  import { Button } from "@/components/ui/button";
12
12
  import {
@@ -28,6 +28,11 @@ import { cn } from "@/utils/cn";
28
28
  import { Events } from "@/utils/events";
29
29
  import { smartMatchFilter } from "@/utils/smartMatch";
30
30
  import { NAMELESS_COLUMN_PREFIX } from "./columns";
31
+ import {
32
+ applyShowOnlyColumns,
33
+ isShowingOnlyColumns,
34
+ } from "./hooks/use-column-visibility";
35
+ import { ShowOnlyColumnButton } from "./show-only-column-button";
31
36
  import { INDEX_COLUMN_NAME, SELECT_COLUMN_ID } from "./types";
32
37
 
33
38
  function getUserColumns<TData>(table: Table<TData>) {
@@ -95,6 +100,23 @@ export const ColumnVisibilityDropdown = <TData,>({
95
100
  > =>
96
101
  action.kind === "select-matching" || action.kind === "deselect-matching",
97
102
  );
103
+ const showOnlyMatchIds =
104
+ list.searchQuery !== ""
105
+ ? list.visibleOptions
106
+ .filter((option) => !option.disabled)
107
+ .map((option) => option.value)
108
+ : [];
109
+ const showOnlyColumnState = useMemo(
110
+ () => ({
111
+ visibleHideableColumnIds: hideableIds.filter(
112
+ (id) => !hiddenIds.includes(id),
113
+ ),
114
+ hideableColumnIdSet: new Set(hideableIds),
115
+ }),
116
+ [hideableIds, hiddenIds],
117
+ );
118
+ const hasSearchBulkActions =
119
+ showOnlyMatchIds.length > 0 || matchingActions.length > 0;
98
120
 
99
121
  return (
100
122
  <Popover open={list.open} onOpenChange={list.setOpen}>
@@ -145,8 +167,25 @@ export const ColumnVisibilityDropdown = <TData,>({
145
167
  <CommandSeparator />
146
168
  </>
147
169
  ) : (
148
- matchingActions.length > 0 && (
170
+ hasSearchBulkActions && (
149
171
  <>
172
+ <CommandItem
173
+ value="__show_only_matching__"
174
+ disabled={
175
+ showOnlyMatchIds.length === 0 ||
176
+ isShowingOnlyColumns(
177
+ showOnlyColumnState,
178
+ showOnlyMatchIds,
179
+ )
180
+ }
181
+ onSelect={() => {
182
+ applyShowOnlyColumns(table, showOnlyMatchIds);
183
+ }}
184
+ className="cursor-pointer"
185
+ >
186
+ <ScanEyeIcon className="w-3 h-3 mr-1.5" />
187
+ Show only {showOnlyMatchIds.length} matching
188
+ </CommandItem>
150
189
  {matchingActions.map((action) => (
151
190
  <CommandItem
152
191
  key={action.kind}
@@ -194,17 +233,26 @@ export const ColumnVisibilityDropdown = <TData,>({
194
233
  />
195
234
  )}
196
235
  {!option.disabled && (
197
- <span
198
- className={cn(
199
- "ml-auto",
200
- hidden ? "text-primary" : "text-muted-foreground",
201
- )}
202
- >
203
- {hidden ? (
204
- <EyeOffIcon className="w-3 h-3" />
205
- ) : (
206
- <EyeIcon className="w-3 h-3" />
207
- )}
236
+ <span className="ml-auto flex items-center gap-0.5">
237
+ <ShowOnlyColumnButton
238
+ table={table}
239
+ columnIds={[option.value]}
240
+ disabled={isShowingOnlyColumns(showOnlyColumnState, [
241
+ option.value,
242
+ ])}
243
+ iconClassName="w-3 h-3"
244
+ />
245
+ <span
246
+ className={cn(
247
+ hidden ? "text-primary" : "text-muted-foreground",
248
+ )}
249
+ >
250
+ {hidden ? (
251
+ <EyeOffIcon className="w-3 h-3" />
252
+ ) : (
253
+ <EyeIcon className="w-3 h-3" />
254
+ )}
255
+ </span>
208
256
  </span>
209
257
  )}
210
258
  </CommandItem>
@@ -45,7 +45,8 @@ export const DatePopover: React.FC<DatePopoverProps> = ({
45
45
 
46
46
  const TimezoneDisplay = ({ date }: { date: Date }) => {
47
47
  const { locale } = useLocale();
48
- const localTimezone = Intl.DateTimeFormat(locale).resolvedOptions().timeZone;
48
+ const localTimezone = new Intl.DateTimeFormat(locale).resolvedOptions()
49
+ .timeZone;
49
50
  const hasSubSeconds = date.getUTCMilliseconds() !== 0;
50
51
 
51
52
  const utcFormatter = useDateFormatter(
@@ -54,3 +54,79 @@ export function getColumnCountForDisplay<TData>(
54
54
  hiddenColumns: counts.hidden,
55
55
  };
56
56
  }
57
+
58
+ export function getShowOnlyVisibility<TData>(
59
+ table: Table<TData>,
60
+ columnIds: string[],
61
+ ): VisibilityState {
62
+ const showOnlySet = new Set(columnIds);
63
+ const visibility: VisibilityState = {};
64
+
65
+ for (const column of table.getAllLeafColumns()) {
66
+ if (!column.getCanHide()) {
67
+ continue;
68
+ }
69
+ visibility[column.id] = showOnlySet.has(column.id);
70
+ }
71
+
72
+ return visibility;
73
+ }
74
+
75
+ export function applyShowOnlyColumns<TData>(
76
+ table: Table<TData>,
77
+ columnIds: string[],
78
+ ): void {
79
+ table.setColumnVisibility((previous) => ({
80
+ ...previous,
81
+ ...getShowOnlyVisibility(table, columnIds),
82
+ }));
83
+ }
84
+
85
+ export interface ShowOnlyColumnState {
86
+ visibleHideableColumnIds: readonly string[];
87
+ hideableColumnIdSet: ReadonlySet<string>;
88
+ }
89
+
90
+ export function getShowOnlyColumnState<TData>(
91
+ table: Table<TData>,
92
+ ): ShowOnlyColumnState {
93
+ const hideableIds: string[] = [];
94
+ const visibleHideableColumnIds: string[] = [];
95
+
96
+ for (const column of table.getAllLeafColumns()) {
97
+ if (!column.getCanHide()) {
98
+ continue;
99
+ }
100
+ hideableIds.push(column.id);
101
+ if (column.getIsVisible()) {
102
+ visibleHideableColumnIds.push(column.id);
103
+ }
104
+ }
105
+
106
+ return {
107
+ visibleHideableColumnIds,
108
+ hideableColumnIdSet: new Set(hideableIds),
109
+ };
110
+ }
111
+
112
+ export function isShowingOnlyColumns(
113
+ state: ShowOnlyColumnState,
114
+ columnIds: readonly string[],
115
+ ): boolean {
116
+ const targetIds = new Set(
117
+ columnIds.filter((id) => state.hideableColumnIdSet.has(id)),
118
+ );
119
+
120
+ if (state.visibleHideableColumnIds.length !== targetIds.size) {
121
+ return false;
122
+ }
123
+
124
+ return state.visibleHideableColumnIds.every((id) => targetIds.has(id));
125
+ }
126
+
127
+ export function isShowingOnly<TData>(
128
+ table: Table<TData>,
129
+ columnIds: string[],
130
+ ): boolean {
131
+ return isShowingOnlyColumns(getShowOnlyColumnState(table), columnIds);
132
+ }