@marimo-team/frontend 0.25.3-dev129 → 0.25.3-dev134

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 (166) hide show
  1. package/dist/assets/{CellStatus-6xDEj3Hs.js → CellStatus-DC6FFQOg.js} +1 -1
  2. package/dist/assets/{ConnectedDataExplorerComponent-DCcLAktu.js → ConnectedDataExplorerComponent-BV1mVpaE.js} +1 -1
  3. package/dist/assets/{ErrorBoundary-98Xo04DS.js → ErrorBoundary-Ce-Ujlwj.js} +2 -2
  4. package/dist/assets/{JsonOutput-V47aiTIK.js → JsonOutput-CfEBzaqW.js} +4 -4
  5. package/dist/assets/{MarimoErrorOutput-DeWZNBgL.js → MarimoErrorOutput-Bh6o9zle.js} +1 -1
  6. package/dist/assets/{RenderHTML-Bjvcs70-.js → RenderHTML-COGZsXQV.js} +1 -1
  7. package/dist/assets/{RunButton-CnvvXD9d.js → RunButton-DQ51plUv.js} +1 -1
  8. package/dist/assets/{add-cell-with-ai-BbuqzITi.js → add-cell-with-ai-D7gtGUsg.js} +1 -1
  9. package/dist/assets/{add-connection-dialog-DIC7owvZ.js → add-connection-dialog-CpMCc97S.js} +1 -1
  10. package/dist/assets/{agent-panel-D8hO2P1x.js → agent-panel-BSFYqJ9B.js} +2 -2
  11. package/dist/assets/{ai-model-dropdown-DgmiG_5j.js → ai-model-dropdown-D575Vid8.js} +3 -3
  12. package/dist/assets/{app-config-button-UZHv1Iim.js → app-config-button-Cfcg_5Bz.js} +1 -1
  13. package/dist/assets/{blob-BPknzzkY.js → blob-CszMu60N.js} +1 -1
  14. package/dist/assets/{cell-editor-CM-K1_wq.js → cell-editor-BLpOlLnM.js} +2 -2
  15. package/dist/assets/cell-link-Cj0gGaMV.js +1 -0
  16. package/dist/assets/{cells-BypTg035.js → cells-SvbLY10y.js} +1 -1
  17. package/dist/assets/{chat-display-BRLNOoTF.js → chat-display-D43_g3TX.js} +1 -1
  18. package/dist/assets/{chat-panel-D02Rk9we.js → chat-panel-B_HAJMwx.js} +1 -1
  19. package/dist/assets/{chat-ui-DFN_RwxF.js → chat-ui-BEcYCphu.js} +2 -2
  20. package/dist/assets/{column-preview-85ORMhfB.js → column-preview-CrzaJKk8.js} +1 -1
  21. package/dist/assets/{command-palette-CtyjjdsA.js → command-palette-Bm9yIVcD.js} +1 -1
  22. package/dist/assets/{common-J265II7i.js → common-BJyUxCzv.js} +1 -1
  23. package/dist/assets/{components-Bd3Dpi92.js → components-D1f_Cz4i.js} +1 -1
  24. package/dist/assets/{datasource-Dy4rzzSP.js → datasource-C8KSVfSD.js} +1 -1
  25. package/dist/assets/{dependency-graph-panel-ByGFFT4E.js → dependency-graph-panel-BhmyJbUl.js} +1 -1
  26. package/dist/assets/{documentation-panel-LxuJCY3M.js → documentation-panel-DcVG0Q0d.js} +1 -1
  27. package/dist/assets/{download-BsBJWH_j.js → download-Bx52VRE4.js} +1 -1
  28. package/dist/assets/{edit-page--d6X-OO9.js → edit-page-DUrwOHR-.js} +6 -6
  29. package/dist/assets/{error-entries-0wTSSuK9.js → error-entries-11OuHzUF.js} +1 -1
  30. package/dist/assets/{error-panel-ZNdbE3Fo.js → error-panel-XJy5S25F.js} +1 -1
  31. package/dist/assets/{feedback-button-C6asPmsh.js → feedback-button-B7jh_B4w.js} +1 -1
  32. package/dist/assets/feedback-button-C-eKtxXE.js +1 -0
  33. package/dist/assets/{file-explorer-panel-0fUP_ptL.js → file-explorer-panel-CnVxbF4A.js} +1 -1
  34. package/dist/assets/{file-name-input-B8lzI5iS.js → file-name-input-BJuqjQqH.js} +2 -2
  35. package/dist/assets/floating-outline-8yyZ-MOJ.js +1 -0
  36. package/dist/assets/{gallery-page-ClR8U-km.js → gallery-page-DJvGHePf.js} +1 -1
  37. package/dist/assets/{glide-data-editor-B6QQBQwS.js → glide-data-editor-Cyc8DHZx.js} +1 -1
  38. package/dist/assets/{home-page-CJnqDcT9.js → home-page-tRZJmSU6.js} +1 -1
  39. package/dist/assets/{hooks-CCek4i9f.js → hooks-CxGwybGw.js} +1 -1
  40. package/dist/assets/index-CoxbqhGH.js +30 -0
  41. package/dist/assets/index-u08m0hQE.css +2 -0
  42. package/dist/assets/{layout-66Urh4Zg.js → layout-DvXJxBiL.js} +5 -5
  43. package/dist/assets/{logs-panel-DFhkIcge.js → logs-panel-KtsY7TrR.js} +1 -1
  44. package/dist/assets/{markdown-renderer-mYYQYD2m.js → markdown-renderer-DUgV7_fm.js} +1 -1
  45. package/dist/assets/{name-cell-input-Crcu3i2z.js → name-cell-input-C3-Cj-Ek.js} +1 -1
  46. package/dist/assets/{outline-panel-BFIPK0H_.js → outline-panel-BzyY4JA6.js} +1 -1
  47. package/dist/assets/{packages-panel-B4KtjgkF.js → packages-panel-DxosbWko.js} +1 -1
  48. package/dist/assets/{panel-accordion-state-D6KtwSF8.js → panel-accordion-state-BRbTib2B.js} +1 -1
  49. package/dist/assets/panels-Da3071Q4.js +1 -0
  50. package/dist/assets/{process-output-DDvMd6Jh.js → process-output-CSwx7rvo.js} +1 -1
  51. package/dist/assets/{readonly-code-display-VDqYn2d0.js → readonly-code-display-B9y9423Y.js} +1 -1
  52. package/dist/assets/{readonly-python-code-CZUKLXJ4.js → readonly-python-code-Dgw6trlk.js} +1 -1
  53. package/dist/assets/{reveal-component-BMmDU1uN.js → reveal-component-B9A4wkG-.js} +1 -1
  54. package/dist/assets/{run-page-BmOPPh2Y.js → run-page-C1MQ5b_A.js} +1 -1
  55. package/dist/assets/{runtime-details-state-CipqynUD.js → runtime-details-state-D_hOQL9T.js} +1 -1
  56. package/dist/assets/scratchpad-panel-CBCsPmMW.js +1 -0
  57. package/dist/assets/secrets-panel-ConQpchl.js +1 -0
  58. package/dist/assets/session-panel-CiHCKPlx.js +1 -0
  59. package/dist/assets/snippets-panel-C0VDE_4i.js +1 -0
  60. package/dist/assets/{state-QfGh3m2G.js → state-DrraMmqz.js} +1 -1
  61. package/dist/assets/{state-BLGvzMB6.js → state-DvU2AiFx.js} +22 -22
  62. package/dist/assets/tracing-C5d51Nmi.js +1 -0
  63. package/dist/assets/{tracing-panel-CsHuzRGP.js → tracing-panel-B89R8dWE.js} +2 -2
  64. package/dist/assets/{tree-actions-BQw_utcj.js → tree-actions-Cph8FVzh.js} +1 -1
  65. package/dist/assets/{useAddCell-_b8InOZC.js → useAddCell-VPkB72pn.js} +1 -1
  66. package/dist/assets/{useCellActionButton-BbgMzBdk.js → useCellActionButton--zI3GFnt.js} +1 -1
  67. package/dist/assets/{useDeleteCell-DhoFbEkU.js → useDeleteCell-CjewKeSr.js} +1 -1
  68. package/dist/assets/{useDependencyPanelTab-COTULhoH.js → useDependencyPanelTab-Bt_ka-wl.js} +1 -1
  69. package/dist/assets/{useNotebookActions-xnA_l3nY.js → useNotebookActions-DV2S6KaG.js} +1 -1
  70. package/dist/assets/{useRunCells-VBCe6CLn.js → useRunCells-BupCZpzk.js} +1 -1
  71. package/dist/assets/{useSplitCell-AvSpVAmq.js → useSplitCell-CaLIR0TS.js} +1 -1
  72. package/dist/index.html +21 -21
  73. package/package.json +1 -1
  74. package/src/__tests__/module-entry.test.ts +32 -0
  75. package/src/components/ai/__tests__/ai-model-dropdown.test.tsx +63 -0
  76. package/src/components/ai/ai-model-dropdown.tsx +11 -6
  77. package/src/components/chat/acp/__tests__/session-tabs.test.tsx +43 -0
  78. package/src/components/chat/acp/blocks.tsx +1 -0
  79. package/src/components/chat/acp/session-tabs.tsx +8 -3
  80. package/src/components/data-table/TableTopBar.tsx +2 -0
  81. package/src/components/data-table/__tests__/data-table.test.tsx +1 -0
  82. package/src/components/data-table/__tests__/keyboard-selection.test.tsx +188 -0
  83. package/src/components/data-table/data-table.tsx +6 -0
  84. package/src/components/data-table/range-focus/atoms.ts +4 -6
  85. package/src/components/data-table/range-focus/use-cell-range-selection.ts +65 -38
  86. package/src/components/data-table/range-focus/use-scroll-into-view.ts +21 -2
  87. package/src/components/data-table/renderers.tsx +16 -7
  88. package/src/components/data-table/row-viewer-panel/__tests__/row-viewer.test.tsx +24 -1
  89. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +2 -2
  90. package/src/components/datasources/datasources.tsx +1 -0
  91. package/src/components/editor/__tests__/package-alert.test.tsx +22 -1
  92. package/src/components/editor/cell/collapse.tsx +5 -3
  93. package/src/components/editor/chrome/panels/outline/__tests__/outline-keyboard.test.tsx +84 -0
  94. package/src/components/editor/chrome/panels/outline/floating-outline.tsx +39 -14
  95. package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +3 -2
  96. package/src/components/editor/chrome/panels/secrets-panel.tsx +1 -0
  97. package/src/components/editor/chrome/panels/snippets-panel.tsx +5 -1
  98. package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +4 -4
  99. package/src/components/editor/controls/__tests__/keyboard-shortcuts.test.tsx +61 -0
  100. package/src/components/editor/controls/keyboard-shortcuts.tsx +14 -5
  101. package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +4 -4
  102. package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +47 -0
  103. package/src/components/editor/file-tree/file-explorer.tsx +35 -3
  104. package/src/components/editor/file-tree/file-name-input.tsx +1 -0
  105. package/src/components/editor/header/status.tsx +28 -5
  106. package/src/components/editor/links/__tests__/cell-link.test.tsx +146 -0
  107. package/src/components/editor/links/cell-link.tsx +14 -5
  108. package/src/components/editor/navigation/focus-utils.ts +4 -4
  109. package/src/components/editor/notebook-cell.tsx +11 -2
  110. package/src/components/editor/output/MarimoTracebackOutput.tsx +17 -15
  111. package/src/components/editor/output/__tests__/traceback.test.tsx +27 -1
  112. package/src/components/editor/package-alert.tsx +8 -3
  113. package/src/components/scratchpad/scratchpad.test.tsx +95 -0
  114. package/src/components/scratchpad/scratchpad.tsx +14 -1
  115. package/src/components/tracing/tracing-keyboard.test.tsx +85 -0
  116. package/src/components/tracing/tracing.tsx +43 -39
  117. package/src/components/ui/__tests__/draggable-popover.test.tsx +24 -0
  118. package/src/components/ui/draggable-popover.tsx +24 -2
  119. package/src/core/attachments/state.ts +2 -2
  120. package/src/core/document/__tests__/codemirror.test.ts +3 -1
  121. package/src/core/document/__tests__/hooks.test.tsx +7 -7
  122. package/src/core/document/__tests__/model.test.ts +44 -11
  123. package/src/core/document/__tests__/scenario-fixture.ts +2 -1
  124. package/src/core/document/__tests__/test-notebook.ts +19 -9
  125. package/src/core/document/draft.ts +1 -1
  126. package/src/core/document/index.ts +3 -10
  127. package/src/core/document/model.ts +14 -11
  128. package/src/core/document/state.ts +1 -1
  129. package/src/core/document/sync.ts +24 -18
  130. package/src/core/host/AGENTS.md +3 -7
  131. package/src/core/host/__tests__/fixtures.ts +30 -0
  132. package/src/core/host/__tests__/{notebook-client.test.ts → replica.test.ts} +42 -74
  133. package/src/core/host/__tests__/wasm.test.ts +8 -0
  134. package/src/core/host/backend.ts +4 -0
  135. package/src/core/host/index.ts +14 -0
  136. package/src/core/host/{notebook-client.ts → replica.ts} +75 -86
  137. package/src/core/host/static.ts +2 -0
  138. package/src/core/host/wasm.ts +10 -1
  139. package/src/core/wasm/bridge.ts +1 -1
  140. package/src/core/websocket/__tests__/backend.test.ts +111 -22
  141. package/src/core/websocket/__tests__/useNotebookReplica.hook.test.tsx +141 -0
  142. package/src/core/websocket/__tests__/useNotebookSession.hook.test.tsx +4 -4
  143. package/src/core/websocket/backend.ts +43 -5
  144. package/src/core/websocket/connection-state.ts +1 -1
  145. package/src/core/websocket/state.ts +3 -3
  146. package/src/core/websocket/transports/__tests__/notebook.test.ts +11 -21
  147. package/src/core/websocket/types.ts +2 -2
  148. package/src/core/websocket/useNotebookReplica.ts +69 -0
  149. package/src/core/websocket/useNotebookSession.tsx +6 -6
  150. package/src/plugins/impl/chat/chat-ui.tsx +2 -1
  151. package/src/plugins/impl/data-explorer/components/column-summary.tsx +4 -2
  152. package/src/plugins/impl/data-frames/__tests__/sidebar.test.tsx +160 -0
  153. package/src/plugins/impl/data-frames/panel.tsx +43 -16
  154. package/dist/assets/cell-link-CAjuFcLK.js +0 -1
  155. package/dist/assets/feedback-button-Bt89tGG2.js +0 -1
  156. package/dist/assets/floating-outline-CRpmOv32.js +0 -1
  157. package/dist/assets/index-B5pWkt7a.js +0 -30
  158. package/dist/assets/index-BnhSnwvB.css +0 -2
  159. package/dist/assets/panels-DiwGKPzK.js +0 -1
  160. package/dist/assets/scratchpad-panel-Drr_kuwb.js +0 -1
  161. package/dist/assets/secrets-panel-D-W1PL76.js +0 -1
  162. package/dist/assets/session-panel-W7JOcog_.js +0 -1
  163. package/dist/assets/snippets-panel-cUPEdm66.js +0 -1
  164. package/dist/assets/tracing-BNFynaTu.js +0 -1
  165. package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +0 -228
  166. package/src/core/websocket/useNotebookClient.ts +0 -89
