Skip to content

feat: CW0 pilot — port crosswinds-blocks/breadcrumbs as artisanpack/breadcrumbs - #567

Merged
ViewFromTheBox merged 2 commits into
feature/495-port-crosswinds-blocksfrom
feature/496-cw0-pilot-breadcrumbs
Jun 11, 2026
Merged

ViewFromTheBox merged 2 commits into
feature/495-port-crosswinds-blocksfrom
feature/496-cw0-pilot-breadcrumbs

Conversation

@ViewFromTheBox

@ViewFromTheBox ViewFromTheBox commented Jun 11, 2026 •

Copy link
Copy Markdown
Member

Description

Forks the upstream crosswinds-blocks/breadcrumbs block into the visual-editor package as artisanpack/breadcrumbs and establishes the pattern for CW1–CW7 to follow.

Closes: #496

Type of Change

  • New feature (adds new functionality)

Related Issue

Issue: #496 (under umbrella #495)

Motivation and Context

CW0 — first of the 8-phase crosswinds-blocks port. Breadcrumbs is the cleanest pilot: single block, server-rendered, no inner blocks, no JS interactivity. Locking in the editor scaffold + three-renderer parity + tests pattern here lets CW1–CW7 fan out in parallel.

Changes Made

  • Editor scaffold at resources/js/visual-editor/blocks/breadcrumbs/ — block.json (separatorIcon, breadcrumbsSchema; full block-supports inheriting upstream), edit.tsx with InspectorControls panel + stub trail preview, save.tsx returning null (dynamic), index.ts, inserter-icon.tsx, shared separators.tsx, breadcrumbs.css. Dropped the upstream breadrcumbsSchema typo for breadcrumbsSchema since this is a fresh namespace.
  • Three renderers under packages/visual-editor-renderer-{blade,react,vue}/ — read a server-stamped _resolvedTrail (Array<{ label, url?, current? }>) and emit <nav><ol>…</ol></nav> with the selected chevron separator. Schema.org BreadcrumbList microdata when breadcrumbsSchema=true. URLs run through the existing UrlSanitizer / safeUrl helpers so unsafe schemes (javascript:, etc.) are dropped.
  • Renderer parity tests — 4 cases × 3 renderers (12 specs, ~50 assertions): schema-on with resolved trail, schema-off + invalid-separator fallback, unsafe URL rejection, empty trail. packages/renderer-parity.json includes artisanpack/breadcrumbs.
  • No transforms — upstream did not define any for breadcrumbs.

How Has This Been Tested?

Testing Environment:

  • Operating System: macOS 25.5.0
  • PHP Version: 8.4.3
  • Project Version: feature/495-port-crosswinds-blocks

Tests Performed:

  1. Inserted the block in the visual-editor; toggled separator + schema toggle; verified preview updates and selections persist.
  2. Full vitest suite — 235 files / 1901 tests, all passing.
  3. Full Pest suite — 1024 tests / 2857 assertions, all passing.
  4. node scripts/verify-renderer-parity.mjs — passes.
  5. CodeRabbit CLI (cr review --base feature/495-port-crosswinds-blocks) — 1 valid finding addressed (URL sanitization), 1 false-positive skipped (SVG path is correct), final pass returned 0 findings.

Accessibility Tests Run

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

Details: The rendered <nav> carries an aria-label (defaulting to "Breadcrumb"); the current page entry carries aria-current="page"; separators are aria-hidden. Schema.org BreadcrumbList microdata is emitted unless the author disables it.

Tests Added

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

Test details: 12 new renderer parity specs (4 per renderer) covering happy-path schema rendering, separator/schema fallback, unsafe-URL rejection, and empty-trail behavior.

Documentation

  • Inline code documentation added

Documentation details: Docblocks on every new file explain the upstream provenance, the dynamic-block contract (server stamps _resolvedTrail), and the editor-vs-renderer split. Follow-ups for runtime + iframe CSS pipeline filed as #565 and #566 under umbrella #495.

Screenshots

Pre-Submission Checklist

  • Followed contributing guidelines
  • Checked for other open PRs for same update
  • Code passes all tests
  • Code has been linted
  • Accessibility tests completed
  • Code follows project style guide
  • Self-review completed
  • Comments added for complex code
  • No new warnings generated

