|
1 | | -import { ResolvedPos, Slice, type Node } from "prosemirror-model"; |
| 1 | +import { Fragment, ResolvedPos, Slice, type Node } from "prosemirror-model"; |
2 | 2 | import { TextSelection, type Transaction } from "prosemirror-state"; |
3 | 3 | import { ReplaceAroundStep } from "prosemirror-transform"; |
4 | 4 | import type { Block, PartialBlock } from "../../../../blocks/defaultBlocks.js"; |
@@ -235,6 +235,73 @@ export function removeAndInsertBlocks< |
235 | 235 | $newPos.pos + $newPos.nodeAfter!.nodeSize, |
236 | 236 | Slice.empty, |
237 | 237 | ); |
| 238 | + } else if ( |
| 239 | + $pos.node().type.name === "columnList" && |
| 240 | + $pos.node().childCount === 2 |
| 241 | + ) { |
| 242 | + // Checks whether removing the entire column would leave only a single |
| 243 | + // remaining `column` node in the columnList. In this case, we need to |
| 244 | + // collapse the column list. |
| 245 | + const column = getBlockInfoFromResolvedPos($pos); |
| 246 | + if (column.blockNoteType !== "column") { |
| 247 | + throw new Error( |
| 248 | + `Block of type ${column.blockNoteType} was found as child of columnList.`, |
| 249 | + ); |
| 250 | + } |
| 251 | + const columnList = getParentBlockInfo(tr.doc, column.bnBlock.beforePos); |
| 252 | + if (!columnList) { |
| 253 | + throw new Error( |
| 254 | + `Block of type column was found without a parent columnList.`, |
| 255 | + ); |
| 256 | + } |
| 257 | + if (columnList?.blockNoteType !== "columnList") { |
| 258 | + throw new Error( |
| 259 | + `Block of type ${columnList.blockNoteType} was found as a parent of column.`, |
| 260 | + ); |
| 261 | + } |
| 262 | + |
| 263 | + if ($pos.node().childCount === 1) { |
| 264 | + tr.replaceWith( |
| 265 | + columnList.bnBlock.beforePos, |
| 266 | + columnList.bnBlock.afterPos, |
| 267 | + Fragment.empty, |
| 268 | + ); |
| 269 | + } |
| 270 | + |
| 271 | + tr.replaceWith( |
| 272 | + columnList.bnBlock.beforePos, |
| 273 | + columnList.bnBlock.afterPos, |
| 274 | + $pos.index() === 0 |
| 275 | + ? columnList.bnBlock.node.lastChild!.content |
| 276 | + : columnList.bnBlock.node.firstChild!.content, |
| 277 | + ); |
| 278 | + } else if ( |
| 279 | + node.type.name === "column" && |
| 280 | + node.attrs.id !== $pos.nodeAfter?.attrs.id |
| 281 | + ) { |
| 282 | + // This is a hacky work around to handle an edge case with the previous |
| 283 | + // `if else` block. When each `column` of a `columnList` is in the |
| 284 | + // `blocksToRemove` array, this is what happens once all but the last 2 |
| 285 | + // columns are removed: |
| 286 | + // |
| 287 | + // 1. The second-to-last `column` is removed. |
| 288 | + // 2. The last `column` and wrapping `columnList` are collapsed. |
| 289 | + // 3. `removedSize` increases by the size of the removed column, and more |
| 290 | + // due to positions at the starts/ends of the last `column` and wrapping |
| 291 | + // `columnList` also getting removed. |
| 292 | + // 3. `tr.doc.descendants` traverses to the last `column`. |
| 293 | + // 4. `removedSize` now includes positions that were removed after the |
| 294 | + // last `column`. In order for `pos - removedSize` to correctly point to |
| 295 | + // the start of the nodes that were previously wrapped by the last |
| 296 | + // `column`, `removedPos` must only include positions removed before it. |
| 297 | + // 5. The deletion is offset by 3, because of those removed positions |
| 298 | + // included in `removedSize` that occur after the last `column`. |
| 299 | + // |
| 300 | + // Hence why we have to shift the start of the deletion range back by 3. |
| 301 | + // The offset for the end of the range is smaller as `node.nodeSize` is |
| 302 | + // the size of the whole second `column`, whereas now we are left with |
| 303 | + // just its children since it's collapsed - a difference of 2 positions. |
| 304 | + tr.delete(pos - removedSize + 3, pos - removedSize + node.nodeSize + 1); |
238 | 305 | } else if ( |
239 | 306 | $pos.node().type.name === "blockGroup" && |
240 | 307 | $pos.node($pos.depth - 1).type.name !== "doc" && |
|
0 commit comments