@marimo-team/frontend 0.14.18-dev21 → 0.14.18-dev24

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 (1159) hide show
  1. package/package.json +3 -2
  2. package/src/README.md +18 -0
  3. package/src/__mocks__/common.ts +160 -0
  4. package/src/__mocks__/notebook.ts +76 -0
  5. package/src/__mocks__/requests.ts +72 -0
  6. package/src/__mocks__/tracebacks.ts +32 -0
  7. package/src/__tests__/CellStatus.test.tsx +263 -0
  8. package/src/__tests__/__snapshots__/CellStatus.test.tsx.snap +523 -0
  9. package/src/__tests__/chat-utils.test.ts +234 -0
  10. package/src/__tests__/lru.test.ts +74 -0
  11. package/src/__tests__/main.test.tsx +174 -0
  12. package/src/__tests__/setup.ts +17 -0
  13. package/src/__tests__/test-helpers.ts +24 -0
  14. package/src/assets/circle-check.ico +0 -0
  15. package/src/assets/circle-play.ico +0 -0
  16. package/src/assets/circle-x.ico +0 -0
  17. package/src/assets/gradient.png +0 -0
  18. package/src/assets/icon-16x16.png +0 -0
  19. package/src/assets/icon-32x32.png +0 -0
  20. package/src/assets/noise.png +0 -0
  21. package/src/components/ai/ai-provider-icon.tsx +47 -0
  22. package/src/components/app-config/ai-config.tsx +760 -0
  23. package/src/components/app-config/app-config-button.tsx +91 -0
  24. package/src/components/app-config/app-config-form.tsx +307 -0
  25. package/src/components/app-config/common.tsx +48 -0
  26. package/src/components/app-config/constants.ts +47 -0
  27. package/src/components/app-config/incorrect-model-id.tsx +41 -0
  28. package/src/components/app-config/is-overridden.tsx +119 -0
  29. package/src/components/app-config/optional-features.tsx +251 -0
  30. package/src/components/app-config/state.ts +18 -0
  31. package/src/components/app-config/user-config-form.tsx +1329 -0
  32. package/src/components/audio/audio-recorder.tsx +63 -0
  33. package/src/components/buttons/clear-button.tsx +23 -0
  34. package/src/components/buttons/undo-button.tsx +35 -0
  35. package/src/components/chat/chat-panel.tsx +772 -0
  36. package/src/components/chat/markdown-renderer.tsx +217 -0
  37. package/src/components/chat/reasoning-accordion.tsx +50 -0
  38. package/src/components/chat/tool-call-accordion.tsx +118 -0
  39. package/src/components/data-table/SearchBar.tsx +66 -0
  40. package/src/components/data-table/TableActions.tsx +183 -0
  41. package/src/components/data-table/__tests__/__snapshots__/chart-spec-model.test.ts.snap +1079 -0
  42. package/src/components/data-table/__tests__/chart-spec-model.test.ts +707 -0
  43. package/src/components/data-table/__tests__/column_formatting.test.ts +115 -0
  44. package/src/components/data-table/__tests__/columns.test.tsx +341 -0
  45. package/src/components/data-table/__tests__/data-table.test.tsx +60 -0
  46. package/src/components/data-table/__tests__/pagination.test.tsx +152 -0
  47. package/src/components/data-table/__tests__/types.test.ts +44 -0
  48. package/src/components/data-table/__tests__/url-detector.test.tsx +169 -0
  49. package/src/components/data-table/__tests__/useColumnPinning.test.ts +76 -0
  50. package/src/components/data-table/cell-selection/__tests__/feature.test.ts +187 -0
  51. package/src/components/data-table/cell-selection/feature.ts +123 -0
  52. package/src/components/data-table/cell-selection/types.ts +49 -0
  53. package/src/components/data-table/cell-styling/feature.ts +40 -0
  54. package/src/components/data-table/cell-styling/types.ts +26 -0
  55. package/src/components/data-table/charts/README.md +65 -0
  56. package/src/components/data-table/charts/__tests__/__snapshots__/spec-snapshot.test.ts.snap +47 -0
  57. package/src/components/data-table/charts/__tests__/altair-generator.test.ts +425 -0
  58. package/src/components/data-table/charts/__tests__/renderer.test.ts +20 -0
  59. package/src/components/data-table/charts/__tests__/spec-snapshot.test.ts +83 -0
  60. package/src/components/data-table/charts/__tests__/spec.test.ts +997 -0
  61. package/src/components/data-table/charts/__tests__/storage.test.ts +103 -0
  62. package/src/components/data-table/charts/chart-spec/altair-generator.ts +162 -0
  63. package/src/components/data-table/charts/chart-spec/encodings.ts +173 -0
  64. package/src/components/data-table/charts/chart-spec/spec.ts +345 -0
  65. package/src/components/data-table/charts/chart-spec/tooltips.ts +168 -0
  66. package/src/components/data-table/charts/chart-spec/types.ts +77 -0
  67. package/src/components/data-table/charts/charts.tsx +492 -0
  68. package/src/components/data-table/charts/components/chart-items.tsx +369 -0
  69. package/src/components/data-table/charts/components/chart-states.tsx +37 -0
  70. package/src/components/data-table/charts/components/form-fields.tsx +872 -0
  71. package/src/components/data-table/charts/components/layouts.tsx +118 -0
  72. package/src/components/data-table/charts/constants.ts +159 -0
  73. package/src/components/data-table/charts/context.ts +20 -0
  74. package/src/components/data-table/charts/forms/common-chart.tsx +202 -0
  75. package/src/components/data-table/charts/forms/heatmap.tsx +44 -0
  76. package/src/components/data-table/charts/forms/pie.tsx +70 -0
  77. package/src/components/data-table/charts/lazy-chart.tsx +56 -0
  78. package/src/components/data-table/charts/schemas.ts +140 -0
  79. package/src/components/data-table/charts/storage.ts +88 -0
  80. package/src/components/data-table/charts/types.ts +124 -0
  81. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +227 -0
  82. package/src/components/data-table/column-formatting/feature.ts +247 -0
  83. package/src/components/data-table/column-formatting/types.ts +54 -0
  84. package/src/components/data-table/column-header.tsx +672 -0
  85. package/src/components/data-table/column-summary/chart-skeleton.tsx +57 -0
  86. package/src/components/data-table/column-summary/chart-spec-model.tsx +916 -0
  87. package/src/components/data-table/column-summary/column-summary.tsx +166 -0
  88. package/src/components/data-table/column-summary/legacy-chart-spec.ts +242 -0
  89. package/src/components/data-table/column-summary/utils.ts +142 -0
  90. package/src/components/data-table/column-wrapping/feature.ts +62 -0
  91. package/src/components/data-table/column-wrapping/types.ts +29 -0
  92. package/src/components/data-table/columns.tsx +528 -0
  93. package/src/components/data-table/copy-column/feature.ts +27 -0
  94. package/src/components/data-table/copy-column/types.ts +19 -0
  95. package/src/components/data-table/data-table.tsx +298 -0
  96. package/src/components/data-table/date-popover.tsx +146 -0
  97. package/src/components/data-table/download-actions.tsx +186 -0
  98. package/src/components/data-table/filter-pills.tsx +120 -0
  99. package/src/components/data-table/filters.ts +202 -0
  100. package/src/components/data-table/focus-row/feature.ts +41 -0
  101. package/src/components/data-table/focus-row/types.ts +32 -0
  102. package/src/components/data-table/header-items.tsx +295 -0
  103. package/src/components/data-table/hooks/use-column-pinning.ts +51 -0
  104. package/src/components/data-table/hooks/use-panel-ownership.ts +98 -0
  105. package/src/components/data-table/loading-table.tsx +56 -0
  106. package/src/components/data-table/mime-cell.tsx +68 -0
  107. package/src/components/data-table/pagination.tsx +329 -0
  108. package/src/components/data-table/range-focus/__tests__/atoms.test.ts +907 -0
  109. package/src/components/data-table/range-focus/__tests__/utils.test.ts +316 -0
  110. package/src/components/data-table/range-focus/atoms.ts +380 -0
  111. package/src/components/data-table/range-focus/cell-selection-indicator.tsx +37 -0
  112. package/src/components/data-table/range-focus/provider.tsx +13 -0
  113. package/src/components/data-table/range-focus/use-cell-range-selection.ts +119 -0
  114. package/src/components/data-table/range-focus/use-scroll-into-view.ts +46 -0
  115. package/src/components/data-table/range-focus/utils.ts +105 -0
  116. package/src/components/data-table/renderers.tsx +247 -0
  117. package/src/components/data-table/row-viewer-panel/__tests__/filter-rows.test.ts +82 -0
  118. package/src/components/data-table/row-viewer-panel/__tests__/row-viewer.test.tsx +58 -0
  119. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +371 -0
  120. package/src/components/data-table/types.ts +81 -0
  121. package/src/components/data-table/uniformSample.tsx +19 -0
  122. package/src/components/data-table/url-detector.tsx +111 -0
  123. package/src/components/data-table/utils.ts +46 -0
  124. package/src/components/databases/display.tsx +66 -0
  125. package/src/components/databases/engine-variable.tsx +51 -0
  126. package/src/components/databases/icon.tsx +91 -0
  127. package/src/components/databases/icons/clickhouse.svg +1 -0
  128. package/src/components/databases/icons/databricks.svg +1 -0
  129. package/src/components/databases/icons/datafusion.png +0 -0
  130. package/src/components/databases/icons/duckdb.svg +1 -0
  131. package/src/components/databases/icons/googlebigquery.svg +1 -0
  132. package/src/components/databases/icons/iceberg.png +0 -0
  133. package/src/components/databases/icons/motherduck.svg +9 -0
  134. package/src/components/databases/icons/mysql.svg +1 -0
  135. package/src/components/databases/icons/postgresql.svg +1 -0
  136. package/src/components/databases/icons/redshift.svg +1 -0
  137. package/src/components/databases/icons/snowflake.svg +1 -0
  138. package/src/components/databases/icons/spark.svg +1 -0
  139. package/src/components/databases/icons/sqlalchemy.svg +1 -0
  140. package/src/components/databases/icons/sqlite.svg +1 -0
  141. package/src/components/databases/icons/timeplus.svg +17 -0
  142. package/src/components/databases/icons/trino.svg +1 -0
  143. package/src/components/datasets/icons.tsx +55 -0
  144. package/src/components/datasources/__tests__/install-package-button.test.tsx +85 -0
  145. package/src/components/datasources/__tests__/utils.test.ts +171 -0
  146. package/src/components/datasources/column-preview.tsx +269 -0
  147. package/src/components/datasources/components.tsx +100 -0
  148. package/src/components/datasources/datasources.tsx +782 -0
  149. package/src/components/datasources/install-package-button.tsx +46 -0
  150. package/src/components/datasources/utils.ts +62 -0
  151. package/src/components/debug/indicator.tsx +19 -0
  152. package/src/components/debugger/debugger-code.css +3 -0
  153. package/src/components/debugger/debugger-code.tsx +222 -0
  154. package/src/components/dependency-graph/custom-node.tsx +89 -0
  155. package/src/components/dependency-graph/dependency-graph-minimap.tsx +197 -0
  156. package/src/components/dependency-graph/dependency-graph-tree.tsx +181 -0
  157. package/src/components/dependency-graph/dependency-graph.css +17 -0
  158. package/src/components/dependency-graph/dependency-graph.tsx +66 -0
  159. package/src/components/dependency-graph/elements.ts +185 -0
  160. package/src/components/dependency-graph/panels.tsx +279 -0
  161. package/src/components/dependency-graph/types.ts +21 -0
  162. package/src/components/dependency-graph/utils/changes.ts +54 -0
  163. package/src/components/dependency-graph/utils/layout.ts +45 -0
  164. package/src/components/dependency-graph/utils/useFitToViewOnDimensionChange.ts +25 -0
  165. package/src/components/editor/Cell.tsx +1175 -0
  166. package/src/components/editor/Disconnected.tsx +72 -0
  167. package/src/components/editor/Output.tsx +462 -0
  168. package/src/components/editor/RecoveryButton.tsx +161 -0
  169. package/src/components/editor/SortableCell.tsx +161 -0
  170. package/src/components/editor/__tests__/data-attributes.test.tsx +173 -0
  171. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +183 -0
  172. package/src/components/editor/actions/name-cell-input.tsx +137 -0
  173. package/src/components/editor/actions/types.ts +53 -0
  174. package/src/components/editor/actions/useCellActionButton.tsx +422 -0
  175. package/src/components/editor/actions/useConfigActions.tsx +182 -0
  176. package/src/components/editor/actions/useCopyNotebook.tsx +41 -0
  177. package/src/components/editor/actions/useHideAllMarkdownCode.ts +53 -0
  178. package/src/components/editor/actions/useNotebookActions.tsx +556 -0
  179. package/src/components/editor/actions/useRestartKernel.tsx +36 -0
  180. package/src/components/editor/ai/__tests__/completion-utils.test.ts +379 -0
  181. package/src/components/editor/ai/add-cell-with-ai.tsx +369 -0
  182. package/src/components/editor/ai/ai-completion-editor.tsx +249 -0
  183. package/src/components/editor/ai/completion-utils.ts +95 -0
  184. package/src/components/editor/ai/merge-editor.css +9 -0
  185. package/src/components/editor/alerts/connecting-alert.tsx +46 -0
  186. package/src/components/editor/alerts/floating-alert.tsx +47 -0
  187. package/src/components/editor/alerts/stdin-blocking-alert.tsx +61 -0
  188. package/src/components/editor/app-container.tsx +53 -0
  189. package/src/components/editor/boundary/ErrorBoundary.tsx +41 -0
  190. package/src/components/editor/cell/CellStatus.tsx +371 -0
  191. package/src/components/editor/cell/CreateCellButton.tsx +132 -0
  192. package/src/components/editor/cell/DeleteButton.tsx +58 -0
  193. package/src/components/editor/cell/PendingDeleteConfirmation.tsx +126 -0
  194. package/src/components/editor/cell/RunButton.tsx +109 -0
  195. package/src/components/editor/cell/StopButton.tsx +36 -0
  196. package/src/components/editor/cell/TinyCode.css +10 -0
  197. package/src/components/editor/cell/TinyCode.tsx +53 -0
  198. package/src/components/editor/cell/cell-actions.tsx +185 -0
  199. package/src/components/editor/cell/cell-context-menu.tsx +243 -0
  200. package/src/components/editor/cell/cell-status.css +21 -0
  201. package/src/components/editor/cell/code/cell-editor.tsx +546 -0
  202. package/src/components/editor/cell/code/icons.tsx +31 -0
  203. package/src/components/editor/cell/code/language-toggle.tsx +140 -0
  204. package/src/components/editor/cell/collapse.tsx +100 -0
  205. package/src/components/editor/cell/toolbar.tsx +89 -0
  206. package/src/components/editor/cell/useAddCell.ts +29 -0
  207. package/src/components/editor/cell/useDeleteCell.tsx +89 -0
  208. package/src/components/editor/cell/useRunCells.ts +86 -0
  209. package/src/components/editor/cell/useShouldShowInterrupt.ts +26 -0
  210. package/src/components/editor/cell/useSplitCell.tsx +41 -0
  211. package/src/components/editor/chrome/components/contribute-snippet-button.tsx +138 -0
  212. package/src/components/editor/chrome/components/feedback-button.tsx +105 -0
  213. package/src/components/editor/chrome/panels/__tests__/write-secret-modal.test.ts +43 -0
  214. package/src/components/editor/chrome/panels/constants.ts +2 -0
  215. package/src/components/editor/chrome/panels/context-aware-panel/atoms.ts +28 -0
  216. package/src/components/editor/chrome/panels/context-aware-panel/context-aware-panel.tsx +167 -0
  217. package/src/components/editor/chrome/panels/datasources-panel.tsx +6 -0
  218. package/src/components/editor/chrome/panels/dependency-graph-panel.tsx +23 -0
  219. package/src/components/editor/chrome/panels/documentation-panel.tsx +29 -0
  220. package/src/components/editor/chrome/panels/empty-state.tsx +28 -0
  221. package/src/components/editor/chrome/panels/error-panel.tsx +35 -0
  222. package/src/components/editor/chrome/panels/file-explorer-panel.tsx +33 -0
  223. package/src/components/editor/chrome/panels/logs-panel.tsx +97 -0
  224. package/src/components/editor/chrome/panels/outline/floating-outline.tsx +129 -0
  225. package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +172 -0
  226. package/src/components/editor/chrome/panels/outline-panel.css +6 -0
  227. package/src/components/editor/chrome/panels/outline-panel.tsx +39 -0
  228. package/src/components/editor/chrome/panels/packages-panel.tsx +635 -0
  229. package/src/components/editor/chrome/panels/packages-state.ts +5 -0
  230. package/src/components/editor/chrome/panels/scratchpad-panel.tsx +8 -0
  231. package/src/components/editor/chrome/panels/secrets-panel.tsx +155 -0
  232. package/src/components/editor/chrome/panels/snippets-panel.css +11 -0
  233. package/src/components/editor/chrome/panels/snippets-panel.tsx +230 -0
  234. package/src/components/editor/chrome/panels/tracing-panel.tsx +28 -0
  235. package/src/components/editor/chrome/panels/variable-panel.tsx +31 -0
  236. package/src/components/editor/chrome/panels/write-secret-modal.tsx +190 -0
  237. package/src/components/editor/chrome/state.ts +102 -0
  238. package/src/components/editor/chrome/types.ts +133 -0
  239. package/src/components/editor/chrome/wrapper/__tests__/minimap-state.test.ts +209 -0
  240. package/src/components/editor/chrome/wrapper/__tests__/storage.test.ts +41 -0
  241. package/src/components/editor/chrome/wrapper/app-chrome.css +22 -0
  242. package/src/components/editor/chrome/wrapper/app-chrome.tsx +256 -0
  243. package/src/components/editor/chrome/wrapper/footer-item.tsx +43 -0
  244. package/src/components/editor/chrome/wrapper/footer-items/ai-status.tsx +47 -0
  245. package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +111 -0
  246. package/src/components/editor/chrome/wrapper/footer-items/copilot-status.tsx +125 -0
  247. package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +185 -0
  248. package/src/components/editor/chrome/wrapper/footer-items/minimap-status.tsx +21 -0
  249. package/src/components/editor/chrome/wrapper/footer-items/rtc-status.tsx +65 -0
  250. package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +370 -0
  251. package/src/components/editor/chrome/wrapper/footer.tsx +90 -0
  252. package/src/components/editor/chrome/wrapper/minimap-state.ts +164 -0
  253. package/src/components/editor/chrome/wrapper/minimap.tsx +443 -0
  254. package/src/components/editor/chrome/wrapper/panels.tsx +10 -0
  255. package/src/components/editor/chrome/wrapper/sidebar.tsx +100 -0
  256. package/src/components/editor/chrome/wrapper/storage.ts +56 -0
  257. package/src/components/editor/chrome/wrapper/utils.ts +8 -0
  258. package/src/components/editor/code/readonly-python-code.tsx +160 -0
  259. package/src/components/editor/columns/__tests__/storage.test.ts +104 -0
  260. package/src/components/editor/columns/cell-column.tsx +105 -0
  261. package/src/components/editor/columns/sortable-column.tsx +175 -0
  262. package/src/components/editor/columns/storage.ts +56 -0
  263. package/src/components/editor/common.ts +20 -0
  264. package/src/components/editor/controls/Controls.tsx +225 -0
  265. package/src/components/editor/controls/command-palette-button.tsx +27 -0
  266. package/src/components/editor/controls/command-palette.tsx +210 -0
  267. package/src/components/editor/controls/keyboard-shortcuts.tsx +309 -0
  268. package/src/components/editor/controls/notebook-menu-dropdown.tsx +157 -0
  269. package/src/components/editor/controls/shutdown-button.tsx +70 -0
  270. package/src/components/editor/database/__tests__/__snapshots__/as-code.test.ts.snap +659 -0
  271. package/src/components/editor/database/__tests__/as-code.test.ts +598 -0
  272. package/src/components/editor/database/__tests__/secrets.test.ts +38 -0
  273. package/src/components/editor/database/add-database-form.tsx +395 -0
  274. package/src/components/editor/database/as-code.ts +786 -0
  275. package/src/components/editor/database/form-renderers.tsx +211 -0
  276. package/src/components/editor/database/schemas.ts +485 -0
  277. package/src/components/editor/database/secrets.ts +25 -0
  278. package/src/components/editor/documentation.css +139 -0
  279. package/src/components/editor/dynamic-favicon.tsx +126 -0
  280. package/src/components/editor/errors/auto-fix.tsx +61 -0
  281. package/src/components/editor/file-tree/__tests__/requesting-tree.test.ts +321 -0
  282. package/src/components/editor/file-tree/file-explorer.tsx +679 -0
  283. package/src/components/editor/file-tree/file-viewer.tsx +283 -0
  284. package/src/components/editor/file-tree/renderers.tsx +83 -0
  285. package/src/components/editor/file-tree/requesting-tree.tsx +228 -0
  286. package/src/components/editor/file-tree/state.tsx +26 -0
  287. package/src/components/editor/file-tree/types.ts +118 -0
  288. package/src/components/editor/file-tree/upload.tsx +101 -0
  289. package/src/components/editor/header/app-header.tsx +28 -0
  290. package/src/components/editor/header/filename-form.tsx +27 -0
  291. package/src/components/editor/header/filename-input.css +21 -0
  292. package/src/components/editor/header/filename-input.tsx +244 -0
  293. package/src/components/editor/header/status.tsx +72 -0
  294. package/src/components/editor/inputs/Inputs.css +118 -0
  295. package/src/components/editor/inputs/Inputs.styles.ts +66 -0
  296. package/src/components/editor/inputs/Inputs.tsx +34 -0
  297. package/src/components/editor/kiosk-mode.tsx +25 -0
  298. package/src/components/editor/links/cell-link-list.tsx +74 -0
  299. package/src/components/editor/links/cell-link.tsx +128 -0
  300. package/src/components/editor/navigation/__tests__/clipboard.test.ts +466 -0
  301. package/src/components/editor/navigation/__tests__/navigation.test.ts +1743 -0
  302. package/src/components/editor/navigation/__tests__/selection.test.ts +194 -0
  303. package/src/components/editor/navigation/clipboard.ts +205 -0
  304. package/src/components/editor/navigation/focus-utils.ts +48 -0
  305. package/src/components/editor/navigation/multi-cell-action-toolbar.tsx +499 -0
  306. package/src/components/editor/navigation/navigation.ts +699 -0
  307. package/src/components/editor/navigation/selection.ts +114 -0
  308. package/src/components/editor/navigation/state.ts +5 -0
  309. package/src/components/editor/navigation/vim-bindings.test.ts +109 -0
  310. package/src/components/editor/navigation/vim-bindings.ts +90 -0
  311. package/src/components/editor/notebook-banner.tsx +75 -0
  312. package/src/components/editor/output/CalloutOutput.styles.ts +22 -0
  313. package/src/components/editor/output/CalloutOutput.tsx +19 -0
  314. package/src/components/editor/output/ConsoleOutput.tsx +276 -0
  315. package/src/components/editor/output/EmotionCacheProvider.tsx +32 -0
  316. package/src/components/editor/output/HtmlOutput.tsx +25 -0
  317. package/src/components/editor/output/ImageOutput.tsx +25 -0
  318. package/src/components/editor/output/JsonOutput.tsx +424 -0
  319. package/src/components/editor/output/MarimoErrorOutput.tsx +511 -0
  320. package/src/components/editor/output/MarimoTracebackOutput.tsx +233 -0
  321. package/src/components/editor/output/Outputs.css +102 -0
  322. package/src/components/editor/output/TextOutput.tsx +42 -0
  323. package/src/components/editor/output/VideoOutput.tsx +11 -0
  324. package/src/components/editor/output/__tests__/ansi.test.ts +39 -0
  325. package/src/components/editor/output/__tests__/json-output.test.ts +269 -0
  326. package/src/components/editor/output/__tests__/traceback.test.tsx +105 -0
  327. package/src/components/editor/output/useWrapText.ts +14 -0
  328. package/src/components/editor/package-alert.tsx +596 -0
  329. package/src/components/editor/renderMimeIcon.tsx +38 -0
  330. package/src/components/editor/renderers/CellArray.tsx +352 -0
  331. package/src/components/editor/renderers/cells-renderer.tsx +96 -0
  332. package/src/components/editor/renderers/grid-layout/grid-layout.tsx +650 -0
  333. package/src/components/editor/renderers/grid-layout/plugin.tsx +146 -0
  334. package/src/components/editor/renderers/grid-layout/styles.css +31 -0
  335. package/src/components/editor/renderers/grid-layout/types.ts +89 -0
  336. package/src/components/editor/renderers/layout-select.tsx +86 -0
  337. package/src/components/editor/renderers/plugins.ts +31 -0
  338. package/src/components/editor/renderers/slides-layout/plugin.tsx +31 -0
  339. package/src/components/editor/renderers/slides-layout/slides-layout.tsx +74 -0
  340. package/src/components/editor/renderers/slides-layout/types.ts +12 -0
  341. package/src/components/editor/renderers/types.ts +75 -0
  342. package/src/components/editor/renderers/vertical-layout/__tests__/useDelayVisibility.test.ts +87 -0
  343. package/src/components/editor/renderers/vertical-layout/__tests__/useFocusFirstEditor.test.ts +123 -0
  344. package/src/components/editor/renderers/vertical-layout/__tests__/vertical-layout.test.ts +173 -0
  345. package/src/components/editor/renderers/vertical-layout/sidebar/__tests__/sidebar.test.tsx +56 -0
  346. package/src/components/editor/renderers/vertical-layout/sidebar/sheet-sidebar.tsx +32 -0
  347. package/src/components/editor/renderers/vertical-layout/sidebar/sidebar-slot.tsx +10 -0
  348. package/src/components/editor/renderers/vertical-layout/sidebar/sidebar.css +20 -0
  349. package/src/components/editor/renderers/vertical-layout/sidebar/sidebar.tsx +30 -0
  350. package/src/components/editor/renderers/vertical-layout/sidebar/state.ts +46 -0
  351. package/src/components/editor/renderers/vertical-layout/sidebar/toggle.tsx +25 -0
  352. package/src/components/editor/renderers/vertical-layout/sidebar/wrapped-with-sidebar.tsx +38 -0
  353. package/src/components/editor/renderers/vertical-layout/useDelayVisibility.ts +32 -0
  354. package/src/components/editor/renderers/vertical-layout/useFocusFirstEditor.ts +107 -0
  355. package/src/components/editor/renderers/vertical-layout/vertical-layout-wrapper.tsx +46 -0
  356. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +451 -0
  357. package/src/components/editor/stdin-blocking-alert.tsx +83 -0
  358. package/src/components/export/export-output-button.tsx +14 -0
  359. package/src/components/find-replace/find-replace.tsx +293 -0
  360. package/src/components/forms/__tests__/form-utils.test.ts +104 -0
  361. package/src/components/forms/form-utils.ts +90 -0
  362. package/src/components/forms/form.tsx +817 -0
  363. package/src/components/forms/options.ts +59 -0
  364. package/src/components/forms/switchable-multi-select.tsx +134 -0
  365. package/src/components/home/components.tsx +189 -0
  366. package/src/components/home/state.ts +30 -0
  367. package/src/components/icons/copy-icon.tsx +59 -0
  368. package/src/components/icons/github-copilot.tsx +17 -0
  369. package/src/components/icons/large-spinner.tsx +39 -0
  370. package/src/components/icons/loading-ellipsis.tsx +46 -0
  371. package/src/components/icons/multi-icon.css +9 -0
  372. package/src/components/icons/multi-icon.tsx +30 -0
  373. package/src/components/icons/spinner.tsx +38 -0
  374. package/src/components/layout/toolbar.tsx +26 -0
  375. package/src/components/modal/ImperativeModal.tsx +187 -0
  376. package/src/components/pages/edit-page.tsx +37 -0
  377. package/src/components/pages/home-page.tsx +514 -0
  378. package/src/components/pages/run-page.tsx +55 -0
  379. package/src/components/scratchpad/scratchpad-history.ts +28 -0
  380. package/src/components/scratchpad/scratchpad.tsx +280 -0
  381. package/src/components/shortcuts/renderShortcut.tsx +208 -0
  382. package/src/components/slides/slides-component.tsx +132 -0
  383. package/src/components/slides/slides.css +101 -0
  384. package/src/components/sort/SortableCellsProvider.tsx +242 -0
  385. package/src/components/static-html/share-modal.tsx +181 -0
  386. package/src/components/static-html/static-banner.tsx +164 -0
  387. package/src/components/terminal/terminal.tsx +110 -0
  388. package/src/components/terminal/xterm.css +3 -0
  389. package/src/components/tracing/tracing-spec.ts +118 -0
  390. package/src/components/tracing/tracing.test.tsx +66 -0
  391. package/src/components/tracing/tracing.tsx +410 -0
  392. package/src/components/ui/accordion.tsx +70 -0
  393. package/src/components/ui/alert-dialog.tsx +176 -0
  394. package/src/components/ui/alert.tsx +64 -0
  395. package/src/components/ui/aria-popover.tsx +43 -0
  396. package/src/components/ui/badge.tsx +41 -0
  397. package/src/components/ui/button.tsx +156 -0
  398. package/src/components/ui/calendar.tsx +231 -0
  399. package/src/components/ui/card.tsx +83 -0
  400. package/src/components/ui/checkbox.tsx +33 -0
  401. package/src/components/ui/combobox.tsx +278 -0
  402. package/src/components/ui/command.tsx +165 -0
  403. package/src/components/ui/context-menu.tsx +193 -0
  404. package/src/components/ui/date-input.tsx +127 -0
  405. package/src/components/ui/date-picker.tsx +188 -0
  406. package/src/components/ui/dialog.tsx +155 -0
  407. package/src/components/ui/draggable-popover.tsx +68 -0
  408. package/src/components/ui/dropdown-menu.tsx +189 -0
  409. package/src/components/ui/field.tsx +90 -0
  410. package/src/components/ui/form.tsx +224 -0
  411. package/src/components/ui/fullscreen.tsx +38 -0
  412. package/src/components/ui/input.tsx +208 -0
  413. package/src/components/ui/kbd.tsx +22 -0
  414. package/src/components/ui/label.tsx +26 -0
  415. package/src/components/ui/links.tsx +23 -0
  416. package/src/components/ui/menu-items.tsx +101 -0
  417. package/src/components/ui/native-select.tsx +39 -0
  418. package/src/components/ui/navigation.tsx +154 -0
  419. package/src/components/ui/number-field.tsx +99 -0
  420. package/src/components/ui/popover.tsx +63 -0
  421. package/src/components/ui/progress.tsx +28 -0
  422. package/src/components/ui/radio-group.tsx +44 -0
  423. package/src/components/ui/range-slider.tsx +102 -0
  424. package/src/components/ui/scroll-area.tsx +47 -0
  425. package/src/components/ui/select.tsx +167 -0
  426. package/src/components/ui/sheet.tsx +143 -0
  427. package/src/components/ui/skeleton.tsx +16 -0
  428. package/src/components/ui/slider.tsx +80 -0
  429. package/src/components/ui/switch.tsx +54 -0
  430. package/src/components/ui/table.tsx +122 -0
  431. package/src/components/ui/tabs.tsx +55 -0
  432. package/src/components/ui/textarea.tsx +104 -0
  433. package/src/components/ui/toast.tsx +133 -0
  434. package/src/components/ui/toaster.tsx +30 -0
  435. package/src/components/ui/toggle.tsx +49 -0
  436. package/src/components/ui/tooltip.tsx +87 -0
  437. package/src/components/ui/typography.tsx +207 -0
  438. package/src/components/ui/use-restore-focus.ts +28 -0
  439. package/src/components/ui/use-toast.ts +224 -0
  440. package/src/components/utils/delay-mount.tsx +81 -0
  441. package/src/components/utils/lazy-mount.tsx +24 -0
  442. package/src/components/variables/common.tsx +37 -0
  443. package/src/components/variables/variables-table.tsx +335 -0
  444. package/src/core/MarimoApp.tsx +103 -0
  445. package/src/core/ai/chat-utils.ts +71 -0
  446. package/src/core/ai/context/__tests__/registry.test.ts +516 -0
  447. package/src/core/ai/context/context.ts +16 -0
  448. package/src/core/ai/context/providers/__tests__/__snapshots__/tables.test.ts.snap +291 -0
  449. package/src/core/ai/context/providers/__tests__/__snapshots__/variable.test.ts.snap +378 -0
  450. package/src/core/ai/context/providers/__tests__/tables.test.ts +271 -0
  451. package/src/core/ai/context/providers/__tests__/variable.test.ts +312 -0
  452. package/src/core/ai/context/providers/common.ts +7 -0
  453. package/src/core/ai/context/providers/tables.ts +208 -0
  454. package/src/core/ai/context/providers/variable.ts +72 -0
  455. package/src/core/ai/context/registry.ts +180 -0
  456. package/src/core/ai/state.ts +58 -0
  457. package/src/core/alerts/state.ts +75 -0
  458. package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +1312 -0
  459. package/src/core/cells/__tests__/add-missing-import.test.ts +78 -0
  460. package/src/core/cells/__tests__/cell.test.ts +193 -0
  461. package/src/core/cells/__tests__/cells.test.ts +2664 -0
  462. package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +239 -0
  463. package/src/core/cells/__tests__/focus.test.ts +271 -0
  464. package/src/core/cells/__tests__/ids.test.ts +90 -0
  465. package/src/core/cells/__tests__/names.test.ts +62 -0
  466. package/src/core/cells/__tests__/pending-delete-service.test.tsx +202 -0
  467. package/src/core/cells/__tests__/runs.test.ts +453 -0
  468. package/src/core/cells/__tests__/session.test.ts +757 -0
  469. package/src/core/cells/__tests__/utils.test.ts +428 -0
  470. package/src/core/cells/actions.ts +21 -0
  471. package/src/core/cells/add-missing-import.ts +114 -0
  472. package/src/core/cells/cell.ts +243 -0
  473. package/src/core/cells/cells.ts +1751 -0
  474. package/src/core/cells/collapseConsoleOutputs.tsx +133 -0
  475. package/src/core/cells/effects.ts +42 -0
  476. package/src/core/cells/focus.ts +128 -0
  477. package/src/core/cells/ids.ts +124 -0
  478. package/src/core/cells/logs.ts +114 -0
  479. package/src/core/cells/names.ts +107 -0
  480. package/src/core/cells/outline.ts +30 -0
  481. package/src/core/cells/outputs.ts +34 -0
  482. package/src/core/cells/pending-delete-service.ts +183 -0
  483. package/src/core/cells/runs.ts +196 -0
  484. package/src/core/cells/scrollCellIntoView.ts +133 -0
  485. package/src/core/cells/session.ts +281 -0
  486. package/src/core/cells/types.ts +128 -0
  487. package/src/core/cells/utils.ts +141 -0
  488. package/src/core/codemirror/__tests__/__snapshots__/setup.test.ts.snap +229 -0
  489. package/src/core/codemirror/__tests__/extensions.test.ts +117 -0
  490. package/src/core/codemirror/__tests__/format.test.ts +227 -0
  491. package/src/core/codemirror/__tests__/setup.test.ts +178 -0
  492. package/src/core/codemirror/ai/request.ts +72 -0
  493. package/src/core/codemirror/ai/resources.ts +90 -0
  494. package/src/core/codemirror/cells/extensions.ts +387 -0
  495. package/src/core/codemirror/cells/state.ts +32 -0
  496. package/src/core/codemirror/cells/traceback-decorations.ts +111 -0
  497. package/src/core/codemirror/cm.ts +267 -0
  498. package/src/core/codemirror/compat/__tests__/jupyter.test.ts +136 -0
  499. package/src/core/codemirror/compat/jupyter.tsx +244 -0
  500. package/src/core/codemirror/completion/Autocompleter.ts +172 -0
  501. package/src/core/codemirror/completion/__tests__/hints.test.ts +84 -0
  502. package/src/core/codemirror/completion/__tests__/keymap.test.ts +44 -0
  503. package/src/core/codemirror/completion/completer.ts +58 -0
  504. package/src/core/codemirror/completion/hints.ts +143 -0
  505. package/src/core/codemirror/completion/keymap.ts +85 -0
  506. package/src/core/codemirror/completion/utils.ts +18 -0
  507. package/src/core/codemirror/completion/variable-completions.ts +100 -0
  508. package/src/core/codemirror/config/extension.ts +63 -0
  509. package/src/core/codemirror/config/types.ts +10 -0
  510. package/src/core/codemirror/copilot/__tests__/copilot.test.ts +260 -0
  511. package/src/core/codemirror/copilot/__tests__/getCodes.test.ts +209 -0
  512. package/src/core/codemirror/copilot/__tests__/trim-utils.test.ts +291 -0
  513. package/src/core/codemirror/copilot/client.ts +123 -0
  514. package/src/core/codemirror/copilot/copilot-config.tsx +285 -0
  515. package/src/core/codemirror/copilot/extension.ts +285 -0
  516. package/src/core/codemirror/copilot/getCodes.ts +130 -0
  517. package/src/core/codemirror/copilot/language-server.ts +255 -0
  518. package/src/core/codemirror/copilot/state.ts +66 -0
  519. package/src/core/codemirror/copilot/trim-utils.ts +33 -0
  520. package/src/core/codemirror/copilot/types.ts +41 -0
  521. package/src/core/codemirror/editing/__tests__/commands.test.ts +106 -0
  522. package/src/core/codemirror/editing/__tests__/debugging.test.ts +193 -0
  523. package/src/core/codemirror/editing/commands.ts +25 -0
  524. package/src/core/codemirror/editing/debugging.ts +58 -0
  525. package/src/core/codemirror/editing/extensions.ts +4 -0
  526. package/src/core/codemirror/extensions.ts +95 -0
  527. package/src/core/codemirror/facet.ts +19 -0
  528. package/src/core/codemirror/find-replace/__tests__/navigate.test.ts +695 -0
  529. package/src/core/codemirror/find-replace/extension.ts +41 -0
  530. package/src/core/codemirror/find-replace/navigate.ts +221 -0
  531. package/src/core/codemirror/find-replace/query.ts +31 -0
  532. package/src/core/codemirror/find-replace/search-highlight.ts +148 -0
  533. package/src/core/codemirror/find-replace/state.ts +167 -0
  534. package/src/core/codemirror/format.ts +120 -0
  535. package/src/core/codemirror/go-to-definition/__tests__/commands.test.ts +205 -0
  536. package/src/core/codemirror/go-to-definition/commands.ts +80 -0
  537. package/src/core/codemirror/go-to-definition/extension.ts +23 -0
  538. package/src/core/codemirror/go-to-definition/underline.ts +223 -0
  539. package/src/core/codemirror/go-to-definition/utils.ts +126 -0
  540. package/src/core/codemirror/keymaps/__tests__/keymaps.test.ts +43 -0
  541. package/src/core/codemirror/keymaps/__tests__/vimrc.test.ts +121 -0
  542. package/src/core/codemirror/keymaps/keymaps.ts +179 -0
  543. package/src/core/codemirror/keymaps/vim.ts +348 -0
  544. package/src/core/codemirror/keymaps/vimrc.ts +149 -0
  545. package/src/core/codemirror/language/LanguageAdapters.ts +23 -0
  546. package/src/core/codemirror/language/__tests__/ast.test.ts +124 -0
  547. package/src/core/codemirror/language/__tests__/extension.test.ts +260 -0
  548. package/src/core/codemirror/language/__tests__/indentOneTab.test.ts +31 -0
  549. package/src/core/codemirror/language/__tests__/markdown.test.ts +495 -0
  550. package/src/core/codemirror/language/__tests__/sql.test.ts +1640 -0
  551. package/src/core/codemirror/language/__tests__/utils.test.ts +166 -0
  552. package/src/core/codemirror/language/commands.ts +59 -0
  553. package/src/core/codemirror/language/embedded/__tests__/embedded-python.test.ts +163 -0
  554. package/src/core/codemirror/language/embedded/embedded-python.ts +131 -0
  555. package/src/core/codemirror/language/embedded/latex.ts +257 -0
  556. package/src/core/codemirror/language/extension.ts +322 -0
  557. package/src/core/codemirror/language/languages/markdown.ts +261 -0
  558. package/src/core/codemirror/language/languages/python.ts +329 -0
  559. package/src/core/codemirror/language/languages/sql-dialects/README.md +5 -0
  560. package/src/core/codemirror/language/languages/sql-dialects/duckdb.ts +22 -0
  561. package/src/core/codemirror/language/languages/sql-dialects/spec_duckdb.py +257 -0
  562. package/src/core/codemirror/language/languages/sql.ts +669 -0
  563. package/src/core/codemirror/language/metadata.ts +71 -0
  564. package/src/core/codemirror/language/panel/markdown.tsx +63 -0
  565. package/src/core/codemirror/language/panel/panel.tsx +197 -0
  566. package/src/core/codemirror/language/panel/sql.tsx +132 -0
  567. package/src/core/codemirror/language/types.ts +41 -0
  568. package/src/core/codemirror/language/utils/ast.ts +84 -0
  569. package/src/core/codemirror/language/utils/indentOneTab.ts +9 -0
  570. package/src/core/codemirror/language/utils/quotes.ts +18 -0
  571. package/src/core/codemirror/language/utils.ts +78 -0
  572. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +860 -0
  573. package/src/core/codemirror/lsp/federated-lsp.ts +235 -0
  574. package/src/core/codemirror/lsp/lens.ts +130 -0
  575. package/src/core/codemirror/lsp/notebook-lsp.ts +604 -0
  576. package/src/core/codemirror/lsp/transports.ts +31 -0
  577. package/src/core/codemirror/lsp/types.ts +55 -0
  578. package/src/core/codemirror/lsp/utils.ts +11 -0
  579. package/src/core/codemirror/markdown/__tests__/commands.test.ts +522 -0
  580. package/src/core/codemirror/markdown/commands.ts +478 -0
  581. package/src/core/codemirror/markdown/completions.ts +273 -0
  582. package/src/core/codemirror/markdown/extension.ts +106 -0
  583. package/src/core/codemirror/misc/__tests__/dnd.test.ts +111 -0
  584. package/src/core/codemirror/misc/__tests__/paste.test.ts +239 -0
  585. package/src/core/codemirror/misc/dnd.ts +48 -0
  586. package/src/core/codemirror/misc/paste.ts +181 -0
  587. package/src/core/codemirror/placeholder/__tests__/extensions.test.ts +132 -0
  588. package/src/core/codemirror/placeholder/extensions.ts +99 -0
  589. package/src/core/codemirror/react-dom/createPanel.tsx +39 -0
  590. package/src/core/codemirror/reactive-references/__tests__/analyzer.test.ts +1222 -0
  591. package/src/core/codemirror/reactive-references/analyzer.ts +608 -0
  592. package/src/core/codemirror/reactive-references/extension.ts +154 -0
  593. package/src/core/codemirror/readonly/__tests__/extension.test.ts +55 -0
  594. package/src/core/codemirror/readonly/extension.ts +187 -0
  595. package/src/core/codemirror/rtc/extension.ts +450 -0
  596. package/src/core/codemirror/rtc/loro/awareness.ts +496 -0
  597. package/src/core/codemirror/rtc/loro/colors.ts +38 -0
  598. package/src/core/codemirror/rtc/loro/sync.ts +159 -0
  599. package/src/core/codemirror/theme/__tests__/light.test.ts +136 -0
  600. package/src/core/codemirror/theme/dark.ts +50 -0
  601. package/src/core/codemirror/theme/light.ts +58 -0
  602. package/src/core/codemirror/types.ts +5 -0
  603. package/src/core/codemirror/utils.ts +103 -0
  604. package/src/core/codemirror/vim/cursor-visibility.ts +58 -0
  605. package/src/core/config/__tests__/config-schema.test.ts +232 -0
  606. package/src/core/config/capabilities.ts +15 -0
  607. package/src/core/config/config-schema.ts +290 -0
  608. package/src/core/config/config.ts +109 -0
  609. package/src/core/config/feature-flag.tsx +60 -0
  610. package/src/core/config/if-capability.tsx +19 -0
  611. package/src/core/config/widths.ts +5 -0
  612. package/src/core/constants.ts +52 -0
  613. package/src/core/datasets/__tests__/all-tables.test.ts +466 -0
  614. package/src/core/datasets/__tests__/data-source.test.ts +461 -0
  615. package/src/core/datasets/data-source-connections.ts +334 -0
  616. package/src/core/datasets/engines.ts +10 -0
  617. package/src/core/datasets/request-registry.ts +34 -0
  618. package/src/core/datasets/state.ts +143 -0
  619. package/src/core/datasets/types.ts +38 -0
  620. package/src/core/debugger/state.ts +10 -0
  621. package/src/core/documentation/state.ts +13 -0
  622. package/src/core/dom/__tests__/htmlUtils.test.ts +22 -0
  623. package/src/core/dom/__tests__/outline.test.ts +370 -0
  624. package/src/core/dom/defineCustomElement.ts +23 -0
  625. package/src/core/dom/events.ts +94 -0
  626. package/src/core/dom/htmlUtils.ts +75 -0
  627. package/src/core/dom/outline.ts +123 -0
  628. package/src/core/dom/ui-element.css +8 -0
  629. package/src/core/dom/ui-element.ts +249 -0
  630. package/src/core/dom/uiregistry.ts +209 -0
  631. package/src/core/edit-app.tsx +189 -0
  632. package/src/core/errors/__tests__/errors.test.ts +62 -0
  633. package/src/core/errors/__tests__/utils.test.ts +108 -0
  634. package/src/core/errors/errors.ts +96 -0
  635. package/src/core/errors/state.ts +44 -0
  636. package/src/core/errors/utils.ts +67 -0
  637. package/src/core/export/hooks.ts +60 -0
  638. package/src/core/functions/FunctionRegistry.ts +18 -0
  639. package/src/core/hotkeys/__tests__/shortcuts.test.ts +166 -0
  640. package/src/core/hotkeys/actions.ts +38 -0
  641. package/src/core/hotkeys/hotkeys.ts +503 -0
  642. package/src/core/hotkeys/shortcuts.ts +117 -0
  643. package/src/core/islands/__tests__/parse.test.ts +89 -0
  644. package/src/core/islands/bridge.ts +196 -0
  645. package/src/core/islands/components/output-wrapper.tsx +154 -0
  646. package/src/core/islands/components/web-components.tsx +120 -0
  647. package/src/core/islands/islands.css +14 -0
  648. package/src/core/islands/main.ts +200 -0
  649. package/src/core/islands/parse.ts +161 -0
  650. package/src/core/islands/state.ts +30 -0
  651. package/src/core/islands/toast.ts +41 -0
  652. package/src/core/islands/utils.ts +5 -0
  653. package/src/core/islands/worker/controller.ts +52 -0
  654. package/src/core/islands/worker/worker.tsx +178 -0
  655. package/src/core/kernel/RuntimeState.ts +94 -0
  656. package/src/core/kernel/__tests__/RuntimeState.test.ts +57 -0
  657. package/src/core/kernel/__tests__/handlers.test.ts +61 -0
  658. package/src/core/kernel/__tests__/session.test.ts +10 -0
  659. package/src/core/kernel/handlers.ts +159 -0
  660. package/src/core/kernel/messages.ts +54 -0
  661. package/src/core/kernel/queryParamHandlers.ts +39 -0
  662. package/src/core/kernel/session.ts +50 -0
  663. package/src/core/layout/layout.ts +99 -0
  664. package/src/core/layout/useTogglePresenting.ts +50 -0
  665. package/src/core/meta/globals.ts +25 -0
  666. package/src/core/meta/state.ts +25 -0
  667. package/src/core/mime.ts +9 -0
  668. package/src/core/mode.ts +80 -0
  669. package/src/core/network/DeferredRequestRegistry.ts +71 -0
  670. package/src/core/network/__tests__/DeferredRequestRegistry.test.ts +37 -0
  671. package/src/core/network/__tests__/api.test.ts +80 -0
  672. package/src/core/network/api.ts +145 -0
  673. package/src/core/network/auth.ts +13 -0
  674. package/src/core/network/connection.ts +33 -0
  675. package/src/core/network/requests-network.ts +398 -0
  676. package/src/core/network/requests-static.ts +88 -0
  677. package/src/core/network/requests-toasting.ts +91 -0
  678. package/src/core/network/requests.ts +24 -0
  679. package/src/core/network/resolve.ts +17 -0
  680. package/src/core/network/types.ts +188 -0
  681. package/src/core/packages/toast-components.tsx +88 -0
  682. package/src/core/packages/useInstallPackage.ts +46 -0
  683. package/src/core/rtc/state.ts +20 -0
  684. package/src/core/run-app.tsx +69 -0
  685. package/src/core/runtime/__tests__/config.test.ts +161 -0
  686. package/src/core/runtime/__tests__/createWsUrl.test.ts +61 -0
  687. package/src/core/runtime/__tests__/runtime.test.ts +603 -0
  688. package/src/core/runtime/config.ts +40 -0
  689. package/src/core/runtime/runtime.ts +277 -0
  690. package/src/core/runtime/types.ts +7 -0
  691. package/src/core/runtime/utils.ts +9 -0
  692. package/src/core/saving/file-state.ts +15 -0
  693. package/src/core/saving/filename.ts +55 -0
  694. package/src/core/saving/save-component.tsx +274 -0
  695. package/src/core/saving/state.ts +51 -0
  696. package/src/core/saving/useAutoSave.ts +68 -0
  697. package/src/core/secrets/request-registry.ts +16 -0
  698. package/src/core/slots/slots.ts +9 -0
  699. package/src/core/state/__tests__/jotai.test.ts +25 -0
  700. package/src/core/state/jotai.ts +69 -0
  701. package/src/core/state/observable.ts +23 -0
  702. package/src/core/static/__tests__/download-html.test.ts +41 -0
  703. package/src/core/static/__tests__/files.test.ts +183 -0
  704. package/src/core/static/__tests__/virtual-file-tracker.test.ts +92 -0
  705. package/src/core/static/download-html.ts +59 -0
  706. package/src/core/static/files.ts +148 -0
  707. package/src/core/static/static-state.ts +19 -0
  708. package/src/core/static/types.ts +8 -0
  709. package/src/core/static/virtual-file-tracker.ts +83 -0
  710. package/src/core/variables/__tests__/state.test.ts +148 -0
  711. package/src/core/variables/state.ts +81 -0
  712. package/src/core/variables/types.ts +22 -0
  713. package/src/core/vscode/vscode-bindings.ts +176 -0
  714. package/src/core/wasm/PyodideLoader.tsx +72 -0
  715. package/src/core/wasm/__tests__/router.test.ts +57 -0
  716. package/src/core/wasm/__tests__/share.test.ts +35 -0
  717. package/src/core/wasm/__tests__/state.test.ts +124 -0
  718. package/src/core/wasm/__tests__/store.test.ts +55 -0
  719. package/src/core/wasm/bridge.ts +622 -0
  720. package/src/core/wasm/router.ts +39 -0
  721. package/src/core/wasm/rpc.ts +32 -0
  722. package/src/core/wasm/share.ts +15 -0
  723. package/src/core/wasm/state.ts +21 -0
  724. package/src/core/wasm/store.ts +122 -0
  725. package/src/core/wasm/utils.ts +12 -0
  726. package/src/core/wasm/worker/bootstrap.ts +223 -0
  727. package/src/core/wasm/worker/constants.ts +2 -0
  728. package/src/core/wasm/worker/fs.ts +90 -0
  729. package/src/core/wasm/worker/getController.ts +16 -0
  730. package/src/core/wasm/worker/getFS.ts +9 -0
  731. package/src/core/wasm/worker/getMarimoWheel.ts +15 -0
  732. package/src/core/wasm/worker/getPyodideVersion.ts +10 -0
  733. package/src/core/wasm/worker/message-buffer.ts +32 -0
  734. package/src/core/wasm/worker/save-worker.ts +107 -0
  735. package/src/core/wasm/worker/tracer.ts +7 -0
  736. package/src/core/wasm/worker/types.ts +97 -0
  737. package/src/core/wasm/worker/worker.ts +375 -0
  738. package/src/core/websocket/StaticWebsocket.ts +61 -0
  739. package/src/core/websocket/connection-utils.ts +59 -0
  740. package/src/core/websocket/types.ts +43 -0
  741. package/src/core/websocket/useMarimoWebSocket.tsx +386 -0
  742. package/src/core/websocket/useWebSocket.tsx +88 -0
  743. package/src/css/admonition.css +127 -0
  744. package/src/css/app/App.css +77 -0
  745. package/src/css/app/Cell.css +425 -0
  746. package/src/css/app/Header.css +25 -0
  747. package/src/css/app/codemirror-completions.css +308 -0
  748. package/src/css/app/codemirror.css +136 -0
  749. package/src/css/app/fonts.css +50 -0
  750. package/src/css/app/print.css +86 -0
  751. package/src/css/app/reset.css +18 -0
  752. package/src/css/codehilite.css +354 -0
  753. package/src/css/common.css +45 -0
  754. package/src/css/globals.css +176 -0
  755. package/src/css/index.css +10 -0
  756. package/src/css/katex-fonts.css +214 -0
  757. package/src/css/katex.min.css +1182 -0
  758. package/src/css/md-tooltip.css +52 -0
  759. package/src/css/md.css +365 -0
  760. package/src/css/progress.css +93 -0
  761. package/src/css/table.css +45 -0
  762. package/src/custom.d.ts +24 -0
  763. package/src/fonts/Fira_Mono/FiraMono-Bold.ttf +0 -0
  764. package/src/fonts/Fira_Mono/FiraMono-Medium.ttf +0 -0
  765. package/src/fonts/Fira_Mono/FiraMono-Regular.ttf +0 -0
  766. package/src/fonts/KaTeX/KaTeX_AMS-Regular.ttf +0 -0
  767. package/src/fonts/KaTeX/KaTeX_AMS-Regular.woff +0 -0
  768. package/src/fonts/KaTeX/KaTeX_AMS-Regular.woff2 +0 -0
  769. package/src/fonts/KaTeX/KaTeX_Caligraphic-Bold.ttf +0 -0
  770. package/src/fonts/KaTeX/KaTeX_Caligraphic-Bold.woff +0 -0
  771. package/src/fonts/KaTeX/KaTeX_Caligraphic-Bold.woff2 +0 -0
  772. package/src/fonts/KaTeX/KaTeX_Caligraphic-Regular.ttf +0 -0
  773. package/src/fonts/KaTeX/KaTeX_Caligraphic-Regular.woff +0 -0
  774. package/src/fonts/KaTeX/KaTeX_Caligraphic-Regular.woff2 +0 -0
  775. package/src/fonts/KaTeX/KaTeX_Fraktur-Bold.ttf +0 -0
  776. package/src/fonts/KaTeX/KaTeX_Fraktur-Bold.woff +0 -0
  777. package/src/fonts/KaTeX/KaTeX_Fraktur-Bold.woff2 +0 -0
  778. package/src/fonts/KaTeX/KaTeX_Fraktur-Regular.ttf +0 -0
  779. package/src/fonts/KaTeX/KaTeX_Fraktur-Regular.woff +0 -0
  780. package/src/fonts/KaTeX/KaTeX_Fraktur-Regular.woff2 +0 -0
  781. package/src/fonts/KaTeX/KaTeX_Main-Bold.ttf +0 -0
  782. package/src/fonts/KaTeX/KaTeX_Main-Bold.woff +0 -0
  783. package/src/fonts/KaTeX/KaTeX_Main-Bold.woff2 +0 -0
  784. package/src/fonts/KaTeX/KaTeX_Main-BoldItalic.ttf +0 -0
  785. package/src/fonts/KaTeX/KaTeX_Main-BoldItalic.woff +0 -0
  786. package/src/fonts/KaTeX/KaTeX_Main-BoldItalic.woff2 +0 -0
  787. package/src/fonts/KaTeX/KaTeX_Main-Italic.ttf +0 -0
  788. package/src/fonts/KaTeX/KaTeX_Main-Italic.woff +0 -0
  789. package/src/fonts/KaTeX/KaTeX_Main-Italic.woff2 +0 -0
  790. package/src/fonts/KaTeX/KaTeX_Main-Regular.ttf +0 -0
  791. package/src/fonts/KaTeX/KaTeX_Main-Regular.woff +0 -0
  792. package/src/fonts/KaTeX/KaTeX_Main-Regular.woff2 +0 -0
  793. package/src/fonts/KaTeX/KaTeX_Math-BoldItalic.ttf +0 -0
  794. package/src/fonts/KaTeX/KaTeX_Math-BoldItalic.woff +0 -0
  795. package/src/fonts/KaTeX/KaTeX_Math-BoldItalic.woff2 +0 -0
  796. package/src/fonts/KaTeX/KaTeX_Math-Italic.ttf +0 -0
  797. package/src/fonts/KaTeX/KaTeX_Math-Italic.woff +0 -0
  798. package/src/fonts/KaTeX/KaTeX_Math-Italic.woff2 +0 -0
  799. package/src/fonts/KaTeX/KaTeX_SansSerif-Bold.ttf +0 -0
  800. package/src/fonts/KaTeX/KaTeX_SansSerif-Bold.woff +0 -0
  801. package/src/fonts/KaTeX/KaTeX_SansSerif-Bold.woff2 +0 -0
  802. package/src/fonts/KaTeX/KaTeX_SansSerif-Italic.ttf +0 -0
  803. package/src/fonts/KaTeX/KaTeX_SansSerif-Italic.woff +0 -0
  804. package/src/fonts/KaTeX/KaTeX_SansSerif-Italic.woff2 +0 -0
  805. package/src/fonts/KaTeX/KaTeX_SansSerif-Regular.ttf +0 -0
  806. package/src/fonts/KaTeX/KaTeX_SansSerif-Regular.woff +0 -0
  807. package/src/fonts/KaTeX/KaTeX_SansSerif-Regular.woff2 +0 -0
  808. package/src/fonts/KaTeX/KaTeX_Script-Regular.ttf +0 -0
  809. package/src/fonts/KaTeX/KaTeX_Script-Regular.woff +0 -0
  810. package/src/fonts/KaTeX/KaTeX_Script-Regular.woff2 +0 -0
  811. package/src/fonts/KaTeX/KaTeX_Size1-Regular.ttf +0 -0
  812. package/src/fonts/KaTeX/KaTeX_Size1-Regular.woff +0 -0
  813. package/src/fonts/KaTeX/KaTeX_Size1-Regular.woff2 +0 -0
  814. package/src/fonts/KaTeX/KaTeX_Size2-Regular.ttf +0 -0
  815. package/src/fonts/KaTeX/KaTeX_Size2-Regular.woff +0 -0
  816. package/src/fonts/KaTeX/KaTeX_Size2-Regular.woff2 +0 -0
  817. package/src/fonts/KaTeX/KaTeX_Size3-Regular.ttf +0 -0
  818. package/src/fonts/KaTeX/KaTeX_Size3-Regular.woff +0 -0
  819. package/src/fonts/KaTeX/KaTeX_Size3-Regular.woff2 +0 -0
  820. package/src/fonts/KaTeX/KaTeX_Size4-Regular.ttf +0 -0
  821. package/src/fonts/KaTeX/KaTeX_Size4-Regular.woff +0 -0
  822. package/src/fonts/KaTeX/KaTeX_Size4-Regular.woff2 +0 -0
  823. package/src/fonts/KaTeX/KaTeX_Typewriter-Regular.ttf +0 -0
  824. package/src/fonts/KaTeX/KaTeX_Typewriter-Regular.woff +0 -0
  825. package/src/fonts/KaTeX/KaTeX_Typewriter-Regular.woff2 +0 -0
  826. package/src/fonts/Lora/Lora-Italic-VariableFont_wght.ttf +0 -0
  827. package/src/fonts/Lora/Lora-VariableFont_wght.ttf +0 -0
  828. package/src/fonts/Lora/static/Lora-Bold.ttf +0 -0
  829. package/src/fonts/Lora/static/Lora-BoldItalic.ttf +0 -0
  830. package/src/fonts/Lora/static/Lora-Italic.ttf +0 -0
  831. package/src/fonts/Lora/static/Lora-Medium.ttf +0 -0
  832. package/src/fonts/Lora/static/Lora-MediumItalic.ttf +0 -0
  833. package/src/fonts/Lora/static/Lora-Regular.ttf +0 -0
  834. package/src/fonts/Lora/static/Lora-SemiBold.ttf +0 -0
  835. package/src/fonts/Lora/static/Lora-SemiBoldItalic.ttf +0 -0
  836. package/src/fonts/PT_Sans/PTSans-Bold.ttf +0 -0
  837. package/src/fonts/PT_Sans/PTSans-BoldItalic.ttf +0 -0
  838. package/src/fonts/PT_Sans/PTSans-Italic.ttf +0 -0
  839. package/src/fonts/PT_Sans/PTSans-Regular.ttf +0 -0
  840. package/src/hooks/__tests__/useBoolean.test.tsx +33 -0
  841. package/src/hooks/__tests__/useDebounce.test.tsx +182 -0
  842. package/src/hooks/__tests__/useEffectSkipFirstRender.test.tsx +42 -0
  843. package/src/hooks/__tests__/useEventListener.test.tsx +148 -0
  844. package/src/hooks/__tests__/useInternalStateWithSync.test.tsx +76 -0
  845. package/src/hooks/__tests__/useInterval.test.tsx +70 -0
  846. package/src/hooks/__tests__/usePackageMetadata.test.tsx +219 -0
  847. package/src/hooks/__tests__/useResizeHandle.test.tsx +240 -0
  848. package/src/hooks/__tests__/useResizeObserver.test.tsx +86 -0
  849. package/src/hooks/__tests__/useTimer.test.tsx +62 -0
  850. package/src/hooks/debug.ts +116 -0
  851. package/src/hooks/useAsyncData.ts +392 -0
  852. package/src/hooks/useAudioRecorder.ts +89 -0
  853. package/src/hooks/useAutoGrowInputProps.ts +56 -0
  854. package/src/hooks/useBoolean.ts +26 -0
  855. package/src/hooks/useCellRenderCount.ts +15 -0
  856. package/src/hooks/useDebounce.ts +95 -0
  857. package/src/hooks/useDeepCompareMemoize.ts +22 -0
  858. package/src/hooks/useEffectSkipFirstRender.ts +24 -0
  859. package/src/hooks/useElapsedTime.ts +25 -0
  860. package/src/hooks/useEvent.ts +2 -0
  861. package/src/hooks/useEventListener.ts +68 -0
  862. package/src/hooks/useHotkey.ts +77 -0
  863. package/src/hooks/useInternalStateWithSync.ts +26 -0
  864. package/src/hooks/useInterval.ts +49 -0
  865. package/src/hooks/useIsDragging.tsx +39 -0
  866. package/src/hooks/useLifecycle.ts +20 -0
  867. package/src/hooks/useLocalStorage.ts +22 -0
  868. package/src/hooks/useNonce.ts +9 -0
  869. package/src/hooks/usePackageMetadata.ts +52 -0
  870. package/src/hooks/useRecentCommands.ts +25 -0
  871. package/src/hooks/useResizeHandle.ts +110 -0
  872. package/src/hooks/useResizeObserver.ts +101 -0
  873. package/src/hooks/useScript.ts +90 -0
  874. package/src/hooks/useSelectAllContent.ts +42 -0
  875. package/src/hooks/useTimer.ts +48 -0
  876. package/src/main.tsx +20 -0
  877. package/src/mount.tsx +331 -0
  878. package/src/plugins/core/BadPlugin.tsx +72 -0
  879. package/src/plugins/core/RenderHTML.tsx +136 -0
  880. package/src/plugins/core/__test__/RenderHTML.test.ts +146 -0
  881. package/src/plugins/core/builder.ts +59 -0
  882. package/src/plugins/core/registerReactComponent.tsx +535 -0
  883. package/src/plugins/core/rpc.ts +55 -0
  884. package/src/plugins/core/sidebar-element.tsx +104 -0
  885. package/src/plugins/impl/ButtonPlugin.tsx +95 -0
  886. package/src/plugins/impl/CheckboxPlugin.tsx +56 -0
  887. package/src/plugins/impl/CodeEditorPlugin.tsx +119 -0
  888. package/src/plugins/impl/DataEditorPlugin.tsx +181 -0
  889. package/src/plugins/impl/DataTablePlugin.tsx +948 -0
  890. package/src/plugins/impl/DatePickerPlugin.tsx +74 -0
  891. package/src/plugins/impl/DateRangePlugin.tsx +82 -0
  892. package/src/plugins/impl/DateTimePickerPlugin.tsx +76 -0
  893. package/src/plugins/impl/DictPlugin.tsx +80 -0
  894. package/src/plugins/impl/DropdownPlugin.tsx +102 -0
  895. package/src/plugins/impl/FileBrowserPlugin.tsx +500 -0
  896. package/src/plugins/impl/FileUploadPlugin.tsx +302 -0
  897. package/src/plugins/impl/FormPlugin.tsx +294 -0
  898. package/src/plugins/impl/MicrophonePlugin.tsx +58 -0
  899. package/src/plugins/impl/MultiselectPlugin.tsx +207 -0
  900. package/src/plugins/impl/NumberPlugin.tsx +84 -0
  901. package/src/plugins/impl/RadioPlugin.tsx +77 -0
  902. package/src/plugins/impl/RangeSliderPlugin.tsx +163 -0
  903. package/src/plugins/impl/RefreshPlugin.tsx +158 -0
  904. package/src/plugins/impl/SearchableSelect.tsx +122 -0
  905. package/src/plugins/impl/SliderPlugin.tsx +166 -0
  906. package/src/plugins/impl/SwitchPlugin.tsx +48 -0
  907. package/src/plugins/impl/TabsPlugin.tsx +83 -0
  908. package/src/plugins/impl/TextAreaPlugin.tsx +131 -0
  909. package/src/plugins/impl/TextInputPlugin.tsx +169 -0
  910. package/src/plugins/impl/__tests__/DateTimePickerPlugin.test.tsx +45 -0
  911. package/src/plugins/impl/__tests__/DropdownPlugin.test.tsx +178 -0
  912. package/src/plugins/impl/__tests__/MultiSelectPlugin.test.ts +41 -0
  913. package/src/plugins/impl/__tests__/NumberPlugin.test.tsx +144 -0
  914. package/src/plugins/impl/anywidget/AnyWidgetPlugin.tsx +269 -0
  915. package/src/plugins/impl/anywidget/__tests__/AnyWidgetPlugin.test.tsx +181 -0
  916. package/src/plugins/impl/anywidget/__tests__/model.test.ts +370 -0
  917. package/src/plugins/impl/anywidget/model.ts +314 -0
  918. package/src/plugins/impl/chat/ChatPlugin.tsx +98 -0
  919. package/src/plugins/impl/chat/chat-ui.tsx +716 -0
  920. package/src/plugins/impl/chat/types.ts +39 -0
  921. package/src/plugins/impl/code/LazyAnyLanguageCodeMirror.tsx +6 -0
  922. package/src/plugins/impl/code/any-language-editor.tsx +68 -0
  923. package/src/plugins/impl/common/error-banner.tsx +111 -0
  924. package/src/plugins/impl/common/intent.ts +18 -0
  925. package/src/plugins/impl/common/labeled.tsx +69 -0
  926. package/src/plugins/impl/data-editor/__tests__/data-utils.test.ts +876 -0
  927. package/src/plugins/impl/data-editor/__tests__/glide-utils.test.ts +452 -0
  928. package/src/plugins/impl/data-editor/components.tsx +179 -0
  929. package/src/plugins/impl/data-editor/data-utils.ts +123 -0
  930. package/src/plugins/impl/data-editor/glide-data-editor.tsx +651 -0
  931. package/src/plugins/impl/data-editor/glide-utils.ts +200 -0
  932. package/src/plugins/impl/data-editor/themes.ts +49 -0
  933. package/src/plugins/impl/data-editor/types.ts +44 -0
  934. package/src/plugins/impl/data-explorer/ConnectedDataExplorerComponent.tsx +268 -0
  935. package/src/plugins/impl/data-explorer/DataExplorerPlugin.tsx +31 -0
  936. package/src/plugins/impl/data-explorer/components/column-summary.tsx +174 -0
  937. package/src/plugins/impl/data-explorer/components/icons.tsx +30 -0
  938. package/src/plugins/impl/data-explorer/components/query-form.tsx +296 -0
  939. package/src/plugins/impl/data-explorer/encoding.ts +107 -0
  940. package/src/plugins/impl/data-explorer/functions/function.ts +83 -0
  941. package/src/plugins/impl/data-explorer/functions/types.ts +32 -0
  942. package/src/plugins/impl/data-explorer/marks.ts +21 -0
  943. package/src/plugins/impl/data-explorer/queries/field-suggestion.ts +65 -0
  944. package/src/plugins/impl/data-explorer/queries/histograms.ts +41 -0
  945. package/src/plugins/impl/data-explorer/queries/queries.ts +204 -0
  946. package/src/plugins/impl/data-explorer/queries/removeUndefined.ts +11 -0
  947. package/src/plugins/impl/data-explorer/queries/types.ts +54 -0
  948. package/src/plugins/impl/data-explorer/queries/utils.ts +85 -0
  949. package/src/plugins/impl/data-explorer/spec.ts +28 -0
  950. package/src/plugins/impl/data-explorer/state/reducer.ts +92 -0
  951. package/src/plugins/impl/data-explorer/state/types.ts +28 -0
  952. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +303 -0
  953. package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +1600 -0
  954. package/src/plugins/impl/data-frames/forms/__tests__/form.test.tsx +67 -0
  955. package/src/plugins/impl/data-frames/forms/context.ts +13 -0
  956. package/src/plugins/impl/data-frames/forms/datatype-icon.tsx +43 -0
  957. package/src/plugins/impl/data-frames/forms/renderers.tsx +518 -0
  958. package/src/plugins/impl/data-frames/panel.tsx +308 -0
  959. package/src/plugins/impl/data-frames/schema.ts +211 -0
  960. package/src/plugins/impl/data-frames/types.ts +91 -0
  961. package/src/plugins/impl/data-frames/utils/__tests__/getUpdatedColumnTypes.test.ts +191 -0
  962. package/src/plugins/impl/data-frames/utils/__tests__/operators.test.ts +116 -0
  963. package/src/plugins/impl/data-frames/utils/getUpdatedColumnTypes.ts +67 -0
  964. package/src/plugins/impl/data-frames/utils/operators.ts +202 -0
  965. package/src/plugins/impl/image-comparison/ImageComparisonComponent.tsx +39 -0
  966. package/src/plugins/impl/multiselectFilterFn.tsx +22 -0
  967. package/src/plugins/impl/panel/PanelPlugin.tsx +266 -0
  968. package/src/plugins/impl/panel/__tests__/utils.test.ts +119 -0
  969. package/src/plugins/impl/panel/utils.ts +104 -0
  970. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +300 -0
  971. package/src/plugins/impl/plotly/__tests__/parse-from-template.test.ts +73 -0
  972. package/src/plugins/impl/plotly/mapbox.css +359 -0
  973. package/src/plugins/impl/plotly/parse-from-template.ts +58 -0
  974. package/src/plugins/impl/plotly/plotly.css +280 -0
  975. package/src/plugins/impl/vega/VegaPlugin.tsx +40 -0
  976. package/src/plugins/impl/vega/__tests__/__snapshots__/make-selectable.test.ts.snap +1210 -0
  977. package/src/plugins/impl/vega/__tests__/encodings.test.ts +172 -0
  978. package/src/plugins/impl/vega/__tests__/loader.test.ts +73 -0
  979. package/src/plugins/impl/vega/__tests__/make-selectable.test.ts +575 -0
  980. package/src/plugins/impl/vega/__tests__/params.test.ts +52 -0
  981. package/src/plugins/impl/vega/__tests__/resolve-data.test.ts +236 -0
  982. package/src/plugins/impl/vega/__tests__/vega.test.ts +603 -0
  983. package/src/plugins/impl/vega/batched.ts +41 -0
  984. package/src/plugins/impl/vega/encodings.ts +111 -0
  985. package/src/plugins/impl/vega/fix-relative-url.ts +15 -0
  986. package/src/plugins/impl/vega/formats.ts +25 -0
  987. package/src/plugins/impl/vega/loader.ts +320 -0
  988. package/src/plugins/impl/vega/make-selectable.ts +248 -0
  989. package/src/plugins/impl/vega/marks.ts +36 -0
  990. package/src/plugins/impl/vega/params.ts +192 -0
  991. package/src/plugins/impl/vega/resolve-data.ts +101 -0
  992. package/src/plugins/impl/vega/types.ts +32 -0
  993. package/src/plugins/impl/vega/utils.ts +46 -0
  994. package/src/plugins/impl/vega/vega-component.tsx +271 -0
  995. package/src/plugins/impl/vega/vega-loader.ts +53 -0
  996. package/src/plugins/impl/vega/vega.css +31 -0
  997. package/src/plugins/layout/AccordionPlugin.tsx +63 -0
  998. package/src/plugins/layout/CalloutPlugin.tsx +34 -0
  999. package/src/plugins/layout/DownloadPlugin.tsx +136 -0
  1000. package/src/plugins/layout/ImageComparisonPlugin.tsx +35 -0
  1001. package/src/plugins/layout/JsonOutputPlugin.tsx +47 -0
  1002. package/src/plugins/layout/LazyPlugin.tsx +98 -0
  1003. package/src/plugins/layout/MimeRenderPlugin.tsx +45 -0
  1004. package/src/plugins/layout/NavigationMenuPlugin.tsx +219 -0
  1005. package/src/plugins/layout/ProgressPlugin.tsx +175 -0
  1006. package/src/plugins/layout/RoutesPlugin.tsx +81 -0
  1007. package/src/plugins/layout/StatPlugin.tsx +100 -0
  1008. package/src/plugins/layout/TexPlugin.tsx +102 -0
  1009. package/src/plugins/layout/__test__/ProgressPlugin.test.ts +26 -0
  1010. package/src/plugins/layout/carousel/CarouselPlugin.tsx +50 -0
  1011. package/src/plugins/layout/mermaid/MermaidPlugin.tsx +26 -0
  1012. package/src/plugins/layout/mermaid/mermaid.tsx +94 -0
  1013. package/src/plugins/layout/navigation-menu.css +37 -0
  1014. package/src/plugins/plugins.ts +116 -0
  1015. package/src/plugins/stateless-plugin.ts +29 -0
  1016. package/src/plugins/types.ts +82 -0
  1017. package/src/stories/__fixtures__/vega.ts +225 -0
  1018. package/src/stories/accordion.stories.tsx +100 -0
  1019. package/src/stories/alert-dialog.mdx +42 -0
  1020. package/src/stories/app-chrome.stories.tsx +26 -0
  1021. package/src/stories/button.stories.tsx +90 -0
  1022. package/src/stories/callout.stories.tsx +73 -0
  1023. package/src/stories/cell-status.stories.tsx +145 -0
  1024. package/src/stories/cell.stories.tsx +336 -0
  1025. package/src/stories/checkbox.stories.tsx +44 -0
  1026. package/src/stories/colors.stories.tsx +156 -0
  1027. package/src/stories/combobox.stories.tsx +133 -0
  1028. package/src/stories/context-menu.mdx +23 -0
  1029. package/src/stories/data-explorer.stories.tsx +30 -0
  1030. package/src/stories/data-table.stories.tsx +130 -0
  1031. package/src/stories/dataframe.stories.tsx +46 -0
  1032. package/src/stories/debugger.stories.tsx +34 -0
  1033. package/src/stories/dialog.stories.tsx +80 -0
  1034. package/src/stories/dropdown-menu.mdx +159 -0
  1035. package/src/stories/editor-inputs.stories.tsx +47 -0
  1036. package/src/stories/editor.stories.tsx +91 -0
  1037. package/src/stories/file-upload.stories.tsx +103 -0
  1038. package/src/stories/form-wrapper.stories.tsx +147 -0
  1039. package/src/stories/input.stories.tsx +56 -0
  1040. package/src/stories/label.mdx +9 -0
  1041. package/src/stories/log-viewer.stories.tsx +74 -0
  1042. package/src/stories/number-field.mdx +17 -0
  1043. package/src/stories/number-field.stories.tsx +41 -0
  1044. package/src/stories/progress-component.stories.tsx +74 -0
  1045. package/src/stories/progress.stories.tsx +33 -0
  1046. package/src/stories/radio-group.mdx +54 -0
  1047. package/src/stories/select-native.stories.tsx +49 -0
  1048. package/src/stories/select.stories.tsx +92 -0
  1049. package/src/stories/slider.stories.tsx +27 -0
  1050. package/src/stories/stat.stories.tsx +123 -0
  1051. package/src/stories/switch.mdx +20 -0
  1052. package/src/stories/switchable-multi-select.stories.tsx +31 -0
  1053. package/src/stories/tabs.mdx +59 -0
  1054. package/src/stories/textarea.stories.tsx +58 -0
  1055. package/src/stories/theme.stories.tsx +111 -0
  1056. package/src/stories/tooltip.mdx +32 -0
  1057. package/src/stories/typography.stories.tsx +80 -0
  1058. package/src/stories/variables.stories.tsx +58 -0
  1059. package/src/stories/vega.stories.tsx +57 -0
  1060. package/src/theme/ThemeProvider.tsx +32 -0
  1061. package/src/theme/namespace.tsx +23 -0
  1062. package/src/theme/useTheme.ts +89 -0
  1063. package/src/utils/Deferred.ts +20 -0
  1064. package/src/utils/Logger.ts +91 -0
  1065. package/src/utils/__tests__/Deferred.test.ts +38 -0
  1066. package/src/utils/__tests__/arrays.test.ts +130 -0
  1067. package/src/utils/__tests__/batch-requests.test.ts +60 -0
  1068. package/src/utils/__tests__/blob.test.ts +52 -0
  1069. package/src/utils/__tests__/cell-urls.test.ts +92 -0
  1070. package/src/utils/__tests__/createReducer.test.ts +184 -0
  1071. package/src/utils/__tests__/data-views.test.ts +112 -0
  1072. package/src/utils/__tests__/dates.test.ts +188 -0
  1073. package/src/utils/__tests__/edit-distance.test.ts +302 -0
  1074. package/src/utils/__tests__/errors.test.ts +54 -0
  1075. package/src/utils/__tests__/filenames.test.ts +30 -0
  1076. package/src/utils/__tests__/id-tree.test.ts +1994 -0
  1077. package/src/utils/__tests__/json-parser.test.ts +79 -0
  1078. package/src/utils/__tests__/local-storage.test.ts +77 -0
  1079. package/src/utils/__tests__/lru.test.ts +74 -0
  1080. package/src/utils/__tests__/maps.test.ts +91 -0
  1081. package/src/utils/__tests__/math.test.ts +29 -0
  1082. package/src/utils/__tests__/numbers.test.ts +76 -0
  1083. package/src/utils/__tests__/path.test.ts +170 -0
  1084. package/src/utils/__tests__/pluralize.test.ts +47 -0
  1085. package/src/utils/__tests__/routes.test.ts +134 -0
  1086. package/src/utils/__tests__/sets.test.ts +41 -0
  1087. package/src/utils/__tests__/shallow-compare.test.ts +55 -0
  1088. package/src/utils/__tests__/strings.test.ts +68 -0
  1089. package/src/utils/__tests__/time.test.ts +61 -0
  1090. package/src/utils/__tests__/timed-cache.test.ts +142 -0
  1091. package/src/utils/__tests__/timeout.test.ts +153 -0
  1092. package/src/utils/__tests__/traceback.test.ts +34 -0
  1093. package/src/utils/__tests__/url.test.ts +100 -0
  1094. package/src/utils/__tests__/urls.test.ts +10 -0
  1095. package/src/utils/__tests__/versions.test.ts +63 -0
  1096. package/src/utils/__tests__/waitForWs.test.ts +76 -0
  1097. package/src/utils/ai/__tests__/ids.test.ts +184 -0
  1098. package/src/utils/ai/ids.ts +61 -0
  1099. package/src/utils/arrays.ts +75 -0
  1100. package/src/utils/assertExists.ts +12 -0
  1101. package/src/utils/assertNever.ts +20 -0
  1102. package/src/utils/batch-requests.ts +28 -0
  1103. package/src/utils/blob.ts +45 -0
  1104. package/src/utils/cell-urls.ts +31 -0
  1105. package/src/utils/cn.ts +8 -0
  1106. package/src/utils/copy.ts +17 -0
  1107. package/src/utils/createReducer.ts +137 -0
  1108. package/src/utils/data-views.ts +54 -0
  1109. package/src/utils/dates.ts +145 -0
  1110. package/src/utils/dereference.ts +10 -0
  1111. package/src/utils/download.ts +47 -0
  1112. package/src/utils/edit-distance.ts +141 -0
  1113. package/src/utils/errors.ts +63 -0
  1114. package/src/utils/events.ts +85 -0
  1115. package/src/utils/fileToBase64.ts +30 -0
  1116. package/src/utils/filenames.ts +29 -0
  1117. package/src/utils/functions.ts +24 -0
  1118. package/src/utils/id-tree.tsx +1032 -0
  1119. package/src/utils/idle.ts +19 -0
  1120. package/src/utils/invariant.ts +37 -0
  1121. package/src/utils/json/__tests__/base64.test.ts +100 -0
  1122. package/src/utils/json/base64.ts +51 -0
  1123. package/src/utils/json/json-parser.ts +65 -0
  1124. package/src/utils/lazy.ts +30 -0
  1125. package/src/utils/links.ts +11 -0
  1126. package/src/utils/localStorage.ts +132 -0
  1127. package/src/utils/lru.ts +68 -0
  1128. package/src/utils/maps.ts +65 -0
  1129. package/src/utils/math.ts +6 -0
  1130. package/src/utils/mergeRefs.ts +14 -0
  1131. package/src/utils/numbers.ts +124 -0
  1132. package/src/utils/objects.ts +105 -0
  1133. package/src/utils/once.ts +17 -0
  1134. package/src/utils/pathUtils.test.ts +113 -0
  1135. package/src/utils/pathUtils.ts +76 -0
  1136. package/src/utils/paths.ts +67 -0
  1137. package/src/utils/pluralize.ts +35 -0
  1138. package/src/utils/python-poet/__tests__/poet.test.ts +286 -0
  1139. package/src/utils/python-poet/poet.ts +196 -0
  1140. package/src/utils/reload-safe.ts +15 -0
  1141. package/src/utils/repl.ts +23 -0
  1142. package/src/utils/routes.ts +36 -0
  1143. package/src/utils/scroll.ts +38 -0
  1144. package/src/utils/sets.ts +30 -0
  1145. package/src/utils/shallow-compare.ts +30 -0
  1146. package/src/utils/staticImplements.ts +7 -0
  1147. package/src/utils/strings.ts +64 -0
  1148. package/src/utils/time.ts +39 -0
  1149. package/src/utils/timed-cache.ts +52 -0
  1150. package/src/utils/timeout.ts +42 -0
  1151. package/src/utils/traceback.ts +104 -0
  1152. package/src/utils/tracer.ts +106 -0
  1153. package/src/utils/typed.ts +17 -0
  1154. package/src/utils/url.ts +12 -0
  1155. package/src/utils/urls.ts +33 -0
  1156. package/src/utils/uuid.ts +8 -0
  1157. package/src/utils/versions.ts +66 -0
  1158. package/src/utils/vitals.ts +30 -0
  1159. package/src/utils/waitForWs.ts +31 -0