Summary by CodeRabbit

  • New Features

    • Added a Breadcrumbs navigation block with configurable separator icons, editor preview, inserter icon, and rich editor controls (spacing, styling, typography, color).
    • Optional schema.org BreadcrumbList microdata support and safe URL handling so unsafe links are excluded.
  • Tests

    • Added comprehensive tests verifying rendering, separator normalization, schema toggling, URL sanitization, and empty-trail behavior across renderers.

…readcrumbs

Forks the upstream crosswinds-blocks breadcrumbs block into the visual-editor
package and establishes the pattern for CW1–CW7 to follow:

- Editor scaffold under `resources/js/visual-editor/blocks/breadcrumbs/`
  (block.json, edit, save, index, inserter-icon, separators, css). Drops the
  upstream `breadrcumbsSchema` typo for `breadcrumbsSchema` since the fresh
  namespace has no legacy markup to preserve.
- Blade + React + Vue renderers reading a server-stamped `_resolvedTrail`
  attribute, emitting `<nav><ol>…</ol></nav>` with the selected chevron
  separator and optional schema.org BreadcrumbList microdata. URLs run
  through the existing UrlSanitizer / safeUrl helpers so unsafe schemes are
  dropped.
- Three-renderer parity tests (12 new assertions per renderer) covering
  schema-on/schema-off, separator fallback, empty trail, and unsafe-URL
  rejection. Manifest in `packages/renderer-parity.json` updated.

No transforms — upstream did not define any for breadcrumbs.

Follow-ups filed under umbrella #495:
- #565 — BreadcrumbsResolver to stamp `_resolvedTrail` on the server
- #566 — Editor canvas iframe pipeline for custom block CSS

Closes #496
@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: fd6f4f6c-1c3e-4d59-b4f6-662a646fe13a

📥 Commits

Reviewing files that changed from the base of the PR and between 2c258b5 and ba57d98.

📒 Files selected for processing (6)
  • packages/visual-editor-renderer-blade/resources/views/blocks/artisanpack/breadcrumbs.blade.php
  • packages/visual-editor-renderer-blade/tests/Unit/BlockRendererTest.php
  • packages/visual-editor-renderer-react/src/blocks/artisanpack/breadcrumbs.tsx
  • packages/visual-editor-renderer-react/tests/BlockTree.test.tsx
  • packages/visual-editor-renderer-vue/src/blocks/artisanpack/breadcrumbs.ts
  • packages/visual-editor-renderer-vue/tests/BlockTree.test.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/visual-editor-renderer-vue/tests/BlockTree.test.ts
  • packages/visual-editor-renderer-react/tests/BlockTree.test.tsx
  • packages/visual-editor-renderer-vue/src/blocks/artisanpack/breadcrumbs.ts
  • packages/visual-editor-renderer-react/src/blocks/artisanpack/breadcrumbs.tsx
  • packages/visual-editor-renderer-blade/tests/Unit/BlockRendererTest.php

📝 Walkthrough

Walkthrough

Adds an artisanpack/breadcrumbs block: block metadata and editor UI, shared separator model, Blade/React/Vue renderers that normalize/sanitize _resolvedTrail and optionally emit Schema.org microdata, registry wiring, styles, and parity tests across all renderers.

Changes

Breadcrumbs Block Implementation

