Overview
When a component is placed it is assumed that it contains at least some HTML, which is wrapped in comments and has a data attribute attached so the XB UI can manipulate it.
However, it is not mandatory for components to output any HTML at all, e.g. if the component contains defensive code such as
{% if image and image.src %}
<img src="{{ image.src }}" alt="{{ image.alt }}" />
{% endif %}
It is also possible for a component to output text, but not HTML.
Proposed resolution
- Layers panel:
Relying on the layers isn't necessarily ideal so there's a trade-off between preview accuracy and discoverability of these components. I'll make sure to discuss this with @callumharrod and @reneelund in future but I don't think this is something we need to solve urgently.
— @lauriii at #3497990-16: [later phase] Support Block's PreviewAwarePluginInterface (and similar for other component sources)
- Canvas: When we are previewing a component that does not contain any HTML tags, detect this special situation and wrap them in a container, so they can still be previewed and manipulated correctly by the UI.
Out of scope: supporting Block plugins' PreviewAwarePluginInterface — that's for #3497990: [later phase] Support Block's PreviewAwarePluginInterface (and similar for other component sources) to handle.
Comments
Comment #2
longwaveComment #3
wim leersMore context: #3509608-54: Unable to save an optional image with its default value (because it does not correspond to a Media entity): allow saving DefaultRelativeUrlPropSource.
How do you propose doing that for code components?
Wouldn't be more accurate?
Comment #4
longwaveThere is nothing stopping an SDC or a block outputting a text string only, with no surrounding tags? I haven't tested but I think this would render as text in the preview but would not be draggable as there is no element to receive the click.
Code components are more tricky and would require hooking into the Astro renderer I guess, I haven't thought about or looked into that yet. Perhaps that can wait for a separate issue, or perhaps because of the way React components work there always has to be a wrapping element? Again, I haven't tested this yet.
Comment #5
wim leersI knew there were existing issues for this problem space already, but couldn't find them. Just stumbled upon one: #3497990: [later phase] Support Block's PreviewAwarePluginInterface (and similar for other component sources).
That's basically the same problem:
—
\Drupal\experience_builder\Plugin\ExperienceBuilder\ComponentSource\BlockComponent::renderComponent()PreviewAwarePluginInterface, but nothing in core actually uses this to render an alternative representation; only Layout Builder does it in a heavy-handed way:… we could use the same strategy, but wrap that string in a wrapper.
Thoughts? And … should we just merge this into #3497990: [later phase] Support Block's PreviewAwarePluginInterface (and similar for other component sources)? 😅
Comment #6
longwaveYep let's handle this in #3497990: [later phase] Support Block's PreviewAwarePluginInterface (and similar for other component sources)
Comment #7
wim leersReopening per @lauriii at #3497990-18: [later phase] Support Block's PreviewAwarePluginInterface (and similar for other component sources).
Thanks to #3518832: ComponentSource robustness: add `ComponentSourceTestBase::testGetClientSideInfo()`, the
sdc.xb_test_sdc.image-optional-without-exampletest case (added by #3507641: Allow components containing non-required images and no examples to be placed) for\Drupal\Tests\experience_builder\Kernel\Plugin\ExperienceBuilder\ComponentSource\ComponentSourceTestBase::testGetClientSideInfo()already provides an empty string example.We of course only want to do this when rendering a component for XB previewing purposes (so:
ComponentSourceInterface::renderComponent(isPreview: TRUE)). Which means the following are closely related — until they're both in, we'll need to be careful with the test coverage:(Because the test coverage that #3518832 added is still expecting the component previews to be rendered with
isPreview: FALSE, which #3518832 is fixing/changing 👍)Comment #8
wim leersMaking what @lauriii proposed more explicit.
Comment #9
wim leers… thinking of this some more, should we use a similar strategy here as for #3485878: Server-rendered component instances should NEVER result in a user-facing error, should fall back to a meaningful error instead (+ log)? 😇
Comment #10
lauriiiWould there be a way for us to only add the wrapper if a component doesn't render anything or renders a text node?
Comment #11
wim leersIf we go as far as #3485878: Server-rendered component instances should NEVER result in a user-facing error, should fall back to a meaningful error instead (+ log): possibly.
But my fear is that Block plugins' highly optimized rendering (which XB currently does not yet support — #3518656: Add Dynamic Page Cache and BigPipe support: `block` ComponentSource does not use placeholders/#lazy_builder is fixing that) will prevent us from doing this.
In fact, I think #3518656: Add Dynamic Page Cache and BigPipe support: `block` ComponentSource does not use placeholders/#lazy_builder should be a blocker to this; otherwise we can't guarantee that this is implemented correctly/completely the first time.
Comment #12
wim leers#3518656: Add Dynamic Page Cache and BigPipe support: `block` ComponentSource does not use placeholders/#lazy_builder is unblocked, so this is now less blocked.
Comment #13
wim leersOops.
Comment #14
lauriii