Skip to content

Commit 1a6fd03

Browse files
rjvelazcospbolton
authored andcommitted
fix: resolve GridColumn schema error when block types are restricted via Settings (#35035)
This PR fixes: #35032 ## Root Cause When the Block Editor's **Settings tab** is used to restrict which block types are allowed, TipTap's `StarterKit` removes the disabled node types from the schema entirely at initialization time. The original `GridColumn` node had a **static content expression** that referenced all possible node types: ``` (paragraph | heading | bulletList | orderedList | codeBlock | blockquote | table | horizontalRule | dotImage | dotVideo | dotContent)+ ``` If any of those types were disabled (e.g. `blockquote`), StarterKit would remove them from the schema, but `GridColumn.content` would still reference them. TipTap throws a schema validation error on init, causing the editor to render as a blank blue button instead of the full editing surface. ## Fix `GridColumn` is converted from a static export to a factory function `createGridColumn(allowedBlocks)` that **dynamically builds the content expression** based on the blocks actually registered in the schema. This ensures `GridColumn` never references a node type that StarterKit has removed. `DotBlockEditorComponent` now calls `createGridColumn(this.allowedBlocks)` at extension initialization time, passing the active allowed list. The original `GridColumn` constant is preserved as a default export (`createGridColumn()` with no args) to avoid breaking other consumers. ## Changes - `grid-column.node.ts` — converts static node to `createGridColumn(allowedBlocks)` factory; adds `buildGridColumnContent()` to derive the TipTap content expression from the allowed list - `dot-block-editor.component.ts` — replaces static `GridColumn` with `createGridColumn(this.allowedBlocks)` - `index.ts` — exports both `GridColumn` (backwards compat) and `createGridColumn` ### Video https://github.com/user-attachments/assets/61727785-0dcf-4824-bb89-64debfa9468b
1 parent 7f82334 commit 1a6fd03

3 files changed

Lines changed: 74 additions & 23 deletions

File tree

core-web/libs/block-editor/src/lib/components/dot-block-editor/dot-block-editor.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ import {
6969
import {
7070
AIContentNode,
7171
ContentletBlock,
72+
createGridColumn,
7273
GridBlock,
73-
GridColumn,
7474
ImageNode,
7575
LoaderNode,
7676
VideoNode
@@ -645,7 +645,7 @@ export class DotBlockEditorComponent implements OnInit, OnChanges, OnDestroy, Co
645645
}),
646646
...DotCMSTableExtensions,
647647
DotTableCellContextMenu(this.viewContainerRef),
648-
GridColumn
648+
createGridColumn(this.allowedBlocks.length > 1 ? this.allowedBlocks : [])
649649
];
650650

651651
if (isAIPluginInstalled) {
Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,74 @@
11
import { Node } from '@tiptap/core';
22

3-
export const GridColumn = Node.create({
4-
name: 'gridColumn',
5-
group: 'gridColumn',
6-
// gridBlock is intentionally excluded to prevent nested grids.
7-
// Nested grid support requires a more robust resize implementation.
8-
content:
9-
'(paragraph | heading | bulletList | orderedList | codeBlock | blockquote | table | horizontalRule | dotImage | dotVideo | dotContent)+',
10-
isolating: true,
11-
12-
parseHTML() {
13-
return [{ tag: 'div[data-type="gridColumn"]' }];
14-
},
15-
16-
renderHTML({ HTMLAttributes }) {
17-
return [
18-
'div',
19-
{ ...HTMLAttributes, 'data-type': 'gridColumn', class: 'grid-block__column' },
20-
0
21-
];
3+
// Maps allowedBlocks keys to their TipTap node names for grid column content.
4+
// Custom nodes such as `aiContent` and `loader` are intentionally absent — they are
5+
// editor-level utilities that do not make sense inside a grid column and are not
6+
// registered as StarterKit node types.
7+
const GRID_COLUMN_CONTENT_MAP: Record<string, string> = {
8+
heading: 'heading',
9+
bulletList: 'bulletList',
10+
orderedList: 'orderedList',
11+
codeBlock: 'codeBlock',
12+
blockquote: 'blockquote',
13+
table: 'table',
14+
horizontalRule: 'horizontalRule',
15+
image: 'dotImage',
16+
video: 'dotVideo',
17+
dotContent: 'dotContent'
18+
};
19+
20+
const ALL_NODE_TYPES = Object.values(GRID_COLUMN_CONTENT_MAP);
21+
const DEFAULT_CONTENT = `(paragraph | ${ALL_NODE_TYPES.join(' | ')})+`;
22+
23+
/**
24+
* Builds the TipTap content expression for GridColumn based on the allowed blocks.
25+
* This is necessary because StarterKit removes disabled node types from the schema at init time,
26+
* so a static content expression that references a removed node (e.g. `blockquote`) causes
27+
* a schema validation error. By deriving the expression from `allowedBlocks`, we ensure
28+
* GridColumn only references nodes that are actually registered in the schema.
29+
*/
30+
function buildGridColumnContent(allowedBlocks: string[]): string {
31+
if (!allowedBlocks.length) {
32+
return DEFAULT_CONTENT;
33+
}
34+
35+
const headingAllowed = allowedBlocks.some((b) => b.startsWith('heading'));
36+
// `paragraph` is always included — StarterKit always registers it and
37+
// DotBlockEditorComponent seeds allowedBlocks with ['paragraph'] at initialization.
38+
const nodeTypes = ['paragraph'];
39+
40+
for (const [key, nodeType] of Object.entries(GRID_COLUMN_CONTENT_MAP)) {
41+
if (key === 'heading') {
42+
if (headingAllowed) nodeTypes.push(nodeType);
43+
} else if (allowedBlocks.includes(key)) {
44+
nodeTypes.push(nodeType);
45+
}
2246
}
23-
});
47+
48+
return `(${nodeTypes.join(' | ')})+`;
49+
}
50+
51+
export function createGridColumn(allowedBlocks: string[] = []) {
52+
return Node.create({
53+
name: 'gridColumn',
54+
group: 'gridColumn',
55+
// gridBlock is intentionally excluded to prevent nested grids.
56+
// Nested grid support requires a more robust resize implementation.
57+
content: buildGridColumnContent(allowedBlocks),
58+
isolating: true,
59+
60+
parseHTML() {
61+
return [{ tag: 'div[data-type="gridColumn"]' }];
62+
},
63+
64+
renderHTML({ HTMLAttributes }) {
65+
return [
66+
'div',
67+
{ ...HTMLAttributes, 'data-type': 'gridColumn', class: 'grid-block__column' },
68+
0
69+
];
70+
}
71+
});
72+
}
73+
74+
export const GridColumn = createGridColumn();
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export { GridBlock } from './grid-block.node';
2-
export { GridColumn } from './grid-column.node';
2+
export { GridColumn, createGridColumn } from './grid-column.node';
33
export { GridResizePlugin, GRID_RESIZE_PLUGIN_KEY } from './grid-resize.plugin';

0 commit comments

Comments
 (0)