Skip to content

feat: add grid block with two-column layout to block editor#34789

Merged
fmontes merged 302 commits intomainfrom
issue-33882-grid-block
Mar 6, 2026
Merged

feat: add grid block with two-column layout to block editor#34789
fmontes merged 302 commits intomainfrom
issue-33882-grid-block

Conversation

@fmontes
Copy link
Member

@fmontes fmontes commented Feb 26, 2026

Summary

  • Adds a new gridBlock TipTap node with two-column layout, following the same pure-node pattern as tables (no Angular components needed)
  • Each column (gridColumn) supports independent nested blocks (paragraphs, headings, images, lists, etc.)
  • Includes CSS Grid styling with dashed borders, focus highlighting, and drag support
  • Integrates into the slash menu as "Grid (2 columns)" and supports Tab/Shift-Tab column navigation

Test plan

  • Open block editor, type / and search for "Grid" — should see "Grid (2 columns)"
  • Select it — should insert a two-column grid with dashed borders
  • Type in each column independently — content should stay in its column
  • Add headings, images, lists inside columns — should work normally
  • Tab between columns — should navigate left→right, Shift-Tab right→left
  • Drag the grid block — should move the entire grid
  • Backspace in a column — should not delete the column itself

🤖 Generated with Claude Code

This PR fixes: #33882

fmontes and others added 30 commits December 12, 2025 22:38
…d virtual scroller initialization for improved user experience
…ze and minHeight properties for better layout control
…d user experience and enhance dropdown options management
…nsive scenarios including lazy loading, filtering, and pinned option functionality
… for improved consistency and functionality across the application
…nput bindings and adding output emission tests for improved coverage
…unnecessary disabled input binding and focusing on FormControl state
…g unused provideNoopAnimations and maintaining essential testing utilities
…t by refining input handling, enhancing output emissions, and ensuring proper state management during filtering and lazy loading
…elect options and improving event handling for better user interaction
…clarify synchronization with ControlValueAccessor and state fetching for content and site objects
…to clear debounce timeout for improved resource management
…t and site fetching logic, ensuring no duplicate API calls for already loaded items
…d improve state management by removing unnecessary logic and enhancing readability
…lity, including lazy loading, filtering, and improved state management
…otThemeComponent for improved theme selection integration
…nt and its associated files to streamline theme selection process
…electorComponent with DotSiteComponent and enhance mock service for site retrieval
…d services and improving mock configurations
…ce and improving event handling for dot-site component
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 94 out of 95 changed files in this pull request and generated 10 comments.

Comments suppressed due to low confidence (1)

core-web/libs/portlets/dot-content-drive/portlet/src/lib/components/dot-content-drive-toolbar/dot-content-drive-toolbar.component.html:14

  • Same issue here: [class] overwrites the element’s entire class list, so the static classes (grid items-center w-full ...) can be lost. Use [ngClass] to add these grid-cols values without overriding other classes.

fmontes and others added 3 commits February 27, 2026 22:08
Reverts changes to dot-analytics and dot-content-drive portlets that
were not part of the grid block feature work.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@claude
Copy link
Contributor

claude bot commented Mar 3, 2026

Claude finished @fmontes's task —— View job


Grid Block PR Security & Design Review

🔴 Critical Security Issue

XSS Vulnerability in Velocity Template (gridBlock.vtl:24)

The Velocity template properly validates and escapes the span value to prevent XSS injection:

## Validate span is a number between 1 and 12 to prevent XSS injection
#if($rawSpan && $rawSpan.toString().matches("^[0-9]+$") && $rawSpan >= 1 && $rawSpan <= 12)
#set($span = $rawSpan)
#else
#set($span = 6)
#end

✅ This XSS concern has been properly addressed. The template validates that span values are numeric (1-12) and falls back to safe defaults, preventing injection attacks.

Frontend Validation Analysis

The frontend implementations also properly validate column arrays:

React SDK (GridBlock.tsx:23-28):

const cols = rawCols.length === 2 && 
    rawCols.every((v: unknown) => typeof v === 'number' && Number.isFinite(v))
    ? rawCols : [6, 6];

Angular SDK (grid-block.component.ts:41-45):

const cols = rawCols.length === 2 && 
    rawCols.every((v: unknown) => typeof v === 'number' && Number.isFinite(v))
    ? rawCols : [6, 6];

Both implementations validate that columns are exactly 2 finite numbers and fall back to [6, 6].

