@marimo-team/frontend 0.25.2-dev12 → 0.25.2-dev4

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 (131) hide show
  1. package/dist/assets/{ConnectedDataExplorerComponent-BFDHLGyp.js → ConnectedDataExplorerComponent-DJ5jwKfp.js} +1 -1
  2. package/dist/assets/{ErrorBoundary-CtGZ1MAN.js → ErrorBoundary-BeE1cdgM.js} +2 -2
  3. package/dist/assets/{LazyAnyLanguageCodeMirror-CaEYnB8x.js → LazyAnyLanguageCodeMirror-B_IYTCX5.js} +2 -2
  4. package/dist/assets/{RunButton-YN1KKz4a.js → RunButton-C2kFUhyO.js} +1 -1
  5. package/dist/assets/{abnfDiagram-VCTEODGH-CqPJWAgx.js → abnfDiagram-VCTEODGH-CSPJSGaM.js} +1 -1
  6. package/dist/assets/{add-cell-with-ai-Dceg80EG.js → add-cell-with-ai-BFgdVPaN.js} +1 -1
  7. package/dist/assets/{agent-panel-CEG8eS3F.js → agent-panel-Dh7yWh9P.js} +1 -1
  8. package/dist/assets/{ai-model-dropdown-SOxGsjRY.js → ai-model-dropdown-DJ2elMLM.js} +1 -1
  9. package/dist/assets/{alert-dialog-BsB0FYEL.js → alert-dialog-CeE3i3Qa.js} +1 -1
  10. package/dist/assets/{any-language-editor-b9spizfh.js → any-language-editor-Cj_HzlZY.js} +1 -1
  11. package/dist/assets/{app-config-button-CTTg_TIX.js → app-config-button-DBCTefOX.js} +1 -1
  12. package/dist/assets/{architectureDiagram-5GKGNRK7-DXjBUUE6.js → architectureDiagram-5GKGNRK7-7iukRoC9.js} +1 -1
  13. package/dist/assets/{blockDiagram-I7D4REHJ-DS6I1u-N.js → blockDiagram-I7D4REHJ-cuhpQB60.js} +1 -1
  14. package/dist/assets/{button-qFeU84ax.js → button-BoklZTGL.js} +1 -1
  15. package/dist/assets/{cache-panel-Ct9EFgP7.js → cache-panel-C0oB1kE2.js} +1 -1
  16. package/dist/assets/{capabilities-BqUNf14U.js → capabilities-Bj3s1hGN.js} +1 -1
  17. package/dist/assets/{cells-CU9huD49.js → cells-CzugpTQu.js} +1 -1
  18. package/dist/assets/{chat-display-DWPnai8M.js → chat-display-DevO4F8W.js} +1 -1
  19. package/dist/assets/{chat-panel-DGnu6v96.js → chat-panel-BGw0bqDk.js} +1 -1
  20. package/dist/assets/{chat-ui-BqLN7iW4.js → chat-ui-CZZFGlZi.js} +1 -1
  21. package/dist/assets/{chunk-IMKFNOWR-s8kQsL8K.js → chunk-IMKFNOWR-BIILwBhp.js} +1 -1
  22. package/dist/assets/{chunk-SHT3W25Y-CM7-8w1-.js → chunk-SHT3W25Y-BtLGdeDB.js} +1 -1
  23. package/dist/assets/{chunk-SVP7TREG-BErtDMhh.js → chunk-SVP7TREG-B0UfxhUP.js} +1 -1
  24. package/dist/assets/{chunk-TICWLB2K-CGVR3aYq.js → chunk-TICWLB2K-BP7vel_P.js} +1 -1
  25. package/dist/assets/{circle-CzTMKZwz.js → circle-CeQt3rdW.js} +1 -1
  26. package/dist/assets/{classDiagram-ZZMXUADV-isldMhyu.js → classDiagram-ZZMXUADV-CoNXKNMZ.js} +1 -1
  27. package/dist/assets/{classDiagram-v2-VYDZK3BY-isldMhyu.js → classDiagram-v2-VYDZK3BY-CoNXKNMZ.js} +1 -1
  28. package/dist/assets/{code-visibility-BGq9NyQN.js → code-visibility-BFNYI7hr.js} +1 -1
  29. package/dist/assets/{command-palette-CyBHUvlK.js → command-palette-DN4JoOLD.js} +1 -1
  30. package/dist/assets/{common-CdJQaC_v.js → common-DUCPhoyP.js} +1 -1
  31. package/dist/assets/{components-DsJLlugL.js → components-CK7CeYlo.js} +1 -1
  32. package/dist/assets/{components-zfCkpDjF.js → components-DAmFBASm.js} +1 -1
  33. package/dist/assets/{config-2Nts63h2.js → config-B4VJJibu.js} +1 -1
  34. package/dist/assets/{config-BdH5RvM0.js → config-BxZgoFvi.js} +1 -1
  35. package/dist/assets/{config-D7CP5wR5.js → config-DpGPGznL.js} +1 -1
  36. package/dist/assets/{copy-B--GzTEX.js → copy-BhJktFeI.js} +1 -1
  37. package/dist/assets/{copy-icon-DQuttmjH.js → copy-icon-DFhUGBjO.js} +1 -1
  38. package/dist/assets/{createReducer-CI8rlZE9.js → createReducer-BPvK7C_R.js} +1 -1
  39. package/dist/assets/{cynefinDiagram-5FMLGOSQ-B7iZDq2a.js → cynefinDiagram-5FMLGOSQ-BARZRQBb.js} +1 -1
  40. package/dist/assets/{dagre-DkKsNZNe.js → dagre-DVyyr7Cb.js} +1 -1
  41. package/dist/assets/{dagre-GXQ25YYZ-CLT8-BB_.js → dagre-GXQ25YYZ-79s0lOP0.js} +1 -1
  42. package/dist/assets/{data-grid-overlay-editor-Bt4aaHfB.js → data-grid-overlay-editor-DPfnIudL.js} +1 -1
  43. package/dist/assets/{dependency-graph-panel-DPFdz5rd.js → dependency-graph-panel-BN4CLayU.js} +1 -1
  44. package/dist/assets/{diagram-S7CK7UJ4-SuzEYncV.js → diagram-S7CK7UJ4-BCviGhvd.js} +1 -1
  45. package/dist/assets/{diagram-UQ7AKVKN-cuBTTzq8.js → diagram-UQ7AKVKN-Ds-BT46T.js} +1 -1
  46. package/dist/assets/{diagram-VX7I27RA-h6SkZKIl.js → diagram-VX7I27RA-BtL2eh0t.js} +1 -1
  47. package/dist/assets/{diagram-Z3DM3KII-C-Vebae0.js → diagram-Z3DM3KII-C6SmbLBS.js} +1 -1
  48. package/dist/assets/{dist-DFI04FfI.js → dist-CyYN7zJg.js} +1 -1
  49. package/dist/assets/{documentation-panel-YTTKKIe_.js → documentation-panel-CzRbXV5u.js} +1 -1
  50. package/dist/assets/{dropdown-menu-Crx6knLg.js → dropdown-menu-VuyoeQOD.js} +1 -1
  51. package/dist/assets/{ebnfDiagram-PWID7BFC-Bm_qbW1t.js → ebnfDiagram-PWID7BFC-D_JU4cMQ.js} +1 -1
  52. package/dist/assets/{edit-page-CWbb1Sdk.js → edit-page-jGNYBqQo.js} +45 -45
  53. package/dist/assets/{erDiagram-RLTQ6QDP-Dwwt91bq.js → erDiagram-RLTQ6QDP-Z9MJ6X-r.js} +1 -1
  54. package/dist/assets/{error-entries-DvgFKvod.js → error-entries-CDSsy76p.js} +1 -1
  55. package/dist/assets/{error-panel-D1XBOiHc.js → error-panel-ABvjFG3p.js} +1 -1
  56. package/dist/assets/{feedback-button-CXjDdARJ.js → feedback-button-CZhLiwkO.js} +1 -1
  57. package/dist/assets/{file-explorer-panel-BKJMBA3O.js → file-explorer-panel-DTiEpmVE.js} +1 -1
  58. package/dist/assets/{file-name-input-Bd3Q-WUK.js → file-name-input-C1C8xrjA.js} +1 -1
  59. package/dist/assets/{filename-rhW-R6K2.js → filename-fxG7K_MU.js} +1 -1
  60. package/dist/assets/{flowDiagram-HODETNUW-CqLwY5NX.js → flowDiagram-HODETNUW-ncLciK2K.js} +1 -1
  61. package/dist/assets/{fullscreen-3wS6IaIC.js → fullscreen-BmzAqMKq.js} +1 -1
  62. package/dist/assets/{gallery-page-CrkxyZTA.js → gallery-page-Moi4ZdJ0.js} +1 -1
  63. package/dist/assets/{glide-data-editor-B5WqL5gm.js → glide-data-editor-CbsCWu-K.js} +4 -4
  64. package/dist/assets/{graphlib-6Yb0YQgW.js → graphlib-3maKwbRO.js} +1 -1
  65. package/dist/assets/has-cJsIKK9t.js +1 -0
  66. package/dist/assets/{home-page-BNKKAvoF.js → home-page-UAgVOkCZ.js} +1 -1
  67. package/dist/assets/{index-C9FPQNuH.js → index-DafnX1Xx.js} +8 -8
  68. package/dist/assets/{infoDiagram-27XIBGKW-dRXMROiS.js → infoDiagram-27XIBGKW-Dk8U81nJ.js} +1 -1
  69. package/dist/assets/{input-D4bMj5Nb.js → input-BDakodZ2.js} +1 -1
  70. package/dist/assets/{ishikawaDiagram-5VMMS53U-CvBCDJJe.js → ishikawaDiagram-5VMMS53U-CzHQlMUQ.js} +1 -1
  71. package/dist/assets/{kanban-definition-UXKFOSKX-fIKpyolW.js → kanban-definition-UXKFOSKX-CVyVYiI6.js} +1 -1
  72. package/dist/assets/{logs-panel-adAvx6o3.js → logs-panel-Bz5ysVX4.js} +1 -1
  73. package/dist/assets/{menu-items-D-vbZmqL.js → menu-items-BBdeXCvU.js} +1 -1
  74. package/dist/assets/{mermaid-DpSqZGNM.js → mermaid-D_jPUVqz.js} +4 -4
  75. package/dist/assets/{mindmap-definition-YA3MSWOX-B95LGKLt.js → mindmap-definition-YA3MSWOX-D5t6Aq5Z.js} +1 -1
  76. package/dist/assets/{number-overlay-editor-Bs5xzKX-.js → number-overlay-editor-FAD8sjFU.js} +1 -1
  77. package/dist/assets/{numbers-DyJNv6Vk.js → numbers-DsgsDslU.js} +1 -1
  78. package/dist/assets/{outline-panel-B9u6Wgol.js → outline-panel-85oiQ0XX.js} +1 -1
  79. package/dist/assets/{packages-panel-D-g71io7.js → packages-panel-ClKIaP5S.js} +1 -1
  80. package/dist/assets/{panels-C5xQNcZv.js → panels-B48zp96D.js} +3 -3
  81. package/dist/assets/{pegDiagram-XKGWAZYB-CMaSc5Ln.js → pegDiagram-XKGWAZYB-BTkTm4ej.js} +1 -1
  82. package/dist/assets/{pieDiagram-E7YTZNPT-CZY0tLgh.js → pieDiagram-E7YTZNPT-Bq6X88M1.js} +1 -1
  83. package/dist/assets/{process-output-CpF79y4D.js → process-output-Cg2ta3vY.js} +1 -1
  84. package/dist/assets/{railroadDiagram-O6MQD6OU-BSMijs6s.js → railroadDiagram-O6MQD6OU-fv8HXW_g.js} +1 -1
  85. package/dist/assets/{requirementDiagram-BXWQKSXE-DjzkUUZk.js → requirementDiagram-BXWQKSXE-DDOOMUfC.js} +1 -1
  86. package/dist/assets/{reveal-component-ZyDayfDQ.js → reveal-component-CR43gpTZ.js} +1 -1
  87. package/dist/assets/{run-page-Ba_64fL5.js → run-page-NR_KFWk8.js} +1 -1
  88. package/dist/assets/{scratchpad-panel-7bxRkpPb.js → scratchpad-panel-DHc-oVb1.js} +1 -1
  89. package/dist/assets/{scroll-to-bottom-button-BLNi0TGS.js → scroll-to-bottom-button-BSCkDXet.js} +1 -1
  90. package/dist/assets/{secrets-panel-DmKgIV5x.js → secrets-panel-C-65ZjnM.js} +1 -1
  91. package/dist/assets/{select-CWHHoM53.js → select-BplWpfFo.js} +1 -1
  92. package/dist/assets/{sequenceDiagram-WJ2MYXX4-Dp7JdkJ6.js → sequenceDiagram-WJ2MYXX4-DdpBhQaS.js} +1 -1
  93. package/dist/assets/{session-ztCnZJHI.js → session-DXKMv4Bs.js} +1 -1
  94. package/dist/assets/{session-panel-D9qVJogC.js → session-panel-DiwQqIbt.js} +1 -1
  95. package/dist/assets/{snippets-panel-QdZvjlBm.js → snippets-panel-BLmXrneD.js} +1 -1
  96. package/dist/assets/{state-0NZOvqJz.js → state-Ozzur_f2.js} +1 -1
  97. package/dist/assets/{stateDiagram-D77RDMKH-CR5QDK_-.js → stateDiagram-D77RDMKH-D3p19fac.js} +1 -1
  98. package/dist/assets/{stateDiagram-v2-MP3YSRHH-BmMYN-vz.js → stateDiagram-v2-MP3YSRHH-CplsDaDl.js} +1 -1
  99. package/dist/assets/{strings-LjhpYwmx.js → strings-BHZPE0Mc.js} +1 -1
  100. package/dist/assets/{swimlanes-42K2YHIH-By_1jYHM.js → swimlanes-42K2YHIH-CLxCSvU4.js} +1 -1
  101. package/dist/assets/{swimlanesDiagram-VR7AAH4N-DjMyvNFc.js → swimlanesDiagram-VR7AAH4N-DPoIFx8T.js} +1 -1
  102. package/dist/assets/{swiper-component-Cbtej5b-.js → swiper-component-rqJChT_P.js} +1 -1
  103. package/dist/assets/{terminal-Ri8br8XX.js → terminal-CY4h1UmO.js} +1 -1
  104. package/dist/assets/{timeline-definition-24CTP7MA-BjNxu6yh.js → timeline-definition-24CTP7MA-Cw2PY--x.js} +1 -1
  105. package/dist/assets/{toast-DXkezxWI.js → toast-KNfsFUiB.js} +1 -1
  106. package/dist/assets/{tooltip-CamoSiGF.js → tooltip-DR2Z2N4w.js} +1 -1
  107. package/dist/assets/{tooltip-BQ9qHrrN.js → tooltip-PLkI_UfK.js} +1 -1
  108. package/dist/assets/{tracing-BxMH9HGb.js → tracing-Q8NAdlrA.js} +1 -1
  109. package/dist/assets/{tracing-panel-EeL3md5x.js → tracing-panel-Ci4kY4dr.js} +2 -2
  110. package/dist/assets/{use-restore-focus-D0UtBPD6.js → use-restore-focus-B98SEiGc.js} +1 -1
  111. package/dist/assets/{useCellActionButton-Di4NkDbT.js → useCellActionButton-DpYtVfFe.js} +1 -1
  112. package/dist/assets/{useEventListener-CUPWI_1X.js → useEventListener-BdZUApHd.js} +1 -1
  113. package/dist/assets/{useInterval-DluQa5sq.js → useInterval-ChchS0Rl.js} +1 -1
  114. package/dist/assets/{useTheme-CnWB5G1X.js → useTheme-DcnXlv0_.js} +1 -1
  115. package/dist/assets/{vega-component-DGTXJwmx.js → vega-component-BpoSew4K.js} +1 -1
  116. package/dist/assets/{vega-embed-container-Din5FYpB.js → vega-embed-container-BOJG8mCA.js} +1 -1
  117. package/dist/assets/{vennDiagram-4TSXK5OY-BR66J2hx.js → vennDiagram-4TSXK5OY-D8bN6lVl.js} +1 -1
  118. package/dist/assets/{wardleyDiagram-VM6X3IG4-Kg0-lASD.js → wardleyDiagram-VM6X3IG4-CbZdo0SA.js} +1 -1
  119. package/dist/assets/{write-secret-modal-wFgr-1dA.js → write-secret-modal-BiG2tahJ.js} +1 -1
  120. package/dist/assets/{xychartDiagram-S5SC5T6Z-BSXFWSRW.js → xychartDiagram-S5SC5T6Z-DUUQ9tau.js} +1 -1
  121. package/dist/assets/{youtube-Ck_NlGi9.js → youtube-A9VT7NHb.js} +1 -1
  122. package/dist/index.html +31 -31
  123. package/package.json +1 -1
  124. package/src/components/editor/actions/useNotebookActions.tsx +0 -20
  125. package/src/core/edit-app.tsx +0 -16
  126. package/src/core/hotkeys/hotkeys.ts +0 -12
  127. package/src/plugins/impl/FileBrowserPlugin.tsx +15 -45
  128. package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +2 -85
  129. package/dist/assets/has-B4C7ywdy.js +0 -1
  130. package/src/components/editor/actions/__tests__/useSetOutputsExpanded.test.ts +0 -42
  131. package/src/components/editor/actions/useSetOutputsExpanded.ts +0 -67
