Skip to content

feat: port crosswinds-blocks grid + grid-item families (CW2) - #569

Merged
ViewFromTheBox merged 2 commits into
feature/495-port-crosswinds-blocksfrom
feature/498-port-crosswinds-blocks-cw2-grid-cluster
Jun 11, 2026
Merged

ViewFromTheBox merged 2 commits into
feature/495-port-crosswinds-blocksfrom
feature/498-port-crosswinds-blocks-cw2-grid-cluster

Conversation

@ViewFromTheBox

@ViewFromTheBox ViewFromTheBox commented Jun 11, 2026 •

Copy link
Copy Markdown
Member

Description

Forks crosswinds-blocks/basic-grid and basic-grid-item into the artisanpack/* namespace with the "basic-" prefix dropped from block names, attribute names, class names, and labels. Part of CW2 in the crosswinds-blocks port (umbrella #495).

Closes: #498

Type of Change

  • New feature (adds new functionality)

Related Issue

Issue: #498

Motivation and Context

CW2 cluster of the crosswinds-blocks port. Brings the grid block family in under the artisanpack/* namespace, drops the legacy "basic-" prefix, and rewires the per-breakpoint responsive story onto the visual-editor's existing artisanpackResponsive HOC + breakpoint registry so the editor and front-end share one source of truth.

Changes Made

  • artisanpack/grid (parent) — single numColumns attribute enrolled in artisanpackResponsive.attributes; gap surfaced via core's spacing.blockGap with horizontal/vertical sides.
  • artisanpack/grid-item (child) — single gridColumnSpan + gridRowSpan (both enrolled in artisanpackResponsive.attributes) plus an innerLayout enum (normal / equal / center / bottom / last-bottom). Column-span max is clamped to the parent grid's numColumns via block context.
  • Blade + React + Vue renderers all emit static classes — ap-grid-has-N-{base|sm|md|lg|xl|2xl}-columns and ap-grid-item-span-N-{bp}-{columns|row} — that the matching media-query rules in grid.css pick up. Mobile-first cascade resolves at viewport time; no per-instance @media or accumulator drain required.
  • grid.css ships from both blocks/grid/ (editor canvas via ?inline) and packages/visual-editor-renderer-blade/resources/assets/frontend/ (front-end via <x-ve-blocks-styles>).
  • BlocksStylesComponent + blocks-styles.blade.php wire the front-end stylesheet alongside accordion/tabs under the emitInteractive flag.
  • canvas-styles.ts injects grid.css into the editor iframe so authors get an accurate preview as they toggle the breakpoint switcher.
  • renderer-parity.json extended with artisanpack/grid + artisanpack/grid-item; verify-renderer-parity passes 135/135 across all three renderers.

How Has This Been Tested?

Testing Environment:

  • Operating System: macOS
  • Browser: Chrome (manual verification in the artisanpack-ui-dev app)
  • PHP Version: 8.4
  • Project Version: feature/495-port-crosswinds-blocks

Tests Performed:

  1. Pest (full): 1042 passed.
  2. Vitest (full): 1929 passed.
  3. node scripts/verify-renderer-parity.mjs: 135/135 across Blade, React, Vue.
  4. Manual browser verification in the dev app — created a grid, set base/sm/md/lg column counts via the editor breakpoint switcher, confirmed responsive overrides persisted (responsive.numColumns: {sm:1, md:2, lg:4}) and the front-end re-flowed columns across 640 / 768 / 1024 px. Repeated for grid-item span attributes.

Accessibility Tests Run

  • Keyboard navigation tested
  • Screen reader tested
  • Color contrast verified
  • ARIA labels checked

Details: No new interactive surfaces — grid + grid-item are pure-layout containers. The block-supports compiler still emits all standard a11y attributes (className, anchor, ariaLabel) on the wrappers.

Tests Added

  • Unit tests added/updated
  • Integration tests added/updated
  • All tests passing

Test details:

  • BlockRendererTest.php — base render, per-breakpoint class emission, clamp behavior, innerLayout fallback, blockGap with sides.
  • GridResponsiveRenderTest.php (Feature) — per-breakpoint classes survive through <x-ve-blocks> and unknown breakpoints are dropped silently.
  • React BlockTree.test.tsx + Vue BlockTree.test.ts — matching coverage of base + responsive class emission + clamps.
  • canvas-styles.test.ts — count bumped from 13 → 14 to include grid styles.

Documentation

  • Inline code documentation added
  • README updated
  • Wiki updated
  • API documentation updated

Documentation details: File headers + inline blocks explain the per-breakpoint cascade and the class-driven approach across each renderer.

Pre-Submission Checklist

  • Followed contributing guidelines
  • Checked for other open PRs for same update
  • Code passes all tests
  • Code has been linted (CodeRabbit CLI: 0 findings)
  • Accessibility tests completed (N/A — no interactive surfaces)
  • Code follows project style guide
  • Self-review completed
  • Comments added for complex code
  • No new warnings generated

Summary by CodeRabbit

  • New Features

    • Added Grid block for responsive column layouts (1–12) and Grid Item child block with alignment variants and column/row span controls.
    • Grid styling and utilities included for editor and renderers; editor UI for configuring columns and item spans added.
    • Renderers added for Blade, React, and Vue to output responsive grid classes.
  • Tests

    • Added unit and feature tests covering base and per-breakpoint class generation, clamping, and safe fallback behaviors.

Forks `crosswinds-blocks/basic-grid` and `basic-grid-item` into the
artisanpack/* namespace with the "basic-" prefix dropped from block
names, attributes, classes, and labels.

Grid family:
- artisanpack/grid (parent) carries a single `numColumns` attribute,
  enrolled in artisanpackResponsive.attributes so the per-breakpoint
  HOC routes overrides into `responsive.numColumns.{bp}`. Gap is
  surfaced through the standard spacing.blockGap support with
  horizontal/vertical sides.
- artisanpack/grid-item (child) carries `gridColumnSpan`, `gridRowSpan`,
  and an `innerLayout` enum (normal/equal/center/bottom/last-bottom).
  Spans are enrolled in artisanpackResponsive.attributes; the
  column-span max is clamped to the grid's `numColumns` via block
  context.

Renderers (Blade + React + Vue):
- Per-breakpoint values encode as static classes:
    `ap-grid-has-N-{base|sm|md|lg|xl|2xl}-columns`
    `ap-grid-item-span-N-{bp}-{columns|row}`
- grid.css ships the matching @media-keyed rules; mobile-first cascade
  picks the active breakpoint's class at runtime. Class-driven (not
  per-instance @media via the accumulator) so the front-end works
  regardless of where `<x-ve-blocks-styles>` lands.

Editor canvas:
- canvas-styles.ts injects grid.css into the iframe so authors get an
  accurate preview as they switch breakpoints.

Tests:
- Renderer-parity tests cover the family in all three renderers
  (Unit) plus a Feature test that verifies the per-breakpoint class
  emission survives through `<x-ve-blocks>`.

Closes #498
@coderabbitai

coderabbitai Bot commented Jun 11, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4fd667c1-7a5f-43a8-8e41-de1371f862f6

📥 Commits

Reviewing files that changed from the base of the PR and between 5b53f9d and 33719c1.

📒 Files selected for processing (7)
  • packages/visual-editor-renderer-blade/resources/assets/frontend/grid.css
  • packages/visual-editor-renderer-blade/resources/views/components/blocks-styles.blade.php
  • packages/visual-editor-renderer-react/src/blocks/artisanpack/grid.tsx
  • packages/visual-editor-renderer-react/tests/BlockTree.test.tsx
  • packages/visual-editor-renderer-vue/src/blocks/artisanpack/grid.ts
  • packages/visual-editor-renderer-vue/tests/BlockTree.test.ts
  • resources/js/visual-editor/blocks/grid/grid.css
🚧 Files skipped from review as they are similar to previous changes (5)
  • resources/js/visual-editor/blocks/grid/grid.css
  • packages/visual-editor-renderer-react/tests/BlockTree.test.tsx
  • packages/visual-editor-renderer-vue/tests/BlockTree.test.ts
  • packages/visual-editor-renderer-react/src/blocks/artisanpack/grid.tsx
  • packages/visual-editor-renderer-blade/resources/assets/frontend/grid.css

📝 Walkthrough

Walkthrough

Adds artisanpack/grid and artisanpack/grid-item: block metadata, editor implementations, Blade/React/Vue renderers, shared grid CSS utilities for responsive columns/spans, registry updates, and tests validating rendering, clamping, and breakpoint handling.

Changes

Grid Block Implementation & Registry

Layer / File(s) Summary
Block Metadata & Registration
packages/renderer-parity.json, resources/js/visual-editor/blocks/grid/block.json, resources/js/visual-editor/blocks/grid-item/block.json, resources/js/visual-editor/blocks/grid/index.ts, resources/js/visual-editor/blocks/grid-item/index.ts, packages/visual-editor-renderer-react/src/blocks/registerCoreBlocks.ts, packages/visual-editor-renderer-vue/src/blocks/registerCoreBlocks.ts
Grid and grid-item blocks registered with numColumns (default 4) and span attributes, responsive context provisioning, and editor support flags; renderer registries updated.
Blade Grid CSS Stylesheet
packages/visual-editor-renderer-blade/resources/assets/frontend/grid.css, resources/js/visual-editor/blocks/grid/grid.css
Foundational responsive stylesheet defining base .ap-grid and .ap-grid-item layout rules plus utility classes for column counts (1–12) and item spans across base/sm/md/lg/xl/2xl.
Blade Grid Block Templates & Stylesheet Wiring
packages/visual-editor-renderer-blade/resources/views/blocks/artisanpack/grid.blade.php, packages/visual-editor-renderer-blade/resources/views/blocks/artisanpack/grid-item.blade.php, packages/visual-editor-renderer-blade/src/View/Components/BlocksStylesComponent.php, packages/visual-editor-renderer-blade/resources/views/components/blocks-styles.blade.php
Blade renderers compute clamped column/row spans and responsive class names from BreakpointRegistry; BlocksStylesComponent wires grid CSS href and view emits grid stylesheet.
Blade Renderer Tests
packages/visual-editor-renderer-blade/tests/Feature/Responsive/GridResponsiveRenderTest.php, packages/visual-editor-renderer-blade/tests/Unit/BlockRendererTest.php
Feature and unit tests verify responsive class emission, value clamping (1–12), unknown breakpoint skipping, safe fallback for invalid innerLayout, and spacing compilation.
React Grid Renderer
packages/visual-editor-renderer-react/src/blocks/artisanpack/grid.tsx, packages/visual-editor-renderer-react/src/blocks/registerCoreBlocks.ts
React components render grid containers and items with base/responsive column-count and span classes derived from attributes; components registered in CORE_BLOCKS.
React Renderer Tests
packages/visual-editor-renderer-react/tests/BlockTree.test.tsx
BlockTree tests assert correct class generation, responsive overrides, ignored non-numeric overrides, and safe clamping/fallback behavior.
Vue Grid Renderer
packages/visual-editor-renderer-vue/src/blocks/artisanpack/grid.ts, packages/visual-editor-renderer-vue/src/blocks/registerCoreBlocks.ts
Vue components render grid/grid-item with static classes encoding base and responsive column counts/spans; components registered in CORE_BLOCKS.
Vue Renderer Tests
packages/visual-editor-renderer-vue/tests/BlockTree.test.ts
BlockTree tests verify base/responsive class output, clamping, ignored overrides, and inner-layout fallback parity.
Gutenberg Editor: Grid Block
resources/js/visual-editor/blocks/grid/edit.tsx, resources/js/visual-editor/blocks/grid/save.tsx, resources/js/visual-editor/blocks/grid/index.ts
Grid editor clamps numColumns to 1–12, exposes context for nested items, renders inspector controls, and uses useInnerBlocksProps restricted to artisanpack/grid-item with template.
Gutenberg Editor: Grid Item Block
resources/js/visual-editor/blocks/grid-item/edit.tsx, resources/js/visual-editor/blocks/grid-item/save.tsx, resources/js/visual-editor/blocks/grid-item/index.ts
Grid item editor clamps spans against parent numColumns, normalizes innerLayout to allowed values, renders inspector controls, and outputs inner blocks via useInnerBlocksProps.
Editor Grid CSS & Canvas Integration
resources/js/visual-editor/blocks/grid/grid.css, resources/js/visual-editor/editor/canvas-styles.ts, resources/js/visual-editor/editor/__tests__/canvas-styles.test.ts
Grid stylesheet defines responsive utility classes for editor context and is added to the canvas iframe stylesheet list; canvas-styles test adjusted to expect the extra entry.
sequenceDiagram
  participant Editor as Gutenberg Editor
  participant GridEdit as GridEdit Component
  participant BlockTree as InnerBlock Tree
  participant Renderer as Blade/React/Vue Renderer
  participant CSS as Grid CSS

  Editor->>GridEdit: setAttributes(numColumns=4)
  GridEdit->>BlockTree: useInnerBlocksProps(artisanpack/grid-item)
  BlockTree->>GridEdit: Nested grid-item blocks
  GridEdit->>Renderer: Render block tree
  Renderer->>CSS: apply ap-grid / ap-grid-item classes
  CSS->>Renderer: grid-template-columns / grid-column/span rules
  Editor->>GridEdit: update responsive.numColumns.md=3
  Renderer->>CSS: apply ap-grid-has-3-md-columns
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • #498: Crosswinds block fork CW2 · Grid cluster — Implements the CW2 Grid cluster by adding artisanpack/grid and artisanpack/grid-item, matching the issue objectives.

Possibly related PRs

Poem

"🐇 I stitched a grid with nimble paws,
Columns lined up without a cause,
From Blade to React and Vue I hop,
Responsive spans that never stop,
A rabbit's cheer — the editor's applause!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: port crosswinds-blocks grid + grid-item families (CW2)' directly and clearly summarizes the main change: porting two crosswinds block families into the artisanpack namespace.
Linked Issues check ✅ Passed All acceptance criteria from issue #498 are met: artisanpack/grid and artisanpack/grid-item are registered with preserved parent-child relationship, titles read 'Grid'/'Grid Item', three-renderer parity is achieved (135/135 verified), and transforms are implemented.
Out of Scope Changes check ✅ Passed All changes are directly in scope for the grid cluster fork: block registration, renderers (Blade/React/Vue), tests, CSS stylesheet, and parity verification. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/498-port-crosswinds-blocks-cw2-grid-cluster

Comment @coderabbitai help to get the list of available commands and usage tips.

@ViewFromTheBox
ViewFromTheBox marked this pull request as ready for review June 11, 2026 21:44

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/visual-editor-renderer-blade/resources/assets/frontend/grid.css`:
- Around line 54-57: The .ap-grid-item.ap-grid-item-layout-bottom rule is using
flex-direction: column but incorrectly uses align-items: flex-end (which
controls cross-axis); change the rule to use justify-content: flex-end to push
children to the bottom when stacked vertically and remove or correct align-items
as needed (update the .ap-grid-item.ap-grid-item-layout-bottom selector to use
justify-content: flex-end and only keep align-items if you need horizontal
alignment).

In
`@packages/visual-editor-renderer-blade/resources/views/components/blocks-styles.blade.php`:
- Around line 5-9: The grid stylesheet is incorrectly gated by the
$emitInteractive conditional; ensure the link tag rendering $gridStyleHref with
data-ve-grid is moved outside (or duplicated outside) the `@if`( $emitInteractive
) block so the grid CSS always loads even when $emitInteractive is false; update
the block that contains the <link rel="stylesheet" href="{{ $gridStyleHref }}"
data-ve-grid> (referencing $gridStyleHref and data-ve-grid) to be rendered
unconditionally while keeping accordion/tabs and the interactivity script
controlled by $emitInteractive.

In `@packages/visual-editor-renderer-react/src/blocks/artisanpack/grid.tsx`:
- Around line 61-63: The code currently clamps raw responsive values with
clampInt before validating, causing non-numeric or malformed inputs to become 1
and emit classes like ap-grid-*-1-*. Update the loop in grid.tsx (where
clampInt(raw, 1, 12, 0) is used) to first validate raw is a parseable finite
integer (e.g., parseInt/Number check or Number.isFinite(Number(raw))) and
skip/continue for invalid values, then call clampInt on the validated numeric
value so only legitimate numbers produce ap-grid classes.

In `@resources/js/visual-editor/blocks/grid/grid.css`:
- Around line 54-57: The .ap-grid-item.ap-grid-item-layout-bottom rule is using
align-items: flex-end with flex-direction: column which moves items
horizontally; change it to use justify-content: flex-end (and remove or leave
align-items as needed) so vertical stacking actually aligns content to the
bottom while keeping flex-direction: column.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: acefc5b3-a9e8-4f50-b71f-e36f1453207c

📥 Commits

Reviewing files that changed from the base of the PR and between 3d71d66 and 5b53f9d.

📒 Files selected for processing (25)
  • packages/renderer-parity.json
  • packages/visual-editor-renderer-blade/resources/assets/frontend/grid.css
  • packages/visual-editor-renderer-blade/resources/views/blocks/artisanpack/grid-item.blade.php
  • packages/visual-editor-renderer-blade/resources/views/blocks/artisanpack/grid.blade.php
  • packages/visual-editor-renderer-blade/resources/views/components/blocks-styles.blade.php
  • packages/visual-editor-renderer-blade/src/View/Components/BlocksStylesComponent.php
  • packages/visual-editor-renderer-blade/tests/Feature/Responsive/GridResponsiveRenderTest.php
  • packages/visual-editor-renderer-blade/tests/Unit/BlockRendererTest.php
  • packages/visual-editor-renderer-react/src/blocks/artisanpack/grid.tsx
  • packages/visual-editor-renderer-react/src/blocks/registerCoreBlocks.ts
  • packages/visual-editor-renderer-react/tests/BlockTree.test.tsx
  • packages/visual-editor-renderer-vue/src/blocks/artisanpack/grid.ts
  • packages/visual-editor-renderer-vue/src/blocks/registerCoreBlocks.ts
  • packages/visual-editor-renderer-vue/tests/BlockTree.test.ts
  • resources/js/visual-editor/blocks/grid-item/block.json
  • resources/js/visual-editor/blocks/grid-item/edit.tsx
  • resources/js/visual-editor/blocks/grid-item/index.ts
  • resources/js/visual-editor/blocks/grid-item/save.tsx
  • resources/js/visual-editor/blocks/grid/block.json
  • resources/js/visual-editor/blocks/grid/edit.tsx
  • resources/js/visual-editor/blocks/grid/grid.css
  • resources/js/visual-editor/blocks/grid/index.ts
  • resources/js/visual-editor/blocks/grid/save.tsx
  • resources/js/visual-editor/editor/__tests__/canvas-styles.test.ts
  • resources/js/visual-editor/editor/canvas-styles.ts

Comment thread packages/visual-editor-renderer-react/src/blocks/artisanpack/grid.tsx Outdated
Comment thread resources/js/visual-editor/blocks/grid/grid.css
- Move grid CSS link outside `$emitInteractive` gate — grid is a pure
  layout family with no companion interactivity script, so it must
  ship even when hosts opt out of accordion/tabs interactivity.
- Fix `.ap-grid-item-layout-bottom`: with `flex-direction: column` the
  main axis is vertical, so `justify-content: flex-end` (not
  `align-items: flex-end`) is what pushes children to the bottom.
- Validate raw `responsive.*` overrides as finite numbers before
  clamping in React + Vue renderers — previously non-numeric values
  silently snapped to the clamp min (1) and emitted bogus
  `ap-grid-*-1-{bp}-*` classes. Regression tests cover the fix.
@ViewFromTheBox
ViewFromTheBox merged commit 1d91687 into feature/495-port-crosswinds-blocks Jun 11, 2026
1 check passed
@ViewFromTheBox
ViewFromTheBox deleted the feature/498-port-crosswinds-blocks-cw2-grid-cluster branch June 11, 2026 22:06
@ViewFromTheBox ViewFromTheBox moved this from In Review to Done in ArtisanPack UI Overview Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

Crosswinds block fork CW2 · Grid cluster (grid, grid-item) [rename from basic-grid*]

1 participant