Design & Implementation Issues

  1. Grid Constraint Logic (grid-resize.plugin.ts:8-12):

    • The snapToGrid function properly constrains columns to 1-11 range
    • Correctly ensures the two columns sum to 12
  2. DOM Position Finding (grid-resize.plugin.ts:17-43):

    • Robust error handling with try-catch blocks
    • Proper boundary checking for document positions
  3. Navigation Logic (Tab/Shift-Tab in grid-block.node.ts:157-242):

    • Complex but thorough column index detection
    • Proper cursor positioning between columns
  4. Empty Grid Deletion (grid-block.node.ts:118-156):

    • Correctly detects when both columns are empty paragraphs
    • Safely replaces grid with empty paragraph

Minor Issues

  • React Component has unused children prop in interface (noted by Copilot)
  • Column validation is duplicated across React/Angular - could be extracted to shared utility
  • CSS Grid vs percentage styling: Frontend uses percentages while backend uses grid-column: span N - both work but inconsistent

Summary

The implementation is secure and well-designed. The critical XSS vulnerability flagged by Copilot has been properly addressed with input validation and sanitization. The grid resizing, navigation, and rendering logic is robust with good error handling and fallbacks.


- Replace CSS custom properties and hardcoded values with Tailwind @apply
- Move styles to :host selector, removing unnecessary top-level wrapper divs
- Wrap naked ::ng-deep selectors in :host to prevent style leakage
- Use @reference instead of @import for Tailwind in component CSS files to avoid bundle bloat
- Apply same @reference fix to template-builder component CSS files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Contributor

claude bot commented Mar 5, 2026

Claude finished @fmontes's task —— View job


Grid Block PR Review

Todo List:

  • Review security aspects of the implementation
  • Check input validation and edge case handling
  • Review frontend SDK implementations (React/Angular)
  • Examine TipTap node implementation and plugins
  • Review CSS-to-utility migration patterns
  • Check for potential design/architecture issues

Critical Issues Found

🔴 CSS Styling Inconsistencies

The implementation uses three different CSS Grid approaches across different contexts, creating inconsistency and potential rendering issues:

  1. Backend Velocity Template (gridBlock.vtl:10): Uses grid-template-columns: repeat(12, 1fr) with grid-column: span N
  2. Frontend SDKs (React/Angular): Calculate percentages and use grid-template-columns: X% Y%
  3. TipTap Editor CSS: Uses flexbox with CSS variables --col-1 and --col-2 percentages

This inconsistency means the same content will render differently in the editor vs. frontend vs. backend, breaking WYSIWYG expectations.

🟡 Input Validation Issues

Division by Zero Risk (grid-resize.plugin.ts:183):

const usableWidth = gridRect.width - gap;
currentRatio = Math.min(11/12, Math.max(1/12, startRatio + deltaX / usableWidth));

If gridRect.width equals gap, usableWidth becomes 0, causing NaN in ratio calculations.

Precision Issues (grid-block.node.ts:44-45, GridBlock.tsx:29-30):

const pct1 = (cols[0] / 12) * 100; // Can produce 33.333333333% 
const pct2 = (cols[1] / 12) * 100;

Long decimal percentages create inconsistent styling. Should use toFixed(2) for clean output.

🟡 Potential Memory Issues

DOM Manipulation Without Cleanup (grid-resize.plugin.ts:86-88):

const editorParent = view.dom.parentElement;
if (editorParent) {
    editorParent.style.position = 'relative'; // Modifies parent styling permanently
}

The plugin modifies parent element styling but never resets it, potentially affecting other components.

🟡 Design Issues

Generic CSS Classes (grid-block.node.ts:63):

class: 'grid-block' // Too generic, could conflict with other grid implementations

Should use more specific prefixed classes like dot-grid-block to avoid conflicts.

Hardcoded Column Limit (grid-block.node.ts:18):

content: 'gridColumn gridColumn', // Fixed to exactly 2 columns

The content spec hardcodes 2 columns but the plugin name suggests it could be extensible. This creates misleading architecture.

🟡 Edge Case Issues

Navigation Logic Complexity (grid-block.node.ts:167-183):
The Tab/Shift-Tab navigation uses complex position calculations that could break with nested structures or dynamic content changes.

Empty Grid Deletion (grid-block.node.ts:128-136):
The deletion logic only checks for empty paragraphs but doesn't handle other empty nodes (lists, headings, etc.) that might be considered "empty content."

Minor Issues

  • Unused Props: React component has unused children prop in interface
  • Code Duplication: Column validation logic duplicated across React/Angular
  • Mixed Units: Some CSS uses px, others use rem - inconsistent with design system standards