@@ -0,0 +1,160 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { act, fireEvent, render, screen } from "@testing-library/react";
4
+ import { useState } from "react";
5
+ import { expect, it, vi } from "vitest";
6
+ import { TooltipProvider } from "@/components/ui/tooltip";
7
+ import { Sidebar, TransformPanel } from "../panel";
8
+ import { type TransformType, TransformTypeSchema } from "../schema";
9
+
10
+ const transform: TransformType = { type: "select_columns", column_ids: [] };
11
+
12
+ it("selects and deletes transforms through independent buttons", () => {
13
+ const onSelect = vi.fn();
14
+ const onDelete = vi.fn();
15
+ render(
16
+ <Sidebar
17
+ items={[{ id: "first", transform }]}
18
+ selected={0}
19
+ onSelect={onSelect}
20
+ onDelete={onDelete}
21
+ onAdd={vi.fn()}
22
+ />,
23
+ );
24
+ const select = screen.getByRole("button", { name: "Select Columns" });
25
+ expect(select).toHaveAttribute("aria-pressed", "true");
26
+ fireEvent.click(select);
27
+ expect(onSelect).toHaveBeenCalledExactlyOnceWith(0);
28
+ const remove = screen.getByRole("button", {
29
+ name: "Delete Select Columns transform 1",
30
+ });
31
+ remove.focus();
32
+ expect(remove).toHaveFocus();
33
+ fireEvent.click(remove);
34
+ expect(onDelete).toHaveBeenCalledExactlyOnceWith(0);
35
+ expect(onSelect).toHaveBeenCalledOnce();
36
+ });
37
+
38
+ it("preserves focused rows across value edits and removal of earlier duplicates", () => {
39
+ const first = { id: "first", transform };
40
+ const second = { id: "second", transform };
41
+ const props = {
42
+ selected: 1,
43
+ onSelect: vi.fn(),
44
+ onDelete: vi.fn(),
45
+ onAdd: vi.fn(),
46
+ };
47
+ const { rerender } = render(<Sidebar {...props} items={[first, second]} />);
48
+ const focused = screen.getAllByRole("button", { name: "Select Columns" })[1];
49
+ act(() => focused.focus());
50
+ const edited = {
51
+ ...second,
52
+ transform: TransformTypeSchema.parse({
53
+ ...transform,
54
+ column_ids: ["name"],
55
+ }),
56
+ };
57
+ rerender(<Sidebar {...props} items={[first, edited]} />);
58
+ expect(screen.getAllByRole("button", { name: "Select Columns" })[1]).toBe(
59
+ focused,
60
+ );
61
+ expect(focused).toHaveFocus();
62
+
63
+ rerender(<Sidebar {...props} items={[edited]} selected={0} />);
64
+ expect(screen.getByRole("button", { name: "Select Columns" })).toBe(focused);
65
+ expect(focused).toHaveFocus();
66
+ fireEvent.click(focused);
67
+ expect(props.onSelect).toHaveBeenLastCalledWith(0);
68
+ });
69
+
70
+ it.each([
71
+ { count: 3, removed: 0, destination: 1 },
72
+ { count: 3, removed: 1, destination: 0 },
73
+ { count: 3, removed: 2, destination: 1 },
74
+ { count: 1, removed: 0, destination: undefined },
75
+ ])(
76
+ "moves focus after deleting row $removed of $count",
77
+ ({ count, removed, destination }) => {
78
+ function Example() {
79
+ const [items, setItems] = useState(
80
+ Array.from({ length: count }, (_, index) => ({
81
+ id: `transform-${index}`,
82
+ transform,
83
+ })),
84
+ );
85
+ return (
86
+ <Sidebar
87
+ items={items}
88
+ selected={undefined}
89
+ onSelect={vi.fn()}
90
+ onDelete={(index) =>
91
+ setItems((current) => current.filter((_, i) => i !== index))
92
+ }
93
+ onAdd={vi.fn()}
94
+ />
95
+ );
96
+ }
97
+ render(<Example />);
98
+ const selectButtons = screen.getAllByRole("button", {
99
+ name: "Select Columns",
100
+ });
101
+ const target =
102
+ destination === undefined
103
+ ? screen.getByRole("button", { name: "Add" })
104
+ : selectButtons[destination];
105
+ const remove = screen.getByRole("button", {
106
+ name: `Delete Select Columns transform ${removed + 1}`,
107
+ });
108
+ act(() => remove.focus());
109
+ fireEvent.click(remove, { detail: 0 });
110
+ expect(remove).not.toBeInTheDocument();
111
+ expect(target).toHaveFocus();
112
+ },
113
+ );
114
+
115
+ it("uses persistent field-array IDs in the transformation panel", () => {
116
+ render(
117
+ <TooltipProvider>
118
+ <TransformPanel
119
+ initialValue={{ transforms: [transform, transform] }}
120
+ columns={new Map()}
121
+ lazy={true}
122
+ onChange={vi.fn()}
123
+ onInvalidChange={vi.fn()}
124
+ getColumnValues={async () => ({ values: [], too_many_values: false })}
125
+ />
126
+ </TooltipProvider>,
127
+ );
128
+ const survivor = screen.getAllByRole("button", { name: "Select Columns" })[1];
129
+ const remove = screen.getByRole("button", {
130
+ name: "Delete Select Columns transform 1",
131
+ });
132
+ act(() => remove.focus());
133
+ fireEvent.click(remove, { detail: 0 });
134
+ expect(screen.getByRole("button", { name: "Select Columns" })).toBe(survivor);
135
+ expect(survivor).toHaveFocus();
136
+ expect(survivor).toHaveAttribute("aria-pressed", "true");
137
+ });
138
+
139
+ it("does not move focus when deletion starts outside the focused row", () => {
140
+ render(
141
+ <>
142
+ <input aria-label="Transform setting" />
143
+ <Sidebar
144
+ items={[{ id: "first", transform }]}
145
+ selected={0}
146
+ onSelect={vi.fn()}
147
+ onDelete={vi.fn()}
148
+ onAdd={vi.fn()}
149
+ />
150
+ </>,
151
+ );
152
+ const input = screen.getByRole("textbox", { name: "Transform setting" });
153
+ act(() => input.focus());
154
+ fireEvent.click(
155
+ screen.getByRole("button", {
156
+ name: "Delete Select Columns transform 1",
157
+ }),
158
+ );
159
+ expect(input).toHaveFocus();
160
+ });
@@ -25,6 +25,7 @@ import React, {
25
25
  useEffect,
26
26
  useImperativeHandle,
27
27
  useMemo,
28
+ useRef,
28
29
  } from "react";
