Skip to content

Commit f2d3ff4

Browse files
committed
feat: migrate columns to use container API
1 parent 56f0c8f commit f2d3ff4

5 files changed

Lines changed: 75 additions & 110 deletions

File tree

packages/xl-multi-column/src/blocks/Columns/index.ts

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,77 @@
1+
import {
2+
createBlockSpec,
3+
createBlockSpecFromTiptapNode,
4+
} from "@blocknote/core";
5+
6+
import { ColumnResizeExtension } from "../../extensions/ColumnResize/ColumnResizeExtension.js";
17
import { MultiColumnDropHandlerExtension } from "../../extensions/DropCursor/multiColumnHandleDropPlugin.js";
2-
import { Column } from "../../pm-nodes/Column.js";
38
import { ColumnList } from "../../pm-nodes/ColumnList.js";
49

5-
import { createBlockSpecFromTiptapNode } from "@blocknote/core";
10+
// Why does each column have a default width of 1, i.e. 100%? Because when
11+
// creating a new column, we want to make sure that existing column widths are
12+
// preserved, while the new one also has a sensible width. If we set it so all
13+
// column widths must add up to 100% instead, then each time a new column is
14+
// created, we'd have to assign it a width depending on the total number of
15+
// columns and also adjust the widths of the others. The same can be said for
16+
// using px instead of percent widths and making them add to the editor width.
17+
// Using flex-grow on the value handles all the resizing for us, instead of
18+
// manually having to set `width` on each column.
19+
const COLUMN_WIDTH_DEFAULT = 1;
620