@@ -1,6 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
- import { type LucideIcon, ChevronRightIcon, CornerLeftUp } from "lucide-react";
3
+ import { type LucideIcon, CornerLeftUp } from "lucide-react";
4
4
  import { type JSX, useEffect, useLayoutEffect, useRef, useState } from "react";
5
5
  import { z } from "zod";
6
6
  import {
@@ -12,6 +12,7 @@ import { Spinner } from "@/components/icons/spinner";
12
12
  import { Button } from "@/components/ui/button";
13
13
  import { Checkbox } from "@/components/ui/checkbox";
14
14
  import { Label } from "@/components/ui/label";
15
+ import { NativeSelect } from "@/components/ui/native-select";
15
16
  import { Table, TableBody, TableCell, TableRow } from "@/components/ui/table";
16
17
  import { toast } from "@/components/ui/use-toast";
17
18
  import { RANDOM_ID_ATTR } from "@/core/dom/ui-element-constants";
@@ -471,19 +472,12 @@ export const FileBrowser = ({
471
472
  //
472
473
  // Assumes that path contains at least one delimiter, which is true
473
474
  // only if this is an absolute path.
474
- const { protocol, parentDirectories } = getProtocolAndParentDirectories({
475
+ const { parentDirectories } = getProtocolAndParentDirectories({
475
476
  path,
476
477
  delimiter,
477
478
  initialPath,
478
479
  restrictNavigation,
479
480
  });
480
- const breadcrumbs = parentDirectories.toReversed().map((dir) => ({
481
- path: dir,
482
- name:
483
- dir === protocol
484
- ? protocol
485
- : (dir.split(delimiter).findLast(Boolean) ?? dir),
486
- }));
487
481
 
488
482
  const selectionKindLabel =
489
483
  selectionMode === "all"
@@ -521,42 +515,18 @@ export const FileBrowser = ({
521
515
  <div>
522
516
  {error && <Banner kind="danger">{error.message}</Banner>}
523
517
  {renderHeader()}
524
- <nav aria-label="Current directory" className="mt-2">
525
- <ol className="flex flex-wrap items-center gap-0.5 text-sm">
526
- {breadcrumbs.map((crumb, index) => {
527
- const isCurrent = index === breadcrumbs.length - 1;
528
- return (
529
- <li key={crumb.path} className="flex items-center gap-0.5">
530
- {index > 0 && (
531
- <ChevronRightIcon
532
- size={14}
533
- className="text-muted-foreground shrink-0"
534
- aria-hidden={true}
535
- />
536
- )}
537
- <button
538
- type="button"
539
- title={crumb.path}
540
- aria-current={isCurrent ? "page" : undefined}
541
- onClick={() => {
542
- if (!isCurrent) {
543
- setNewPath(crumb.path);
544
- }
545
- }}
546
- className={cn(
547
- "rounded px-1 focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring",
548
- isCurrent
549
- ? "font-medium cursor-default"
550
- : "text-muted-foreground hover:bg-accent hover:text-foreground",
551
- )}
552
- >
553
- {crumb.name}
554
- </button>
555
- </li>
556
- );
557
- })}
558
- </ol>
559
- </nav>
518
+ <NativeSelect
519
+ className="mt-2 w-full"
520
+ placeholder={path}
521
+ value={path}
522
+ onChange={(e) => setNewPath(e.target.value)}
523
+ >
524
+ {parentDirectories.map((dir) => (
525
+ <option value={dir} key={dir}>
526
+ {dir}
527
+ </option>
528
+ ))}
529
+ </NativeSelect>
560
530
 
561
531
  {data && typeof data.total_count === "number" && (
562
532
  <div className="text-xs text-muted-foreground mt-1 px-1">
@@ -1,12 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
- import {
4
- fireEvent,
5
- render,
6
- screen,
7
- waitFor,
8
- within,
9
- } from "@testing-library/react";
3
+ import { fireEvent, render, screen, waitFor } from "@testing-library/react";
10
4
  import { beforeAll, describe, expect, it, vi } from "vitest";
11
5
  import { SetupMocks } from "@/__mocks__/common";
12
6
  import { initialModeAtom } from "@/core/mode";
@@ -193,7 +187,7 @@ describe("FileBrowserPlugin keyboard accessibility", () => {
193
187
  const docsRow = docs.closest('[role="row"]')!;
194
188
  fireEvent.keyDown(docsRow, { key: "ArrowDown" }); // move active off the parent
195
189
  fireEvent.click(docs); // navigate into "docs"
196
- await within(screen.getByRole("grid")).findByText("docs"); // listing reloads (mock returns same files)
190
+ await screen.findByText("docs"); // listing reloads (mock returns same files)
197
191
  const rows = screen.getAllByRole("row");
198
192
  expect(rows[0]).toHaveAttribute("tabindex", "0");
199
193
  // the focused row must match the only tabbable row
@@ -367,80 +361,3 @@ describe("FileBrowserPlugin keyboard accessibility", () => {
367
361
  function rowFor(name: string): HTMLElement {
368
362
  return screen.getByText(name).closest('[role="row"]') as HTMLElement;
369
363
  }
370
-
371
- describe("FileBrowserPlugin breadcrumbs", () => {
372
- function breadcrumbs() {
373
- return within(
374
- screen.getByRole("navigation", { name: "Current directory" }),
375
- );
376
- }
377
-
378
- it("renders a crumb per ancestor with the current directory last", async () => {
379
- renderBrowser();
380
- await screen.findByText("docs");
381
- const items = breadcrumbs().getAllByRole("listitem");
382
- expect(items.map((li) => li.textContent)).toEqual(["/", "home", "user"]);
383
- expect(breadcrumbs().getByRole("button", { name: "user" })).toHaveAttribute(
384
- "aria-current",
385
- "page",
386
- );
387
- expect(
388
- breadcrumbs().getByRole("button", { name: "home" }),
389
- ).not.toHaveAttribute("aria-current");
390
- });
391
-
392
- it("keeps focus on a crumb after navigating to it", async () => {
393
- const { listDirectory } = renderBrowser();
394
- await screen.findByText("docs");
395
- const home = breadcrumbs().getByRole("button", { name: "home" });
396
- home.focus();
397
- fireEvent.click(home);
398
- await waitFor(() =>
399
- expect(listDirectory).toHaveBeenLastCalledWith({ path: "/home" }),
400
- );
401
- const current = breadcrumbs().getByRole("button", { name: "home" });
402
- expect(current).toHaveAttribute("aria-current", "page");
403
- expect(current).toBe(home);
404
- expect(current).toHaveFocus();
405
- });
406
-
407
- it("does not reload when the current crumb is clicked", async () => {
408
- const { listDirectory } = renderBrowser();
409
- await screen.findByText("docs");
410
- fireEvent.click(breadcrumbs().getByRole("button", { name: "user" }));
411
- expect(listDirectory).toHaveBeenCalledTimes(1);
412
- });
413
-
414
- it("navigates to an ancestor when a crumb is clicked", async () => {
415
- const { listDirectory } = renderBrowser();
416
- await screen.findByText("docs");
417
- fireEvent.click(breadcrumbs().getByRole("button", { name: "home" }));
418
- await waitFor(() =>
419
- expect(listDirectory).toHaveBeenLastCalledWith({ path: "/home" }),
420
- );
421
- fireEvent.click(breadcrumbs().getByRole("button", { name: "/" }));
422
- await waitFor(() =>
423
- expect(listDirectory).toHaveBeenLastCalledWith({ path: "/" }),
424
- );
425
- });
426
-
427
- it("hides ancestors outside the initial path when navigation is restricted", async () => {
428
- render(
429
- <FileBrowser
430
- initialPath="/home/user"
431
- filetypes={[]}
432
- selectionMode="all"
433
- multiple={true}
434
- label={null}
435
- restrictNavigation={true}
436
- value={[]}
437
- setValue={vi.fn()}
438
- host={document.createElement("div")}
439
- list_directory={mockListDirectory(FILES)}
440
- />,
441
- );
442
- await screen.findByText("docs");
443
- const items = breadcrumbs().getAllByRole("listitem");
444
- expect(items.map((li) => li.textContent)).toEqual(["user"]);
445
- });
446
- });
@@ -1 +0,0 @@
1
- import{Wa as e}from"./index-C9FPQNuH.js";var t=Object.prototype.hasOwnProperty;function n(e,n){return e!=null&&t.call(e,n)}function r(t,r){return t!=null&&e(t,r,n)}export{r as t};
@@ -1,42 +0,0 @@
1
- /* Copyright 2026 Marimo. All rights reserved. */
2
-
3
- import { describe, expect, it } from "vitest";
4
- import { MockNotebook } from "@/__mocks__/notebook";
5
- import type { OutputMessage } from "@/core/kernel/messages";
6
- import { outputExpansionConfigs } from "../useSetOutputsExpanded";
7
-
8
- const output: OutputMessage = {
9
- channel: "output",
10
- mimetype: "text/plain",
11
- data: "hello",
12
- timestamp: 0,
13
- };
14
-
15
- describe("outputExpansionConfigs", () => {
16
- const [withOutput, withoutOutput, expanded, expandedWithoutOutput] =
17
- MockNotebook.cellIds();
18
- const notebook = MockNotebook.notebookState({
19
- cellData: {
20
- [withOutput]: {},
21
- [withoutOutput]: {},
22
- [expanded]: { config: { expand_output: true } },
23
- [expandedWithoutOutput]: { config: { expand_output: true } },
24
- },
25
- cellRuntime: {
26
- [withOutput]: { output },
27
- [expanded]: { output },
28
- },
29
- });
30
-
31
- it("expands clamped cells with output and skips cells without output", () => {
32
- expect(outputExpansionConfigs(notebook, true)).toEqual({
33
- [withOutput]: { expand_output: true },
34
- });
35
- });
36
-
37
- it("clamps expanded cells with output and skips cells without output", () => {
38
- expect(outputExpansionConfigs(notebook, false)).toEqual({
39
- [expanded]: { expand_output: false },
40
- });
41
- });
42
- });
@@ -1,67 +0,0 @@
1
- /* Copyright 2026 Marimo. All rights reserved. */
2
-
3
- import { useCallback } from "react";
4
- import {
5
- getNotebook,
6
- type NotebookState,
7
- useCellActions,
8
- } from "@/core/cells/cells";
9
- import type { CellId } from "@/core/cells/ids";
10
- import { isOutputEmpty } from "@/core/cells/outputs";
11
- import { useRequestClient } from "@/core/network/requests";
12
- import type { CellConfig } from "@/core/network/types";
13
- import { Objects } from "@/utils/objects";
14
-
15
- /**
16
- * The `expand_output` config changes needed to expand or clamp every output.
17
- *
18
- * Both actions skip cells without output, so their source isn't annotated
19
- * with a config that has no effect.
20
- */
21
- export function outputExpansionConfigs(
22
- notebook: NotebookState,
23
- expanded: boolean,
24
- ): Record<CellId, Partial<CellConfig>> {
25
- const configs: Record<CellId, Partial<CellConfig>> = {};
26
- for (const cellId of notebook.cellIds.inOrderIds) {
27
- const cell = notebook.cellData[cellId];
28
- if (
29
- cell === undefined ||
30
- (cell.config.expand_output ?? false) === expanded
31
- ) {
32
- continue;
33
- }
34
- if (isOutputEmpty(notebook.cellRuntime[cellId]?.output)) {
35
- continue;
36
- }
37
- configs[cellId] = { expand_output: expanded };
38
- }
39
- return configs;
40
- }
41
-
42
- /**
43
- * Hook returning a callback that shows every cell's output in full, or clamps
44
- * every output to a fixed height, by setting each cell's `expand_output` config.
45
- */
46
- export const useSetOutputsExpanded = () => {
47
- const { updateCellConfig } = useCellActions();
48
- const { saveCellConfig } = useRequestClient();
49
-
50
- return useCallback(
51
- async (expanded: boolean) => {
52
- const newConfigs = outputExpansionConfigs(getNotebook(), expanded);
53
-
54
- const entries = Objects.entries(newConfigs);
55
- if (entries.length === 0) {
56
- return;
57
- }
58
-
59
- await saveCellConfig({ configs: newConfigs });
60
-
61
- for (const [cellId, config] of entries) {
62
- updateCellConfig({ cellId, config });
63
- }
64
- },
65
- [updateCellConfig, saveCellConfig],
66
- );
67
- };