Positive Aspects

Security: XSS vulnerability properly addressed with input validation and escaping
Error Handling: Good try-catch blocks and null checking in resize plugin
Accessibility: Proper keyboard navigation with Tab/Shift-Tab support


Recommendation: Address the CSS styling inconsistencies before merging as they break the WYSIWYG principle. The different rendering approaches need to be unified across all contexts.

…ind utilities

Replace dotCMS CSS custom properties with PrimeNG-mapped Tailwind utilities:
- var(--gray-N) → surface-N (tailwindcss-primeui surface palette)
- var(--color-palette-primary-N) → primary-N (PrimeNG primary palette)
- var(--color-palette-primary-op-N) → color-mix() for opacity variants
- All layout properties converted to @apply directives
- Added @reference imports for tailwindcss and tailwindcss-primeui

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Contributor

claude bot commented Mar 5, 2026

Claude finished @fmontes's task —— View job


Grid Block PR Review

Reviewing the grid block implementation for security issues, edge cases, and design problems.

Todo List:

  • Review core grid block implementation files
  • Check Velocity template for XSS vulnerabilities
  • Examine frontend SDK implementations (React/Angular)
  • Review TipTap node implementation and resize plugin
  • Check CSS styling consistency across contexts
  • Summarize critical findings

Critical Issues Found

🔴 CSS Styling Inconsistencies

The implementation uses three different CSS Grid approaches across different contexts, creating inconsistency and potential rendering issues:

  1. Backend Velocity Template (gridBlock.vtl:10): Uses grid-template-columns: repeat(12, 1fr) with grid-column: span N
  2. Frontend SDKs (React/Angular): Calculate percentages and use grid-template-columns: X% Y%
  3. TipTap Editor CSS: Uses flexbox with CSS variables --col-1 and --col-2 percentages

This inconsistency means the same content will render differently in the editor vs. frontend vs. backend, breaking WYSIWYG expectations.

🟡 Input Validation Issues

Division by Zero Risk (grid-resize.plugin.ts:183):

const usableWidth = gridRect.width - gap;
currentRatio = Math.min(11/12, Math.max(1/12, startRatio + deltaX / usableWidth));

If gridRect.width equals gap, usableWidth becomes 0, causing NaN in ratio calculations.

Precision Issues (grid-block.node.ts:44-45, GridBlock.tsx:29-30):

const pct1 = (cols[0] / 12) * 100; // Can produce 33.333333333% 
const pct2 = (cols[1] / 12) * 100;

Long decimal percentages create inconsistent styling. Should use toFixed(2) for clean output.

🟡 Potential Memory Issues

DOM Manipulation Without Cleanup (grid-resize.plugin.ts:86-88):

const editorParent = view.dom.parentElement;
if (editorParent) {
    editorParent.style.position = 'relative'; // Modifies parent styling permanently
}

The plugin modifies parent element styling but never resets it, potentially affecting other components.

🟡 Design Issues

Generic CSS Classes (grid-block.node.ts:63):

class: 'grid-block' // Too generic, could conflict with other grid implementations

Should use more specific prefixed classes like dot-grid-block to avoid conflicts.

Hardcoded Column Limit (grid-block.node.ts:18):

content: 'gridColumn gridColumn', // Fixed to exactly 2 columns

The content spec hardcodes 2 columns but the plugin name suggests it could be extensible. This creates misleading architecture.

🟡 Edge Case Issues

Navigation Logic Complexity (grid-block.node.ts:167-183):
The Tab/Shift-Tab navigation uses complex position calculations that could break with nested structures or dynamic content changes.

Empty Grid Deletion (grid-block.node.ts:128-136):
The deletion logic only checks for empty paragraphs but doesn't handle other empty nodes (lists, headings, etc.) that might be considered "empty content."

Minor Issues

  • Unused Props: React component has unused children prop in interface
  • Code Duplication: Column validation logic duplicated across React/Angular
  • Mixed Units: Some CSS uses px, others use rem - inconsistent with design system standards

Positive Aspects

Security: XSS vulnerability properly addressed with input validation and escaping
Error Handling: Good try-catch blocks and null checking in resize plugin
Accessibility: Proper keyboard navigation with Tab/Shift-Tab support


Recommendation: Address the CSS styling inconsistencies before merging as they break the WYSIWYG principle. The different rendering approaches need to be unified across all contexts.


… properties

