@marimo-team/islands 0.25.3-dev197 → 0.25.3-dev198

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 (135) hide show
  1. package/dist/{ConnectedDataExplorerComponent-BRuwLOIx.js → ConnectedDataExplorerComponent-BsWiIPFk.js} +4 -4
  2. package/dist/{ErrorBoundary-jQVF8yMb.js → ErrorBoundary-D1Z3KAf_.js} +2 -2
  3. package/dist/{abnfDiagram-VCTEODGH-LlJTOOU_.js → abnfDiagram-VCTEODGH-I2x4Yu25.js} +2 -2
  4. package/dist/{architectureDiagram-5GKGNRK7-9PQtGLLZ.js → architectureDiagram-5GKGNRK7-1bSQMKzK.js} +1 -1
  5. package/dist/{arrays-DA6KkLfq.js → arrays-DoQ-AILx.js} +7 -21
  6. package/dist/{capabilities-CvWU-ey_.js → capabilities-C2QUNRXi.js} +1 -1
  7. package/dist/{chat-ui-Bl2euMBD.js → chat-ui-BAyHM_GD.js} +524 -524
  8. package/dist/{chunk-IMKFNOWR-DcXv-BD5.js → chunk-IMKFNOWR-fsCGAJ9G.js} +1 -1
  9. package/dist/{chunk-SHT3W25Y-VwnELN23.js → chunk-SHT3W25Y-D2STW4hj.js} +1 -1
  10. package/dist/{chunk-SVP7TREG-DgQpI5Zi.js → chunk-SVP7TREG-CiY7cQG-.js} +1 -1
  11. package/dist/{chunk-TICWLB2K-CTg6VTJT.js → chunk-TICWLB2K-C_t5RBp9.js} +1 -1
  12. package/dist/{classDiagram-ZZMXUADV-UzmcFrnW.js → classDiagram-ZZMXUADV-B2JvZAP4.js} +2 -2
  13. package/dist/{classDiagram-v2-VYDZK3BY-DhjiI6IQ.js → classDiagram-v2-VYDZK3BY-L8VsZG5A.js} +2 -2
  14. package/dist/{code-visibility-CjZo_SV8.js → code-visibility-CInEQd1e.js} +19 -19
  15. package/dist/{common-CFLvScF3.js → common-W5HfVJPN.js} +4362 -4362
  16. package/dist/{cynefinDiagram-5FMLGOSQ-O4ShIbJX.js → cynefinDiagram-5FMLGOSQ-DdllC264.js} +1 -1
  17. package/dist/{dagre-GXQ25YYZ-dtHhhcPu.js → dagre-GXQ25YYZ-BaWHw4_f.js} +1 -1
  18. package/dist/{data-grid-overlay-editor-CzW3mY6m.js → data-grid-overlay-editor-BQCaV0fI.js} +1 -1
  19. package/dist/{diagram-S7CK7UJ4-ppPYVZ6W.js → diagram-S7CK7UJ4-pFt-tUDe.js} +1 -1
  20. package/dist/{diagram-UQ7AKVKN-CMZDf--k.js → diagram-UQ7AKVKN-DqGJiBp4.js} +1 -1
  21. package/dist/{diagram-VX7I27RA-CFvJdx-C.js → diagram-VX7I27RA-Dr-yzMjf.js} +1 -1
  22. package/dist/{diagram-Z3DM3KII-Dt6_uFbv.js → diagram-Z3DM3KII-8xzJzv-w.js} +1 -1
  23. package/dist/{dropdown-menu-CeaOsjWZ.js → dropdown-menu-NlnsmNA6.js} +2 -2
  24. package/dist/{ebnfDiagram-PWID7BFC-DpRFrKK-.js → ebnfDiagram-PWID7BFC-Br04Wy-E.js} +2 -2
  25. package/dist/{erDiagram-RLTQ6QDP-CqAU4b0u.js → erDiagram-RLTQ6QDP-D5-XVgvv.js} +1 -1
  26. package/dist/{error-entries-CYGwr5-O.js → error-entries-BacCWMWj.js} +4678 -5028
  27. package/dist/{feedback-button-GR_8U4Vo.js → feedback-button-DLXUcQ7l.js} +113 -113
  28. package/dist/{flowDiagram-HODETNUW-i8-Gw8HO.js → flowDiagram-HODETNUW-CVl2kREF.js} +2 -2
  29. package/dist/{formats-BtoHHy42.js → formats-BCYthwyc.js} +1 -1
  30. package/dist/{glide-data-editor-Dfdxc22H.js → glide-data-editor-D5YaHPKx.js} +5 -5
  31. package/dist/{globals-CxjzBEbP.js → globals-DjX1uxzy.js} +2 -2
  32. package/dist/{html-to-image-Cy5UDpQJ.js → html-to-image-DAmgSo5P.js} +624 -573
  33. package/dist/{infoDiagram-27XIBGKW-DpfOKdLL.js → infoDiagram-27XIBGKW-BJ4vNcZE.js} +1 -1
  34. package/dist/{ishikawaDiagram-5VMMS53U-Dg7mrMG7.js → ishikawaDiagram-5VMMS53U-B_Jy1Dsm.js} +1 -1
  35. package/dist/{kanban-definition-UXKFOSKX-QB6e3Jrj.js → kanban-definition-UXKFOSKX-C6MkS9vw.js} +1 -1
  36. package/dist/main.js +1117 -1117
  37. package/dist/{mermaid-CeWG4Egr.js → mermaid-Bh918qrq.js} +34 -34
  38. package/dist/{mindmap-definition-YA3MSWOX-BTz3uTGe.js → mindmap-definition-YA3MSWOX-BP3ZTuir.js} +1 -1
  39. package/dist/{number-overlay-editor-CwHYeI4e.js → number-overlay-editor-3C_K6w_0.js} +1 -1
  40. package/dist/{once-DWGO2mQ2.js → once-NnpX_HnX.js} +1 -1
  41. package/dist/{pegDiagram-XKGWAZYB-3ZIEa3mB.js → pegDiagram-XKGWAZYB-nNGOQtnt.js} +2 -2
  42. package/dist/{pieDiagram-E7YTZNPT-BJAlk046.js → pieDiagram-E7YTZNPT-CpRz5BZz.js} +1 -1
  43. package/dist/{process-output-q9MTAIMX.js → process-output-DweUmAmV.js} +3 -3
  44. package/dist/{railroadDiagram-O6MQD6OU-Dn3bsSRa.js → railroadDiagram-O6MQD6OU-BqOEN4I0.js} +2 -2
  45. package/dist/{requirementDiagram-BXWQKSXE-wcOmQQCL.js → requirementDiagram-BXWQKSXE-CEfg6vu9.js} +1 -1
  46. package/dist/{reveal-component-C5bOqXlB.js → reveal-component-JjJRTT9d.js} +17 -17
  47. package/dist/{sequenceDiagram-WJ2MYXX4-DSh_qxoF.js → sequenceDiagram-WJ2MYXX4-IOmpQcOi.js} +1 -1
  48. package/dist/{spec-C7Fos-If.js → spec-Dkp64vVQ.js} +1 -1
  49. package/dist/{stateDiagram-D77RDMKH-DH_H8NMH.js → stateDiagram-D77RDMKH-tgU-EY9_.js} +2 -2
  50. package/dist/{stateDiagram-v2-MP3YSRHH-D_JM7MEK.js → stateDiagram-v2-MP3YSRHH-BofhG6q1.js} +2 -2
  51. package/dist/{swimlanes-42K2YHIH-CfoTJO-9.js → swimlanes-42K2YHIH-DW4vWDBd.js} +1 -1
  52. package/dist/{swimlanesDiagram-VR7AAH4N-Z_QhvK0G.js → swimlanesDiagram-VR7AAH4N-BJcrqUJr.js} +2 -2
  53. package/dist/{swiper-component-D2geL1Ku.js → swiper-component-BVfnhbnt.js} +1 -1
  54. package/dist/{timeline-definition-24CTP7MA-BFtdScaL.js → timeline-definition-24CTP7MA-D_QU3NGs.js} +1 -1
  55. package/dist/{toDate-CQAFSwos.js → toDate-BNDEXbfV.js} +30 -30
  56. package/dist/{useAsyncData-BeyZyjso.js → useAsyncData-ASDni9vH.js} +1 -1
  57. package/dist/{useDeepCompareMemoize-DOQgae0W.js → useDeepCompareMemoize-B1Ogyf53.js} +1 -1
  58. package/dist/{useIframeCapabilities-DNvaj9wM.js → useIframeCapabilities-6a_yDNXp.js} +1 -1
  59. package/dist/{useLifecycle-n2lnCFS8.js → useLifecycle-Bfpa2m7k.js} +1 -1
  60. package/dist/{useTheme-CY777LXN.js → useTheme-5TwyOh3B.js} +66 -66
  61. package/dist/{vega-component-0nQzA-I8.js → vega-component-BHS9UOtC.js} +19 -19
  62. package/dist/{vennDiagram-4TSXK5OY-BXY8IGCA.js → vennDiagram-4TSXK5OY-YFYsNIAh.js} +1 -1
  63. package/dist/{wardleyDiagram-VM6X3IG4-D0tFe6eC.js → wardleyDiagram-VM6X3IG4-i_n8mAWC.js} +1 -1
  64. package/dist/{xychartDiagram-S5SC5T6Z-Dx8wFM-y.js → xychartDiagram-S5SC5T6Z-BYGN95wW.js} +1 -1
  65. package/package.json +1 -1
  66. package/src/__mocks__/document.tsx +13 -4
  67. package/src/__mocks__/notebook.ts +1 -2
  68. package/src/components/datasources/datasources.tsx +1 -1
  69. package/src/components/dependency-graph/custom-node.tsx +1 -1
  70. package/src/components/dependency-graph/minimap-content.tsx +12 -14
  71. package/src/components/editor/actions/useSetCodeVisibility.ts +1 -1
  72. package/src/components/editor/actions/useSetOutputsExpanded.ts +1 -1
  73. package/src/components/editor/alerts/stdin-blocking-alert.tsx +1 -1
  74. package/src/components/editor/cell/code/cell-editor.tsx +1 -1
  75. package/src/components/editor/cell/useSplitCell.tsx +8 -5
  76. package/src/components/editor/chrome/panels/dependency-graph-panel.tsx +1 -1
  77. package/src/components/editor/chrome/panels/session-panel.tsx +1 -1
  78. package/src/components/editor/chrome/panels/variable-panel.tsx +1 -5
  79. package/src/components/editor/chrome/wrapper/minimap-state.ts +1 -1
  80. package/src/components/editor/columns/__tests__/cell-column.test.tsx +1 -1
  81. package/src/components/editor/columns/cell-column.tsx +1 -1
  82. package/src/components/editor/columns/sortable-column.tsx +1 -1
  83. package/src/components/editor/links/__tests__/cell-link.test.tsx +1 -1
  84. package/src/components/editor/links/cell-link-list.tsx +1 -1
  85. package/src/components/editor/links/cell-link.tsx +1 -1
  86. package/src/components/editor/navigation/__tests__/navigation.test.ts +20 -6
  87. package/src/components/editor/navigation/__tests__/selection.test.ts +1 -2
  88. package/src/components/editor/navigation/clipboard.ts +5 -3
  89. package/src/components/editor/renderers/cell-array.tsx +7 -12
  90. package/src/components/editor/renderers/slides-layout/slides-layout.tsx +1 -1
  91. package/src/components/editor/renderers/vertical-layout/__tests__/useFocusFirstEditor.test.ts +4 -4
  92. package/src/components/editor/renderers/vertical-layout/useFocusFirstEditor.ts +1 -1
  93. package/src/components/editor/stdin-blocking-alert.tsx +1 -1
  94. package/src/components/slides/__tests__/minimap-actions.test.tsx +13 -4
  95. package/src/components/slides/__tests__/minimap.test.ts +38 -19
  96. package/src/components/slides/minimap.tsx +11 -10
  97. package/src/components/sort/SortableCellsProvider.tsx +2 -21
  98. package/src/components/tracing/tracing.tsx +1 -1
  99. package/src/core/ai/__tests__/staged-cells.test.ts +1 -1
  100. package/src/core/ai/context/providers/__tests__/cell-output.test.ts +8 -12
  101. package/src/core/ai/context/providers/cell-output.ts +2 -2
  102. package/src/core/ai/tools/__tests__/edit-notebook-tool.test.ts +34 -66
  103. package/src/core/ai/tools/edit-notebook-tool.ts +12 -10
  104. package/src/core/cells/__tests__/actions.test.ts +64 -25
  105. package/src/core/cells/__tests__/arrange.test.ts +156 -4
  106. package/src/core/cells/__tests__/cells.test.ts +12 -290
  107. package/src/core/cells/__tests__/document.test.ts +2 -46
  108. package/src/core/cells/__tests__/harness.ts +28 -4
  109. package/src/core/cells/__tests__/layout.test.ts +42 -54
  110. package/src/core/cells/__tests__/session.test.ts +0 -2
  111. package/src/core/cells/__tests__/utils.test.ts +9 -107
  112. package/src/core/cells/actions.ts +112 -26
  113. package/src/core/cells/add-missing-import.ts +1 -1
  114. package/src/core/cells/arrange.ts +206 -13
  115. package/src/core/cells/cells.ts +28 -256
  116. package/src/core/cells/document.ts +18 -122
  117. package/src/core/cells/layout.ts +79 -10
  118. package/src/core/cells/pending-delete-service.ts +1 -1
  119. package/src/core/cells/utils.ts +4 -4
  120. package/src/core/codemirror/copilot/__tests__/getCodes.test.ts +6 -7
  121. package/src/core/codemirror/copilot/getCodes.ts +2 -2
  122. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +1 -2
  123. package/src/core/codemirror/lsp/utils.ts +1 -1
  124. package/src/core/documentation/doc-lookup.ts +1 -1
  125. package/src/core/edit-app.tsx +2 -5
  126. package/src/core/errors/error-entries.ts +1 -1
  127. package/src/core/islands/__tests__/bootstrap.test.ts +2 -6
  128. package/src/core/islands/components/web-components.tsx +1 -1
  129. package/src/core/notebook/document/__tests__/codemirror.test.ts +8 -0
  130. package/src/core/session/__tests__/useNotebookSession.hook.test.tsx +1 -1
  131. package/src/stories/cell.stories.tsx +1 -2
  132. package/src/stories/layout/vertical/one-column.stories.tsx +1 -2
  133. package/src/stories/runtime-story.tsx +2 -3
  134. package/src/utils/__tests__/id-tree.test.ts +0 -617
  135. package/src/utils/id-tree.tsx +0 -609
