@marimo-team/islands 0.25.2-dev99 → 0.25.3-dev10

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 (205) hide show
  1. package/dist/{ConnectedDataExplorerComponent-BZmqc_F0.js → ConnectedDataExplorerComponent-CNMliVzw.js} +15 -15
  2. package/dist/{ErrorBoundary-CXkr_IcB.js → ErrorBoundary-BsqSMK9Y.js} +12 -12
  3. package/dist/{ImageComparisonComponent-Cpfz30OZ.js → ImageComparisonComponent-uU8FSKZE.js} +3 -3
  4. package/dist/{Plot-CTyjbQDT.js → Plot-DdYOe1UK.js} +2 -2
  5. package/dist/{abnfDiagram-VCTEODGH-C_Lmaa2j.js → abnfDiagram-VCTEODGH-D-Ez91gV.js} +3 -3
  6. package/dist/{any-language-editor-BFzqhOBR.js → any-language-editor-DZ_YTVus.js} +7 -7
  7. package/dist/{architectureDiagram-5GKGNRK7-BKMataHB.js → architectureDiagram-5GKGNRK7-CTpcNtO8.js} +5 -5
  8. package/dist/assets/__vite-browser-external-BXYkiFsk.js +1 -0
  9. package/dist/assets/worker-HPY9fbhz.js +114 -0
  10. package/dist/{blockDiagram-I7D4REHJ-BeHOjyDk.js → blockDiagram-I7D4REHJ-Cg25UrxT.js} +9 -9
  11. package/dist/{button-BtsM2UqM.js → button-CvjkwdSk.js} +5 -5
  12. package/dist/{c4Diagram-7LVT6UL2-Bao10t_O.js → c4Diagram-7LVT6UL2-BxFgrnNV.js} +7 -7
  13. package/dist/{capabilities-A5jrzjCJ.js → capabilities-CQ5IjhzL.js} +1 -1
  14. package/dist/{channel-BxCkvUgE.js → channel-CPObtJXj.js} +1 -1
  15. package/dist/{chat-ui-CwOWzoSO.js → chat-ui-0lKdOoQ3.js} +1588 -1396
  16. package/dist/{check-CNP79M3A.js → check-EDwSwP89.js} +1 -1
  17. package/dist/{chunk-4HAMMTFA-CH7Gpamd.js → chunk-4HAMMTFA-D4eFPyFh.js} +5 -5
  18. package/dist/{chunk-75Z2AOVW-AI7CvgKn.js → chunk-75Z2AOVW-D7gxIs2Q.js} +1 -1
  19. package/dist/{chunk-DU6HZSFF-BSvuTkX4.js → chunk-DU6HZSFF-BwiyaNpg.js} +1 -1
  20. package/dist/{chunk-F27PBJKO-CLshwT9T.js → chunk-F27PBJKO-ufseIn5y.js} +1 -1
  21. package/dist/{chunk-GMAD6QVW-wnHcn-lH.js → chunk-GMAD6QVW-BhaJx0X3.js} +3 -3
  22. package/dist/{chunk-GVQU2GXP-7O2p8hut.js → chunk-GVQU2GXP-Cwbt-lF0.js} +2 -2
  23. package/dist/{chunk-IMKFNOWR-Bu0Vh_Yi.js → chunk-IMKFNOWR-DGxi-zeo.js} +5 -5
  24. package/dist/{chunk-L3NEJ4N5-B9_Alrxb.js → chunk-L3NEJ4N5-n-zgIVSy.js} +5 -5
  25. package/dist/{chunk-OSK3NFVY-PeQPH2fD.js → chunk-OSK3NFVY-DXa-Cxbn.js} +6 -6
  26. package/dist/{chunk-P2QGCYS3-D9twiFuU.js → chunk-P2QGCYS3-B_Zd3-X0.js} +1 -1
  27. package/dist/{chunk-POPQ4Y6H-BUiNs18s.js → chunk-POPQ4Y6H-hYOXbYH_.js} +1 -1
  28. package/dist/{chunk-PWAF6VOD-D8S9NPCy.js → chunk-PWAF6VOD-CQw5qATZ.js} +1 -1
  29. package/dist/{chunk-SHT3W25Y-B2dyNZ31.js → chunk-SHT3W25Y-CV9J3rAB.js} +7 -7
  30. package/dist/{chunk-SVP7TREG-D7UPvB10.js → chunk-SVP7TREG-BL-9Fqgg.js} +2 -2
  31. package/dist/{chunk-TICWLB2K-BNaGoadd.js → chunk-TICWLB2K-Cu_XMjDM.js} +5 -5
  32. package/dist/{chunk-YOKDWASO-DrWbKnxA.js → chunk-YOKDWASO-DPZk8vhS.js} +6 -6
  33. package/dist/classDiagram-ZZMXUADV-BXXV13Hq.js +30 -0
  34. package/dist/classDiagram-v2-VYDZK3BY-B7FXJ1Cp.js +30 -0
  35. package/dist/{code-visibility-pPjYsRTH.js → code-visibility-CXQvUXHT.js} +18 -18
  36. package/dist/{common-CkvBp0B4.js → common-CuD-CAC-.js} +6128 -7136
  37. package/dist/{compiler-runtime-Cj8ZWiNS.js → compiler-runtime-CldRdSsv.js} +2 -2
  38. package/dist/{copy-icon-BY7jgcaV.js → copy-icon-Ft7t9bqz.js} +6 -6
  39. package/dist/{cynefinDiagram-5FMLGOSQ-CCDn4Z9e.js → cynefinDiagram-5FMLGOSQ-CH96rwba.js} +3 -3
  40. package/dist/{dagre-GXQ25YYZ-BJiUO_SV.js → dagre-GXQ25YYZ-BD3PmpFY.js} +10 -10
  41. package/dist/{data-grid-overlay-editor-L6ELxFAh.js → data-grid-overlay-editor-DgeyYmC1.js} +7 -7
  42. package/dist/{data-grid-types-BucVmDDp.js → data-grid-types-BH_r7g7l.js} +1 -1
  43. package/dist/{diagram-S7CK7UJ4-BZfxFNRR.js → diagram-S7CK7UJ4-BsSJJldB.js} +4 -4
  44. package/dist/{diagram-UQ7AKVKN-1xcsiIMg.js → diagram-UQ7AKVKN-muQtNZc4.js} +3 -3
  45. package/dist/{diagram-VSXAHHWV-DPAWJ9Nw.js → diagram-VSXAHHWV-BJWcVVJY.js} +2 -2
  46. package/dist/{diagram-VX7I27RA-DmRsnHYY.js → diagram-VX7I27RA-CdhuZAqR.js} +5 -5
  47. package/dist/{diagram-Z3DM3KII--b49ryKx.js → diagram-Z3DM3KII-BD8mXjOj.js} +3 -3
  48. package/dist/{dialog-CmExhUDI.js → dialog-CEBFZNyc.js} +6 -6
  49. package/dist/{dist-CcyKTBTF.js → dist-DpBpA_n1.js} +2 -2
  50. package/dist/{dropdown-menu-Cz4TdOJh.js → dropdown-menu-CP_qCYHC.js} +139 -139
  51. package/dist/{ebnfDiagram-PWID7BFC-rSwVyh4y.js → ebnfDiagram-PWID7BFC-BIN1sweE.js} +3 -3
  52. package/dist/{erDiagram-RLTQ6QDP-Bfd3iAoC.js → erDiagram-RLTQ6QDP-Ctp5cfoN.js} +12 -12
  53. package/dist/{error-banner-D30nA9nE.js → error-banner-D-WCIiMt.js} +16 -11
  54. package/dist/{cells-DZi0ioak.js → error-entries-DSvFWT_M.js} +6171 -5075
  55. package/dist/{esm-DAVrGVKP.js → esm-AMFssoNp.js} +4 -4
  56. package/dist/{feedback-button-D-pV0Qji.js → feedback-button-DZMj9PF3.js} +119 -120
  57. package/dist/flowDiagram-HODETNUW-3EfLrlFb.js +16 -0
  58. package/dist/{formats-DhhbdyAH.js → formats-CeOmU1MU.js} +6 -6
  59. package/dist/{ganttDiagram-EL5Y4UJY-B4m_YsKa.js → ganttDiagram-EL5Y4UJY-BQT16JSc.js} +2 -2
  60. package/dist/{gitGraphDiagram-WWUBYQGX-QRBbvWXh.js → gitGraphDiagram-WWUBYQGX-D5nSIzdE.js} +2 -2
  61. package/dist/{glide-data-editor-D6CfYwdr.js → glide-data-editor-g_L8FLAC.js} +60 -60
  62. package/dist/{glide-utils-BVJ4fkxX.js → glide-utils-DJyqh0EM.js} +4 -4
  63. package/dist/{globals-BwK9YGrX.js → globals-CYGlmBXb.js} +3 -3
  64. package/dist/{highlighted-body-KPVGNVTW-Ad3MKZ18.js → highlighted-body-KPVGNVTW-zwjq21tf.js} +4 -4
  65. package/dist/{html-to-image-Cn1_16-x.js → html-to-image-B8s5SgGm.js} +37 -37
  66. package/dist/{infoDiagram-27XIBGKW-DVQFYvhg.js → infoDiagram-27XIBGKW-DipQoHxl.js} +2 -2
  67. package/dist/{ishikawaDiagram-5VMMS53U-viPND-nm.js → ishikawaDiagram-5VMMS53U-DgFMjSGz.js} +3 -3
  68. package/dist/{journeyDiagram-3NMN7TZE-BeeJdJo3.js → journeyDiagram-3NMN7TZE-BaLqn-dZ.js} +2 -2
  69. package/dist/{jsx-runtime-DgDPJV9S.js → jsx-runtime-3BD1kT0s.js} +1 -1
  70. package/dist/{kanban-definition-UXKFOSKX-Dcl_ECO9.js → kanban-definition-UXKFOSKX-w1ACVjgl.js} +9 -9
  71. package/dist/{katex-BNCmKUol.js → katex-BIdZGsyO.js} +141 -116
  72. package/dist/{label-DQO1jFjf.js → label-BDKF3Afc.js} +10 -10
  73. package/dist/{loader-Cm-ATtou.js → loader-BQOfjTIJ.js} +1 -1
  74. package/dist/main.js +623 -590
  75. package/dist/{mermaid-BfhcnSj-.js → mermaid-CHo49Yv-.js} +56 -56
  76. package/dist/mermaid-HWGCJPDP-ByCsZnYF.js +2 -0
  77. package/dist/{mhchem-BEc7A1or.js → mhchem-CdWPJK6g.js} +1 -1
  78. package/dist/{mindmap-definition-YA3MSWOX-BdxxhF-5.js → mindmap-definition-YA3MSWOX-CrT0KSfX.js} +11 -11
  79. package/dist/{number-overlay-editor-tMylyldi.js → number-overlay-editor-9VRv-pdj.js} +5 -5
  80. package/dist/{pegDiagram-XKGWAZYB-Du5p2s0w.js → pegDiagram-XKGWAZYB-BqvywNJA.js} +3 -3
  81. package/dist/{pieDiagram-E7YTZNPT-DJg-SOIq.js → pieDiagram-E7YTZNPT-BfxJ_XCc.js} +3 -3
  82. package/dist/{process-output-CUG57KRp.js → process-output-CKRXyszb.js} +5 -5
  83. package/dist/{quadrantDiagram-AXDQQJYC-keLfFx9f.js → quadrantDiagram-AXDQQJYC-Ccw0xMjN.js} +1 -1
  84. package/dist/{railroadDiagram-O6MQD6OU-C0ojm-6_.js → railroadDiagram-O6MQD6OU-8vFLVTPu.js} +3 -3
  85. package/dist/{react-dom-BUgJ-ab_.js → react-dom-DUmH0GXv.js} +29 -21
  86. package/dist/{react-ofJbxM4x.js → react-sHtZdjeP.js} +103 -94
  87. package/dist/{react-vega-ewj7q_U5.js → react-vega-BED0DjiB.js} +3 -3
  88. package/dist/{requirementDiagram-BXWQKSXE-CNwNBmI3.js → requirementDiagram-BXWQKSXE-a_MxGvxe.js} +11 -11
  89. package/dist/{reveal-component-LXUMcqWX.js → reveal-component-C87mv9Mn.js} +906 -878
  90. package/dist/{sankeyDiagram-P5KCCOFB-Bh4EsJox.js → sankeyDiagram-P5KCCOFB-ELvOcnZH.js} +1 -1
  91. package/dist/{select-Bs-nmvm6.js → select-BButFi-d.js} +11 -11
  92. package/dist/{sequenceDiagram-WJ2MYXX4-DQaW5qBG.js → sequenceDiagram-WJ2MYXX4-CXFMnxGh.js} +4 -4
  93. package/dist/{spec-DVsoMvYT.js → spec-BwarBpUJ.js} +4 -4
  94. package/dist/{stateDiagram-D77RDMKH-BDa515QC.js → stateDiagram-D77RDMKH-DQeA_CwI.js} +13 -13
  95. package/dist/stateDiagram-v2-MP3YSRHH-BxxQucm1.js +30 -0
  96. package/dist/style.css +1 -1
  97. package/dist/{swimlanes-42K2YHIH-M4IdGi8J.js → swimlanes-42K2YHIH-Do6L-cYg.js} +10 -10
  98. package/dist/swimlanesDiagram-VR7AAH4N-DUzPvSVU.js +30 -0
  99. package/dist/{swiper-component-CpN-hewZ.js → swiper-component-DKntyn8p.js} +5 -5
  100. package/dist/{timeline-definition-24CTP7MA-DH-kvakg.js → timeline-definition-24CTP7MA-D3c46WM5.js} +3 -3
  101. package/dist/{toDate-vEi5kTfY.js → toDate-vIXljnsr.js} +43 -42
  102. package/dist/{toast-DfEpJedt.js → toast-B9UMEi8u.js} +9 -9
  103. package/dist/{tooltip-CuNWg2ay.js → tooltip-BO1REbqs.js} +7 -7
  104. package/dist/{use-restore-focus-kmgwrL8q.js → use-restore-focus-BEM7sFWl.js} +2042 -1827
  105. package/dist/{use-vega-container-remeasure-4DwJbPWu.js → use-vega-container-remeasure-Bz4PZMtt.js} +2 -2
  106. package/dist/{useAsyncData-rkAlR_vh.js → useAsyncData-Deh5kszT.js} +3 -3
  107. package/dist/{useDateFormatter-C-tz65rD.js → useDateFormatter-D8XruNGG.js} +4 -4
  108. package/dist/{useDeepCompareMemoize-BlHFBj5_.js → useDeepCompareMemoize-DXwzRINI.js} +2 -2
  109. package/dist/{useIframeCapabilities-C1Bt04Iz.js → useIframeCapabilities-DBETvvPl.js} +2 -2
  110. package/dist/{useLifecycle-B68iY077.js → useLifecycle-j7D9uD1o.js} +6 -6
  111. package/dist/{useTheme-BwSgeAFb.js → useTheme-CRnjkku0.js} +7 -7
  112. package/dist/{vega-component-C-bPttRN.js → vega-component-DTG6zxaY.js} +14 -14
  113. package/dist/{vega-embed-container-sSR5hAsy.js → vega-embed-container-BNHE18G9.js} +5 -5
  114. package/dist/{vennDiagram-4TSXK5OY-d5g7XeiI.js → vennDiagram-4TSXK5OY-BSZD8JcZ.js} +3 -3
  115. package/dist/{wardleyDiagram-VM6X3IG4-BfX3bSzR.js → wardleyDiagram-VM6X3IG4-48cUWkfA.js} +3 -3
  116. package/dist/{xychartDiagram-S5SC5T6Z-C1QsLZg7.js → xychartDiagram-S5SC5T6Z-CswYgYeu.js} +5 -5
  117. package/package.json +25 -22
  118. package/src/__tests__/fixtures/{pair-preview.ts → pair-config.ts} +3 -2
  119. package/src/__tests__/host-imports.test.ts +100 -0
  120. package/src/__tests__/mount.test.ts +8 -8
  121. package/src/components/data-table/__tests__/column_formatting.test.ts +30 -0
  122. package/src/components/data-table/__tests__/columns.test.tsx +70 -0
  123. package/src/components/data-table/__tests__/context-menu.test.ts +176 -0
  124. package/src/components/data-table/__tests__/date-filter-inputs.test.tsx +24 -1
  125. package/src/components/data-table/__tests__/export-actions.test.tsx +329 -6
  126. package/src/components/data-table/column-formatting/feature.ts +20 -1
  127. package/src/components/data-table/columns.tsx +25 -18
  128. package/src/components/data-table/context-menu.tsx +125 -26
  129. package/src/components/data-table/date-filter-inputs.tsx +15 -42
  130. package/src/components/data-table/export-actions.tsx +192 -116
  131. package/src/components/data-table/schemas.ts +14 -36
  132. package/src/components/data-table/utils.ts +18 -0
  133. package/src/components/editor/Output.tsx +9 -2
  134. package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +80 -252
  135. package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +186 -34
  136. package/src/components/editor/actions/pair-with-agent-commands.ts +42 -51
  137. package/src/components/editor/actions/pair-with-agent-modal.tsx +96 -36
  138. package/src/components/editor/chrome/panels/error-panel.tsx +1 -0
  139. package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +372 -0
  140. package/src/components/editor/chrome/wrapper/footer-item.tsx +32 -24
  141. package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +237 -0
  142. package/src/components/editor/chrome/wrapper/footer.tsx +2 -0
  143. package/src/components/editor/controls/__tests__/notebook-menu-dropdown.test.tsx +4 -3
  144. package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +548 -0
  145. package/src/components/editor/errors/send-error-report-button.tsx +69 -0
  146. package/src/components/editor/output/MarimoErrorOutput.tsx +21 -5
  147. package/src/components/editor/output/MarimoTracebackOutput.tsx +35 -20
  148. package/src/components/editor/output/__tests__/ansi-reduce.test.ts +18 -0
  149. package/src/components/editor/output/ansi-reduce.ts +6 -0
  150. package/src/components/editor/output/console/ConsoleOutput.tsx +5 -3
  151. package/src/components/editor/output/console/__tests__/ConsoleOutput.test.tsx +18 -0
  152. package/src/components/storage/__tests__/storage-file-viewer.test.tsx +2 -1
  153. package/src/core/attachments/__tests__/toast.test.tsx +58 -0
  154. package/src/core/attachments/state.ts +21 -0
  155. package/src/core/attachments/toast.ts +15 -0
  156. package/src/core/cells/__tests__/cells.test.ts +52 -0
  157. package/src/core/cells/__tests__/document-roundtrip.test.ts +16 -0
  158. package/src/core/cells/__tests__/error-report.test.ts +139 -0
  159. package/src/core/cells/__tests__/session.test.ts +50 -1
  160. package/src/core/cells/error-report.ts +63 -0
  161. package/src/core/cells/session.ts +28 -1
  162. package/src/core/codemirror/copilot/__tests__/completion-integration.test.ts +447 -0
  163. package/src/core/codemirror/copilot/__tests__/inline-completion.test.ts +395 -0
  164. package/src/core/codemirror/copilot/__tests__/language-server.test.ts +511 -2
  165. package/src/core/codemirror/copilot/__tests__/rpc-cancellation.test.ts +201 -0
  166. package/src/core/codemirror/copilot/extension.ts +22 -11
  167. package/src/core/codemirror/copilot/language-server.ts +109 -60
  168. package/src/core/codemirror/language/__tests__/sql.test.ts +4 -3
  169. package/src/core/codemirror/language/embedded/__tests__/embedded-python.test.ts +138 -26
  170. package/src/core/codemirror/language/embedded/embedded-python.ts +47 -13
  171. package/src/core/codemirror/language/embedded/latex.ts +20 -13
  172. package/src/core/config/pair.ts +5 -3
  173. package/src/core/datasets/__tests__/data-source-discovery.test.ts +18 -11
  174. package/src/core/host/AGENTS.md +6 -0
  175. package/src/core/host/__tests__/protocol.test.ts +214 -0
  176. package/src/core/host/protocol.ts +1943 -0
  177. package/src/core/islands/__tests__/bootstrap.test.ts +26 -0
  178. package/src/core/islands/bootstrap.ts +1 -0
  179. package/src/core/islands/bridge.ts +2 -2
  180. package/src/core/kernel/messages.ts +4 -7
  181. package/src/core/network/__tests__/api.test.ts +114 -1
  182. package/src/core/network/api.ts +3 -2
  183. package/src/core/wasm/bridge.ts +2 -2
  184. package/src/core/wasm/worker/types.ts +2 -2
  185. package/src/core/websocket/__tests__/useMarimoKernelConnection.hook.test.tsx +193 -0
  186. package/src/core/websocket/useMarimoKernelConnection.tsx +9 -0
  187. package/src/css/katex-css.test.ts +1 -1
  188. package/src/css/katex.min.css +6 -1
  189. package/src/hooks/__tests__/useEventListener.test.tsx +45 -1
  190. package/src/hooks/useEventListener.ts +6 -1
  191. package/src/mount.tsx +3 -3
  192. package/src/plugins/impl/NumberPlugin.tsx +20 -3
  193. package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +84 -0
  194. package/src/plugins/impl/__tests__/NumberPlugin.test.tsx +159 -1
  195. package/src/utils/__tests__/dates.test.ts +116 -0
  196. package/src/utils/dates.ts +94 -0
  197. package/dist/assets/__vite-browser-external-BqAtzd2P.js +0 -1
  198. package/dist/assets/worker-Bf8dt6S-.js +0 -109
  199. package/dist/classDiagram-ZZMXUADV-Bbo2n384.js +0 -30
  200. package/dist/classDiagram-v2-VYDZK3BY-xR8cGP0r.js +0 -30
  201. package/dist/error-entries-BovkFYNy.js +0 -56
  202. package/dist/flowDiagram-HODETNUW-D7IBKS12.js +0 -16
  203. package/dist/mermaid-HWGCJPDP-DYCzSILp.js +0 -2
  204. package/dist/stateDiagram-v2-MP3YSRHH-ChNddepZ.js +0 -30
  205. package/dist/swimlanesDiagram-VR7AAH4N-FUSwmzEp.js +0 -30