Replace dotCMS CSS variables with PrimeNG tokens in _tables.css and _prosemirror.css:
- var(--gray-N) → var(--p-surface-N)
- var(--color-palette-primary-N) → var(--p-primary-N)
- var(--color-palette-primary-op-N) → color-mix() for opacity variants
- Add comments explaining why @apply cannot be used in plain CSS partials

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Contributor

claude bot commented Mar 5, 2026

Claude finished @fmontes's task —— View job


Critical Issues Found

🔴 CSS Styling Inconsistencies

The implementation uses three different CSS Grid approaches across different contexts, creating inconsistency and potential rendering issues:

  1. Backend Velocity Template (gridBlock.vtl:10): Uses grid-template-columns: repeat(12, 1fr) with grid-column: span N
  2. Frontend SDKs (React/Angular): Calculate percentages and use grid-template-columns: X% Y%
  3. TipTap Editor CSS: Uses flexbox with CSS variables --col-1 and --col-2 percentages

This inconsistency means the same content will render differently in the editor vs. frontend vs. backend, breaking WYSIWYG expectations.

🟡 Input Validation Issues

Division by Zero Risk (grid-resize.plugin.ts:183):

const usableWidth = gridRect.width - gap;
currentRatio = Math.min(11/12, Math.max(1/12, startRatio + deltaX / usableWidth));

If gridRect.width equals gap, usableWidth becomes 0, causing NaN in ratio calculations.

Precision Issues (grid-block.node.ts:44-45, GridBlock.tsx:29-30):

const pct1 = (cols[0] / 12) * 100; // Can produce 33.333333333% 
const pct2 = (cols[1] / 12) * 100;

Long decimal percentages create inconsistent styling. Should use toFixed(2) for clean output.

🟡 Potential Memory Issues

DOM Manipulation Without Cleanup (grid-resize.plugin.ts:86-88):

const editorParent = view.dom.parentElement;
if (editorParent) {
    editorParent.style.position = 'relative'; // Modifies parent styling permanently
}

The plugin modifies parent element styling but never resets it, potentially affecting other components.

🟡 Design Issues

Generic CSS Classes (grid-block.node.ts:63):

class: 'grid-block' // Too generic, could conflict with other grid implementations

Should use more specific prefixed classes like dot-grid-block to avoid conflicts.

Hardcoded Column Limit (grid-block.node.ts:18):

content: 'gridColumn gridColumn', // Fixed to exactly 2 columns

The content spec hardcodes 2 columns but the plugin name suggests it could be extensible. This creates misleading architecture.

🟡 Edge Case Issues

Navigation Logic Complexity (grid-block.node.ts:167-183):
The Tab/Shift-Tab navigation uses complex position calculations that could break with nested structures or dynamic content changes.

Empty Grid Deletion (grid-block.node.ts:128-136):
The deletion logic only checks for empty paragraphs but doesn't handle other empty nodes (lists, headings, etc.) that might be considered "empty content."

Minor Issues

  • Unused Props: React component has unused children prop in interface
  • Code Duplication: Column validation logic duplicated across React/Angular
  • Mixed Units: Some CSS uses px, others use rem - inconsistent with design system standards

Positive Aspects

Security: XSS vulnerability properly addressed with input validation and escaping
Error Handling: Good try-catch blocks and null checking in resize plugin
Accessibility: Proper keyboard navigation with Tab/Shift-Tab support


Recommendation: Address the CSS styling inconsistencies before merging as they break the WYSIWYG principle. The different rendering approaches need to be unified across all contexts.


Use :scope > .grid-block__column selectors instead of .grid-block__column
to restrict column lookup to direct children only. Without :scope, querySelector
would match columns belonging to nested inner grid blocks, causing the outer
grid block resize handle to be positioned incorrectly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Contributor

claude bot commented Mar 5, 2026

Claude finished @fmontes's task —— View job


Grid Block PR Review

Todo List:

  • Read repository guidelines (CLAUDE.md)
  • Review core grid block implementation files
  • Check security aspects and input validation
  • Review frontend SDK implementations
  • Analyze edge cases and design issues
  • Provide comprehensive review feedback

Critical Issues Found

🔴 CSS Styling Inconsistencies

The implementation uses three different CSS Grid approaches across contexts, creating inconsistency and breaking WYSIWYG principles:

  1. Backend Velocity Template (gridBlock.vtl:10): Uses grid-template-columns: repeat(12, 1fr) with grid-column: span N
  2. Frontend SDKs (React/Angular): Calculate percentages and use grid-template-columns: X% Y%
  3. TipTap Editor CSS: Uses flexbox with CSS variables --col-1 and --col-2 percentages