@@ -1,617 +0,0 @@
1
- /* Copyright 2026 Marimo. All rights reserved. */
2
- import { beforeEach, describe, expect, it } from "vitest";
3
- import { SETUP_CELL_ID } from "@/core/cells/ids";
4
- import {
5
- type CellColumnId,
6
- type CellIndex,
7
- CollapsibleTree,
8
- MultiColumn,
9
- } from "../id-tree";
10
-
11
- let tree: CollapsibleTree<string>;
12
-
13
- describe("CollapsibleTree", () => {
14
- beforeEach(() => {
15
- tree = CollapsibleTree.from(["one", "two", "three", "four"]);
16
- });
17
-
18
- it("initializes correctly", () => {
19
- expect(tree.toString()).toMatchInlineSnapshot(`
20
- "one
21
- two
22
- three
23
- four
24
- "
25
- `);
26
- });
27
-
28
- it("inserts nodes correctly", () => {
29
- tree = tree.insert("newNode", 1);
30
- expect(tree.toString()).toMatchInlineSnapshot(`
31
- "one
32
- newNode
33
- two
34
- three
35
- four
36
- "
37
- `);
38
-
39
- tree = tree.insert("newNode2", tree.length - 1);
40
- expect(tree.toString()).toMatchInlineSnapshot(`
41
- "one
42
- newNode
43
- two
44
- three
45
- newNode2
46
- four
47
- "
48
- `);
49
-
50
- tree = tree.insert("newNode3", 10_000);
51
- expect(tree.toString()).toMatchInlineSnapshot(`
52
- "one
53
- newNode
54
- two
55
- three
56
- newNode2
57
- four
58
- newNode3
59
- "
60
- `);
61
- });
62
-
63
- it("can delete non-collapsed nodes without throwing", () => {
64
- // Deleting a non-collapsed node should not throw
65
- // (previously this would throw "Node is already expanded" internally)
66
- const result = tree.deleteAtIndex(1);
67
- expect(result.toString()).toMatchInlineSnapshot(`
68
- "one
69
- three
70
- four
71
- "
72
- `);
73
- });
74
-
75
- it("fails to delete nodes", () => {
76
- expect(() => tree.deleteAtIndex(5)).toThrowErrorMatchingInlineSnapshot(
77
- "[Error: Node at index 5 not found in tree]",
78
- );
79
- });
80
-
81
- it("atOrThrow throws if not found", () => {
82
- expect(() => tree.atOrThrow(5)).toThrowErrorMatchingInlineSnapshot(
83
- "[Error: Node at index 5 not found in tree]",
84
- );
85
- });
86
-
87
- it("first and last are correct", () => {
88
- expect(tree.first()).toBe("one");
89
- expect(tree.last()).toBe("four");
90
- });
91
-
92
- it("handles slice correctly", () => {
93
- // Normal slice in middle
94
- expect(tree.slice(1, 3)).toEqual(["two", "three"]);
95
-
96
- // Slice from beginning
97
- expect(tree.slice(0, 2)).toEqual(["one", "two"]);
98
-
99
- // Slice to end
100
- expect(tree.slice(2, 4)).toEqual(["three", "four"]);
101
-
102
- // Slice entire array
103
- expect(tree.slice(0, 4)).toEqual(["one", "two", "three", "four"]);
104
-
105
- // Slice with out-of-bounds end
106
- expect(tree.slice(2, 10)).toEqual(["three", "four"]);
107
-
108
- // Slice with negative start (should work like normal array slice)
109
- expect(tree.slice(-2, 4)).toEqual(["three", "four"]);
110
-
111
- // Slice with start > end (should return empty array)
112
- expect(tree.slice(3, 1)).toEqual([]);
113
-
114
- // Slice with same start and end
115
- expect(tree.slice(2, 2)).toEqual([]);
116
-
117
- // Slice single element
118
- expect(tree.slice(1, 2)).toEqual(["two"]);
119
- });
120
-
121
- it("handles after correctly", () => {
122
- // Normal case - get next node
123
- expect(tree.after("one")).toBe("two");
124
- expect(tree.after("two")).toBe("three");
125
- expect(tree.after("three")).toBe("four");
126
-
127
- // Edge case - last node should return undefined
128
- expect(tree.after("four")).toBeUndefined();
129
-
130
- // Edge case - non-existent node should throw
131
- expect(() => tree.after("nonexistent")).toThrow(
132
- "Node nonexistent not found in tree. Valid ids: one,two,three,four",
133
- );
134
- });
135
-
136
- it("handles before correctly", () => {
137
- // Normal case - get previous node
138
- expect(tree.before("two")).toBe("one");
139
- expect(tree.before("three")).toBe("two");
140
- expect(tree.before("four")).toBe("three");
141
-
142
- // Edge case - first node should return undefined
143
- expect(tree.before("one")).toBeUndefined();
144
-
145
- // Edge case - non-existent node should throw
146
- expect(() => tree.before("nonexistent")).toThrow(
147
- "Node nonexistent not found in tree. Valid ids: one,two,three,four",
148
- );
149
- });
150
-
151
- it("handles slice on empty tree", () => {
152
- const emptyTree = CollapsibleTree.from([]);
153
- expect(emptyTree.slice(0, 1)).toEqual([]);
154
- expect(emptyTree.slice(0, 0)).toEqual([]);
155
- });
156
-
157
- it("handles after/before on single element tree", () => {
158
- const singleTree = CollapsibleTree.from(["single"]);
159
- expect(singleTree.after("single")).toBeUndefined();
160
- expect(singleTree.before("single")).toBeUndefined();
161
- });
162
-
163
- it("handles split correctly", () => {
164
- const [left, right] = tree.split("two");
165
- expect(left.toString()).toMatchInlineSnapshot(`
166
- "one
167
- "
168
- `);
169
- expect(right?.toString()).toMatchInlineSnapshot(`
170
- "two
171
- three
172
- four
173
- "
174
- `);
175
- });
176
-
177
- it("handles split at the beginning", () => {
178
- const [left, right] = tree.split("one");
179
- expect(left.toString()).toMatchInlineSnapshot(`
180
- ""
181
- `);
182
- expect(right?.toString()).toMatchInlineSnapshot(`
183
- "one
184
- two
185
- three
186
- four
187
- "
188
- `);
189
- });
190
-
191
- it("handles split at the end", () => {
192
- const [left, right] = tree.split("four");
193
- expect(left.toString()).toMatchInlineSnapshot(`
194
- "one
195
- two
196
- three
197
- "
198
- `);
199
- expect(right?.toString()).toMatchInlineSnapshot(`
200
- "four
201
- "
202
- `);
203
- });
204
-
205
- it("throws when splitting on non-existent node", () => {
206
- expect(() => tree.split("five")).toThrow("Node five not found in tree");
207
- });
208
- });
209
-
210
- describe("CollapsibleTree edge cases", () => {
211
- let tree: CollapsibleTree<string>;
212
-
213
- beforeEach(() => {
214
- tree = CollapsibleTree.from(["A", "B", "C", "D"]);
215
- });
216
-
217
- it("handles insert at start and end", () => {
218
- tree = tree.insertAtStart("Z");
219
- expect(tree.topLevelIds).toEqual(["Z", "A", "B", "C", "D"]);
220
- tree = tree.insertAtEnd("Y");
221
- expect(tree.topLevelIds).toEqual(["Z", "A", "B", "C", "D", "Y"]);
222
- });
223
-
224
- it("handles edge cases for first and last", () => {
225
- expect(tree.first()).toBe("A");
226
- expect(tree.last()).toBe("D");
227
- tree = CollapsibleTree.from([]);
228
- expect(() => tree.first()).toThrow("Node at index 0 not found in tree");
229
- expect(() => tree.last()).toThrow("Node at index -1 not found in tree");
230
- });
231
- });
232
-
233
- describe("MultiColumn", () => {
234
- let multiColumn: MultiColumn<string>;
235
- let columnIds: CellColumnId[];
236
-
237
- beforeEach(() => {
238
- multiColumn = MultiColumn.from([
239
- ["A1", "A2", "A3"],
240
- ["B1", "B2"],
241
- ["C1", "C2", "C3", "C4"],
242
- ]);
243
-
244
- columnIds = multiColumn.getColumns().map((c) => c.id);
245
- });
246
-
247
- it("initializes correctly", () => {
248
- expect(multiColumn.colLength).toBe(3);
249
- expect(multiColumn.idLength).toBe(9);
250
- expect(multiColumn.topLevelIds).toEqual([
251
- ["A1", "A2", "A3"],
252
- ["B1", "B2"],
253
- ["C1", "C2", "C3", "C4"],
254
- ]);
255
- });
256
-
257
- it("creates from empty array", () => {
258
- const emptyMultiColumn = MultiColumn.from([]);
259
- expect(emptyMultiColumn.colLength).toBe(1);
260
- expect(emptyMultiColumn.idLength).toBe(0);
261
- expect(emptyMultiColumn.isEmpty()).toBe(true);
262
- });
263
-
264
- it("creates from ids and columns", () => {
265
- const idAndColumns: [string, number | undefined | null][] = [
266
- ["A1", 0],
267
- ["A2", 0],
268
- ["B1", 1],
269
- ["C1", 2],
270
- ["C2", undefined],
271
- ["D1", null],
272
- ["E1", -1],
273
- ];
274
- const fromIdsAndColumns = MultiColumn.fromIdsAndColumns(idAndColumns);
275
- expect(fromIdsAndColumns.colLength).toBe(3);
276
- expect(fromIdsAndColumns.topLevelIds).toEqual([
277
- ["A1", "A2"],
278
- ["B1"],
279
- ["C1", "C2", "D1", "E1"],
280
- ]);
281
- });
282
-
283
- it("iterates top-level ids", () => {
284
- const ids = [...multiColumn.iterateTopLevelIds];
285
- expect(ids).toEqual(["A1", "A2", "A3", "B1", "B2", "C1", "C2", "C3", "C4"]);
286
- });
287
-
288
- it("gets in-order ids", () => {
289
- expect(multiColumn.inOrderIds).toEqual([
290
- "A1",
291
- "A2",
292
- "A3",
293
- "B1",
294
- "B2",
295
- "C1",
296
- "C2",
297
- "C3",
298
- "C4",
299
- ]);
300
- });
301
-
302
- it("checks if it has only one column", () => {
303
- expect(multiColumn.hasOnlyOneColumn()).toBe(false);
304
- const singleColumn = MultiColumn.from([["A1", "A2"]]);
305
- expect(singleColumn.hasOnlyOneColumn()).toBe(true);
306
- });
307
-
308
- it("checks if it has only one id", () => {
309
- expect(multiColumn.hasOnlyOneId()).toBe(false);
310
- const singleId = MultiColumn.from([["A1"], ["B1"], ["C1"]]);
311
- expect(singleId.hasOnlyOneId()).toBe(false);
312
- const singleIdSingleColumn = MultiColumn.from([["A1"]]);
313
- expect(singleIdSingleColumn.hasOnlyOneId()).toBe(true);
314
- });
315
-
316
- it("adds a column", () => {
317
- const columnId = multiColumn.getColumns()[0].id;
318
- const newMultiColumn = multiColumn.addColumn(columnId);
319
- expect(newMultiColumn.colLength).toBe(4);
320
- expect(newMultiColumn.topLevelIds[1]).toEqual([]);
321
- });
322
-
323
- it("inserts a breakpoint", () => {
324
- const withBreakpoint = multiColumn.insertBreakpoint("C3");
325
- expect(withBreakpoint.colLength).toBe(4);
326
- expect(withBreakpoint.topLevelIds).toEqual([
327
- ["A1", "A2", "A3"],
328
- ["B1", "B2"],
329
- ["C1", "C2"],
330
- ["C3", "C4"],
331
- ]);
332
- });
333
-
334
- it("deletes a column", () => {
335
- const withoutBreakpoint = multiColumn.delete(columnIds[1]);
336
- expect(withoutBreakpoint.colLength).toBe(2);
337
- expect(withoutBreakpoint.topLevelIds).toEqual([
338
- ["A1", "A2", "A3", "B1", "B2"],
339
- ["C1", "C2", "C3", "C4"],
340
- ]);
341
- });
342
-
343
- it("deletes a column with only one column", () => {
344
- const singleColumn = MultiColumn.from([["A1", "A2"]]);
345
- const deleted = singleColumn.delete(columnIds[0]);
346
- expect(deleted.colLength).toBe(1);
347
- expect(deleted.topLevelIds).toEqual([["A1", "A2"]]);
348
- });
349
-
350
- it("deletes the first column", () => {
351
- const deleted = multiColumn.delete(columnIds[0]);
352
- expect(deleted.colLength).toBe(2);
353
- expect(deleted.topLevelIds).toEqual([
354
- ["B1", "B2", "A1", "A2", "A3"],
355
- ["C1", "C2", "C3", "C4"],
356
- ]);
357
- });
358
-
359
- it("merges all columns", () => {
360
- const merged = multiColumn.mergeAllColumns();
361
- expect(merged.colLength).toBe(1);
362
- expect(merged.topLevelIds).toEqual([
363
- ["A1", "A2", "A3", "B1", "B2", "C1", "C2", "C3", "C4"],
364
- ]);
365
- });
366
-
367
- it("moves a column", () => {
368
- const moved = multiColumn.moveColumn(columnIds[0], columnIds[2]);
369
- expect(moved.topLevelIds).toEqual([
370
- ["B1", "B2"],
371
- ["C1", "C2", "C3", "C4"],
372
- ["A1", "A2", "A3"],
373
- ]);
374
- });
375
-
376
- it("moves a column before", () => {
377
- const moved = multiColumn.moveColumn(columnIds[1], columnIds[0]);
378
- expect(moved.topLevelIds).toEqual([
379
- ["B1", "B2"],
380
- ["A1", "A2", "A3"],
381
- ["C1", "C2", "C3", "C4"],
382
- ]);
383
- });
384
-
385
- it("moves to the left", () => {
386
- const moved = multiColumn.moveColumn(columnIds[1], "_left_");
387
- expect(moved.topLevelIds).toEqual([
388
- ["B1", "B2"],
389
- ["A1", "A2", "A3"],
390
- ["C1", "C2", "C3", "C4"],
391
- ]);
392
- });
393
-
394
- it("moves to the right", () => {
395
- const moved = multiColumn.moveColumn(columnIds[1], "_right_");
396
- expect(moved.topLevelIds).toEqual([
397
- ["A1", "A2", "A3"],
398
- ["C1", "C2", "C3", "C4"],
399
- ["B1", "B2"],
400
- ]);
401
- });
402
-
403
- it("gets column with id", () => {
404
- const column = multiColumn.findWithId("B2");
405
- expect(multiColumn.indexOf(column)).toBe(1);
406
- expect(column.topLevelIds).toEqual(["B1", "B2"]);
407
- });
408
-
409
- it("transforms by id", () => {
410
- const transformed = multiColumn.transformWithCellId("B1", (tree) =>
411
- tree.delete("B1"),
412
- );
413
- expect(transformed.topLevelIds[1]).toEqual(["B2"]);
414
- });
415
-
416
- it("transforms all columns", () => {
417
- const transformed = multiColumn.transformAll((tree) =>
418
- tree.insertAtStart("NEW"),
419
- );
420
- expect(transformed.topLevelIds).toEqual([
421
- ["NEW", "A1", "A2", "A3"],
422
- ["NEW", "B1", "B2"],
423
- ["NEW", "C1", "C2", "C3", "C4"],
424
- ]);
425
- });
426
-
427
- it("inserts an id", () => {
428
- const inserted = multiColumn.insertId("D1", columnIds[1], 1 as CellIndex);
429
- expect(inserted.topLevelIds[1]).toEqual(["B1", "D1", "B2"]);
430
- });
431
-
432
- it("compacts", () => {
433
- const withEmpty = MultiColumn.from([["A1"], [], ["C1"], []]);
434
- const compacted = withEmpty.compact();
435
- expect(compacted.colLength).toBe(2);
436
- expect(compacted.topLevelIds).toEqual([["A1"], ["C1"]]);
437
- });
438
-
439
- it("handles errors", () => {
440
- expect(() => multiColumn.findWithId("Z1")).toThrow(
441
- "Cell Z1 not found in any column",
442
- );
443
- expect(multiColumn.colLength).toBeGreaterThan(2);
444
- expect(() => multiColumn.delete("123" as CellColumnId)).toThrow(
445
- /Column 123 not found/,
446
- );
447
- });
448
-
449
- it("checks if it's empty", () => {
450
- expect(multiColumn.isEmpty()).toBe(false);
451
- const emptyMultiColumn = MultiColumn.from([[]]);
452
- expect(emptyMultiColumn.isEmpty()).toBe(true);
453
- });
454
-
455
- it("gets columns", () => {
456
- const columns = multiColumn.getColumns();
457
- expect(columns.length).toBe(3);
458
- expect(columns[0].topLevelIds).toEqual(["A1", "A2", "A3"]);
459
- });
460
-
461
- it("gets index of a column", () => {
462
- const column = multiColumn.atOrThrow(1);
463
- const index = multiColumn.indexOf(column);
464
- expect(index).toBe(1);
465
- });
466
-
467
- it("handles at and atOrThrow", () => {
468
- expect(multiColumn.at(1)?.topLevelIds).toEqual(["B1", "B2"]);
469
- expect(multiColumn.atOrThrow(1).topLevelIds).toEqual(["B1", "B2"]);
470
- expect(multiColumn.at(5)).toBeUndefined();
471
- expect(() => multiColumn.atOrThrow(5)).toThrow("Column 5 not found");
472
- });
473
-
474
- it("handles inserting at out-of-bounds indices", () => {
475
- const multiColumn = MultiColumn.from([["A1"], ["B1"]]);
476
- const columnId = multiColumn.atOrThrow(1).id;
477
- const inserted = multiColumn.insertId("C1", columnId, 10 as CellIndex);
478
- expect(inserted.topLevelIds).toEqual([["A1"], ["B1", "C1"]]);
479
- });
480
-
481
- it("handles moving a column to its own position", () => {
482
- const multiColumn = MultiColumn.from([["A1"], ["B1"], ["C1"]]);
483
- const moved = multiColumn.moveColumn(columnIds[1], columnIds[1]);
484
- expect(moved.topLevelIds).toEqual([["A1"], ["B1"], ["C1"]]);
485
- });
486
-
487
- it("handles compacting when all columns are empty", () => {
488
- const multiColumn = MultiColumn.from([[], [], []]);
489
- const compacted = multiColumn.compact();
490
- expect(compacted.colLength).toBe(1);
491
- expect(compacted.isEmpty()).toBe(true);
492
- });
493
-
494
- it("handles transformById when id is not found", () => {
495
- const multiColumn = MultiColumn.from([["A1"], ["B1"]]);
496
- const transformed = multiColumn.transformWithCellId("C1", (tree) =>
497
- tree.insertAtEnd("C2"),
498
- );
499
- expect(transformed).toBe(multiColumn);
500
- });
501
-
502
- it("handles multiple operations in sequence", () => {
503
- let multiColumn = MultiColumn.from([
504
- ["A1", "A2"],
505
- ["B1", "B2"],
506
- ["C1", "C2"],
507
- ]);
508
- const columnIds = multiColumn.getColumns().map((c) => c.id);
509
- multiColumn = multiColumn.insertId("D1", columnIds[2], 1 as CellIndex);
510
- expect(multiColumn.topLevelIds).toEqual([
511
- ["A1", "A2"],
512
- ["B1", "B2"],
513
- ["C1", "D1", "C2"],
514
- ]);
515
- multiColumn = multiColumn.transformWithCellId("B1", (tree) =>
516
- tree.delete("B1"),
517
- );
518
- expect(multiColumn.topLevelIds).toEqual([
519
- ["A1", "A2"],
520
- ["B2"],
521
- ["C1", "D1", "C2"],
522
- ]);
523
- multiColumn = multiColumn.moveColumn(columnIds[0], columnIds[2]);
524
- expect(multiColumn.topLevelIds).toEqual([
525
- ["B2"],
526
- ["C1", "D1", "C2"],
527
- ["A1", "A2"],
528
- ]);
529
- multiColumn = multiColumn.compact();
530
- expect(multiColumn.topLevelIds).toEqual([
531
- ["B2"],
532
- ["C1", "D1", "C2"],
533
- ["A1", "A2"],
534
- ]);
535
- });
536
-
537
- it("handles setup cell existence", () => {
538
- const multiColumn = MultiColumn.from([["A1"], ["B1"], ["C1"]]);
539
- const columnIds = multiColumn.getColumnIds();
540
- expect(multiColumn.setupCellExists()).toBe(false);
541
- const multiColumn2 = multiColumn.insertId(SETUP_CELL_ID, columnIds[0], 0);
542
- expect(multiColumn2.setupCellExists()).toBe(true);
543
- const multiColumn3 = multiColumn2.transformWithCellId(
544
- SETUP_CELL_ID,
545
- (tree) => tree.delete(SETUP_CELL_ID),
546
- );
547
- expect(multiColumn3.setupCellExists()).toBe(false);
548
- });
549
-
550
- it("handles get method", () => {
551
- const column = multiColumn.get(columnIds[1]);
552
- expect(column?.topLevelIds).toEqual(["B1", "B2"]);
553
- });
554
-
555
- it("handles get method with non-existent column id", () => {
556
- const column = multiColumn.get("non-existent-id" as CellColumnId);
557
- expect(column).toBeUndefined();
558
- });
559
-
560
- it("handles indexOfOrThrow method", () => {
561
- expect(multiColumn.indexOfOrThrow(columnIds[1])).toBe(1);
562
- });
563
-
564
- it("handles indexOfOrThrow method with non-existent column id", () => {
565
- expect(() =>
566
- multiColumn.indexOfOrThrow("non-existent-id" as CellColumnId),
567
- ).toThrow("Column non-existent-id not found. Possible values: ");
568
- });
569
-
570
- it("handles transform method", () => {
571
- const transformed = multiColumn.transform(columnIds[1], (tree) =>
572
- tree.delete("B1"),
573
- );
574
- expect(transformed.topLevelIds[1]).toEqual(["B2"]);
575
- });
576
-
577
- it("handles transform method with non-existent column id", () => {
578
- const transformed = multiColumn.transform(
579
- "non-existent-id" as CellColumnId,
580
- (tree) => tree.delete("B2"),
581
- );
582
- const columns1 = multiColumn.getColumns();
583
- const columns2 = transformed.getColumns();
584
- const allEqual = columns1.every((c, i) => c.equals(columns2[i]));
585
- expect(allEqual).toBe(true);
586
- expect(transformed).toBe(multiColumn);
587
- });
588
-
589
- it("handles inserting a breakpoint at the start of a column", () => {
590
- const withBreakpoint = multiColumn.insertBreakpoint("A1");
591
- expect(withBreakpoint.colLength).toBe(4);
592
- expect(withBreakpoint.topLevelIds).toEqual([
593
- [],
594
- ["A1", "A2", "A3"],
595
- ["B1", "B2"],
596
- ["C1", "C2", "C3", "C4"],
597
- ]);
598
- });
599
-
600
- it("handles inserting a breakpoint at the end of a column", () => {
601
- const withBreakpoint = multiColumn.insertBreakpoint("A3");
602
- expect(withBreakpoint.colLength).toBe(4);
603
- expect(withBreakpoint.topLevelIds).toEqual([
604
- ["A1", "A2"],
605
- ["A3"],
606
- ["B1", "B2"],
607
- ["C1", "C2", "C3", "C4"],
608
- ]);
609
- });
610
-
611
- it("handles inserting a breakpoint in a single-item column", () => {
612
- const singleItemColumn = MultiColumn.from([["A1"], ["B1"], ["C1"]]);
613
- const withBreakpoint = singleItemColumn.insertBreakpoint("B1");
614
- expect(withBreakpoint.colLength).toBe(4);
615
- expect(withBreakpoint.topLevelIds).toEqual([["A1"], [], ["B1"], ["C1"]]);
616
- });
617
- });