Layer / File(s) Summary
Block Definition & Separator Icons
resources/js/visual-editor/blocks/breadcrumbs/block.json, resources/js/visual-editor/blocks/breadcrumbs/separators.tsx
Block metadata declares separatorIcon (enum) and breadcrumbsSchema (boolean); shared separator icon model defines name list, SVG path map, and SeparatorIcon renderer.
Editor UI Components & Styling
resources/js/visual-editor/blocks/breadcrumbs/edit.tsx, resources/js/visual-editor/blocks/breadcrumbs/inserter-icon.tsx, resources/js/visual-editor/blocks/breadcrumbs/save.tsx, resources/js/visual-editor/blocks/breadcrumbs/breadcrumbs.css, resources/js/visual-editor/blocks/breadcrumbs/index.ts
Edit component adds Inspector controls (separator select, schema toggle), preview stub trail and separators, inserter SVG icon, save returns null (server-rendered), CSS for editor preview, and entrypoint wiring/exports.
Blade Server Renderer
packages/visual-editor-renderer-blade/resources/views/blocks/artisanpack/breadcrumbs.blade.php, packages/visual-editor-renderer-blade/tests/Unit/BlockRendererTest.php
Blade template normalizes _resolvedTrail, sanitizes URLs, emits optional BreadcrumbList/ListItem microdata, renders links/current item and SVG separators; tests cover normal render, schema toggle, unsafe URL filtering, and empty trail.
React Renderer & Registration
packages/visual-editor-renderer-react/src/blocks/artisanpack/breadcrumbs.tsx, packages/visual-editor-renderer-react/src/blocks/registerCoreBlocks.ts, packages/visual-editor-renderer-react/tests/BlockTree.test.tsx
React renderer normalizes separator and trail (safeUrl), conditionally emits schema microdata and aria-current, renders separators, and is registered in CORE_BLOCKS; tests validate schema output, invalid separator fallback, URL sanitization, and empty state.
Vue Renderer & Registration
packages/visual-editor-renderer-vue/src/blocks/artisanpack/breadcrumbs.ts, packages/visual-editor-renderer-vue/src/blocks/registerCoreBlocks.ts, packages/visual-editor-renderer-vue/tests/BlockTree.test.ts
Vue renderer defines separator mapping, normalizes/sanitizes _resolvedTrail, renders links or current <span> with optional Schema.org markup and separators, and is registered; tests mirror React/Blade cases.
Renderer Parity Registry
packages/renderer-parity.json
Added "artisanpack/breadcrumbs" to the blocks array for renderer parity tracking.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • #565: Adds renderers and block metadata consuming _resolvedTrail; this PR implements the block renderers that expect a server-side Breadcrumbs resolver.
  • #495: Implements the CW0 breadcrumbs fork into artisanpack/*, matching the CW0 pilot objectives for three-renderer parity and registration.

Possibly related PRs

Poem

🐰
I hop on trails of crumbs so neat,
Blade, React, and Vue I greet,
Tiny separators lead the way,
Safe links guide the reader's stay,
Hop—our breadcrumbs brighten the site.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.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 clearly and concisely describes the main change: porting a breadcrumbs block from crosswinds-blocks to artisanpack, which is the primary objective of this PR.
Linked Issues check ✅ Passed The PR successfully addresses all coding requirements from #496: registers artisanpack/breadcrumbs block with full editor scaffold, implements three-renderer parity (Blade, React, Vue), includes comprehensive parity tests, and establishes the porting pattern.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the breadcrumbs block porting objective; no unrelated modifications found beyond the block registration, editor scaffold, renderers, and tests.

✏️ 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/496-cw0-pilot-breadcrumbs

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

@ViewFromTheBox ViewFromTheBox moved this from Backlog to In Review in ArtisanPack UI Overview Jun 11, 2026
@ViewFromTheBox ViewFromTheBox linked an issue Jun 11, 2026 that may be closed by this pull request
4 tasks
@ViewFromTheBox
ViewFromTheBox marked this pull request as ready for review June 11, 2026 15:04

@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: 1

🧹 Nitpick comments (1)
packages/visual-editor-renderer-react/src/blocks/artisanpack/breadcrumbs.tsx (1)

114-114: ⚡ Quick win

Consider using index-only React key for stability.

Currently the key combines position and item.label. While position ensures uniqueness, using the loop index directly would be simpler and more stable. Labels might contain special characters or be duplicated in edge cases.

♻️ Suggested improvement

Replace the existing map callback to capture the index parameter and use it in the key:

-                {trail.map((item, index) => {
+                {trail.map((item, idx) => {
                     const isLast = index === trail.length - 1;
                     const position = index + 1;

                     const itemProps = breadcrumbsSchema
                         ? {
                               className: 'ap-breadcrumbs__item',
                               itemProp: 'itemListElement',
                               itemScope: true,
                               itemType: 'https://schema.org/ListItem',
                           }
                         : { className: 'ap-breadcrumbs__item' };

                     return (
-                        <li key={`${position}-${item.label}`} {...itemProps}>
+                        <li key={idx} {...itemProps}>

Or keep index as the parameter name and use it directly:

                     return (
-                        <li key={`${position}-${item.label}`} {...itemProps}>
+                        <li key={index} {...itemProps}>
🤖 Prompt for 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.

In `@packages/visual-editor-renderer-react/src/blocks/artisanpack/breadcrumbs.tsx`
at line 114, The list item key currently uses a combination of position and
item.label which can be unstable; update the map callback that renders the <li>
(where variables item, position, and itemProps are used) to capture the array
index (e.g., add an index parameter to the map) and use that index as the key
instead of `${position}-${item.label}` so each <li> uses the loop index for
stable uniqueness.
🤖 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-vue/src/blocks/artisanpack/breadcrumbs.ts`:
- Around line 119-145: The else branch in artisanpack/breadcrumbs.ts always
assigns class 'ap-breadcrumbs__current' to non-link spans even when item.current
is false (happens when URL was sanitized to null); update the span rendering so
the class is added only when item.current is true (mirror the conditional used
for href branch), i.e., modify the code paths that build labelAttrs in the
non-link branch (the logic around labelAttrs and item.current) to conditionally
add 'ap-breadcrumbs__current' only when item.current === true; then apply the
same conditional class fix to the Blade and React breadcrumb renderers to keep
outputs consistent.

---

Nitpick comments:
In
`@packages/visual-editor-renderer-react/src/blocks/artisanpack/breadcrumbs.tsx`:
- Line 114: The list item key currently uses a combination of position and
item.label which can be unstable; update the map callback that renders the <li>
(where variables item, position, and itemProps are used) to capture the array
index (e.g., add an index parameter to the map) and use that index as the key
instead of `${position}-${item.label}` so each <li> uses the loop index for
stable uniqueness.
🪄 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: 1c468976-8845-4003-89b6-9e0f03b68101

📥 Commits

Reviewing files that changed from the base of the PR and between 3600fdc and 2c258b5.

📒 Files selected for processing (16)
  • packages/renderer-parity.json
  • packages/visual-editor-renderer-blade/resources/views/blocks/artisanpack/breadcrumbs.blade.php
  • packages/visual-editor-renderer-blade/tests/Unit/BlockRendererTest.php
  • packages/visual-editor-renderer-react/src/blocks/artisanpack/breadcrumbs.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/breadcrumbs.ts
  • packages/visual-editor-renderer-vue/src/blocks/registerCoreBlocks.ts
  • packages/visual-editor-renderer-vue/tests/BlockTree.test.ts
  • resources/js/visual-editor/blocks/breadcrumbs/block.json
  • resources/js/visual-editor/blocks/breadcrumbs/breadcrumbs.css
  • resources/js/visual-editor/blocks/breadcrumbs/edit.tsx
  • resources/js/visual-editor/blocks/breadcrumbs/index.ts
  • resources/js/visual-editor/blocks/breadcrumbs/inserter-icon.tsx
  • resources/js/visual-editor/blocks/breadcrumbs/save.tsx
  • resources/js/visual-editor/blocks/breadcrumbs/separators.tsx

- Only mark the breadcrumb span with `ap-breadcrumbs__current` when the
  trail entry is actually `current`. Previously every non-link branch
  carried the class — so an entry whose URL was sanitized away rendered
  as 'current' even when it wasn't the trail's final crumb. Mirrored
  across all three renderers (Blade, React, Vue).
- React: use the loop index for the `<li>` key instead of a
  position+label composite — labels can collide and the array index is
  already stable for this list.
- Add an assertion to the unsafe-URL parity tests confirming exactly one
  `ap-breadcrumbs__current` occurrence in the rendered output.
@ViewFromTheBox
ViewFromTheBox merged commit fb258ee into feature/495-port-crosswinds-blocks Jun 11, 2026
1 check passed
@ViewFromTheBox
ViewFromTheBox deleted the feature/496-cw0-pilot-breadcrumbs branch June 11, 2026 15:19
@github-project-automation github-project-automation Bot 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 CW0 · Pilot (breadcrumbs)

1 participant