This means the same content renders differently in editor vs. frontend vs. backend, fundamentally breaking WYSIWYG expectations.

🟡 Input Validation Issues

Division by Zero Risk (grid-resize.plugin.ts:182-183):

const usableWidth = gridRect.width - gap;
const startRatio = firstCol.getBoundingClientRect().width / usableWidth;

If gridRect.width equals gap, usableWidth becomes 0, causing NaN in ratio calculations and breaking the resize logic.

Precision Issues (grid-block.node.ts:44-45):

const pct1 = (cols[0] / 12) * 100; // Can produce 33.333333333%
const pct2 = (cols[1] / 12) * 100;

Long decimal percentages create inconsistent styling and DOM bloat. Should use toFixed(2) for clean output.

🟡 Memory/DOM Issues

DOM Manipulation Without Cleanup (grid-resize.plugin.ts:86-87):

if (editorParent) {
    editorParent.style.position = 'relative'; // Modifies parent styling permanently
}

The plugin modifies parent element styling but never resets it, potentially affecting other components.

Generic CSS Classes (grid-block.node.ts:63):

class: 'grid-block' // Too generic, could conflict with other grid implementations

Should use more specific prefixed classes like dot-grid-block to avoid conflicts.

🟡 Edge Cases & Design Issues

Navigation Logic Complexity (grid-block.node.ts:167-183):
The Tab/Shift-Tab navigation uses complex position calculations that could break with nested structures or dynamic content changes.

Empty Grid Deletion Logic (grid-block.node.ts:128-136):
The deletion logic only checks for empty paragraphs but doesn't handle other empty nodes (lists, headings, etc.) that might be considered "empty content."

Hardcoded Column Limit (grid-block.node.ts:18):

content: 'gridColumn gridColumn', // Fixed to exactly 2 columns

The content spec hardcodes 2 columns but the plugin architecture suggests extensibility. This creates misleading expectations.

Minor Issues

  • Unused Props: React component has unused children prop in interface (GridBlock.tsx:5)
  • Code Duplication: Column validation logic duplicated across React/Angular SDKs
  • Mixed Units: Some CSS uses px, others use rem - inconsistent with design system

Positive Aspects

Security: XSS vulnerability properly addressed with input validation and escaping in Velocity template
Error Handling: Good try-catch blocks and null checking in resize plugin
Accessibility: Proper keyboard navigation with Tab/Shift-Tab support


Recommendation: Address the CSS styling inconsistencies before merging as they break the fundamental WYSIWYG principle. The different rendering approaches need to be unified across all contexts (editor, React SDK, Angular SDK, Velocity template).


- Restrict gridColumn content schema to exclude gridBlock nodes
- Guard insertGridBlock command to return false when cursor is inside a gridColumn
- Clean up grid-resize plugin removing failed nested-grid position resolution attempts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Contributor

claude bot commented Mar 5, 2026

Claude finished @fmontes's task —— View job


Grid Block PR Review

Todo List:

  • Read and analyze core grid block implementation files
  • Check Velocity template for XSS vulnerabilities
  • Examine frontend SDK implementations (React/Angular)
  • Review TipTap node implementation and resize plugin
  • Check CSS styling consistency across contexts
  • Summarize critical findings

Critical Issues Found

🔴 CSS Styling Inconsistencies

The implementation uses three different CSS Grid approaches across contexts, creating inconsistency and breaking WYSIWYG principles:

  1. Backend Velocity Template (gridBlock.vtl:10): Uses grid-template-columns: repeat(12, 1fr) with grid-column: span N
  2. Frontend SDKs (React/Angular): Calculate percentages and use grid-template-columns: X% Y%
  3. TipTap Editor CSS: Uses flexbox with CSS variables --col-1 and --col-2 percentages

This means the same content renders differently in editor vs. frontend vs. backend, fundamentally breaking WYSIWYG expectations.

🟡 Input Validation Issues

Division by Zero Risk (grid-resize.plugin.ts:182-183):

const usableWidth = gridRect.width - gap;
const startRatio = firstCol.getBoundingClientRect().width / usableWidth;

If gridRect.width equals gap, usableWidth becomes 0, causing NaN in ratio calculations and breaking the resize logic.

Precision Issues (grid-block.node.ts:44-45):

const pct1 = (cols[0] / 12) * 100; // Can produce 33.333333333%
const pct2 = (cols[1] / 12) * 100;

