@marimo-team/islands 0.23.7-dev18 → 0.23.7-dev19
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.
- package/dist/{code-visibility-CG4-R_b9.js → code-visibility-DWei3hY2.js} +1 -1
- package/dist/main.js +2 -2
- package/dist/{reveal-component-CAlN98g0.js → reveal-component-DFFQKVN0.js} +1 -1
- package/package.json +1 -1
- package/src/components/editor/navigation/__tests__/clipboard.test.ts +0 -1
- package/src/components/editor/navigation/clipboard.ts +20 -24
- package/src/core/cells/__tests__/cells.test.ts +12 -12
- package/src/core/cells/__tests__/pending-cut-service.test.tsx +14 -36
- package/src/core/cells/pending-cut-service.ts +1 -10
- package/src/css/app/Cell.css +2 -5
|
@@ -25691,7 +25691,7 @@ ${_}`,
|
|
|
25691
25691
|
return Logger.warn("Failed to get version from mount config"), null;
|
|
25692
25692
|
}
|
|
25693
25693
|
}
|
|
25694
|
-
marimoVersionAtom = atom(getVersionFromMountConfig() || "0.23.7-
|
|
25694
|
+
marimoVersionAtom = atom(getVersionFromMountConfig() || "0.23.7-dev19");
|
|
25695
25695
|
showCodeInRunModeAtom = atom(true);
|
|
25696
25696
|
atom(null);
|
|
25697
25697
|
var import_compiler_runtime = require_compiler_runtime();
|
package/dist/main.js
CHANGED
|
@@ -26,7 +26,7 @@ import { $ as useCellActions, At as DeferredRequestRegistry, B as safeExtractSet
|
|
|
26
26
|
import { __tla as __tla_1 } from "./chunk-5FQGJX7Z-BOg95xG5.js";
|
|
27
27
|
import { o as useSize, s as Root$2, u as createLucideIcon } from "./dist-D3ZI9nhS.js";
|
|
28
28
|
import { A as SquareFunction, C as DEFAULT_COLOR_SCHEME, D as SCALE_TYPE_DESCRIPTIONS, E as EMPTY_VALUE$1, O as TIME_UNIT_DESCRIPTIONS, S as DEFAULT_AGGREGATION, T as DEFAULT_TIME_UNIT, _ as AGGREGATION_TYPE_DESCRIPTIONS, a as AGGREGATION_FNS$1, b as COLOR_SCHEMES, c as COLOR_BY_FIELDS, d as NONE_VALUE, f as SELECTABLE_DATA_TYPES, g as TIME_UNITS, h as STRING_AGGREGATION_FNS, i as convertDataTypeToSelectable, j as ChartColumn, k as escapeFieldName, l as COMBINED_TIME_UNITS, m as SORT_TYPES, n as createSpecWithoutData, o as BIN_AGGREGATION, p as SINGLE_TIME_UNITS, r as isFieldSet, s as CHART_TYPES, t as augmentSpecWithData, u as ChartType, v as AGGREGATION_TYPE_ICON, w as DEFAULT_MAX_BINS_FACET, x as COUNT_FIELD, y as CHART_TYPE_ICON } from "./spec-hVaaZsY5.js";
|
|
29
|
-
import { $ as filtersToFilterGroup, A as contextAwarePanelOwner, At as Funnel, B as TableCell, Bt as ChevronLeft, C as prettifyRowCount, Ct as useOverflowDetection, D as ContextAwarePanelItem, Dt as EmotionCacheProvider, E as ComboboxItem, Et as HtmlOutput, F as Toggle, Ft as Code, G as generateColumns, H as TableHeader, I as Fill, It as ChevronsUpDown, J as ColumnChartContext, K as inferFieldTypes, L as Provider$1, Lt as ChevronsRight, M as isCellAwareAtom, N as SlotNames, Nt as Ellipsis, O as PANEL_TYPES, Ot as TextWrap, P as slotsController, Pt as Download, Q as usePrevious$1, R as Table, Rt as ChevronsLeft, S as prettifyRowColumnCount, St as LazyVegaEmbed, T as Combobox, Tt as Kbd, U as TableRow, V as TableHead, Vt as ArrowDownWideNarrow, W as NAMELESS_COLUMN_PREFIX, X as DelayMount, Y as ColumnChartSpecModel, Z as useIntersectionObserver, _ as downloadBlob, _t as TabsList, at as TOO_MANY_ROWS, b as Progress, bt as ChartInfoState, c as Slide, ct as Command, d as JsonOutput, dt as CommandItem, et as getPageIndexForRow, f as OutputArea, ft as CommandList, g as ADD_PRINTING_CLASS, gt as TabsContent, h as InstallPackageButton, ht as Tabs, it as SELECT_COLUMN_ID, j as contextAwarePanelType, jt as EyeOff, k as contextAwarePanelOpen, kt as GripHorizontal, l as RadioGroup, lt as CommandEmpty, m as DataTable, mt as Maps, n as marimoVersionAtom, nt as loadTableData, o as SLIDE_TYPE_OPTIONS_BY_VALUE, ot as toFieldTypes, p as OutputRenderer, pt as CommandSeparator, q as renderCellValue, r as showCodeInRunModeAtom, rt as INDEX_COLUMN_NAME, st as getMimeValues, t as useNotebookCodeAvailable, tt as loadTableAndRawData, u as RadioGroupItem, ut as CommandInput, v as downloadByURL, vt as TabsTrigger, w as useInternalStateWithSync, wt as RenderTextWithLinks, x as Filenames, xt as ChartLoadingState, y as downloadHTMLAsImage, yt as ChartErrorState, z as TableBody, zt as ChevronsDownUp, __tla as __tla_2 } from "./code-visibility-
|
|
29
|
+
import { $ as filtersToFilterGroup, A as contextAwarePanelOwner, At as Funnel, B as TableCell, Bt as ChevronLeft, C as prettifyRowCount, Ct as useOverflowDetection, D as ContextAwarePanelItem, Dt as EmotionCacheProvider, E as ComboboxItem, Et as HtmlOutput, F as Toggle, Ft as Code, G as generateColumns, H as TableHeader, I as Fill, It as ChevronsUpDown, J as ColumnChartContext, K as inferFieldTypes, L as Provider$1, Lt as ChevronsRight, M as isCellAwareAtom, N as SlotNames, Nt as Ellipsis, O as PANEL_TYPES, Ot as TextWrap, P as slotsController, Pt as Download, Q as usePrevious$1, R as Table, Rt as ChevronsLeft, S as prettifyRowColumnCount, St as LazyVegaEmbed, T as Combobox, Tt as Kbd, U as TableRow, V as TableHead, Vt as ArrowDownWideNarrow, W as NAMELESS_COLUMN_PREFIX, X as DelayMount, Y as ColumnChartSpecModel, Z as useIntersectionObserver, _ as downloadBlob, _t as TabsList, at as TOO_MANY_ROWS, b as Progress, bt as ChartInfoState, c as Slide, ct as Command, d as JsonOutput, dt as CommandItem, et as getPageIndexForRow, f as OutputArea, ft as CommandList, g as ADD_PRINTING_CLASS, gt as TabsContent, h as InstallPackageButton, ht as Tabs, it as SELECT_COLUMN_ID, j as contextAwarePanelType, jt as EyeOff, k as contextAwarePanelOpen, kt as GripHorizontal, l as RadioGroup, lt as CommandEmpty, m as DataTable, mt as Maps, n as marimoVersionAtom, nt as loadTableData, o as SLIDE_TYPE_OPTIONS_BY_VALUE, ot as toFieldTypes, p as OutputRenderer, pt as CommandSeparator, q as renderCellValue, r as showCodeInRunModeAtom, rt as INDEX_COLUMN_NAME, st as getMimeValues, t as useNotebookCodeAvailable, tt as loadTableAndRawData, u as RadioGroupItem, ut as CommandInput, v as downloadByURL, vt as TabsTrigger, w as useInternalStateWithSync, wt as RenderTextWithLinks, x as Filenames, xt as ChartLoadingState, y as downloadHTMLAsImage, yt as ChartErrorState, z as TableBody, zt as ChevronsDownUp, __tla as __tla_2 } from "./code-visibility-DWei3hY2.js";
|
|
30
30
|
import { c as Calendar, i as createReducerAndAtoms, n as useOnUnmount, o as ToggleLeft, t as useOnMount } from "./useLifecycle-BF6-z62y.js";
|
|
31
31
|
import { n as $fb18d541ea1ad717$export$ad991b66133851cf, r as $5a387cc49350e6db$export$722debc0e56fea39, t as $896ba0a80a8f4d36$export$85fd5fdf27bacc79 } from "./useDateFormatter-B_9k85Ex.js";
|
|
32
32
|
import { t as Check } from "./check-BcUIXnUT.js";
|
|
@@ -44600,7 +44600,7 @@ ${c}
|
|
|
44600
44600
|
if (l && l !== "slide") return l;
|
|
44601
44601
|
if (c == null ? void 0 : c.has(e)) return "skip";
|
|
44602
44602
|
}
|
|
44603
|
-
var LazySlidesComponent = import_react.lazy(() => import("./reveal-component-
|
|
44603
|
+
var LazySlidesComponent = import_react.lazy(() => import("./reveal-component-DFFQKVN0.js"));
|
|
44604
44604
|
const SlidesLayoutPlugin = {
|
|
44605
44605
|
type: "slides",
|
|
44606
44606
|
name: "Slides",
|
|
@@ -8,7 +8,7 @@ import { t as require_react } from "./react-DA-nE2FX.js";
|
|
|
8
8
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
9
9
|
import "./html-to-image-q0T1ijn_.js";
|
|
10
10
|
import "./chunk-5FQGJX7Z-BOg95xG5.js";
|
|
11
|
-
import { Ft as Code, Mt as Expand, a as DEFAULT_SLIDE_TYPE, c as Slide, i as DEFAULT_DECK_TRANSITION, jt as EyeOff, s as SlideSidebar, t as useNotebookCodeAvailable } from "./code-visibility-
|
|
11
|
+
import { Ft as Code, Mt as Expand, a as DEFAULT_SLIDE_TYPE, c as Slide, i as DEFAULT_DECK_TRANSITION, jt as EyeOff, s as SlideSidebar, t as useNotebookCodeAvailable } from "./code-visibility-DWei3hY2.js";
|
|
12
12
|
import "./input-Cc1Vvw9A.js";
|
|
13
13
|
import "./toDate-CJWlVNGD.js";
|
|
14
14
|
import "./react-dom-BWRJ_g_k.js";
|
package/package.json
CHANGED
|
@@ -42,9 +42,19 @@ const ClipboardCellDataSchema = z.object({
|
|
|
42
42
|
version: z.literal("1.0"),
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
interface ClipboardCellInput {
|
|
46
|
+
code: string;
|
|
47
|
+
name?: string;
|
|
48
|
+
config?: CellConfig;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function toPlainText(cells: ClipboardCellInput[]): string {
|
|
52
|
+
return cells.map((cell) => cell.code).join("\n\n");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function writeCellsToClipboard(
|
|
56
|
+
cells: ClipboardCellInput[],
|
|
57
|
+
): Promise<void> {
|
|
48
58
|
const clipboardData: ClipboardCellData = {
|
|
49
59
|
cells: cells.map((cell) => ({
|
|
50
60
|
code: cell.code,
|
|
@@ -53,17 +63,9 @@ function buildClipboardPayload(
|
|
|
53
63
|
})),
|
|
54
64
|
version: "1.0",
|
|
55
65
|
};
|
|
56
|
-
const plainText = cells.map((cell) => cell.code).join("\n\n");
|
|
57
|
-
return { clipboardData, plainText };
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async function writeCellsToClipboard(
|
|
61
|
-
clipboardData: ClipboardCellData,
|
|
62
|
-
plainText: string,
|
|
63
|
-
): Promise<void> {
|
|
64
66
|
const clipboardItem = new ClipboardItemBuilder()
|
|
65
67
|
.add(MARIMO_CELL_MIMETYPE, clipboardData)
|
|
66
|
-
.add("text/plain",
|
|
68
|
+
.add("text/plain", toPlainText(cells))
|
|
67
69
|
.build();
|
|
68
70
|
await navigator.clipboard.write([clipboardItem]);
|
|
69
71
|
}
|
|
@@ -80,14 +82,11 @@ export function useCellClipboard() {
|
|
|
80
82
|
.filter(Boolean);
|
|
81
83
|
|
|
82
84
|
if (cells.length === 0) {
|
|
83
|
-
// No cells to copy
|
|
84
85
|
return;
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
const { clipboardData, plainText } = buildClipboardPayload(cells);
|
|
88
|
-
|
|
89
88
|
try {
|
|
90
|
-
await writeCellsToClipboard(
|
|
89
|
+
await writeCellsToClipboard(cells);
|
|
91
90
|
pendingCutActions.clear();
|
|
92
91
|
toastSuccess(cells.length);
|
|
93
92
|
} catch (error) {
|
|
@@ -95,7 +94,7 @@ export function useCellClipboard() {
|
|
|
95
94
|
|
|
96
95
|
// Fallback to simple text copy
|
|
97
96
|
try {
|
|
98
|
-
await copyToClipboard(
|
|
97
|
+
await copyToClipboard(toPlainText(cells));
|
|
99
98
|
pendingCutActions.clear();
|
|
100
99
|
toastSuccess(cells.length);
|
|
101
100
|
} catch {
|
|
@@ -110,21 +109,18 @@ export function useCellClipboard() {
|
|
|
110
109
|
const cells = validCellIds.map((cellId) => notebook.cellData[cellId]);
|
|
111
110
|
|
|
112
111
|
if (cells.length === 0) {
|
|
113
|
-
// No cells to cut
|
|
114
112
|
return;
|
|
115
113
|
}
|
|
116
114
|
|
|
117
|
-
const { clipboardData, plainText } = buildClipboardPayload(cells);
|
|
118
|
-
|
|
119
115
|
try {
|
|
120
|
-
await writeCellsToClipboard(
|
|
121
|
-
pendingCutActions.markForCut({ cellIds: validCellIds
|
|
116
|
+
await writeCellsToClipboard(cells);
|
|
117
|
+
pendingCutActions.markForCut({ cellIds: validCellIds });
|
|
122
118
|
} catch (error) {
|
|
123
119
|
Logger.error("Failed to cut cells to clipboard", error);
|
|
124
120
|
try {
|
|
125
|
-
await copyToClipboard(
|
|
121
|
+
await copyToClipboard(toPlainText(cells));
|
|
126
122
|
// Mark cells as pending cut instead of deleting immediately
|
|
127
|
-
pendingCutActions.markForCut({ cellIds: validCellIds
|
|
123
|
+
pendingCutActions.markForCut({ cellIds: validCellIds });
|
|
128
124
|
} catch {
|
|
129
125
|
toastError();
|
|
130
126
|
}
|
|
@@ -622,7 +622,7 @@ describe("cell reducer", () => {
|
|
|
622
622
|
before: false,
|
|
623
623
|
});
|
|
624
624
|
actions.createNewCell({
|
|
625
|
-
cellId: "1"
|
|
625
|
+
cellId: cellId("1"),
|
|
626
626
|
before: false,
|
|
627
627
|
});
|
|
628
628
|
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
@@ -637,8 +637,8 @@ describe("cell reducer", () => {
|
|
|
637
637
|
|
|
638
638
|
// Move first two cells after the third
|
|
639
639
|
actions.moveCellsRelativeTo({
|
|
640
|
-
cellIds: [firstCellId, "1"
|
|
641
|
-
targetCellId: "2"
|
|
640
|
+
cellIds: [firstCellId, cellId("1")],
|
|
641
|
+
targetCellId: cellId("2"),
|
|
642
642
|
position: "after",
|
|
643
643
|
});
|
|
644
644
|
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
@@ -658,7 +658,7 @@ describe("cell reducer", () => {
|
|
|
658
658
|
before: false,
|
|
659
659
|
});
|
|
660
660
|
actions.createNewCell({
|
|
661
|
-
cellId: "1"
|
|
661
|
+
cellId: cellId("1"),
|
|
662
662
|
before: false,
|
|
663
663
|
});
|
|
664
664
|
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
@@ -682,14 +682,14 @@ describe("cell reducer", () => {
|
|
|
682
682
|
{
|
|
683
683
|
columnId: col.id,
|
|
684
684
|
index: col.indexOfOrThrow(
|
|
685
|
-
"1"
|
|
685
|
+
cellId("1"),
|
|
686
686
|
) as import("@/utils/id-tree").CellIndex,
|
|
687
687
|
},
|
|
688
688
|
];
|
|
689
689
|
|
|
690
690
|
actions.moveCellsRelativeTo({
|
|
691
|
-
cellIds: [firstCellId, "1"
|
|
692
|
-
targetCellId: "2"
|
|
691
|
+
cellIds: [firstCellId, cellId("1")],
|
|
692
|
+
targetCellId: cellId("2"),
|
|
693
693
|
position: "after",
|
|
694
694
|
previousPlacements,
|
|
695
695
|
});
|
|
@@ -721,7 +721,7 @@ describe("cell reducer", () => {
|
|
|
721
721
|
before: false,
|
|
722
722
|
});
|
|
723
723
|
actions.createNewCell({
|
|
724
|
-
cellId: "1"
|
|
724
|
+
cellId: cellId("1"),
|
|
725
725
|
before: false,
|
|
726
726
|
});
|
|
727
727
|
|
|
@@ -736,14 +736,14 @@ describe("cell reducer", () => {
|
|
|
736
736
|
{
|
|
737
737
|
columnId: col.id,
|
|
738
738
|
index: col.indexOfOrThrow(
|
|
739
|
-
"1"
|
|
739
|
+
cellId("1"),
|
|
740
740
|
) as import("@/utils/id-tree").CellIndex,
|
|
741
741
|
},
|
|
742
742
|
];
|
|
743
743
|
|
|
744
744
|
actions.moveCellsRelativeTo({
|
|
745
|
-
cellIds: [firstCellId, "1"
|
|
746
|
-
targetCellId: "2"
|
|
745
|
+
cellIds: [firstCellId, cellId("1")],
|
|
746
|
+
targetCellId: cellId("2"),
|
|
747
747
|
position: "after",
|
|
748
748
|
previousPlacements,
|
|
749
749
|
});
|
|
@@ -757,7 +757,7 @@ describe("cell reducer", () => {
|
|
|
757
757
|
"
|
|
758
758
|
`);
|
|
759
759
|
|
|
760
|
-
actions.deleteCell({ cellId: "2"
|
|
760
|
+
actions.deleteCell({ cellId: cellId("2") });
|
|
761
761
|
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
762
762
|
"
|
|
763
763
|
[0] ''
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { act, renderHook } from "@testing-library/react";
|
|
4
4
|
import { createStore, Provider } from "jotai";
|
|
5
5
|
import { describe, expect, it } from "vitest";
|
|
6
|
+
import { cellId } from "@/__tests__/branded";
|
|
6
7
|
import type { CellId } from "@/core/cells/ids";
|
|
7
8
|
import {
|
|
8
9
|
pendingCutStateAtom,
|
|
@@ -20,15 +21,10 @@ function createTestWrapper() {
|
|
|
20
21
|
return { wrapper, store };
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
const mockClipboardData = {
|
|
24
|
-
cells: [{ code: "x = 1", name: "cell1" }],
|
|
25
|
-
version: "1.0" as const,
|
|
26
|
-
};
|
|
27
|
-
|
|
28
24
|
describe("pending-cut-service", () => {
|
|
29
|
-
it("markForCut sets cellIds
|
|
25
|
+
it("markForCut sets cellIds", () => {
|
|
30
26
|
const { wrapper, store } = createTestWrapper();
|
|
31
|
-
const cellIds: CellId[] = ["cell-1"
|
|
27
|
+
const cellIds: CellId[] = [cellId("cell-1"), cellId("cell-2")];
|
|
32
28
|
|
|
33
29
|
const { result } = renderHook(
|
|
34
30
|
() => ({
|
|
@@ -39,20 +35,16 @@ describe("pending-cut-service", () => {
|
|
|
39
35
|
);
|
|
40
36
|
|
|
41
37
|
act(() => {
|
|
42
|
-
result.current.actions.markForCut({
|
|
43
|
-
cellIds,
|
|
44
|
-
clipboardData: mockClipboardData,
|
|
45
|
-
});
|
|
38
|
+
result.current.actions.markForCut({ cellIds });
|
|
46
39
|
});
|
|
47
40
|
|
|
48
41
|
const state = store.get(pendingCutStateAtom);
|
|
49
42
|
expect(state.cellIds).toEqual(new Set(cellIds));
|
|
50
|
-
expect(state.clipboardData).toEqual(mockClipboardData);
|
|
51
43
|
});
|
|
52
44
|
|
|
53
45
|
it("clear resets to initial state", () => {
|
|
54
46
|
const { wrapper, store } = createTestWrapper();
|
|
55
|
-
const cellIds: CellId[] = ["cell-1"
|
|
47
|
+
const cellIds: CellId[] = [cellId("cell-1")];
|
|
56
48
|
|
|
57
49
|
const { result } = renderHook(
|
|
58
50
|
() => ({
|
|
@@ -63,10 +55,7 @@ describe("pending-cut-service", () => {
|
|
|
63
55
|
);
|
|
64
56
|
|
|
65
57
|
act(() => {
|
|
66
|
-
result.current.actions.markForCut({
|
|
67
|
-
cellIds,
|
|
68
|
-
clipboardData: mockClipboardData,
|
|
69
|
-
});
|
|
58
|
+
result.current.actions.markForCut({ cellIds });
|
|
70
59
|
});
|
|
71
60
|
expect(store.get(pendingCutStateAtom).cellIds.size).toBe(1);
|
|
72
61
|
|
|
@@ -75,28 +64,24 @@ describe("pending-cut-service", () => {
|
|
|
75
64
|
});
|
|
76
65
|
const state = store.get(pendingCutStateAtom);
|
|
77
66
|
expect(state.cellIds.size).toBe(0);
|
|
78
|
-
expect(state.clipboardData).toBeNull();
|
|
79
67
|
});
|
|
80
68
|
|
|
81
69
|
it("useIsPendingCut returns true when cellId is marked for cut", () => {
|
|
82
70
|
const { wrapper } = createTestWrapper();
|
|
83
|
-
const
|
|
71
|
+
const targetCellId = cellId("cell-1");
|
|
84
72
|
|
|
85
73
|
const { result: actionsResult } = renderHook(() => usePendingCutActions(), {
|
|
86
74
|
wrapper,
|
|
87
75
|
});
|
|
88
76
|
const { result: isPendingResult } = renderHook(
|
|
89
|
-
() => useIsPendingCut(
|
|
77
|
+
() => useIsPendingCut(targetCellId),
|
|
90
78
|
{ wrapper },
|
|
91
79
|
);
|
|
92
80
|
|
|
93
81
|
expect(isPendingResult.current).toBe(false);
|
|
94
82
|
|
|
95
83
|
act(() => {
|
|
96
|
-
actionsResult.current.markForCut({
|
|
97
|
-
cellIds: [cellId],
|
|
98
|
-
clipboardData: mockClipboardData,
|
|
99
|
-
});
|
|
84
|
+
actionsResult.current.markForCut({ cellIds: [targetCellId] });
|
|
100
85
|
});
|
|
101
86
|
|
|
102
87
|
expect(isPendingResult.current).toBe(true);
|
|
@@ -104,19 +89,15 @@ describe("pending-cut-service", () => {
|
|
|
104
89
|
|
|
105
90
|
it("useIsPendingCut returns false when cellId is not marked for cut", () => {
|
|
106
91
|
const { wrapper } = createTestWrapper();
|
|
107
|
-
const { result } = renderHook(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
);
|
|
92
|
+
const { result } = renderHook(() => useIsPendingCut(cellId("other-cell")), {
|
|
93
|
+
wrapper,
|
|
94
|
+
});
|
|
111
95
|
|
|
112
96
|
const { result: actionsResult } = renderHook(() => usePendingCutActions(), {
|
|
113
97
|
wrapper,
|
|
114
98
|
});
|
|
115
99
|
act(() => {
|
|
116
|
-
actionsResult.current.markForCut({
|
|
117
|
-
cellIds: ["cell-1" as CellId],
|
|
118
|
-
clipboardData: mockClipboardData,
|
|
119
|
-
});
|
|
100
|
+
actionsResult.current.markForCut({ cellIds: [cellId("cell-1")] });
|
|
120
101
|
});
|
|
121
102
|
|
|
122
103
|
expect(result.current).toBe(false);
|
|
@@ -134,10 +115,7 @@ describe("pending-cut-service", () => {
|
|
|
134
115
|
expect(hasPendingResult.current).toBe(false);
|
|
135
116
|
|
|
136
117
|
act(() => {
|
|
137
|
-
actionsResult.current.markForCut({
|
|
138
|
-
cellIds: ["cell-1" as CellId],
|
|
139
|
-
clipboardData: mockClipboardData,
|
|
140
|
-
});
|
|
118
|
+
actionsResult.current.markForCut({ cellIds: [cellId("cell-1")] });
|
|
141
119
|
});
|
|
142
120
|
|
|
143
121
|
expect(hasPendingResult.current).toBe(true);
|
|
@@ -1,31 +1,24 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
3
|
import { atom, useAtomValue } from "jotai";
|
|
4
|
-
import type { ClipboardCellData } from "@/components/editor/navigation/clipboard";
|
|
5
4
|
import type { CellId } from "@/core/cells/ids";
|
|
6
5
|
import { createReducerAndAtoms } from "@/utils/createReducer";
|
|
7
6
|
|
|
8
7
|
interface PendingCutState {
|
|
9
8
|
cellIds: Set<CellId>;
|
|
10
|
-
clipboardData: ClipboardCellData | null;
|
|
11
9
|
}
|
|
12
10
|
|
|
13
11
|
const initialState = (): PendingCutState => ({
|
|
14
12
|
cellIds: new Set(),
|
|
15
|
-
clipboardData: null,
|
|
16
13
|
});
|
|
17
14
|
|
|
18
15
|
const {
|
|
19
16
|
valueAtom: pendingCutStateAtom,
|
|
20
17
|
useActions: usePendingCutActionsInternal,
|
|
21
18
|
} = createReducerAndAtoms(initialState, {
|
|
22
|
-
markForCut: (
|
|
23
|
-
_state,
|
|
24
|
-
action: { cellIds: CellId[]; clipboardData: ClipboardCellData },
|
|
25
|
-
) => {
|
|
19
|
+
markForCut: (_state, action: { cellIds: CellId[] }) => {
|
|
26
20
|
return {
|
|
27
21
|
cellIds: new Set(action.cellIds),
|
|
28
|
-
clipboardData: action.clipboardData,
|
|
29
22
|
};
|
|
30
23
|
},
|
|
31
24
|
clear: () => {
|
|
@@ -33,10 +26,8 @@ const {
|
|
|
33
26
|
},
|
|
34
27
|
});
|
|
35
28
|
|
|
36
|
-
// Re-export the state atom
|
|
37
29
|
export { pendingCutStateAtom };
|
|
38
30
|
|
|
39
|
-
// Derived atom just for cell IDs (for easier consumption)
|
|
40
31
|
export const pendingCutCellIdsAtom = atom(
|
|
41
32
|
(get) => get(pendingCutStateAtom).cellIds,
|
|
42
33
|
);
|
package/src/css/app/Cell.css
CHANGED
|
@@ -75,14 +75,11 @@
|
|
|
75
75
|
|
|
76
76
|
/* Styling for cells marked for cut */
|
|
77
77
|
&.pending-cut {
|
|
78
|
-
opacity: 0.6;
|
|
79
|
-
border-style: dashed;
|
|
80
|
-
border-color: var(--amber-7);
|
|
81
|
-
|
|
82
78
|
.output-area,
|
|
83
79
|
.cm-gutters,
|
|
84
80
|
.cm {
|
|
85
|
-
background-color: var(--
|
|
81
|
+
background-color: var(--gray-2);
|
|
82
|
+
opacity: 0.55;
|
|
86
83
|
}
|
|
87
84
|
}
|
|
88
85
|
|