29
30
  import { useFieldArray, useForm } from "react-hook-form";
30
31
  import useEvent from "react-use-event-hook";
@@ -187,7 +188,10 @@ export const TransformPanel: React.FC<Props> = ({
187
188
  className="relative flex flex-row max-h-[400px] overflow-hidden bg-background"
188
189
  >
189
190
  <Sidebar
190
- items={form.watch("transforms")}
191
+ items={transformsField.fields.map((field, index) => ({
192
+ id: field.id,
193
+ transform: transforms[index],
194
+ }))}
191
195
  selected={selectedTransform}
192
196
  onSelect={(index) => {
193
197
  setSelectedTransform(index);
@@ -274,7 +278,7 @@ export const TransformPanel: React.FC<Props> = ({
274
278
  };
275
279
 
276
280
  interface SidebarProps {
277
- items: TransformType[];
281
+ items: { id: string; transform: TransformType }[];
278
282
  selected: number | undefined;
279
283
  onSelect: (index: number) => void;
280
284
  onDelete: (index: number) => void;
@@ -288,34 +292,56 @@ export const Sidebar: React.FC<SidebarProps> = ({
288
292
  onSelect,
289
293
  onDelete,
290
294
  }) => {
295
+ const selectionButtons = useRef(new Map<string, HTMLButtonElement>());
296
+ const addButton = useRef<HTMLButtonElement>(null);
297
+
291
298
  return (
292
299
  <div className="flex flex-col overflow-y-hidden w-[180px] shadow-xs h-full">
293
300
  <div className="flex flex-col overflow-y-auto grow">
294
- {items.map((item, idx) => {
301
+ {items.map(({ id, transform }, idx) => {
295
302
  return (
296
303
  <div
297
- key={`${JSON.stringify(item)}-${idx}`}
298
- onClick={() => {
299
- onSelect(idx);
300
- }}
304
+ key={id}
301
305
  className={cn(
302
- "flex flex-row min-h-[40px] items-center px-2 cursor-pointer hover:bg-accent/50 text-sm overflow-hidden hover-actions-parent border border-muted border-l-2 border-l-transparent",
306
+ "group flex flex-row min-h-[40px] items-center px-2 cursor-pointer hover:bg-accent/50 text-sm overflow-hidden border border-muted border-l-2 border-l-transparent",
303
307
  {
304
308
  "border-l-primary bg-accent text-accent-foreground":
305
309
  selected === idx,
306
310
  },
307
311
  )}
308
312
  >
309
- <div className="grow text-ellipsis">
310
- {Strings.startCase(item.type)}
311
- </div>
312
- <Trash2Icon
313
- className="w-3 h-3 hover-action text-muted-foreground hover:text-destructive"
314
- onClick={(e) => {
313
+ <button
314
+ ref={(button) => {
315
+ if (button) {
316
+ selectionButtons.current.set(id, button);
317
+ } else {
318
+ selectionButtons.current.delete(id);
319
+ }
320
+ }}
321
+ type="button"
322
+ className="grow text-left text-ellipsis py-2 focus-visible:outline focus-visible:outline-ring"
323
+ aria-pressed={selected === idx}
324
+ onClick={() => onSelect(idx)}
325
+ >
326
+ {Strings.startCase(transform.type)}
327
+ </button>
328
+ <button
329
+ type="button"
330
+ aria-label={`Delete ${Strings.startCase(transform.type)} transform ${idx + 1}`}
331
+ className="opacity-0 group-hover:opacity-100 focus-visible:opacity-100 text-muted-foreground hover:text-destructive focus-visible:outline focus-visible:outline-ring"
332
+ onClick={(event) => {
333
+ if (event.currentTarget.matches(":focus")) {
334
+ const neighbor = items[idx - 1] ?? items[idx + 1];
335
+ const target = neighbor
336
+ ? selectionButtons.current.get(neighbor.id)
337
+ : addButton.current;
338
+ target?.focus();
339
+ }
315
340
  onDelete(idx);
316
- e.stopPropagation();
317
341
  }}
318
- />
342
+ >
343
+ <Trash2Icon className="w-3 h-3" />
344
+ </button>
319
345
  </div>
320
346
  );
321
347
  })}
@@ -323,6 +349,7 @@ export const Sidebar: React.FC<SidebarProps> = ({
323
349
  <div className="flex flex-row shrink-0">
324
350
  <AddTransformDropdown onAdd={onAdd}>
325
351
  <Button
352
+ ref={addButton}
326
353
  data-testid="marimo-plugin-data-frames-add-transform"
327
354
  variant="text"
328
355
  className="w-full rounded-none m-0 hover:text-accent-foreground"
@@ -1 +0,0 @@
1
- import{c as e,l as t,t as n,u as r}from"./useEvent-BDjgaBtz.js";import{D as i,In as a,M as o,P as s,gr as c,xo as l,za as u}from"./cells-BypTg035.js";import{t as d}from"./compiler-runtime-BrajqUja.js";import{p as f}from"./config-CXnC3MRv.js";import{g as p}from"./useEventListener-DPOTkksd.js";import{i as m}from"./utils-B4K466FK.js";import{c as h}from"./session-BHgGkjDm.js";import{T as g,_}from"./config-7IjqNuVp.js";import{t as v}from"./cn-ldLVeaqm.js";import{t as y}from"./jsx-runtime-B74pBk57.js";import{n as b}from"./paths-bkIFVj8h.js";import{b as x}from"./write-secret-modal-CBi2vNK_.js";import{r as S}from"./requests-BIFR-h4M.js";var C=d();function w(){return t(u)}function T(){let t=(0,C.c)(5),[i]=e(_),a=r(u),{openAlert:o}=x(),{sendRename:s}=S(),c;return t[0]!==i.state||t[1]!==o||t[2]!==s||t[3]!==a?(c=async e=>{let t=f();return i.state===g.OPEN?(h(t=>{e===null?t.delete(m.filePath):t.set(m.filePath,e)}),s({filename:e}).then(()=>(a(e),document.title=t.app_title||b.basename(e)||`Untitled Notebook`,e)).catch(e=>(o(e.message),null))):(o(`Failed to save notebook: not connected to a kernel.`),null)},t[0]=i.state,t[1]=o,t[2]=s,t[3]=a,t[4]=c):c=t[4],n(c)}var E=y(),D=e=>{let t=(0,C.c)(12),{className:n,cellId:r,variant:c,onClick:l,formatCellName:u,skipScroll:d}=e,f=s()[r]??``,p=o().inOrderIds.indexOf(r),{showCellIfHidden:m}=i(),h=u??j,g;t[0]===n?g=t[1]:(g=v(`inline-block cursor-pointer text-link hover:underline`,n),t[0]=n,t[1]=g);let _;t[2]!==r||t[3]!==l||t[4]!==m||t[5]!==d||t[6]!==c?(_=e=>{if(r===`__scratch__`)return!1;m({cellId:r}),e.stopPropagation(),e.preventDefault(),requestAnimationFrame(()=>{A(r,c,d)&&l?.()})},t[2]=r,t[3]=l,t[4]=m,t[5]=d,t[6]=c,t[7]=_):_=t[7];let y=h(a(f,p)),b;return t[8]!==g||t[9]!==_||t[10]!==y?(b=(0,E.jsx)(`div`,{className:g,role:`link`,tabIndex:-1,onClick:_,children:y}),t[8]=g,t[9]=_,t[10]=y,t[11]=b):b=t[11],b},O=e=>{let t=(0,C.c)(2),n;return t[0]===e?n=t[1]:(n=(0,E.jsx)(D,{...e,variant:`destructive`}),t[0]=e,t[1]=n),n},k=e=>{let t=(0,C.c)(10),{cellId:n,lineNumber:r}=e,i=w(),a;t[0]!==n||t[1]!==r?(a=()=>c(n,r),t[0]=n,t[1]=r,t[2]=a):a=t[2];let o;t[3]!==n||t[4]!==i?(o=e=>n===`__scratch__`?`scratch`:`marimo://${i||`untitled`}#cell=${e}`,t[3]=n,t[4]=i,t[5]=o):o=t[5];let s;return t[6]!==n||t[7]!==a||t[8]!==o?(s=(0,E.jsx)(D,{cellId:n,onClick:a,skipScroll:!0,variant:`destructive`,className:`traceback-cell-link`,formatCellName:o}),t[6]=n,t[7]=a,t[8]=o,t[9]=s):s=t[9],s};function A(e,t,n){let r=l.create(e),i=document.getElementById(r),a=i?.classList.contains(`has-error`);return i===null?(p.error(`Cell ${r} not found on page.`),!1):(n||i.scrollIntoView({behavior:`smooth`,block:`center`}),(t===`destructive`||a&&t===void 0)&&(i.classList.add(`error-outline`),setTimeout(()=>{i.classList.remove(`error-outline`)},2e3)),(t===`focus`||!a&&t===void 0)&&(i.classList.add(`focus-outline`),setTimeout(()=>{i.classList.remove(`focus-outline`)},2e3)),!0)}function j(e){return e}export{w as a,A as i,O as n,T as o,k as r,D as t};
@@ -1 +0,0 @@
1
- import{n as e}from"./feedback-button-C6asPmsh.js";export{e as FeedbackModal};
@@ -1 +0,0 @@
1
- import{a as e}from"./rolldown-runtime-B0Z9INg1.js";import{l as t}from"./useEvent-BDjgaBtz.js";import{t as n}from"./react-DVplv7_D.js";import{S as r,ct as i}from"./cells-BypTg035.js";import{t as a}from"./compiler-runtime-BrajqUja.js";import{g as o}from"./useEventListener-DPOTkksd.js";import{d as s}from"./session-BHgGkjDm.js";import{t as c}from"./cn-ldLVeaqm.js";import{t as l}from"./jsx-runtime-B74pBk57.js";var u=a(),d=e(n(),1);function f(){return s()===`edit`?document.getElementById(`App`):void 0}function p(e){let t=(0,u.c)(7),[n,r]=(0,d.useState)(void 0),[a,o]=(0,d.useState)(void 0),s=(0,d.useRef)(null),c=(0,d.useRef)(null),l;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(l=new Map,t[0]=l):l=t[0];let p=(0,d.useRef)(l),h,g;t[1]===e?(h=t[2],g=t[3]):(h=()=>e.length===0?void 0:(s.current=new IntersectionObserver(e=>{let t=!1;if(e.forEach(e=>{let n=e.target;e.isIntersecting?(!c.current||n.getBoundingClientRect().top<c.current.getBoundingClientRect().top)&&(c.current=n,t=!0):n===c.current&&(c.current=null,t=!0)}),t&&c.current){let e=i(c.current),t=`id`in e?e.id:e.path;r(t),o(p.current.get(c.current))}},{root:f(),rootMargin:`0px`,threshold:0}),e.forEach(t=>{if(t){let n=i(t[0]),r=e.map(m).filter(e=>`id`in n?e.id===n.id:e.textContent===t[0].textContent).indexOf(t[0]);p.current.set(t[0],r),s.current?.observe(t[0])}}),()=>{s.current&&s.current.disconnect(),c.current=null}),g=[e],t[1]=e,t[2]=h,t[3]=g),(0,d.useEffect)(h,g);let _;return t[4]!==n||t[5]!==a?(_={activeHeaderId:n,activeOccurrences:a},t[4]=n,t[5]=a,t[6]=_):_=t[6],_}function m(e){let[t]=e;return t}function h(e){if(e.length===0)return[];let t=new Map;return e.map(e=>{let n=`id`in e.by?e.by.id:e.by.path,r=t.get(n)??0;t.set(n,r+1);let i=_(e,r);return i?[i,n]:null}).filter(Boolean)}function g(e,t){let n=_(e,t);if(!n){o.warn(`Could not find element for outline item`,e);return}n.scrollIntoView({behavior:`smooth`,block:`start`}),n.classList.add(`outline-item-highlight`),setTimeout(()=>{n.classList.remove(`outline-item-highlight`)},3e3)}function _(e,t){return`id`in e.by?document.querySelectorAll(`[id="${CSS.escape(e.by.id)}"]`)[t]:document.evaluate(e.by.path,document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue}var v=l(),y=()=>{let e=(0,u.c)(19),{items:n}=t(r),i;e[0]===n?i=e[1]:(i=h(n),e[0]=n,e[1]=i);let{activeHeaderId:a,activeOccurrences:o}=p(i),[s,l]=d.useState(!1);if(n.length<2)return null;let f,m,g;e[2]===Symbol.for(`react.memo_cache_sentinel`)?(f=()=>l(!0),m=()=>l(!1),g=c(`fixed top-[25vh] right-8 z-10000 print:hidden`,`hidden md:block`),e[2]=f,e[3]=m,e[4]=g):(f=e[2],m=e[3],g=e[4]);let _=s?`left-[-280px] opacity-100`:`left-[300px] opacity-0`,y;e[5]===_?y=e[6]:(y=c(`-top-4 max-h-[70vh] bg-background rounded-lg shadow-lg absolute overflow-auto transition-all duration-300 w-[300px] border`,_),e[5]=_,e[6]=y);let S;e[7]!==a||e[8]!==o||e[9]!==n||e[10]!==y?(S=(0,v.jsx)(x,{className:y,items:n,activeHeaderId:a,activeOccurrences:o}),e[7]=a,e[8]=o,e[9]=n,e[10]=y,e[11]=S):S=e[11];let C;e[12]!==a||e[13]!==o||e[14]!==n?(C=(0,v.jsx)(b,{items:n,activeHeaderId:a,activeOccurrences:o}),e[12]=a,e[13]=o,e[14]=n,e[15]=C):C=e[15];let w;return e[16]!==S||e[17]!==C?(w=(0,v.jsxs)(`div`,{onMouseEnter:f,onMouseLeave:m,className:g,children:[S,C]}),e[16]=S,e[17]=C,e[18]=w):w=e[18],w},b=e=>{let t=(0,u.c)(8),{items:n,activeHeaderId:r,activeOccurrences:i}=e,a,o;if(t[0]!==r||t[1]!==i||t[2]!==n){let e=new Map;a=`flex flex-col gap-4 items-end max-h-[70vh] overflow-hidden`,o=n.map((t,n)=>{let a=`id`in t.by?t.by.id:t.by.path,o=e.get(a)??0;return e.set(a,o+1),(0,v.jsx)(`div`,{className:c(`h-[2px] bg-muted-foreground/60`,t.level===1&&`w-5`,t.level===2&&`w-4`,t.level===3&&`w-3`,t.level===4&&`w-2`,o===i&&r===a&&`bg-foreground`),onClick:()=>g(t,o)},`${a}-${n}`)}),t[0]=r,t[1]=i,t[2]=n,t[3]=a,t[4]=o}else a=t[3],o=t[4];let s;return t[5]!==a||t[6]!==o?(s=(0,v.jsx)(`div`,{className:a,children:o}),t[5]=a,t[6]=o,t[7]=s):s=t[7],s},x=e=>{let t=(0,u.c)(11),{items:n,activeHeaderId:r,activeOccurrences:i,className:a}=e,o,s;if(t[0]!==r||t[1]!==i||t[2]!==a||t[3]!==n){let e=new Map;t[6]===a?o=t[7]:(o=c(`flex flex-col overflow-auto py-4 pl-2`,a),t[6]=a,t[7]=o),s=n.map((t,n)=>{let a=`id`in t.by?t.by.id:t.by.path,o=e.get(a)??0;e.set(a,o+1);let s=`${a}-${n}`,l={className:c(`px-2 py-1 cursor-pointer hover:bg-accent/50 hover:text-accent-foreground rounded-l`,t.level===1&&`font-semibold`,t.level===2&&`ml-3`,t.level===3&&`ml-6`,t.level===4&&`ml-9`,o===i&&r===a&&`text-accent-foreground`),onClick:()=>g(t,o)};return t.html?(0,v.jsx)(`div`,{...l,dangerouslySetInnerHTML:{__html:t.html}},s):(0,v.jsx)(`div`,{...l,children:t.name},s)}),t[0]=r,t[1]=i,t[2]=a,t[3]=n,t[4]=o,t[5]=s}else o=t[4],s=t[5];let l;return t[8]!==o||t[9]!==s?(l=(0,v.jsx)(`div`,{className:o,children:s}),t[8]=o,t[9]=s,t[10]=l):l=t[10],l};export{p as i,x as n,h as r,y as t};