Long decimal percentages create inconsistent styling and DOM bloat. Should use toFixed(2) for clean output.

🟡 Memory/DOM Issues

DOM Manipulation Without Cleanup (grid-resize.plugin.ts:86-87):

if (editorParent) {
    editorParent.style.position = 'relative'; // Modifies parent styling permanently
}

The plugin modifies parent element styling but never resets it, potentially affecting other components.

Generic CSS Classes (grid-block.node.ts:63):

class: 'grid-block' // Too generic, could conflict with other grid implementations

Should use more specific prefixed classes like dot-grid-block to avoid conflicts.

🟡 Edge Cases & Design Issues

Navigation Logic Complexity (grid-block.node.ts:167-183):
The Tab/Shift-Tab navigation uses complex position calculations that could break with nested structures or dynamic content changes.

Empty Grid Deletion Logic (grid-block.node.ts:128-136):
The deletion logic only checks for empty paragraphs but doesn't handle other empty nodes (lists, headings, etc.) that might be considered "empty content."

Hardcoded Column Limit (grid-block.node.ts:18):

content: 'gridColumn gridColumn', // Fixed to exactly 2 columns

The content spec hardcodes 2 columns but the plugin architecture suggests extensibility. This creates misleading expectations.

Minor Issues

  • Unused Props: React component has unused children prop in interface (GridBlock.tsx:5)
  • Code Duplication: Column validation logic duplicated across React/Angular SDKs
  • Mixed Units: Some CSS uses px, others use rem - inconsistent with design system

Positive Aspects

Security: XSS vulnerability properly addressed with input validation and escaping in Velocity template
Error Handling: Good try-catch blocks and null checking in resize plugin
Accessibility: Proper keyboard navigation with Tab/Shift-Tab support


Recommendation: Address the CSS styling inconsistencies before merging as they break the fundamental WYSIWYG principle. The different rendering approaches need to be unified across all contexts (editor, React SDK, Angular SDK, Velocity template).


Replace percentage-based gridTemplateColumns with repeat(12, 1fr) and
grid-column: span N on each column, matching the VTL renderer approach.
This ensures consistent rendering across editor, React SDK, Angular SDK,
and the Velocity template.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Contributor

claude bot commented Mar 5, 2026

Claude finished @fmontes's task —— View job


Grid Block PR Review

Todo List:

  • Read repository guidelines (CLAUDE.md)
  • Review core grid block implementation files
  • Check security aspects and input validation
  • Review frontend SDK implementations
  • Analyze edge cases and design issues
  • Provide comprehensive review feedback

Critical Issues Found

🔴 CSS Styling Inconsistencies

The implementation uses three different CSS Grid approaches across contexts, creating inconsistency and breaking WYSIWYG principles:

  1. Backend Velocity Template (gridBlock.vtl:10): Uses grid-template-columns: repeat(12, 1fr) with grid-column: span N
  2. Frontend SDKs (React/Angular): Calculate percentages and use grid-template-columns: X% Y%
  3. TipTap Editor CSS: Uses flexbox with CSS variables --col-1 and --col-2 percentages

This means the same content renders differently in editor vs. frontend vs. backend, fundamentally breaking WYSIWYG expectations.

🟡 Input Validation Issues

Division by Zero Risk (grid-resize.plugin.ts:182-183):

const usableWidth = gridRect.width - gap;
const startRatio = firstCol.getBoundingClientRect().width / usableWidth;

If gridRect.width equals gap, usableWidth becomes 0, causing NaN in ratio calculations and breaking the resize logic.

Precision Issues (grid-block.node.ts:44-45):

const pct1 = (cols[0] / 12) * 100; // Can produce 33.333333333%
const pct2 = (cols[1] / 12) * 100;

Long decimal percentages create inconsistent styling and DOM bloat. Should use toFixed(2) for clean output.

🟡 Memory/DOM Issues

DOM Manipulation Without Cleanup (grid-resize.plugin.ts:86-87):

if (editorParent) {
    editorParent.style.position = 'relative'; // Modifies parent styling permanently
}

The plugin modifies parent element styling but never resets it, potentially affecting other components.

Generic CSS Classes (grid-block.node.ts:63):

class: 'grid-block' // Too generic, could conflict with other grid implementations

Should use more specific prefixed classes like dot-grid-block to avoid conflicts.

🟡 Edge Cases & Design Issues

