Overview

Quoting @mherchel from #3520487-57: Refuse editing an individual node's component tree (and bring back after 1.0 once exposed slots are allowed):

Had a discussion with @penyaskito at https://drupal.slack.com/archives/C072JMEPUS1/p1759435412275339, and he asked me leave a comment here.

I have a use case where I override the field template for the canvas field field--canvas-page--components.html.twig. The use case to add a CSS class that sets default spacing on all direct children below it, and overriding the template works perfectly.

However this template isn't called within the iframe preview within the canvas editor.


One of the main issues is that I'd hope that the markup of the page would be consistent (as possible). Removing this field template only on the editor iframe introduces inconsistencies that other people might run into.

  1. #3520487: Refuse editing an individual node's component tree (and bring back after 1.0 once exposed slots are allowed) made the editor frame's preview consistent with the live site, by making field--component-tree.html.twig not render any markup.
  2. #3548854: Add test coverage ensuring consistency on previews markup and live markup when using a content template still needs to add test coverage proving the editor frame preview is always consistent with the live site

However, both of those assume that field--component-tree.html.twig does NOT get customized.

@mherchel's theme is overriding that template, and even on a per-entity type/bundle basis.

Proposed resolution

Update the editor frame's preview rendering to be aware of the host entity type + bundle, and wrap the rendered component tree in the appropriate field--component-tree.html.twig.

\Drupal\canvas\Controller\ApiLayoutController::buildPreviewRenderable() is currently rendering the component tree directly, which is why this isn't showing up.

User interface changes

Imperfect → perfect previews!

Comments

wim leers created an issue. See original summary.

wim leers’s picture

Title: Ensure themes that override `components.html.twig` have their effects appear in Canvas' editor frame preview » Ensure themes that override Canvas' field type's default Twig template have their effects appear in Canvas' editor frame preview
Status: Active » Needs work

Here's a first stab. AFAICT this should result in what you want, but it'll have broken the ability for the canvas UI to render outlines around the component instances. There's a @todo in there with pointers on how to fix that.

diff --git a/src/Controller/ApiLayoutController.php b/src/Controller/ApiLayoutController.php
index 627927d6a..30c68a56c 100644
--- a/src/Controller/ApiLayoutController.php
+++ b/src/Controller/ApiLayoutController.php
@@ -378,15 +378,13 @@ final class ApiLayoutController {
   }
 
   private function buildPreviewRenderable(ContentTemplate|FieldableEntityInterface $entity, ?FieldableEntityInterface $preview_entity = NULL): array {
-    $renderable = $entity instanceof ContentTemplate
+    $build = $entity instanceof ContentTemplate
       // @phpstan-ignore-next-line
       ? $entity->build($preview_entity, isPreview: TRUE)
-      : $this->componentTreeLoader->load($entity)->toRenderable($entity, isPreview: TRUE);
-
-    $build = [];
-    if (isset($renderable[ComponentTreeItemList::ROOT_UUID])) {
-      $build = $renderable[ComponentTreeItemList::ROOT_UUID];
-    }
+      // ⚠️ Do not render the component tree directly, this would lose the
+      // wrapper markup for the content entity and the component tree field.
+      // @todo this does result in a call to \Drupal\canvas\Plugin\Field\FieldType\ComponentTreeItemList::toRenderable(), but it still needs to receive `isPreview: TRUE`. Without this, the Canvas UI won't be able to identify the boundaries of rendered component instances.
+      : $this->entityTypeManager->getViewBuilder($entity->getEntityTypeId())->view($entity);
 
     $build['#prefix'] = !empty($build)
       ? Markup::create('<!-- canvas-region-start-content -->')
effulgentsia’s picture

I agree that we need to make Preview and Published consistent, but I think we should go the other way and make sure that when a Canvas field is rendered on the published page, it's rendered without all the theme('field') stuff. The mental model should be that on a Page and on a Content Template (and when we get to it, within exposed slots of nodes), the Canvas defines the entirety of what's being rendered within the "content" region and/or exposed slot.

The use case is to add a CSS class that sets default spacing on all direct children below it

The <body> has a canvas-page class, and the content region has a region--content class, so can you achieve this use case by using .canvas-page .region--content as your selector or prefix?

mherchel’s picture

The has a canvas-page class, and the content region has a region--content class, so can you achieve this use case by using .canvas-page .region--content as your selector or prefix?

Yep I can. I'm doing something similar as a work-around right now.

Agree that the most important thing is making it consistent.