|
| 1 | +import { |
| 2 | + createBlockSpec, |
| 3 | + createBlockSpecFromTiptapNode, |
| 4 | +} from "@blocknote/core"; |
| 5 | + |
| 6 | +import { ColumnResizeExtension } from "../../extensions/ColumnResize/ColumnResizeExtension.js"; |
1 | 7 | import { MultiColumnDropHandlerExtension } from "../../extensions/DropCursor/multiColumnHandleDropPlugin.js"; |
2 | | -import { Column } from "../../pm-nodes/Column.js"; |
3 | 8 | import { ColumnList } from "../../pm-nodes/ColumnList.js"; |
4 | 9 |
|
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; |
6 | 20 |
|
7 | | -export const ColumnBlock = createBlockSpecFromTiptapNode( |
| 21 | +export const ColumnBlock = createBlockSpec( |
8 | 22 | { |
9 | | - node: Column, |
10 | | - type: "column", |
| 23 | + type: "column" as const, |
| 24 | + propSchema: { |
| 25 | + width: { |
| 26 | + default: COLUMN_WIDTH_DEFAULT, |
| 27 | + }, |
| 28 | + }, |
11 | 29 | 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 }, |
12 | 35 | }, |
13 | 36 | { |
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 | + }; |
16 | 71 | }, |
17 | 72 | }, |
18 | | - [MultiColumnDropHandlerExtension()], |
19 | | -); |
| 73 | + [MultiColumnDropHandlerExtension(), ColumnResizeExtension()], |
| 74 | +)(); |
20 | 75 |
|
21 | 76 | export const ColumnListBlock = createBlockSpecFromTiptapNode( |
22 | 77 | { |
|
0 commit comments