Navigation Logic Complexity (grid-block.node.ts:167-183):
The Tab/Shift-Tab navigation uses complex position calculations that could break with nested structures or dynamic content changes.

Empty Grid Deletion Logic (grid-block.node.ts:128-136):
The deletion logic only checks for empty paragraphs but doesn't handle other empty nodes (lists, headings, etc.) that might be considered "empty content."

Hardcoded Column Limit (grid-block.node.ts:18):

content: 'gridColumn gridColumn', // Fixed to exactly 2 columns

The content spec hardcodes 2 columns but the plugin architecture suggests extensibility. This creates misleading expectations.

Minor Issues

  • Unused Props: React component has unused children prop in interface (GridBlock.tsx:5)
  • Code Duplication: Column validation logic duplicated across React/Angular SDKs
  • Mixed Units: Some CSS uses px, others use rem - inconsistent with design system

Positive Aspects

Security: XSS vulnerability properly addressed with input validation and escaping in Velocity template
Error Handling: Good try-catch blocks and null checking in resize plugin
Accessibility: Proper keyboard navigation with Tab/Shift-Tab support


Recommendation: Address the CSS styling inconsistencies before merging as they break the fundamental WYSIWYG principle. The different rendering approaches need to be unified across all contexts (editor, React SDK, Angular SDK, Velocity template).


@claude
Copy link
Contributor

claude bot commented Mar 5, 2026

Claude finished @fmontes's task —— View job


Grid Block PR Review

Todo List:

  • Review core grid block implementation files
  • Check Velocity template for XSS vulnerabilities
  • Examine frontend SDK implementations (React/Angular)
  • Review TipTap node implementation and resize plugin
  • Check CSS styling consistency across contexts
  • Summarize critical findings

Critical Issues Found

🔴 CSS Styling Inconsistencies

The implementation uses three different CSS Grid approaches across contexts, creating inconsistency and breaking WYSIWYG principles:

  1. Backend Velocity Template (gridBlock.vtl:10): Uses grid-template-columns: repeat(12, 1fr) with grid-column: span N
  2. Frontend SDKs (React/Angular): Calculate percentages and use grid-template-columns: X% Y%
  3. TipTap Editor CSS: Uses flexbox with CSS variables --col-1 and --col-2 percentages

This means the same content renders differently in editor vs. frontend vs. backend, fundamentally breaking WYSIWYG expectations.

🟡 Input Validation Issues

Division by Zero Risk (grid-resize.plugin.ts:182-183):

const usableWidth = gridRect.width - gap;
const startRatio = firstCol.getBoundingClientRect().width / usableWidth;

If gridRect.width equals gap, usableWidth becomes 0, causing NaN in ratio calculations and breaking the resize logic.

Precision Issues (grid-block.node.ts:44-45):

const pct1 = (cols[0] / 12) * 100; // Can produce 33.333333333%
const pct2 = (cols[1] / 12) * 100;

Long decimal percentages create inconsistent styling and DOM bloat. Should use toFixed(2) for clean output.

🟡 Memory/DOM Issues

DOM Manipulation Without Cleanup (grid-resize.plugin.ts:86-87):

if (editorParent) {
    editorParent.style.position = 'relative'; // Modifies parent styling permanently
}

The plugin modifies parent element styling but never resets it, potentially affecting other components.

Generic CSS Classes (grid-block.node.ts:63):

class: 'grid-block' // Too generic, could conflict with other grid implementations

Should use more specific prefixed classes like dot-grid-block to avoid conflicts.

🟡 Edge Cases & Design Issues

Navigation Logic Complexity (grid-block.node.ts:167-183):
The Tab/Shift-Tab navigation uses complex position calculations that could break with nested structures or dynamic content changes.

Empty Grid Deletion Logic (grid-block.node.ts:128-136):
The deletion logic only checks for empty paragraphs but doesn't handle other empty nodes (lists, headings, etc.) that might be considered "empty content."

Hardcoded Column Limit (grid-block.node.ts:18):

content: 'gridColumn gridColumn', // Fixed to exactly 2 columns

The content spec hardcodes 2 columns but the plugin architecture suggests extensibility. This creates misleading expectations.

Minor Issues

  • Unused Props: React component has unused children prop in interface (GridBlock.tsx:5)
  • Code Duplication: Column validation logic duplicated across React/Angular SDKs
  • Mixed Units: Some CSS uses px, others use rem - inconsistent with design system

Positive Aspects