7-
export const ColumnBlock = createBlockSpecFromTiptapNode(
21+
export const ColumnBlock = createBlockSpec(
822
{
9-
node: Column,
10-
type: "column",
23+
type: "column" as const,
24+
propSchema: {
25+
width: {
26+
default: COLUMN_WIDTH_DEFAULT,
27+
},
28+
},
1129
content: "none",
30+
// Columns only ever live inside a `columnList` (whose content expression
31+
// is `column column+`). `topLevel: false` keeps column out of the
32+
// generic `blockGroupChild` group so it can't be inserted at the document
33+
// root or as a child of any other block.
34+
container: { topLevel: false },
1235
},
1336
{
14-
width: {
15-
default: 1,
37+
render: (block) => {
38+
const dom = document.createElement("div");
39+
dom.className = "bn-block-column";
40+
const width = block.props.width ?? COLUMN_WIDTH_DEFAULT;
41+
dom.style.flexGrow = String(width);
42+
dom.setAttribute("data-node-type", "column");
43+
dom.setAttribute("data-id", block.id);
44+
if (width !== COLUMN_WIDTH_DEFAULT) {
45+
dom.setAttribute("data-width", String(width));
46+
}
47+
48+
return {
49+
dom,
50+
contentDOM: dom,
51+
update: (newNode: {
52+
type: { name: string };
53+
attrs: { id?: string; width?: number };
54+
}) => {
55+
if (newNode.type.name !== "column") {
56+
return false;
57+
}
58+
const newWidth = newNode.attrs.width ?? COLUMN_WIDTH_DEFAULT;
59+
dom.style.flexGrow = String(newWidth);
60+
if (newWidth !== COLUMN_WIDTH_DEFAULT) {
61+
dom.setAttribute("data-width", String(newWidth));
62+
} else {
63+
dom.removeAttribute("data-width");
64+
}
65+
if (newNode.attrs.id) {
66+
dom.setAttribute("data-id", newNode.attrs.id);
67+
}
68+
return true;
69+
},
70+
};
1671
},
1772
},
18-
[MultiColumnDropHandlerExtension()],
19-
);
73+
[MultiColumnDropHandlerExtension(), ColumnResizeExtension()],
74+
)();
2075

2176
export const ColumnListBlock = createBlockSpecFromTiptapNode(
2277
{

packages/xl-multi-column/src/extensions/ColumnResize/ColumnResizeExtension.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import { BlockNoteEditor, getNodeById } from "@blocknote/core";
1+
import {
2+
BlockNoteEditor,
3+
createExtension,
4+
getNodeById,
5+
} from "@blocknote/core";
26
import { SideMenuExtension } from "@blocknote/core/extensions";
3-
import { Extension } from "@tiptap/core";
47
import { Node } from "prosemirror-model";
58
import { Plugin, PluginKey, PluginView } from "prosemirror-state";
69
import { Decoration, DecorationSet, EditorView } from "prosemirror-view";
@@ -356,12 +359,7 @@ const createColumnResizePlugin = (editor: BlockNoteEditor<any, any, any>) =>
356359
view: (view) => new ColumnResizePluginView(editor, view),
357360
});
358361

359-
export const createColumnResizeExtension = (
360-
editor: BlockNoteEditor<any, any, any>,
361-
) =>
362-
Extension.create({
363-
name: "columnResize",
364-
addProseMirrorPlugins() {
365-
return [createColumnResizePlugin(editor)];
366-
},
367-
});
362+
export const ColumnResizeExtension = createExtension(({ editor }) => ({
363+
key: "columnResize",
364+
prosemirrorPlugins: [createColumnResizePlugin(editor)],
365+
}));

packages/xl-multi-column/src/pm-nodes/Column.ts

Lines changed: 0 additions & 88 deletions
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<div class="bn-block-column-list" data-node-type="columnList" data-id="1" style="display: flex;"><div class="bn-block-column" data-node-type="column" data-id="2" data-width="1" style="flex-grow: 1;" data-nesting-level="1"><p data-nesting-level="2">Column Paragraph 0</p><p data-nesting-level="2">Column Paragraph 1</p></div><div class="bn-block-column" data-node-type="column" data-id="5" data-width="1" style="flex-grow: 1;" data-nesting-level="1"><p data-nesting-level="2">Column Paragraph 2</p><p data-nesting-level="2">Column Paragraph 3</p></div></div>
1+
<div class="bn-block-column-list" data-node-type="columnList" data-id="1" style="display: flex;"><div class="bn-block-column" style="flex-grow: 1;" data-node-type="column" data-id="2" data-nesting-level="1"><p data-nesting-level="2">Column Paragraph 0</p><p data-nesting-level="2">Column Paragraph 1</p></div><div class="bn-block-column" style="flex-grow: 1;" data-node-type="column" data-id="5" data-nesting-level="1"><p data-nesting-level="2">Column Paragraph 2</p><p data-nesting-level="2">Column Paragraph 3</p></div></div>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-column-list" data-node-type="columnList" data-id="1" style="display: flex;"><div class="bn-block-column" data-node-type="column" data-id="2" data-width="1" style="flex-grow: 1;"><div class="bn-block-outer" data-node-type="blockOuter" data-id="3"><div class="bn-block" data-node-type="blockContainer" data-id="3"><div class="bn-block-content" data-content-type="paragraph"><p class="bn-inline-content">Column Paragraph 0</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="4"><div class="bn-block" data-node-type="blockContainer" data-id="4"><div class="bn-block-content" data-content-type="paragraph"><p class="bn-inline-content">Column Paragraph 1</p></div></div></div></div><div class="bn-block-column" data-node-type="column" data-id="5" data-width="1" style="flex-grow: 1;"><div class="bn-block-outer" data-node-type="blockOuter" data-id="6"><div class="bn-block" data-node-type="blockContainer" data-id="6"><div class="bn-block-content" data-content-type="paragraph"><p class="bn-inline-content">Column Paragraph 2</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="7"><div class="bn-block" data-node-type="blockContainer" data-id="7"><div class="bn-block-content" data-content-type="paragraph"><p class="bn-inline-content">Column Paragraph 3</p></div></div></div></div></div></div>
1+
<div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-column-list" data-node-type="columnList" data-id="1" style="display: flex;"><div class="bn-block-column" style="flex-grow: 1;" data-node-type="column" data-id="2"><div class="bn-block-outer" data-node-type="blockOuter" data-id="3"><div class="bn-block" data-node-type="blockContainer" data-id="3"><div class="bn-block-content" data-content-type="paragraph"><p class="bn-inline-content">Column Paragraph 0</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="4"><div class="bn-block" data-node-type="blockContainer" data-id="4"><div class="bn-block-content" data-content-type="paragraph"><p class="bn-inline-content">Column Paragraph 1</p></div></div></div></div><div class="bn-block-column" style="flex-grow: 1;" data-node-type="column" data-id="5"><div class="bn-block-outer" data-node-type="blockOuter" data-id="6"><div class="bn-block" data-node-type="blockContainer" data-id="6"><div class="bn-block-content" data-content-type="paragraph"><p class="bn-inline-content">Column Paragraph 2</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="7"><div class="bn-block" data-node-type="blockContainer" data-id="7"><div class="bn-block-content" data-content-type="paragraph"><p class="bn-inline-content">Column Paragraph 3</p></div></div></div></div></div></div>

0 commit comments

Comments
 (0)