@@ -0,0 +1,1994 @@
1
+ /* Copyright 2024 Marimo. All rights reserved. */
2
+ import { beforeEach, describe, expect, it } from "vitest";
3
+ import {
4
+ type CellColumnId,
5
+ type CellIndex,
6
+ CollapsibleTree,
7
+ MultiColumn,
8
+ } from "../id-tree";
9
+
10
+ let tree: CollapsibleTree<string>;
11
+
12
+ describe("CollapsibleTree", () => {
13
+ beforeEach(() => {
14
+ tree = CollapsibleTree.from(["one", "two", "three", "four"]);
15
+ });
16
+
17
+ it("initializes correctly", () => {
18
+ expect(tree.toString()).toMatchInlineSnapshot(`
19
+ "one
20
+ two
21
+ three
22
+ four
23
+ "
24
+ `);
25
+ });
26
+
27
+ it("collapses nodes correctly with no end", () => {
28
+ const collapsedTree = tree.collapse("two", undefined);
29
+ expect(collapsedTree.nodes[1].isCollapsed).toBe(true);
30
+ expect(collapsedTree.isCollapsed("two")).toBe(true);
31
+ expect(collapsedTree.toString()).toMatchInlineSnapshot(`
32
+ "one
33
+ two (collapsed)
34
+ three
35
+ four
36
+ "
37
+ `);
38
+ });
39
+
40
+ it("collapses nodes correctly with an 'until' in the middle", () => {
41
+ const collapsedTree = tree.collapse("two", "three");
42
+ expect(collapsedTree.nodes[1].isCollapsed).toBe(true);
43
+ expect(collapsedTree.toString()).toMatchInlineSnapshot(`
44
+ "one
45
+ two (collapsed)
46
+ three
47
+ four
48
+ "
49
+ `);
50
+ });
51
+
52
+ it("collapses nodes correctly with an 'until' at the end", () => {
53
+ const collapsedTree = tree.collapse("two", "four");
54
+ expect(collapsedTree.nodes[1].isCollapsed).toBe(true);
55
+ expect(collapsedTree.toString()).toMatchInlineSnapshot(`
56
+ "one
57
+ two (collapsed)
58
+ three
59
+ four
60
+ "
61
+ `);
62
+ });
63
+
64
+ it("collapses nodes correctly if just the last node", () => {
65
+ const collapsedTree = tree.collapse("four", undefined);
66
+ expect(collapsedTree.nodes[3].isCollapsed).toBe(true);
67
+ expect(collapsedTree.toString()).toMatchInlineSnapshot(`
68
+ "one
69
+ two
70
+ three
71
+ four (collapsed)
72
+ "
73
+ `);
74
+ });
75
+
76
+ it("collapses nodes correctly if just the first node", () => {
77
+ const collapsedTree = tree.collapse("one", undefined);
78
+ expect(collapsedTree.nodes[0].isCollapsed).toBe(true);
79
+ expect(collapsedTree.toString()).toMatchInlineSnapshot(`
80
+ "one (collapsed)
81
+ two
82
+ three
83
+ four
84
+ "
85
+ `);
86
+ });
87
+
88
+ it("can double collapse", () => {
89
+ const collapsedTree = tree
90
+ .collapse("three", undefined)
91
+ .collapse("two", undefined);
92
+ expect(collapsedTree.toString()).toMatchInlineSnapshot(`
93
+ "one
94
+ two (collapsed)
95
+ three (collapsed)
96
+ four
97
+ "
98
+ `);
99
+ });
100
+
101
+ it("failures to collapse", () => {
102
+ expect(() =>
103
+ tree.collapse("five", undefined),
104
+ ).toThrowErrorMatchingInlineSnapshot(
105
+ "[Error: Node five not found in tree. Valid ids: one,two,three,four]",
106
+ );
107
+ expect(() =>
108
+ tree.collapse("one", "five"),
109
+ ).toThrowErrorMatchingInlineSnapshot(
110
+ "[Error: Node five not found in tree]",
111
+ );
112
+ expect(() =>
113
+ tree.collapse("two", "one"),
114
+ ).toThrowErrorMatchingInlineSnapshot(
115
+ "[Error: Node one is before node two]",
116
+ );
117
+ expect(() => {
118
+ tree = tree.collapse("two", undefined);
119
+ tree = tree.collapse("two", undefined);
120
+ }).toThrowErrorMatchingInlineSnapshot(
121
+ "[Error: Node two is already collapsed]",
122
+ );
123
+ });
124
+
125
+ it("collapses all nodes from leaves to root in one call", () => {
126
+ const collapsedTree = tree.collapseAll([
127
+ { id: "one", until: undefined },
128
+ { id: "two", until: undefined },
129
+ { id: "three", until: undefined },
130
+ { id: "four", until: undefined },
131
+ ]);
132
+ expect(collapsedTree.toString()).toMatchInlineSnapshot(`
133
+ "one (collapsed)
134
+ two (collapsed)
135
+ three (collapsed)
136
+ four (collapsed)
137
+ "
138
+ `);
139
+ });
140
+
141
+ it("collapses some nodes from leaves to root in one call", () => {
142
+ const collapsedTree = tree.collapseAll([
143
+ { id: "one", until: undefined },
144
+ null,
145
+ { id: "three", until: "four" },
146
+ null,
147
+ ]);
148
+ expect(collapsedTree.toString()).toMatchInlineSnapshot(`
149
+ "one (collapsed)
150
+ two
151
+ three (collapsed)
152
+ four
153
+ "
154
+ `);
155
+ });
156
+
157
+ it("failures to collapse all", () => {
158
+ expect(() => tree.collapseAll([])).toThrowErrorMatchingInlineSnapshot(
159
+ "[Error: No collapse ranges provided]",
160
+ );
161
+ expect(() =>
162
+ tree.collapseAll([
163
+ { id: "one", until: undefined },
164
+ { id: "two", until: undefined },
165
+ ]),
166
+ ).toThrowErrorMatchingInlineSnapshot(
167
+ "[Error: Collapse ranges length 2 does not match tree length 4]",
168
+ );
169
+ expect(() =>
170
+ tree.collapseAll([null, { id: "one", until: undefined }, null, null]),
171
+ ).toThrowErrorMatchingInlineSnapshot(
172
+ "[Error: Node two does not match collapse range id one]",
173
+ );
174
+ expect(() =>
175
+ tree.collapseAll([{ id: "one", until: "five" }, null, null, null]),
176
+ ).toThrowErrorMatchingInlineSnapshot(
177
+ "[Error: Node five not found in tree]",
178
+ );
179
+ expect(() =>
180
+ tree.collapseAll([null, { id: "two", until: "one" }, null, null]),
181
+ ).toThrowErrorMatchingInlineSnapshot(
182
+ "[Error: Node one is before node two]",
183
+ );
184
+ });
185
+
186
+ it("expands nodes correctly", () => {
187
+ const collapsed = tree.collapse("two", undefined);
188
+ expect(collapsed.nodes[1].isCollapsed).toBe(true);
189
+ const expandedTree = collapsed.expand("two");
190
+ expect(expandedTree.nodes[1].isCollapsed).toBe(false);
191
+ expect(expandedTree.toString()).toMatchInlineSnapshot(`
192
+ "one
193
+ two
194
+ three
195
+ four
196
+ "
197
+ `);
198
+ });
199
+
200
+ it("expands all nested collapsed nodes correctly in one call", () => {
201
+ let collapsed = tree.collapse("three", undefined);
202
+ expect(collapsed.nodes[2].isCollapsed).toBe(true);
203
+ collapsed = collapsed.collapse("two", undefined);
204
+ expect(collapsed.nodes[1].isCollapsed).toBe(true);
205
+ const expandedTree = collapsed.expandAll();
206
+ expect(expandedTree.nodes[1].isCollapsed).toBe(false);
207
+ expect(expandedTree.toString()).toMatchInlineSnapshot(`
208
+ "one
209
+ two
210
+ three
211
+ four
212
+ "
213
+ `);
214
+ });
215
+
216
+ it("fails to expand", () => {
217
+ expect(() => tree.expand("five")).toThrowErrorMatchingInlineSnapshot(
218
+ "[Error: Node five not found in tree. Valid ids: one,two,three,four]",
219
+ );
220
+ expect(() => {
221
+ tree.expand("one");
222
+ tree.expand("one");
223
+ }).toThrowErrorMatchingInlineSnapshot(
224
+ "[Error: Node one is already expanded]",
225
+ );
226
+ });
227
+
228
+ it("moves nodes correctly", () => {
229
+ const movedTree = tree.move(0, 1);
230
+ expect(movedTree.toString()).toMatchInlineSnapshot(`
231
+ "two
232
+ one
233
+ three
234
+ four
235
+ "
236
+ `);
237
+ });
238
+
239
+ it("moves a collapsed node correctly", () => {
240
+ const collapsed = tree.collapse("two", "three");
241
+ expect(collapsed.toString()).toMatchInlineSnapshot(`
242
+ "one
243
+ two (collapsed)
244
+ three
245
+ four
246
+ "
247
+ `);
248
+ const movedTree = collapsed.move(1, 2);
249
+ expect(movedTree.toString()).toMatchInlineSnapshot(`
250
+ "one
251
+ four
252
+ two (collapsed)
253
+ three
254
+ "
255
+ `);
256
+ });
257
+
258
+ it("inserts nodes correctly", () => {
259
+ tree = tree.insert("newNode", 1);
260
+ expect(tree.toString()).toMatchInlineSnapshot(`
261
+ "one
262
+ newNode
263
+ two
264
+ three
265
+ four
266
+ "
267
+ `);
268
+
269
+ tree = tree.insert("newNode2", tree.length - 1);
270
+ expect(tree.toString()).toMatchInlineSnapshot(`
271
+ "one
272
+ newNode
273
+ two
274
+ three
275
+ newNode2
276
+ four
277
+ "
278
+ `);
279
+
280
+ tree = tree.insert("newNode3", 10_000);
281
+ expect(tree.toString()).toMatchInlineSnapshot(`
282
+ "one
283
+ newNode
284
+ two
285
+ three
286
+ newNode2
287
+ four
288
+ newNode3
289
+ "
290
+ `);
291
+ });
292
+
293
+ it("counts children correctly", () => {
294
+ expect(tree.getCount("who")).toBe(0);
295
+ expect(tree.getCount("one")).toBe(0);
296
+ // Collapse three and get count
297
+ tree = tree.collapse("three", undefined);
298
+ expect(tree.getCount("three")).toBe(1);
299
+ // Collapse two and get count
300
+ tree = tree.collapse("two", undefined);
301
+ expect(tree.getCount("two")).toBe(2);
302
+ });
303
+
304
+ it("finds deep correctly", () => {
305
+ expect(tree.find("three")).toEqual(["three"]);
306
+ tree = tree.collapse("three", undefined).collapse("two", undefined);
307
+ expect(tree.find("three")).toEqual(["two", "three"]);
308
+ expect(tree.find("four")).toEqual(["two", "three", "four"]);
309
+ expect(tree.toString()).toMatchInlineSnapshot(`
310
+ "one
311
+ two (collapsed)
312
+ three (collapsed)
313
+ four
314
+ "
315
+ `);
316
+ });
317
+
318
+ it("finds and expands correctly at a leaf", () => {
319
+ tree = tree.collapse("three", undefined).collapse("two", undefined);
320
+ expect(tree.toString()).toMatchInlineSnapshot(`
321
+ "one
322
+ two (collapsed)
323
+ three (collapsed)
324
+ four
325
+ "
326
+ `);
327
+ const prevTree = tree;
328
+ tree = tree.findAndExpandDeep("four");
329
+ expect(tree.toString()).toMatchInlineSnapshot(`
330
+ "one
331
+ two
332
+ three
333
+ four
334
+ "
335
+ `);
336
+ // doesn't mutate
337
+ expect(prevTree.toString()).not.toEqual(tree.toString());
338
+ });
339
+
340
+ it("finds and expands correctly at a non-leaf", () => {
341
+ tree = tree.collapse("three", undefined).collapse("two", undefined);
342
+ expect(tree.toString()).toMatchInlineSnapshot(`
343
+ "one
344
+ two (collapsed)
345
+ three (collapsed)
346
+ four
347
+ "
348
+ `);
349
+ const prevTree = tree;
350
+ tree = tree.findAndExpandDeep("three");
351
+ expect(tree.toString()).toMatchInlineSnapshot(`
352
+ "one
353
+ two
354
+ three
355
+ four
356
+ "
357
+ `);
358
+ // doesn't mutate
359
+ expect(prevTree.toString()).not.toEqual(tree.toString());
360
+ });
361
+
362
+ it("can delete nodes", () => {
363
+ tree = tree.collapse("three", undefined).collapse("two", undefined);
364
+ expect(tree.toString()).toMatchInlineSnapshot(`
365
+ "one
366
+ two (collapsed)
367
+ three (collapsed)
368
+ four
369
+ "
370
+ `);
371
+ tree = tree.deleteAtIndex(1);
372
+ expect(tree.toString()).toMatchInlineSnapshot(`
373
+ "one
374
+ three (collapsed)
375
+ four
376
+ "
377
+ `);
378
+ });
379
+
380
+ it("fails to delete nodes", () => {
381
+ expect(() => tree.deleteAtIndex(5)).toThrowErrorMatchingInlineSnapshot(
382
+ "[Error: Node at index 5 not found in tree]",
383
+ );
384
+ });
385
+
386
+ it("top-level ids are correct", () => {
387
+ expect(tree.topLevelIds).toMatchInlineSnapshot(`
388
+ [
389
+ "one",
390
+ "two",
391
+ "three",
392
+ "four",
393
+ ]
394
+ `);
395
+
396
+ const collapsed = tree.collapse("two", undefined);
397
+ expect(collapsed.topLevelIds).toMatchInlineSnapshot(`
398
+ [
399
+ "one",
400
+ "two",
401
+ ]
402
+ `);
403
+ });
404
+
405
+ it("in order ids are correct", () => {
406
+ expect(tree.inOrderIds).toMatchInlineSnapshot(`
407
+ [
408
+ "one",
409
+ "two",
410
+ "three",
411
+ "four",
412
+ ]
413
+ `);
414
+
415
+ const collapsed = tree.collapse("two", undefined);
416
+
417
+ // Not mutable
418
+ expect(tree.inOrderIds).toEqual(tree.inOrderIds);
419
+
420
+ expect(collapsed.inOrderIds).toMatchInlineSnapshot(`
421
+ [
422
+ "one",
423
+ "two",
424
+ "three",
425
+ "four",
426
+ ]
427
+ `);
428
+ });
429
+
430
+ it("atOrThrow throws if not found", () => {
431
+ expect(() => tree.atOrThrow(5)).toThrowErrorMatchingInlineSnapshot(
432
+ "[Error: Node at index 5 not found in tree]",
433
+ );
434
+ });
435
+
436
+ it("first and last are correct", () => {
437
+ expect(tree.first()).toBe("one");
438
+ expect(tree.last()).toBe("four");
439
+ });
440
+
441
+ it("length is correct", () => {
442
+ expect(tree.length).toBe(4);
443
+
444
+ const collapsed = tree.collapse("two", undefined);
445
+ expect(collapsed.length).toBe(2);
446
+ });
447
+
448
+ it("moves to front and back correctly", () => {
449
+ tree = tree.collapse("three", undefined).moveToBack("three");
450
+ expect(tree.toString()).toMatchInlineSnapshot(`
451
+ "one
452
+ two
453
+ three (collapsed)
454
+ four
455
+ "
456
+ `);
457
+
458
+ tree = tree.moveToFront("two");
459
+ expect(tree.toString()).toMatchInlineSnapshot(`
460
+ "two
461
+ one
462
+ three (collapsed)
463
+ four
464
+ "
465
+ `);
466
+ });
467
+
468
+ it("getDescendants correctly", () => {
469
+ expect(tree.getDescendants("two")).toEqual([]);
470
+ expect(tree.getDescendants("who")).toEqual([]);
471
+
472
+ tree = tree.collapse("three", undefined).collapse("two", undefined);
473
+ expect(tree.getDescendants("two")).toMatchInlineSnapshot(`
474
+ [
475
+ "three",
476
+ "four",
477
+ ]
478
+ `);
479
+
480
+ // We only get descendants of the top level
481
+ expect(tree.getDescendants("three")).toMatchInlineSnapshot("[]");
482
+ });
483
+
484
+ it("handles slice correctly", () => {
485
+ // Normal slice in middle
486
+ expect(tree.slice(1, 3)).toEqual(["two", "three"]);
487
+
488
+ // Slice from beginning
489
+ expect(tree.slice(0, 2)).toEqual(["one", "two"]);
490
+
491
+ // Slice to end
492
+ expect(tree.slice(2, 4)).toEqual(["three", "four"]);
493
+
494
+ // Slice entire array
495
+ expect(tree.slice(0, 4)).toEqual(["one", "two", "three", "four"]);
496
+
497
+ // Slice with out-of-bounds end
498
+ expect(tree.slice(2, 10)).toEqual(["three", "four"]);
499
+
500
+ // Slice with negative start (should work like normal array slice)
501
+ expect(tree.slice(-2, 4)).toEqual(["three", "four"]);
502
+
503
+ // Slice with start > end (should return empty array)
504
+ expect(tree.slice(3, 1)).toEqual([]);
505
+
506
+ // Slice with same start and end
507
+ expect(tree.slice(2, 2)).toEqual([]);
508
+
509
+ // Slice single element
510
+ expect(tree.slice(1, 2)).toEqual(["two"]);
511
+ });
512
+
513
+ it("handles slice with collapsed nodes", () => {
514
+ const collapsed = tree.collapse("two", "three");
515
+
516
+ // Should only return top-level nodes, not descendants
517
+ expect(collapsed.slice(0, 2)).toEqual(["one", "two"]);
518
+ expect(collapsed.slice(1, 3)).toEqual(["two", "four"]);
519
+ });
520
+
521
+ it("handles after correctly", () => {
522
+ // Normal case - get next node
523
+ expect(tree.after("one")).toBe("two");
524
+ expect(tree.after("two")).toBe("three");
525
+ expect(tree.after("three")).toBe("four");
526
+
527
+ // Edge case - last node should return undefined
528
+ expect(tree.after("four")).toBeUndefined();
529
+
530
+ // Edge case - non-existent node should throw
531
+ expect(() => tree.after("nonexistent")).toThrow(
532
+ "Node nonexistent not found in tree. Valid ids: one,two,three,four",
533
+ );
534
+ });
535
+
536
+ it("handles after with collapsed nodes", () => {
537
+ const collapsed = tree.collapse("two", "three");
538
+
539
+ // Should return next top-level node
540
+ expect(collapsed.after("one")).toBe("two");
541
+ expect(collapsed.after("two")).toBe("four");
542
+ expect(collapsed.after("four")).toBeUndefined();
543
+
544
+ // Should throw for collapsed children that aren't top-level
545
+ expect(() => collapsed.after("three")).toThrow();
546
+ });
547
+
548
+ it("handles before correctly", () => {
549
+ // Normal case - get previous node
550
+ expect(tree.before("two")).toBe("one");
551
+ expect(tree.before("three")).toBe("two");
552
+ expect(tree.before("four")).toBe("three");
553
+
554
+ // Edge case - first node should return undefined
555
+ expect(tree.before("one")).toBeUndefined();
556
+
557
+ // Edge case - non-existent node should throw
558
+ expect(() => tree.before("nonexistent")).toThrow(
559
+ "Node nonexistent not found in tree. Valid ids: one,two,three,four",
560
+ );
561
+ });
562
+
563
+ it("handles before with collapsed nodes", () => {
564
+ const collapsed = tree.collapse("two", "three");
565
+
566
+ // Should return previous top-level node
567
+ expect(collapsed.before("two")).toBe("one");
568
+ expect(collapsed.before("four")).toBe("two");
569
+ expect(collapsed.before("one")).toBeUndefined();
570
+
571
+ // Should throw for collapsed children that aren't top-level
572
+ expect(() => collapsed.before("three")).toThrow();
573
+ });
574
+
575
+ it("handles slice on empty tree", () => {
576
+ const emptyTree = CollapsibleTree.from([]);
577
+ expect(emptyTree.slice(0, 1)).toEqual([]);
578
+ expect(emptyTree.slice(0, 0)).toEqual([]);
579
+ });
580
+
581
+ it("handles after/before on single element tree", () => {
582
+ const singleTree = CollapsibleTree.from(["single"]);
583
+ expect(singleTree.after("single")).toBeUndefined();
584
+ expect(singleTree.before("single")).toBeUndefined();
585
+ });
586
+
587
+ it("handles split correctly", () => {
588
+ const [left, right] = tree.split("two");
589
+ expect(left.toString()).toMatchInlineSnapshot(`
590
+ "one
591
+ "
592
+ `);
593
+ expect(right?.toString()).toMatchInlineSnapshot(`
594
+ "two
595
+ three
596
+ four
597
+ "
598
+ `);
599
+ });
600
+
601
+ it("handles split at the beginning", () => {
602
+ const [left, right] = tree.split("one");
603
+ expect(left.toString()).toMatchInlineSnapshot(`
604
+ ""
605
+ `);
606
+ expect(right?.toString()).toMatchInlineSnapshot(`
607
+ "one
608
+ two
609
+ three
610
+ four
611
+ "
612
+ `);
613
+ });
614
+
615
+ it("handles split at the end", () => {
616
+ const [left, right] = tree.split("four");
617
+ expect(left.toString()).toMatchInlineSnapshot(`
618
+ "one
619
+ two
620
+ three
621
+ "
622
+ `);
623
+ expect(right?.toString()).toMatchInlineSnapshot(`
624
+ "four
625
+ "
626
+ `);
627
+ });
628
+
629
+ it("throws when splitting on non-existent node", () => {
630
+ expect(() => tree.split("five")).toThrow("Node five not found in tree");
631
+ });
632
+ });
633
+
634
+ describe("CollapsibleTree edge cases", () => {
635
+ let tree: CollapsibleTree<string>;
636
+
637
+ beforeEach(() => {
638
+ tree = CollapsibleTree.from(["A", "B", "C", "D"]);
639
+ });
640
+
641
+ it("handles insert at start and end", () => {
642
+ tree = tree.insertAtStart("Z");
643
+ expect(tree.topLevelIds).toEqual(["Z", "A", "B", "C", "D"]);
644
+ tree = tree.insertAtEnd("Y");
645
+ expect(tree.topLevelIds).toEqual(["Z", "A", "B", "C", "D", "Y"]);
646
+ });
647
+
648
+ it("handles delete with expand", () => {
649
+ tree = tree.collapse("B", "D");
650
+ tree = tree.deleteAtIndex(1);
651
+ expect(tree.topLevelIds).toEqual(["A", "C", "D"]);
652
+ });
653
+
654
+ it("finds nodes correctly", () => {
655
+ tree = tree.collapse("B", "D");
656
+ expect(tree.find("C")).toEqual(["B", "C"]);
657
+ expect(tree.find("E")).toEqual([]);
658
+ });
659
+
660
+ it("handles equality check", () => {
661
+ const tree2 = CollapsibleTree.from(["A", "B", "C", "D"]);
662
+ expect(tree.equals(tree2)).toBe(true);
663
+ tree2.collapse("B", "C");
664
+ expect(tree.equals(tree2)).toBe(true);
665
+ });
666
+
667
+ it("handles getCount correctly", () => {
668
+ tree = tree.collapse("B", "D");
669
+ expect(tree.getCount("A")).toBe(0);
670
+ expect(tree.getCount("B")).toBe(2);
671
+ expect(tree.getCount("C")).toBe(0);
672
+ });
673
+
674
+ it("handles findAndExpandDeep", () => {
675
+ tree = tree.collapse("B", "D");
676
+ tree = tree.findAndExpandDeep("C");
677
+ expect(tree.topLevelIds).toEqual(["A", "B", "C", "D"]);
678
+ });
679
+
680
+ it("handles multiple collapses and expands", () => {
681
+ tree = tree.collapse("B", "C").collapse("A", "D");
682
+ expect(tree.topLevelIds).toEqual(["A"]);
683
+ tree = tree.expand("A").expand("B");
684
+ expect(tree.topLevelIds).toEqual(["A", "B", "C", "D"]);
685
+ });
686
+
687
+ it("handles edge cases for first and last", () => {
688
+ expect(tree.first()).toBe("A");
689
+ expect(tree.last()).toBe("D");
690
+ tree = CollapsibleTree.from([]);
691
+ expect(() => tree.first()).toThrow();
692
+ expect(() => tree.last()).toThrow();
693
+ });
694
+
695
+ it("handles inOrderIds with nested structure", () => {
696
+ tree = tree.collapse("B", "C");
697
+ expect(tree.inOrderIds).toEqual(["A", "B", "C", "D"]);
698
+ });
699
+
700
+ it("handles moving within bounds", () => {
701
+ tree = tree.move(0, 2);
702
+ expect(tree.topLevelIds).toEqual(["B", "C", "A", "D"]);
703
+ });
704
+
705
+ it("handles moving out of bounds", () => {
706
+ tree = tree.move(0, 10);
707
+ expect(tree.topLevelIds).toEqual(["B", "C", "D", "A"]);
708
+ });
709
+ });
710
+
711
+ describe("MultiColumn", () => {
712
+ let multiColumn: MultiColumn<string>;
713
+ let columnIds: CellColumnId[];
714
+
715
+ beforeEach(() => {
716
+ multiColumn = MultiColumn.from([
717
+ ["A1", "A2", "A3"],
718
+ ["B1", "B2"],
719
+ ["C1", "C2", "C3", "C4"],
720
+ ]);
721
+
722
+ columnIds = multiColumn.getColumns().map((c) => c.id);
723
+ });
724
+
725
+ it("initializes correctly", () => {
726
+ expect(multiColumn.colLength).toBe(3);
727
+ expect(multiColumn.idLength).toBe(9);
728
+ expect(multiColumn.topLevelIds).toEqual([
729
+ ["A1", "A2", "A3"],
730
+ ["B1", "B2"],
731
+ ["C1", "C2", "C3", "C4"],
732
+ ]);
733
+ });
734
+
735
+ it("creates from empty array", () => {
736
+ const emptyMultiColumn = MultiColumn.from([]);
737
+ expect(emptyMultiColumn.colLength).toBe(1);
738
+ expect(emptyMultiColumn.idLength).toBe(0);
739
+ expect(emptyMultiColumn.isEmpty()).toBe(true);
740
+ });
741
+
742
+ it("creates from ids and columns", () => {
743
+ const idAndColumns: Array<[string, number | undefined | null]> = [
744
+ ["A1", 0],
745
+ ["A2", 0],
746
+ ["B1", 1],
747
+ ["C1", 2],
748
+ ["C2", undefined],
749
+ ["D1", null],
750
+ ["E1", -1],
751
+ ];
752
+ const fromIdsAndColumns = MultiColumn.fromIdsAndColumns(idAndColumns);
753
+ expect(fromIdsAndColumns.colLength).toBe(3);
754
+ expect(fromIdsAndColumns.topLevelIds).toEqual([
755
+ ["A1", "A2"],
756
+ ["B1"],
757
+ ["C1", "C2", "D1", "E1"],
758
+ ]);
759
+ });
760
+
761
+ it("iterates top-level ids", () => {
762
+ const ids = [...multiColumn.iterateTopLevelIds];
763
+ expect(ids).toEqual(["A1", "A2", "A3", "B1", "B2", "C1", "C2", "C3", "C4"]);
764
+ });
765
+
766
+ it("gets in-order ids", () => {
767
+ expect(multiColumn.inOrderIds).toEqual([
768
+ "A1",
769
+ "A2",
770
+ "A3",
771
+ "B1",
772
+ "B2",
773
+ "C1",
774
+ "C2",
775
+ "C3",
776
+ "C4",
777
+ ]);
778
+ });
779
+
780
+ it("checks if it has only one column", () => {
781
+ expect(multiColumn.hasOnlyOneColumn()).toBe(false);
782
+ const singleColumn = MultiColumn.from([["A1", "A2"]]);
783
+ expect(singleColumn.hasOnlyOneColumn()).toBe(true);
784
+ });
785
+
786
+ it("checks if it has only one id", () => {
787
+ expect(multiColumn.hasOnlyOneId()).toBe(false);
788
+ const singleId = MultiColumn.from([["A1"], ["B1"], ["C1"]]);
789
+ expect(singleId.hasOnlyOneId()).toBe(false);
790
+ const singleIdSingleColumn = MultiColumn.from([["A1"]]);
791
+ expect(singleIdSingleColumn.hasOnlyOneId()).toBe(true);
792
+ });
793
+
794
+ it("adds a column", () => {
795
+ const columnId = multiColumn.getColumns()[0].id;
796
+ const newMultiColumn = multiColumn.addColumn(columnId);
797
+ expect(newMultiColumn.colLength).toBe(4);
798
+ expect(newMultiColumn.topLevelIds[1]).toEqual([]);
799
+ });
800
+
801
+ it("inserts a breakpoint", () => {
802
+ const withBreakpoint = multiColumn.insertBreakpoint("C3");
803
+ expect(withBreakpoint.colLength).toBe(4);
804
+ expect(withBreakpoint.topLevelIds).toEqual([
805
+ ["A1", "A2", "A3"],
806
+ ["B1", "B2"],
807
+ ["C1", "C2"],
808
+ ["C3", "C4"],
809
+ ]);
810
+ });
811
+
812
+ it("deletes a column", () => {
813
+ const withoutBreakpoint = multiColumn.delete(columnIds[1]);
814
+ expect(withoutBreakpoint.colLength).toBe(2);
815
+ expect(withoutBreakpoint.topLevelIds).toEqual([
816
+ ["A1", "A2", "A3", "B1", "B2"],
817
+ ["C1", "C2", "C3", "C4"],
818
+ ]);
819
+ });
820
+
821
+ it("deletes a column with only one column", () => {
822
+ const singleColumn = MultiColumn.from([["A1", "A2"]]);
823
+ const deleted = singleColumn.delete(columnIds[0]);
824
+ expect(deleted.colLength).toBe(1);
825
+ expect(deleted.topLevelIds).toEqual([["A1", "A2"]]);
826
+ });
827
+
828
+ it("deletes the first column", () => {
829
+ const deleted = multiColumn.delete(columnIds[0]);
830
+ expect(deleted.colLength).toBe(2);
831
+ expect(deleted.topLevelIds).toEqual([
832
+ ["B1", "B2", "A1", "A2", "A3"],
833
+ ["C1", "C2", "C3", "C4"],
834
+ ]);
835
+ });
836
+
837
+ it("merges all columns", () => {
838
+ const merged = multiColumn.mergeAllColumns();
839
+ expect(merged.colLength).toBe(1);
840
+ expect(merged.topLevelIds).toEqual([
841
+ ["A1", "A2", "A3", "B1", "B2", "C1", "C2", "C3", "C4"],
842
+ ]);
843
+ });
844
+
845
+ it("moves within a column", () => {
846
+ const moved = multiColumn.moveWithinColumn(
847
+ columnIds[0],
848
+ 0 as CellIndex,
849
+ 2 as CellIndex,
850
+ );
851
+ expect(moved.topLevelIds[0]).toEqual(["A2", "A3", "A1"]);
852
+ });
853
+
854
+ it("moves across columns", () => {
855
+ const moved = multiColumn.moveAcrossColumns(
856
+ columnIds[0],
857
+ "A1",
858
+ columnIds[1],
859
+ "B1",
860
+ );
861
+ expect(moved.topLevelIds).toEqual([
862
+ ["A2", "A3"],
863
+ ["A1", "B1", "B2"],
864
+ ["C1", "C2", "C3", "C4"],
865
+ ]);
866
+ });
867
+
868
+ it("moves a column", () => {
869
+ const moved = multiColumn.moveColumn(columnIds[0], columnIds[2]);
870
+ expect(moved.topLevelIds).toEqual([
871
+ ["B1", "B2"],
872
+ ["C1", "C2", "C3", "C4"],
873
+ ["A1", "A2", "A3"],
874
+ ]);
875
+ });
876
+
877
+ it("moves a column before", () => {
878
+ const moved = multiColumn.moveColumn(columnIds[1], columnIds[0]);
879
+ expect(moved.topLevelIds).toEqual([
880
+ ["B1", "B2"],
881
+ ["A1", "A2", "A3"],
882
+ ["C1", "C2", "C3", "C4"],
883
+ ]);
884
+ });
885
+
886
+ it("moves to the left", () => {
887
+ const moved = multiColumn.moveColumn(columnIds[1], "_left_");
888
+ expect(moved.topLevelIds).toEqual([
889
+ ["B1", "B2"],
890
+ ["A1", "A2", "A3"],
891
+ ["C1", "C2", "C3", "C4"],
892
+ ]);
893
+ });
894
+
895
+ it("moves to the right", () => {
896
+ const moved = multiColumn.moveColumn(columnIds[1], "_right_");
897
+ expect(moved.topLevelIds).toEqual([
898
+ ["A1", "A2", "A3"],
899
+ ["C1", "C2", "C3", "C4"],
900
+ ["B1", "B2"],
901
+ ]);
902
+ });
903
+
904
+ it("moves to a new column", () => {
905
+ const newColumn = multiColumn.moveToNewColumn("B1");
906
+ expect(newColumn.colLength).toBe(4);
907
+ expect(newColumn.topLevelIds).toEqual([
908
+ ["A1", "A2", "A3"],
909
+ ["B2"],
910
+ ["C1", "C2", "C3", "C4"],
911
+ ["B1"],
912
+ ]);
913
+ });
914
+
915
+ it("gets column with id", () => {
916
+ const column = multiColumn.findWithId("B2");
917
+ expect(multiColumn.indexOf(column)).toBe(1);
918
+ expect(column.topLevelIds).toEqual(["B1", "B2"]);
919
+ });
920
+
921
+ it("transforms by id", () => {
922
+ const transformed = multiColumn.transformWithCellId("B1", (tree) =>
923
+ tree.moveToFront("B2"),
924
+ );
925
+ expect(transformed.topLevelIds[1]).toEqual(["B2", "B1"]);
926
+ });
927
+
928
+ it("transforms all columns", () => {
929
+ const transformed = multiColumn.transformAll((tree) =>
930
+ tree.insertAtStart("NEW"),
931
+ );
932
+ expect(transformed.topLevelIds).toEqual([
933
+ ["NEW", "A1", "A2", "A3"],
934
+ ["NEW", "B1", "B2"],
935
+ ["NEW", "C1", "C2", "C3", "C4"],
936
+ ]);
937
+ });
938
+
939
+ it("inserts an id", () => {
940
+ const inserted = multiColumn.insertId("D1", columnIds[1], 1 as CellIndex);
941
+ expect(inserted.topLevelIds[1]).toEqual(["B1", "D1", "B2"]);
942
+ });
943
+
944
+ it("deletes by id", () => {
945
+ const deleted = multiColumn.deleteById("B1");
946
+ expect(deleted.topLevelIds[1]).toEqual(["B2"]);
947
+ });
948
+
949
+ it("compacts", () => {
950
+ const withEmpty = MultiColumn.from([["A1"], [], ["C1"], []]);
951
+ const compacted = withEmpty.compact();
952
+ expect(compacted.colLength).toBe(2);
953
+ expect(compacted.topLevelIds).toEqual([["A1"], ["C1"]]);
954
+ });
955
+
956
+ it("handles errors", () => {
957
+ expect(() => multiColumn.findWithId("Z1")).toThrow(
958
+ "Cell Z1 not found in any column",
959
+ );
960
+ expect(multiColumn.colLength).toBeGreaterThan(2);
961
+ expect(() => multiColumn.delete("123" as CellColumnId)).toThrow();
962
+ });
963
+
964
+ it("checks if it's empty", () => {
965
+ expect(multiColumn.isEmpty()).toBe(false);
966
+ const emptyMultiColumn = MultiColumn.from([[]]);
967
+ expect(emptyMultiColumn.isEmpty()).toBe(true);
968
+ });
969
+
970
+ it("gets columns", () => {
971
+ const columns = multiColumn.getColumns();
972
+ expect(columns.length).toBe(3);
973
+ expect(columns[0].topLevelIds).toEqual(["A1", "A2", "A3"]);
974
+ });
975
+
976
+ it("gets index of a column", () => {
977
+ const column = multiColumn.atOrThrow(1);
978
+ const index = multiColumn.indexOf(column);
979
+ expect(index).toBe(1);
980
+ });
981
+
982
+ it("handles at and atOrThrow", () => {
983
+ expect(multiColumn.at(1)?.topLevelIds).toEqual(["B1", "B2"]);
984
+ expect(multiColumn.atOrThrow(1).topLevelIds).toEqual(["B1", "B2"]);
985
+ expect(multiColumn.at(5)).toBeUndefined();
986
+ expect(() => multiColumn.atOrThrow(5)).toThrow();
987
+ });
988
+
989
+ it("handles moving the last item in a column", () => {
990
+ const multiColumn = MultiColumn.from([["A1", "A2"], ["B1"]]);
991
+ const columnIds = multiColumn.getColumns().map((c) => c.id);
992
+ const moved = multiColumn.moveAcrossColumns(
993
+ columnIds[1],
994
+ "B1",
995
+ columnIds[0],
996
+ "A2",
997
+ );
998
+ expect(moved.topLevelIds).toEqual([["A1", "B1", "A2"], []]);
999
+ expect(moved.colLength).toBe(2);
1000
+ });
1001
+
1002
+ it("handles moving all items from a column", () => {
1003
+ const multiColumn = MultiColumn.from([
1004
+ ["A1", "A2"],
1005
+ ["B1", "B2"],
1006
+ ]);
1007
+ const columnIds = multiColumn.getColumns().map((c) => c.id);
1008
+ let moved = multiColumn.moveAcrossColumns(
1009
+ columnIds[1],
1010
+ "B1",
1011
+ columnIds[0],
1012
+ "A2",
1013
+ );
1014
+ moved = moved.moveAcrossColumns(columnIds[1], "B2", columnIds[0], "A2");
1015
+ expect(moved.topLevelIds).toEqual([["A1", "B1", "B2", "A2"], []]);
1016
+ expect(moved.colLength).toBe(2);
1017
+ });
1018
+
1019
+ it("handles inserting at out-of-bounds indices", () => {
1020
+ const multiColumn = MultiColumn.from([["A1"], ["B1"]]);
1021
+ const columnId = multiColumn.atOrThrow(1).id;
1022
+ const inserted = multiColumn.insertId("C1", columnId, 10 as CellIndex);
1023
+ expect(inserted.topLevelIds).toEqual([["A1"], ["B1", "C1"]]);
1024
+ });
1025
+
1026
+ it("handles collapsing and expanding in multi-column setup", () => {
1027
+ let multiColumn = MultiColumn.from([
1028
+ ["A1", "A2", "A3"],
1029
+ ["B1", "B2"],
1030
+ ]);
1031
+ multiColumn = multiColumn.transformWithCellId("A1", (tree) =>
1032
+ tree.collapse("A1", "A3"),
1033
+ );
1034
+ expect(multiColumn.topLevelIds).toEqual([["A1"], ["B1", "B2"]]);
1035
+ multiColumn = multiColumn.transformWithCellId("A1", (tree) =>
1036
+ tree.expand("A1"),
1037
+ );
1038
+ expect(multiColumn.topLevelIds).toEqual([
1039
+ ["A1", "A2", "A3"],
1040
+ ["B1", "B2"],
1041
+ ]);
1042
+ });
1043
+
1044
+ it("handles moving a column to its own position", () => {
1045
+ const multiColumn = MultiColumn.from([["A1"], ["B1"], ["C1"]]);
1046
+ const moved = multiColumn.moveColumn(columnIds[1], columnIds[1]);
1047
+ expect(moved.topLevelIds).toEqual([["A1"], ["B1"], ["C1"]]);
1048
+ });
1049
+
1050
+ it("handles compacting when all columns are empty", () => {
1051
+ const multiColumn = MultiColumn.from([[], [], []]);
1052
+ const compacted = multiColumn.compact();
1053
+ expect(compacted.colLength).toBe(1);
1054
+ expect(compacted.isEmpty()).toBe(true);
1055
+ });
1056
+
1057
+ it("handles transformById when id is not found", () => {
1058
+ const multiColumn = MultiColumn.from([["A1"], ["B1"]]);
1059
+ const transformed = multiColumn.transformWithCellId("C1", (tree) =>
1060
+ tree.insertAtEnd("C2"),
1061
+ );
1062
+ expect(transformed).toBe(multiColumn);
1063
+ });
1064
+
1065
+ it("handles nested collapses and expands", () => {
1066
+ let multiColumn = MultiColumn.from([["A1", "A2", "A3", "A4", "A5"]]);
1067
+ multiColumn = multiColumn.transformWithCellId("A1", (tree) =>
1068
+ tree.collapse("A2", "A4"),
1069
+ );
1070
+ multiColumn = multiColumn.transformWithCellId("A1", (tree) =>
1071
+ tree.collapse("A1", undefined),
1072
+ );
1073
+ expect(multiColumn.topLevelIds).toEqual([["A1"]]);
1074
+ multiColumn = multiColumn.transformWithCellId("A1", (tree) =>
1075
+ tree.expand("A1"),
1076
+ );
1077
+ expect(multiColumn.topLevelIds).toEqual([["A1", "A2", "A5"]]);
1078
+ multiColumn = multiColumn.transformWithCellId("A1", (tree) =>
1079
+ tree.expand("A2"),
1080
+ );
1081
+ expect(multiColumn.topLevelIds).toEqual([["A1", "A2", "A3", "A4", "A5"]]);
1082
+ });
1083
+
1084
+ it("handles moving to a new column when it's the last item", () => {
1085
+ let multiColumn = MultiColumn.from([["A1"], ["B1"]]);
1086
+ multiColumn = multiColumn.moveToNewColumn("B1");
1087
+ expect(multiColumn.colLength).toBe(3);
1088
+ expect(multiColumn.topLevelIds).toEqual([["A1"], [], ["B1"]]);
1089
+ });
1090
+
1091
+ it("handles deleting the last item in a column", () => {
1092
+ let multiColumn = MultiColumn.from([["A1"], ["B1"], ["C1"]]);
1093
+ multiColumn = multiColumn.deleteById("B1");
1094
+ expect(multiColumn.colLength).toBe(3);
1095
+ expect(multiColumn.topLevelIds).toEqual([["A1"], [], ["C1"]]);
1096
+ });
1097
+
1098
+ it("handles multiple operations in sequence", () => {
1099
+ let multiColumn = MultiColumn.from([
1100
+ ["A1", "A2"],
1101
+ ["B1", "B2"],
1102
+ ["C1", "C2"],
1103
+ ]);
1104
+ const columnIds = multiColumn.getColumns().map((c) => c.id);
1105
+ multiColumn = multiColumn.moveAcrossColumns(
1106
+ columnIds[0],
1107
+ "A2",
1108
+ columnIds[1],
1109
+ "B1",
1110
+ );
1111
+ expect(multiColumn.topLevelIds).toEqual([
1112
+ ["A1"],
1113
+ ["A2", "B1", "B2"],
1114
+ ["C1", "C2"],
1115
+ ]);
1116
+ multiColumn = multiColumn.insertId("D1", columnIds[2], 1 as CellIndex);
1117
+ expect(multiColumn.topLevelIds).toEqual([
1118
+ ["A1"],
1119
+ ["A2", "B1", "B2"],
1120
+ ["C1", "D1", "C2"],
1121
+ ]);
1122
+ multiColumn = multiColumn.deleteById("B1");
1123
+ expect(multiColumn.topLevelIds).toEqual([
1124
+ ["A1"],
1125
+ ["A2", "B2"],
1126
+ ["C1", "D1", "C2"],
1127
+ ]);
1128
+ multiColumn = multiColumn.moveColumn(columnIds[0], columnIds[2]);
1129
+ expect(multiColumn.topLevelIds).toEqual([
1130
+ ["A2", "B2"],
1131
+ ["C1", "D1", "C2"],
1132
+ ["A1"],
1133
+ ]);
1134
+ multiColumn = multiColumn.compact();
1135
+ expect(multiColumn.topLevelIds).toEqual([
1136
+ ["A2", "B2"],
1137
+ ["C1", "D1", "C2"],
1138
+ ["A1"],
1139
+ ]);
1140
+ });
1141
+
1142
+ it("handles get method", () => {
1143
+ const column = multiColumn.get(columnIds[1]);
1144
+ expect(column?.topLevelIds).toEqual(["B1", "B2"]);
1145
+ });
1146
+
1147
+ it("handles get method with non-existent column id", () => {
1148
+ const column = multiColumn.get("non-existent-id" as CellColumnId);
1149
+ expect(column).toBeUndefined();
1150
+ });
1151
+
1152
+ it("handles indexOfOrThrow method", () => {
1153
+ expect(multiColumn.indexOfOrThrow(columnIds[1])).toBe(1);
1154
+ });
1155
+
1156
+ it("handles indexOfOrThrow method with non-existent column id", () => {
1157
+ expect(() =>
1158
+ multiColumn.indexOfOrThrow("non-existent-id" as CellColumnId),
1159
+ ).toThrow("Column non-existent-id not found. Possible values: ");
1160
+ });
1161
+
1162
+ it("handles transform method", () => {
1163
+ const transformed = multiColumn.transform(columnIds[1], (tree) =>
1164
+ tree.moveToFront("B2"),
1165
+ );
1166
+ expect(transformed.topLevelIds[1]).toEqual(["B2", "B1"]);
1167
+ });
1168
+
1169
+ it("handles transform method with non-existent column id", () => {
1170
+ const transformed = multiColumn.transform(
1171
+ "non-existent-id" as CellColumnId,
1172
+ (tree) => tree.moveToFront("B2"),
1173
+ );
1174
+ const columns1 = multiColumn.getColumns();
1175
+ const columns2 = transformed.getColumns();
1176
+ const allEqual = columns1.every((c, i) => c.equals(columns2[i]));
1177
+ expect(allEqual).toBe(true);
1178
+ expect(transformed).toBe(multiColumn);
1179
+ });
1180
+
1181
+ it("handles moving across columns with undefined toId", () => {
1182
+ const moved = multiColumn.moveAcrossColumns(
1183
+ columnIds[0],
1184
+ "A1",
1185
+ columnIds[1],
1186
+ undefined,
1187
+ );
1188
+ expect(moved.topLevelIds).toEqual([
1189
+ ["A2", "A3"],
1190
+ ["A1", "B1", "B2"],
1191
+ ["C1", "C2", "C3", "C4"],
1192
+ ]);
1193
+ });
1194
+
1195
+ it("handles moving across columns to an empty column", () => {
1196
+ const emptyColumnMultiColumn = multiColumn
1197
+ .deleteById("B1")
1198
+ .deleteById("B2");
1199
+ const moved = emptyColumnMultiColumn.moveAcrossColumns(
1200
+ columnIds[0],
1201
+ "A1",
1202
+ columnIds[1],
1203
+ undefined,
1204
+ );
1205
+ expect(moved.topLevelIds).toEqual([
1206
+ ["A2", "A3"],
1207
+ ["A1"],
1208
+ ["C1", "C2", "C3", "C4"],
1209
+ ]);
1210
+ });
1211
+
1212
+ it("handles inserting a breakpoint at the start of a column", () => {
1213
+ const withBreakpoint = multiColumn.insertBreakpoint("A1");
1214
+ expect(withBreakpoint.colLength).toBe(4);
1215
+ expect(withBreakpoint.topLevelIds).toEqual([
1216
+ [],
1217
+ ["A1", "A2", "A3"],
1218
+ ["B1", "B2"],
1219
+ ["C1", "C2", "C3", "C4"],
1220
+ ]);
1221
+ });
1222
+
1223
+ it("handles inserting a breakpoint at the end of a column", () => {
1224
+ const withBreakpoint = multiColumn.insertBreakpoint("A3");
1225
+ expect(withBreakpoint.colLength).toBe(4);
1226
+ expect(withBreakpoint.topLevelIds).toEqual([
1227
+ ["A1", "A2"],
1228
+ ["A3"],
1229
+ ["B1", "B2"],
1230
+ ["C1", "C2", "C3", "C4"],
1231
+ ]);
1232
+ });
1233
+
1234
+ it("handles inserting a breakpoint in a single-item column", () => {
1235
+ const singleItemColumn = MultiColumn.from([["A1"], ["B1"], ["C1"]]);
1236
+ const withBreakpoint = singleItemColumn.insertBreakpoint("B1");
1237
+ expect(withBreakpoint.colLength).toBe(4);
1238
+ expect(withBreakpoint.topLevelIds).toEqual([["A1"], [], ["B1"], ["C1"]]);
1239
+ });
1240
+ });
1241
+
1242
+ describe("MultiColumn.fromWithPreviousShape", () => {
1243
+ it("creates a new MultiColumn with a single column when no previous shape is provided", () => {
1244
+ const ids = ["A1", "A2", "A3"];
1245
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1246
+ ids,
1247
+ MultiColumn.from([]),
1248
+ );
1249
+
1250
+ expect(multiColumn.colLength).toBe(1);
1251
+ expect(multiColumn.topLevelIds).toEqual([ids]);
1252
+ expect(multiColumn.inOrderIds).toEqual(ids);
1253
+ });
1254
+
1255
+ it("preserves column structure when ids exist in previous columns", () => {
1256
+ const previousMultiColumn = MultiColumn.from([
1257
+ ["A1", "A2"],
1258
+ ["B1", "B2"],
1259
+ ["C1", "C2"],
1260
+ ]);
1261
+
1262
+ // Subset of ids from different columns
1263
+ const ids = ["A1", "B2", "C1"];
1264
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1265
+ ids,
1266
+ previousMultiColumn,
1267
+ );
1268
+
1269
+ expect(multiColumn.colLength).toBe(3);
1270
+ expect(multiColumn.topLevelIds).toEqual([["A1"], ["B2"], ["C1"]]);
1271
+ });
1272
+
1273
+ it("preserves column structure with different ordering", () => {
1274
+ const previousMultiColumn = MultiColumn.from([
1275
+ ["A1", "A2", "A3"],
1276
+ ["B1", "B2", "B3"],
1277
+ ]);
1278
+
1279
+ // Same ids but different order
1280
+ const ids = ["A3", "B1", "A1", "B3"];
1281
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1282
+ ids,
1283
+ previousMultiColumn,
1284
+ );
1285
+
1286
+ expect(multiColumn.colLength).toBe(2);
1287
+ expect(multiColumn.topLevelIds).toEqual([
1288
+ ["A3", "A1"],
1289
+ ["B1", "B3"],
1290
+ ]);
1291
+ });
1292
+
1293
+ it("handles ids not present in previous shape", () => {
1294
+ const previousMultiColumn = MultiColumn.from([
1295
+ ["A1", "A2"],
1296
+ ["B1", "B2"],
1297
+ ]);
1298
+
1299
+ // Include new ids not in previous shape
1300
+ const ids = ["A1", "B1", "C1", "D1"];
1301
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1302
+ ids,
1303
+ previousMultiColumn,
1304
+ );
1305
+
1306
+ // New ids should be added to the last column
1307
+ expect(multiColumn.colLength).toBe(2);
1308
+ expect(multiColumn.topLevelIds).toEqual([["A1"], ["B1", "C1", "D1"]]);
1309
+ expect(multiColumn.inOrderIds).toEqual(["A1", "B1", "C1", "D1"]);
1310
+ });
1311
+
1312
+ it("preserves collapsed state from previous shape", () => {
1313
+ // Create a previous shape with collapsed nodes
1314
+ let previousMultiColumn = MultiColumn.from([
1315
+ ["A1", "A2", "A3"],
1316
+ ["B1", "B2", "B3"],
1317
+ ]);
1318
+
1319
+ // Collapse A1 to include A2
1320
+ const columnIds = previousMultiColumn.getColumnIds();
1321
+ previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
1322
+ tree.collapse("A1", "A2"),
1323
+ );
1324
+
1325
+ // Create new shape with same ids
1326
+ const ids = ["A1", "A2", "A3", "B1", "B2", "B3"];
1327
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1328
+ ids,
1329
+ previousMultiColumn,
1330
+ );
1331
+
1332
+ // Check that A1 is still collapsed
1333
+ const column = multiColumn.atOrThrow(0);
1334
+ expect(column.isCollapsed("A1")).toBe(true);
1335
+
1336
+ // Check that the structure is preserved
1337
+ expect(multiColumn.colLength).toBe(2);
1338
+ expect(multiColumn.topLevelIds).toEqual([
1339
+ ["A1", "A3"],
1340
+ ["B1", "B2", "B3"],
1341
+ ]);
1342
+ });
1343
+
1344
+ it("handles empty columns in previous shape", () => {
1345
+ // Create a previous shape with an empty column
1346
+ const previousMultiColumn = MultiColumn.from([
1347
+ ["A1", "A2"],
1348
+ [],
1349
+ ["C1", "C2"],
1350
+ ]);
1351
+
1352
+ const ids = ["A1", "C2"];
1353
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1354
+ ids,
1355
+ previousMultiColumn,
1356
+ );
1357
+
1358
+ // Should preserve the column structure
1359
+ expect(multiColumn.colLength).toBe(3);
1360
+ expect(multiColumn.topLevelIds).toEqual([["A1"], [], ["C2"]]);
1361
+ });
1362
+
1363
+ it("handles subset of ids with nested collapsed structure", () => {
1364
+ // Create a previous shape with nested collapsed structure
1365
+ let previousMultiColumn = MultiColumn.from([
1366
+ ["A1", "A2", "A3", "A4", "A5"],
1367
+ ["B1", "B2", "B3"],
1368
+ ]);
1369
+
1370
+ // Collapse A1 to include A2, A3
1371
+ const columnIds = previousMultiColumn.getColumnIds();
1372
+ previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
1373
+ tree.collapse("A1", "A3"),
1374
+ );
1375
+
1376
+ // Create new shape with subset of ids
1377
+ const ids = ["A1", "A2", "A3", "A4", "B1"];
1378
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1379
+ ids,
1380
+ previousMultiColumn,
1381
+ );
1382
+
1383
+ // Check that collapsed state is preserved
1384
+ const column = multiColumn.atOrThrow(0);
1385
+ expect(column.isCollapsed("A1")).toBe(true);
1386
+
1387
+ // Check that the structure is preserved
1388
+ expect(multiColumn.colLength).toBe(2);
1389
+ expect(multiColumn.topLevelIds).toEqual([["A1", "A4"], ["B1"]]);
1390
+ expect(multiColumn.inOrderIds).toEqual(["A1", "A2", "A3", "A4", "B1"]);
1391
+ });
1392
+
1393
+ it("handles reordering of columns", () => {
1394
+ // Create a previous shape with specific column order
1395
+ const previousMultiColumn = MultiColumn.from([
1396
+ ["A1", "A2"],
1397
+ ["B1", "B2"],
1398
+ ["C1", "C2"],
1399
+ ]);
1400
+
1401
+ // Create new shape with ids in different order
1402
+ const ids = ["C1", "A1", "B1"];
1403
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1404
+ ids,
1405
+ previousMultiColumn,
1406
+ );
1407
+
1408
+ // Column order should be preserved
1409
+ expect(multiColumn.colLength).toBe(3);
1410
+ expect(multiColumn.topLevelIds).toEqual([["A1"], ["B1"], ["C1"]]);
1411
+ });
1412
+
1413
+ it("handles completely different set of ids", () => {
1414
+ const previousMultiColumn = MultiColumn.from([
1415
+ ["A1", "A2"],
1416
+ ["B1", "B2"],
1417
+ ]);
1418
+
1419
+ // Completely different set of ids
1420
+ const ids = ["X1", "X2", "X3"];
1421
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1422
+ ids,
1423
+ previousMultiColumn,
1424
+ );
1425
+
1426
+ // New ids should be added to the last column
1427
+ expect(multiColumn.colLength).toBe(2);
1428
+ expect(multiColumn.topLevelIds).toEqual([["X1", "X2", "X3"], []]);
1429
+ expect(multiColumn.inOrderIds).toEqual(["X1", "X2", "X3"]);
1430
+ });
1431
+
1432
+ it("preserves tree structure within columns", () => {
1433
+ // Create a previous shape with complex tree structure
1434
+ let previousMultiColumn = MultiColumn.from([
1435
+ ["A1", "A2", "A3", "A4"],
1436
+ ["B1", "B2", "B3"],
1437
+ ]);
1438
+
1439
+ // Create complex tree structure by collapsing nodes
1440
+ const columnIds = previousMultiColumn.getColumnIds();
1441
+ previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
1442
+ tree.collapse("A1", "A2"),
1443
+ );
1444
+ previousMultiColumn = previousMultiColumn.transform(columnIds[1], (tree) =>
1445
+ tree.collapse("B1", "B2"),
1446
+ );
1447
+
1448
+ // Create new shape with same ids
1449
+ const ids = ["A1", "A2", "A3", "A4", "B1", "B2", "B3"];
1450
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1451
+ ids,
1452
+ previousMultiColumn,
1453
+ );
1454
+
1455
+ // Check that collapsed state is preserved in both columns
1456
+ expect(multiColumn.atOrThrow(0).isCollapsed("A1")).toBe(true);
1457
+ expect(multiColumn.atOrThrow(1).isCollapsed("B1")).toBe(true);
1458
+
1459
+ // Check that the structure is preserved
1460
+ expect(multiColumn.colLength).toBe(2);
1461
+ expect(multiColumn.topLevelIds).toEqual([
1462
+ ["A1", "A3", "A4"],
1463
+ ["B1", "B3"],
1464
+ ]);
1465
+ });
1466
+
1467
+ it("handles empty array of ids", () => {
1468
+ const previousMultiColumn = MultiColumn.from([
1469
+ ["A1", "A2"],
1470
+ ["B1", "B2"],
1471
+ ]);
1472
+
1473
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1474
+ [],
1475
+ previousMultiColumn,
1476
+ );
1477
+
1478
+ expect(multiColumn.colLength).toBe(2);
1479
+ expect(multiColumn.topLevelIds).toEqual([[], []]);
1480
+ expect(multiColumn.inOrderIds).toEqual([]);
1481
+ });
1482
+
1483
+ it("handles single id", () => {
1484
+ const previousMultiColumn = MultiColumn.from([
1485
+ ["A1", "A2"],
1486
+ ["B1", "B2"],
1487
+ ]);
1488
+
1489
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1490
+ ["A1"],
1491
+ previousMultiColumn,
1492
+ );
1493
+
1494
+ expect(multiColumn.colLength).toBe(2);
1495
+ expect(multiColumn.topLevelIds).toEqual([["A1"], []]);
1496
+ expect(multiColumn.inOrderIds).toEqual(["A1"]);
1497
+ });
1498
+
1499
+ it("preserves complex nested structure across multiple columns", () => {
1500
+ // Create a complex structure with multiple columns and nested collapsed nodes
1501
+ let previousMultiColumn = MultiColumn.from([
1502
+ ["A1", "A2", "A3", "A4", "A5"],
1503
+ ["B1", "B2", "B3", "B4"],
1504
+ ["C1", "C2", "C3"],
1505
+ ]);
1506
+
1507
+ // Create complex nested structure
1508
+ const columnIds = previousMultiColumn.getColumnIds();
1509
+
1510
+ // Collapse in first column
1511
+ previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
1512
+ tree.collapse("A1", "A2"),
1513
+ );
1514
+ previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
1515
+ tree.collapse("A3", "A4"),
1516
+ );
1517
+
1518
+ // Collapse in second column
1519
+ previousMultiColumn = previousMultiColumn.transform(columnIds[1], (tree) =>
1520
+ tree.collapse("B1", "B2"),
1521
+ );
1522
+
1523
+ // Collapse in third column
1524
+ previousMultiColumn = previousMultiColumn.transform(columnIds[2], (tree) =>
1525
+ tree.collapse("C1", "C2"),
1526
+ );
1527
+
1528
+ // Create new shape with all ids
1529
+ const ids = [
1530
+ "A1",
1531
+ "A2",
1532
+ "A3",
1533
+ "A4",
1534
+ "A5",
1535
+ "B1",
1536
+ "B2",
1537
+ "B3",
1538
+ "B4",
1539
+ "C1",
1540
+ "C2",
1541
+ "C3",
1542
+ ];
1543
+
1544
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1545
+ ids,
1546
+ previousMultiColumn,
1547
+ );
1548
+
1549
+ // Check that all collapsed states are preserved
1550
+ expect(multiColumn.atOrThrow(0).isCollapsed("A1")).toBe(true);
1551
+ expect(multiColumn.atOrThrow(0).isCollapsed("A3")).toBe(true);
1552
+ expect(multiColumn.atOrThrow(1).isCollapsed("B1")).toBe(true);
1553
+ expect(multiColumn.atOrThrow(2).isCollapsed("C1")).toBe(true);
1554
+
1555
+ // Check that the structure is preserved
1556
+ expect(multiColumn.colLength).toBe(3);
1557
+ expect(multiColumn.topLevelIds).toEqual([
1558
+ ["A1", "A3", "A5"],
1559
+ ["B1", "B3", "B4"],
1560
+ ["C1", "C3"],
1561
+ ]);
1562
+ });
1563
+
1564
+ it("handles case where ids are distributed differently than in previous shape", () => {
1565
+ const previousMultiColumn = MultiColumn.from([
1566
+ ["A1", "A2"],
1567
+ ["B1", "B2"],
1568
+ ["C1", "C2"],
1569
+ ]);
1570
+
1571
+ // Create new shape with ids from different columns grouped together
1572
+ const ids = ["A1", "B1", "C1", "A2", "B2", "C2"];
1573
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1574
+ ids,
1575
+ previousMultiColumn,
1576
+ );
1577
+
1578
+ // Should preserve the original column structure
1579
+ expect(multiColumn.colLength).toBe(3);
1580
+ expect(multiColumn.topLevelIds).toEqual([
1581
+ ["A1", "A2"],
1582
+ ["B1", "B2"],
1583
+ ["C1", "C2"],
1584
+ ]);
1585
+ });
1586
+
1587
+ it("handles case where previous shape has collapsed nodes but new ids don't include children", () => {
1588
+ // Create a previous shape with collapsed nodes
1589
+ let previousMultiColumn = MultiColumn.from([
1590
+ ["A1", "A2", "A3"],
1591
+ ["B1", "B2", "B3"],
1592
+ ]);
1593
+
1594
+ // Collapse nodes in both columns
1595
+ const columnIds = previousMultiColumn.getColumnIds();
1596
+ previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
1597
+ tree.collapse("A1", "A2"),
1598
+ );
1599
+ previousMultiColumn = previousMultiColumn.transform(columnIds[1], (tree) =>
1600
+ tree.collapse("B1", "B2"),
1601
+ );
1602
+
1603
+ // Create new shape without the collapsed children
1604
+ const ids = ["A1", "A3", "B1", "B3"];
1605
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1606
+ ids,
1607
+ previousMultiColumn,
1608
+ );
1609
+
1610
+ // Nodes should not be collapsed since children are missing
1611
+ expect(multiColumn.atOrThrow(0).isCollapsed("A1")).toBe(false);
1612
+ expect(multiColumn.atOrThrow(1).isCollapsed("B1")).toBe(false);
1613
+
1614
+ // Check that the structure is preserved
1615
+ expect(multiColumn.colLength).toBe(2);
1616
+ expect(multiColumn.topLevelIds).toEqual([
1617
+ ["A1", "A3"],
1618
+ ["B1", "B3"],
1619
+ ]);
1620
+ });
1621
+
1622
+ it("handles deeply nested collapsed structure", () => {
1623
+ // Create a tree with deeply nested collapsed structure
1624
+ let previousTree = CollapsibleTree.from([
1625
+ "one",
1626
+ "two",
1627
+ "three",
1628
+ "four",
1629
+ "five",
1630
+ "six",
1631
+ "seven",
1632
+ "eight",
1633
+ ]);
1634
+
1635
+ // Create nested collapses
1636
+ previousTree = previousTree.collapse("one", "two");
1637
+
1638
+ // Get the collapsed node and collapse its children
1639
+ const oneNode = previousTree._nodeMap.get("one");
1640
+ expect(oneNode).toBeDefined();
1641
+
1642
+ // Create a new tree with the same structure
1643
+ const tree = CollapsibleTree.fromWithPreviousShape(
1644
+ ["one", "two", "three", "four", "five", "six", "seven", "eight"],
1645
+ previousTree,
1646
+ );
1647
+
1648
+ // Check that collapsed state is preserved
1649
+ expect(tree.isCollapsed("one")).toBe(true);
1650
+ expect(tree.topLevelIds).toEqual([
1651
+ "one",
1652
+ "three",
1653
+ "four",
1654
+ "five",
1655
+ "six",
1656
+ "seven",
1657
+ "eight",
1658
+ ]);
1659
+ });
1660
+
1661
+ it("handles case where collapsed node is at the end", () => {
1662
+ // Create a tree with collapsed node at the end
1663
+ let previousTree = CollapsibleTree.from([
1664
+ "one",
1665
+ "two",
1666
+ "three",
1667
+ "four",
1668
+ "five",
1669
+ ]);
1670
+ previousTree = previousTree.collapse("four", "five");
1671
+
1672
+ // Create new tree with same ids
1673
+ const tree = CollapsibleTree.fromWithPreviousShape(
1674
+ ["one", "two", "three", "four", "five"],
1675
+ previousTree,
1676
+ );
1677
+
1678
+ // Check that collapsed state is preserved
1679
+ expect(tree.isCollapsed("four")).toBe(true);
1680
+ expect(tree.topLevelIds).toEqual(["one", "two", "three", "four"]);
1681
+ });
1682
+
1683
+ it("handles case with multiple collapsed nodes in the same column", () => {
1684
+ // Create a previous shape with multiple collapsed nodes in the same column
1685
+ let previousMultiColumn = MultiColumn.from([
1686
+ ["A1", "A2", "A3", "A4", "A5", "A6"],
1687
+ ["B1", "B2"],
1688
+ ]);
1689
+
1690
+ // Collapse multiple nodes in the first column
1691
+ const columnIds = previousMultiColumn.getColumnIds();
1692
+ previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
1693
+ tree.collapse("A1", "A2"),
1694
+ );
1695
+ previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
1696
+ tree.collapse("A3", "A4"),
1697
+ );
1698
+ previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
1699
+ tree.collapse("A5", "A6"),
1700
+ );
1701
+
1702
+ // Create new shape with same ids
1703
+ const ids = ["A1", "A2", "A3", "A4", "A5", "A6", "B1", "B2"];
1704
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1705
+ ids,
1706
+ previousMultiColumn,
1707
+ );
1708
+
1709
+ // Check that all collapsed states are preserved
1710
+ expect(multiColumn.atOrThrow(0).isCollapsed("A1")).toBe(true);
1711
+ expect(multiColumn.atOrThrow(0).isCollapsed("A3")).toBe(true);
1712
+ expect(multiColumn.atOrThrow(0).isCollapsed("A5")).toBe(true);
1713
+
1714
+ // Check that the structure is preserved
1715
+ expect(multiColumn.colLength).toBe(2);
1716
+ expect(multiColumn.topLevelIds).toEqual([
1717
+ ["A1", "A3", "A5"],
1718
+ ["B1", "B2"],
1719
+ ]);
1720
+ });
1721
+
1722
+ it("handles case where all columns are empty in previous shape", () => {
1723
+ // Create a previous shape with all empty columns
1724
+ const previousMultiColumn = MultiColumn.from([[], [], []]);
1725
+
1726
+ // Create new shape with new ids
1727
+ const ids = ["A1", "B1", "C1"];
1728
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1729
+ ids,
1730
+ previousMultiColumn,
1731
+ );
1732
+
1733
+ // New ids should be added to the last column
1734
+ expect(multiColumn.colLength).toBe(3);
1735
+ expect(multiColumn.topLevelIds).toEqual([["A1", "B1", "C1"], [], []]);
1736
+ expect(multiColumn.inOrderIds).toEqual(["A1", "B1", "C1"]);
1737
+ });
1738
+
1739
+ it("handles case with very large number of ids", () => {
1740
+ // Create a previous shape with a reasonable number of ids
1741
+ const previousIds1 = Array.from({ length: 50 }, (_, i) => `A${i}`);
1742
+ const previousIds2 = Array.from({ length: 50 }, (_, i) => `B${i}`);
1743
+ const previousMultiColumn = MultiColumn.from([previousIds1, previousIds2]);
1744
+
1745
+ // Create a large set of ids
1746
+ const ids = [
1747
+ ...Array.from({ length: 50 }, (_, i) => `A${i}`),
1748
+ ...Array.from({ length: 50 }, (_, i) => `B${i}`),
1749
+ ...Array.from({ length: 50 }, (_, i) => `C${i}`),
1750
+ ];
1751
+
1752
+ const multiColumn = MultiColumn.fromWithPreviousShape(
1753
+ ids,
1754
+ previousMultiColumn,
1755
+ );
1756
+
1757
+ // Should preserve the column structure for existing ids and add new ids to last column
1758
+ expect(multiColumn.colLength).toBe(2);
1759
+ expect(multiColumn.topLevelIds[0].length).toBe(50);
1760
+ expect(multiColumn.topLevelIds[1].length).toBe(100); // 50 B ids + 50 C ids
1761
+ expect(multiColumn.inOrderIds.length).toBe(150); // All ids should be included
1762
+ });
1763
+ });
1764
+
1765
+ describe("CollapsibleTree.fromWithPreviousShape", () => {
1766
+ it("creates a new tree when no previous tree is provided", () => {
1767
+ const ids = ["one", "two", "three"];
1768
+ const tree = CollapsibleTree.fromWithPreviousShape(ids);
1769
+
1770
+ expect(tree.topLevelIds).toEqual(ids);
1771
+ expect(tree.inOrderIds).toEqual(ids);
1772
+ expect(tree.nodes.length).toBe(3);
1773
+ expect(tree.nodes.every((node) => !node.isCollapsed)).toBe(true);
1774
+ });
1775
+
1776
+ it("preserves the tree ID when previous tree is provided", () => {
1777
+ const previousTree = CollapsibleTree.from(["one", "two", "three"]);
1778
+ const tree = CollapsibleTree.fromWithPreviousShape(
1779
+ ["one", "two"],
1780
+ previousTree,
1781
+ );
1782
+
1783
+ expect(tree.id).toBe(previousTree.id);
1784
+ });
1785
+
1786
+ it("preserves collapsed state from previous tree", () => {
1787
+ // Create a tree with collapsed nodes
1788
+ let previousTree = CollapsibleTree.from(["one", "two", "three", "four"]);
1789
+ previousTree = previousTree.collapse("one", "two");
1790
+
1791
+ // Create new tree with same ids
1792
+ const tree = CollapsibleTree.fromWithPreviousShape(
1793
+ ["one", "two", "three", "four"],
1794
+ previousTree,
1795
+ );
1796
+
1797
+ // Check that one is still collapsed
1798
+ expect(tree.isCollapsed("one")).toBe(true);
1799
+ expect(tree.topLevelIds).toEqual(["one", "three", "four"]);
1800
+ });
1801
+
1802
+ it("handles subset of ids from previous tree", () => {
1803
+ // Create a tree with collapsed nodes
1804
+ let previousTree = CollapsibleTree.from([
1805
+ "one",
1806
+ "two",
1807
+ "three",
1808
+ "four",
1809
+ "five",
1810
+ ]);
1811
+ previousTree = previousTree.collapse("one", "two");
1812
+ previousTree = previousTree.collapse("three", "four");
1813
+
1814
+ // Create new tree with subset of ids
1815
+ const tree = CollapsibleTree.fromWithPreviousShape(
1816
+ ["one", "two", "three"],
1817
+ previousTree,
1818
+ );
1819
+
1820
+ // Check that collapsed state is preserved for existing nodes
1821
+ expect(tree.isCollapsed("one")).toBe(true);
1822
+ expect(tree.topLevelIds).toEqual(["one", "three"]);
1823
+ });
1824
+
1825
+ it("handles different ordering of ids", () => {
1826
+ // Create a tree with collapsed nodes
1827
+ let previousTree = CollapsibleTree.from(["one", "two", "three", "four"]);
1828
+ previousTree = previousTree.collapse("one", "two");
1829
+
1830
+ // Create new tree with different order
1831
+ const tree = CollapsibleTree.fromWithPreviousShape(
1832
+ ["three", "one", "two", "four"],
1833
+ previousTree,
1834
+ );
1835
+
1836
+ // Check that collapsed state is preserved
1837
+ expect(tree.isCollapsed("one")).toBe(true);
1838
+ expect(tree.topLevelIds).toEqual(["three", "one", "four"]);
1839
+ });
1840
+
1841
+ it("handles new ids not in previous tree", () => {
1842
+ // Create a tree with collapsed nodes
1843
+ let previousTree = CollapsibleTree.from(["one", "two", "three"]);
1844
+ previousTree = previousTree.collapse("one", "two");
1845
+
1846
+ // Create new tree with new ids
1847
+ const tree = CollapsibleTree.fromWithPreviousShape(
1848
+ ["one", "two", "three", "four", "five"],
1849
+ previousTree,
1850
+ );
1851
+
1852
+ // Check that collapsed state is preserved for existing nodes
1853
+ expect(tree.isCollapsed("one")).toBe(true);
1854
+ expect(tree.topLevelIds).toEqual(["one", "three", "four", "five"]);
1855
+ });
1856
+
1857
+ it("handles completely different set of ids", () => {
1858
+ // Create a tree with collapsed nodes
1859
+ let previousTree = CollapsibleTree.from(["one", "two", "three"]);
1860
+ previousTree = previousTree.collapse("one", "two");
1861
+
1862
+ // Create new tree with completely different ids
1863
+ const tree = CollapsibleTree.fromWithPreviousShape(
1864
+ ["four", "five", "six"],
1865
+ previousTree,
1866
+ );
1867
+
1868
+ // Should have no collapsed nodes
1869
+ expect(tree.nodes.every((node) => !node.isCollapsed)).toBe(true);
1870
+ expect(tree.topLevelIds).toEqual(["four", "five", "six"]);
1871
+ });
1872
+
1873
+ it("preserves nested collapsed structure", () => {
1874
+ // Create a tree with nested collapsed structure
1875
+ let previousTree = CollapsibleTree.from([
1876
+ "one",
1877
+ "two",
1878
+ "three",
1879
+ "four",
1880
+ "five",
1881
+ "six",
1882
+ ]);
1883
+ previousTree = previousTree.collapse("one", "two");
1884
+
1885
+ // Collapse the node that contains the collapsed children
1886
+ const oneNode = previousTree.nodes.find((n) => n.value === "one");
1887
+ expect(oneNode).toBeDefined();
1888
+ expect(oneNode?.children.length).toBeGreaterThan(0);
1889
+
1890
+ // Create a new tree with the same structure
1891
+ const tree = CollapsibleTree.fromWithPreviousShape(
1892
+ ["one", "two", "three", "four", "five", "six"],
1893
+ previousTree,
1894
+ );
1895
+
1896
+ // Check that collapsed state is preserved
1897
+ expect(tree.isCollapsed("one")).toBe(true);
1898
+ expect(tree.topLevelIds).toEqual(["one", "three", "four", "five", "six"]);
1899
+ });
1900
+
1901
+ it("collapses using the last available child when some children are missing", () => {
1902
+ // Create a tree with collapsed nodes
1903
+ let previousTree = CollapsibleTree.from(["one", "two", "three", "four"]);
1904
+ previousTree = previousTree.collapse("one", "three");
1905
+
1906
+ // Create new tree without "two" but with "three"
1907
+ const tree = CollapsibleTree.fromWithPreviousShape(
1908
+ ["one", "three", "four"],
1909
+ previousTree,
1910
+ );
1911
+
1912
+ // Should still collapse "one" with "three" as the child
1913
+ expect(tree.isCollapsed("one")).toBe(true);
1914
+ expect(tree.topLevelIds).toEqual(["one", "four"]);
1915
+ });
1916
+
1917
+ it("preserves collapse state when children order changes", () => {
1918
+ // Create a tree with collapsed nodes
1919
+ let previousTree = CollapsibleTree.from(["one", "two", "three", "four"]);
1920
+ previousTree = previousTree.collapse("one", "two");
1921
+
1922
+ // Create new tree with children in different order
1923
+ const tree = CollapsibleTree.fromWithPreviousShape(
1924
+ ["one", "three", "two", "four"],
1925
+ previousTree,
1926
+ );
1927
+
1928
+ // Should still be collapsed
1929
+ expect(tree.isCollapsed("one")).toBe(true);
1930
+ // But the topLevelIds will be different because the children order changed
1931
+ expect(tree.topLevelIds).toEqual(["one", "four"]);
1932
+ });
1933
+
1934
+ it("handles empty arrays correctly", () => {
1935
+ const previousTree = CollapsibleTree.from(["one", "two", "three"]);
1936
+ const tree = CollapsibleTree.fromWithPreviousShape([], previousTree);
1937
+
1938
+ expect(tree.nodes.length).toBe(0);
1939
+ expect(tree.topLevelIds).toEqual([]);
1940
+ expect(tree.inOrderIds).toEqual([]);
1941
+ });
1942
+
1943
+ it("handles single item arrays correctly", () => {
1944
+ let previousTree = CollapsibleTree.from(["one", "two", "three"]);
1945
+ previousTree = previousTree.collapse("one", "two");
1946
+
1947
+ const tree = CollapsibleTree.fromWithPreviousShape(["one"], previousTree);
1948
+
1949
+ expect(tree.nodes.length).toBe(1);
1950
+ expect(tree.topLevelIds).toEqual(["one"]);
1951
+ expect(tree.inOrderIds).toEqual(["one"]);
1952
+ // Should not be collapsed since there are no children
1953
+ expect(tree.isCollapsed("one")).toBe(false);
1954
+ });
1955
+
1956
+ it("handles multiple collapsed nodes in sequence", () => {
1957
+ let previousTree = CollapsibleTree.from([
1958
+ "one",
1959
+ "two",
1960
+ "three",
1961
+ "four",
1962
+ "five",
1963
+ "six",
1964
+ ]);
1965
+ previousTree = previousTree.collapse("one", "two");
1966
+ previousTree = previousTree.collapse("three", "four");
1967
+ previousTree = previousTree.collapse("five", "six");
1968
+
1969
+ const tree = CollapsibleTree.fromWithPreviousShape(
1970
+ ["one", "two", "three", "four", "five", "six"],
1971
+ previousTree,
1972
+ );
1973
+
1974
+ expect(tree.isCollapsed("one")).toBe(true);
1975
+ expect(tree.isCollapsed("three")).toBe(true);
1976
+ expect(tree.isCollapsed("five")).toBe(true);
1977
+ expect(tree.topLevelIds).toEqual(["one", "three", "five"]);
1978
+ });
1979
+
1980
+ it("handles case where collapsed node's children are not in new ids", () => {
1981
+ let previousTree = CollapsibleTree.from(["one", "two", "three", "four"]);
1982
+ previousTree = previousTree.collapse("one", "two");
1983
+
1984
+ // Create new tree without the collapsed child
1985
+ const tree = CollapsibleTree.fromWithPreviousShape(
1986
+ ["one", "three", "four"],
1987
+ previousTree,
1988
+ );
1989
+
1990
+ // Should not be collapsed since the child is missing
1991
+ expect(tree.isCollapsed("one")).toBe(false);
1992
+ expect(tree.topLevelIds).toEqual(["one", "three", "four"]);
1993
+ });
1994
+ });