Security: XSS vulnerability properly addressed with input validation and escaping in Velocity template
Error Handling: Good try-catch blocks and null checking in resize plugin
Accessibility: Proper keyboard navigation with Tab/Shift-Tab support


Recommendation: Address the CSS styling inconsistencies before merging as they break the fundamental WYSIWYG principle. The different rendering approaches need to be unified across all contexts (editor, React SDK, Angular SDK, Velocity template).


@claude
Copy link
Contributor

claude bot commented Mar 6, 2026

Claude finished @fmontes's task —— View job


Grid Block PR Review

Todo List:

  • Review core grid block implementation files
  • Check Velocity template for XSS vulnerabilities
  • Examine frontend SDK implementations (React/Angular)
  • Review TipTap node implementation and resize plugin
  • Check CSS styling consistency across contexts
  • Summarize critical findings

Critical Issues Found

🔴 CSS Styling Inconsistencies

The implementation uses three different CSS Grid approaches across different contexts, creating inconsistency and potential rendering issues:

  1. Backend Velocity Template (gridBlock.vtl:10): Uses grid-template-columns: repeat(12, 1fr) with grid-column: span N
  2. Frontend SDKs (React/Angular): Calculate percentages and use grid-template-columns: X% Y%
  3. TipTap Editor CSS: Uses flexbox with CSS variables --col-1 and --col-2 percentages

This inconsistency means the same content will render differently in the editor vs. frontend vs. backend, breaking WYSIWYG expectations.

🟡 Input Validation Issues

Division by Zero Risk (grid-resize.plugin.ts:182-183):

const usableWidth = gridRect.width - gap;
const startRatio = firstCol.getBoundingClientRect().width / usableWidth;

If gridRect.width equals gap, usableWidth becomes 0, causing NaN in ratio calculations and breaking the resize logic.

Precision Issues (grid-block.node.ts:44-45):

const pct1 = (cols[0] / 12) * 100; // Can produce 33.333333333%
const pct2 = (cols[1] / 12) * 100;

Long decimal percentages create inconsistent styling and DOM bloat. Should use toFixed(2) for clean output.

🟡 Memory/DOM Issues

DOM Manipulation Without Cleanup (grid-resize.plugin.ts:86-87):

if (editorParent) {
    editorParent.style.position = 'relative'; // Modifies parent styling permanently
}

The plugin modifies parent element styling but never resets it, potentially affecting other components.

Generic CSS Classes (grid-block.node.ts:63):

class: 'grid-block' // Too generic, could conflict with other grid implementations

Should use more specific prefixed classes like dot-grid-block to avoid conflicts.

🟡 Edge Cases & Design Issues

Navigation Logic Complexity (grid-block.node.ts:167-183):
The Tab/Shift-Tab navigation uses complex position calculations that could break with nested structures or dynamic content changes.

Empty Grid Deletion Logic (grid-block.node.ts:128-136):
The deletion logic only checks for empty paragraphs but doesn't handle other empty nodes (lists, headings, etc.) that might be considered "empty content."

Hardcoded Column Limit (grid-block.node.ts:18):

content: 'gridColumn gridColumn', // Fixed to exactly 2 columns

The content spec hardcodes 2 columns but the plugin architecture suggests extensibility. This creates misleading expectations.

Minor Issues

  • Unused Props: React component has unused children prop in interface (GridBlock.tsx:5)
  • Code Duplication: Column validation logic duplicated across React/Angular SDKs
  • Mixed Units: Some CSS uses px, others use rem - inconsistent with design system

Positive Aspects

Security: XSS vulnerability properly addressed with input validation and escaping in Velocity template
Error Handling: Good try-catch blocks and null checking in resize plugin
Accessibility: Proper keyboard navigation with Tab/Shift-Tab support


Recommendation: Address the CSS styling inconsistencies before merging as they break the fundamental WYSIWYG principle. The different rendering approaches need to be unified across all contexts (editor, React SDK, Angular SDK, Velocity template).


@fmontes fmontes added this pull request to the merge queue Mar 6, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Mar 6, 2026
@fmontes fmontes added this pull request to the merge queue Mar 6, 2026
Merged via the queue into main with commit 6e0dd63 Mar 6, 2026
44 checks passed
@fmontes fmontes deleted the issue-33882-grid-block branch March 6, 2026 19:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area : Backend PR changes Java/Maven backend code Area : Frontend PR changes Angular/TypeScript frontend code Area : SDK PR changes SDK libraries

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Modernization: Lara Theme - Upgrade Angular from 20 to 21 & PrimeNG from 17 to 21

10 participants