@@ -6,14 +6,14 @@ import { Popover as PopoverPrimitive } from "radix-ui";
6
6
  const PopoverClose = PopoverPrimitive.Close;
7
7
 
8
8
  import type { Column, ColumnDef } from "@tanstack/react-table";
9
- import { formatDate, isValid } from "date-fns";
9
+ import { isValid } from "date-fns";
10
10
  import { useRef } from "react";
11
11
  import { useLocale, useNumberFormatter } from "react-aria";
12
12
  import { WithLocale } from "@/core/i18n/with-locale";
13
13
  import type { DataType } from "@/core/kernel/messages";
14
14
  import type { CalculateTopKRows } from "@/plugins/impl/DataTablePlugin";
15
15
  import { cn } from "@/utils/cn";
16
- import { type DateFormat, exactDateTime, getDateFormat } from "@/utils/dates";
16
+ import { exactDateTime } from "@/utils/dates";
17
17
  import { Events } from "@/utils/events";
18
18
  import { Logger } from "@/utils/Logger";
19
19
  import { Maps } from "@/utils/maps";
@@ -583,21 +583,19 @@ function renderDate({
583
583
  value,
584
584
  dataType,
585
585
  dtype,
586
- format,
586
+ displayValue,
587
587
  locale,
588
588
  }: {
589
589
  value: Date;
590
590
  dataType?: DataType;
591
591
  dtype?: string;
592
- format?: DateFormat | null;
592
+ displayValue?: string;
593
593
  locale: string;
594
594
  }): React.ReactNode {
595
595
  const type = dataType === "date" ? "date" : "datetime";
596
596
  const timezone = extractTimezone(dtype);
597
597
 
598
- const exactValue = format
599
- ? formatDate(value, format)
600
- : exactDateTime(value, timezone, locale);
598
+ const exactValue = displayValue ?? exactDateTime(value, timezone, locale);
601
599
 
602
600
  return (
603
601
  <DatePopover date={value} type={type}>
@@ -640,7 +638,8 @@ export function renderCellValue<TData, TValue>({
640
638
 
641
639
  if (dataType === "datetime" && typeof value === "string") {
642
640
  try {
643
- if (!isValid(value)) {
641
+ const date = new Date(value);
642
+ if (!format || !isValid(date)) {
644
643
  return (
645
644
  <div onClick={selectCell} className={cellStyles}>
646
645
  {value}
@@ -648,14 +647,15 @@ export function renderCellValue<TData, TValue>({
648
647
  );
649
648
  }
650
649
 
651
- const date = new Date(value);
652
- const format = getDateFormat(value);
650
+ const displayValue = String(column.applyColumnFormatting(value));
653
651
  return (
654
- <WithLocale>
655
- {(locale) =>
656
- renderDate({ value: date, dataType, dtype, format, locale })
657
- }
658
- </WithLocale>
652
+ <div onClick={selectCell} className={cellStyles}>
653
+ <WithLocale>
654
+ {(locale) =>
655
+ renderDate({ value: date, dataType, dtype, displayValue, locale })
656
+ }
657
+ </WithLocale>
658
+ </div>
659
659
  );
660
660
  } catch (error) {
661
661
  Logger.error("Error parsing datetime, fallback to string", error);
@@ -672,10 +672,17 @@ export function renderCellValue<TData, TValue>({
672
672
  }
673
673
 
674
674
  // e.g. 2010-10-07 17:15:00
675
+ const displayValue = format
676
+ ? String(column.applyColumnFormatting(value))
677
+ : undefined;
675
678
  return (
676
- <WithLocale>
677
- {(locale) => renderDate({ value, dataType, dtype, locale })}
678
- </WithLocale>
679
+ <div onClick={selectCell} className={cellStyles}>
680
+ <WithLocale>
681
+ {(locale) =>
682
+ renderDate({ value, dataType, dtype, displayValue, locale })
683
+ }
684
+ </WithLocale>
685
+ </div>
679
686
  );
680
687
  }
681
688
 
@@ -1,12 +1,19 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
+ import type { DataType } from "@/core/kernel/messages";
4
+ import { assertNever } from "@/utils/assertNever";
5
+ import { copyToClipboard } from "@/utils/copy";
6
+ import {
7
+ parseLocalISODate,
8
+ parseLocalISODateTime,
9
+ parseTimeToDate,
10
+ } from "@/utils/dates";
11
+ import { Logger } from "@/utils/Logger";
3
12
  import type { Cell } from "@tanstack/react-table";
4
13
  import { useAtomValue } from "jotai";
5
14
  import { CopyIcon, FilterIcon, SquareStack } from "lucide-react";
6
15
  import type { RefObject } from "react";
7
16
  import useEvent from "react-use-event-hook";
8
- import { copyToClipboard } from "@/utils/copy";
9
- import { Logger } from "@/utils/Logger";
10
17
  import {
11
18
  ContextMenu,
12
19
  ContextMenuContent,
@@ -16,13 +23,94 @@ import {
16
23
  ContextMenuTrigger,
17
24
  } from "../ui/context-menu";
18
25
  import { DATA_CELL_ID } from "./cell-utils";
19
- import {
20
- Filter,
21
- isMembershipFilterType,
22
- type MembershipFilterType,
23
- } from "./filters";
26
+ import { type FilterType, Filter } from "./filters";
24
27
  import { selectedCellsAtom } from "./range-focus/atoms";
25
- import { getClipboardContent, getRawValue } from "./utils";
28
+ import { getClipboardContent, getRawValue, isNullishSentinel } from "./utils";
29
+
30
+ type Comparison = "eq" | "neq";
31
+
32
+ const symbolOp = {
33
+ eq: "==",
34
+ neq: "!=",
35
+ } as const;
36
+
37
+ const textOp = {
38
+ eq: "equals",
39
+ neq: "does_not_equal",
40
+ } as const;
41
+
42
+ export function buildCellFilter({
43
+ type,
44
+ value,
45
+ comparison = "eq",
46
+ dataType,
47
+ dtype,
48
+ }: {
49
+ type: FilterType;
50
+ value: unknown;
51
+ comparison?: Comparison;
52
+ dataType?: DataType;
53
+ dtype?: string;
54
+ }) {
55
+ if (isNullishSentinel(value, dataType, dtype)) {
56
+ return { type, operator: comparison === "eq" ? "is_null" : "is_not_null" };
57
+ }
58
+
59
+ switch (type) {
60
+ case "number":
61
+ if (typeof value !== "number") {
62
+ return undefined;
63
+ }
64
+
65
+ return Filter.number({
66
+ operator: symbolOp[comparison],
67
+ value,
68
+ });
69
+ case "text":
70
+ return Filter.text({
71
+ operator: textOp[comparison],
72
+ text: value as string,
73
+ });
74
+ case "date": {
75
+ const date = parseLocalISODate(value as string);
76
+ if (!date) {
77
+ return undefined;
78
+ }
79
+ return Filter.date({
80
+ operator: symbolOp[comparison],
81
+ value: date,
82
+ });
83
+ }
84
+ case "datetime": {
85
+ const date = parseLocalISODateTime(value as string);
86
+ if (!date) {
87
+ return undefined;
88
+ }
89
+ return Filter.datetime({
90
+ operator: symbolOp[comparison],
91
+ value: date,
92
+ });
93
+ }
94
+ case "time": {
95
+ const time = parseTimeToDate(value as string);
96
+ if (!time) {
97
+ return undefined;
98
+ }
99
+ return Filter.time({
100
+ operator: symbolOp[comparison],
101
+ value: time,
102
+ });
103
+ }
104
+ case "boolean": {
105
+ const target = comparison === "eq" ? value : !(value as boolean);
106
+ return Filter.boolean({
107
+ operator: target ? "is_true" : "is_false",
108
+ });
109
+ }
110
+ default:
111
+ assertNever(type);
112
+ }
113
+ }
26
114
 
27
115
  export const DataTableContextMenu = <TData,>({
28
116
  contextMenuRef,
@@ -102,19 +190,34 @@ export const CellContextMenu = <TData,>({
102
190
 
103
191
  const column = cell.column;
104
192
  const filterType = column.columnDef.meta?.filterType;
105
- const membershipFilterType: MembershipFilterType | undefined =
106
- column.getCanFilter() && filterType && isMembershipFilterType(filterType)
107
- ? filterType
193
+ const dataType = column.columnDef.meta?.dataType;
194
+ const dtype = column.columnDef.meta?.dtype;
195
+
196
+ const canFilter = Boolean(filterType && column.getCanFilter());
197
+ const buildFilter = (comparison: Comparison) =>
198
+ canFilter
199
+ ? buildCellFilter({
200
+ type: filterType as FilterType,
201
+ value: rawValue,
202
+ comparison,
203
+ dataType,
204
+ dtype,
205
+ })
108
206
  : undefined;
207
+ const eqFilter = buildFilter("eq");
208
+ const canFilterByValue = eqFilter !== undefined;
209
+
210
+ const handleFilterCellByValue = (comparison: Comparison) => {
211
+ if (!filterType) {
212
+ return;
213
+ }
214
+
215
+ const filter = comparison === "eq" ? eqFilter : buildFilter("neq");
216
+
217
+ if (!filter) {
218
+ return;
219
+ }
109
220
 
110
- const handleFilterCell = (
111
- type: MembershipFilterType,
112
- operator: "in" | "not_in",
113
- ) => {
114
- const filter =
115
- type === "number"
116
- ? Filter.number({ operator, values: [rawValue] })
117
- : Filter.text({ operator, values: [rawValue] });
118
221
  column.setFilterValue(filter);
119
222
  };
120
223
 
@@ -130,18 +233,14 @@ export const CellContextMenu = <TData,>({
130
233
  Copy selected cells
131
234
  </ContextMenuItem>
132
235
  )}
133
- {membershipFilterType && (
236
+ {canFilterByValue && (
134
237
  <>
135
238
  <ContextMenuSeparator />
136
- <ContextMenuItem
137
- onClick={() => handleFilterCell(membershipFilterType, "in")}
138
- >
239
+ <ContextMenuItem onClick={() => handleFilterCellByValue("eq")}>
139
240
  <FilterIcon className="mo-dropdown-icon h-3 w-3" />
140
241
  Filter by this value
141
242
  </ContextMenuItem>
142
- <ContextMenuItem
143
- onClick={() => handleFilterCell(membershipFilterType, "not_in")}
144
- >
243
+ <ContextMenuItem onClick={() => handleFilterCellByValue("neq")}>
145
244
  <FilterIcon className="mo-dropdown-icon h-3 w-3" />
146
245
  Remove rows with this value
147
246
  </ContextMenuItem>
@@ -14,6 +14,9 @@ import {
14
14
  dateToLocalISODate,
15
15
  dateToLocalISODateTime,
16
16
  dateToLocalISOTime,
17
+ parseLocalISODate,
18
+ parseLocalISODateTime,
19
+ parseTimeToDate,
17
20
  } from "@/utils/dates";
18
21
  import type { FilterType } from "./filters";
19
22
 
@@ -72,53 +75,23 @@ export function parsePastedDate(
72
75
  return undefined;
73
76
  }
74
77
 
75
- const timeMatch =
76
- filterType === "time"
77
- ? trimmed.match(/^(\d{1,2}):(\d{2})(?::(\d{2}))?\s*(am|pm)?$/i)
78
- : null;
79
- if (timeMatch) {
80
- const [, hStr, mStr, sStr, ampm] = timeMatch;
81
- let hour = Number.parseInt(hStr, 10);
82
- const minute = Number.parseInt(mStr, 10);
83
- const second = sStr ? Number.parseInt(sStr, 10) : 0;
84
- if (ampm) {
85
- const isPm = ampm.toLowerCase() === "pm";
86
- if (hour === 12) {
87
- hour = isPm ? 12 : 0;
88
- } else if (isPm) {
89
- hour += 12;
90
- }
78
+ if (filterType === "time") {
79
+ const date = parseTimeToDate(trimmed);
80
+ if (date) {
81
+ return date;
91
82
  }
92
- return new Date(1970, 0, 1, hour, minute, second);
93
83
  }
94
84
 
95
- const dateOnlyMatch = trimmed.match(/^(\d{4})-(\d{2})-(\d{2})$/);
96
- if (dateOnlyMatch) {
97
- const [, y, m, d] = dateOnlyMatch;
98
- return new Date(
99
- Number.parseInt(y, 10),
100
- Number.parseInt(m, 10) - 1,
101
- Number.parseInt(d, 10),
102
- );
85
+ if (filterType === "date") {
86
+ const date = parseLocalISODate(trimmed);
87
+ if (date) {
88
+ return date;
89
+ }
103
90
  }
104
91
 
105
- // Parse ISO datetimes as wall-clock to stay consistent with the picker's
106
- // local-time basis. Trailing `Z` or offsets are stripped so that pasting
107
- // `2024-01-15T08:30:00Z` displays `08:30` instead of being shifted by the
108
- // viewer's timezone.
109
- const isoMatch = trimmed.match(
110
- /^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?$/,
111
- );
112
- if (isoMatch) {
113
- const [, y, mo, d, h, mi, s] = isoMatch;
114
- return new Date(
115
- Number.parseInt(y, 10),
116
- Number.parseInt(mo, 10) - 1,
117
- Number.parseInt(d, 10),
118
- Number.parseInt(h, 10),
119
- Number.parseInt(mi, 10),
120
- s ? Number.parseInt(s, 10) : 0,
121
- );
92
+ const isoDateTime = parseLocalISODateTime(trimmed);
93
+ if (isoDateTime) {
94
+ return isoDateTime;
122
95
  }
123
96
 
124
97
  const parsed = new Date(trimmed);