Patch (to be ported)
Project:
Drupal Canvas
Version:
1.x-dev
Component:
Shape matching
Priority:
Major
Category:
Task
Assigned:
Issue tags:
Reporter:
Created:
4 Jun 2025 at 13:13 UTC
Updated:
6 Oct 2025 at 15:37 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
effulgentsia commented"alpha blocker" was a typo. This is a blocker for beta.
Comment #3
wim leersComment #4
wim leersThis issue's title/summary is misleading: #3524130: Define JSON Schema $refs for linking/embedding videos and linking documents introduces not ONE "video" shape, but 2: one for local, one for remote.
The local one is about to land: [#3524130#21], the remote one won't land today for sure. oEmbed is hard.
Comment #5
wim leersAs of #3524130-24: Define JSON Schema $refs for linking/embedding videos and linking documents, local video shape matching is working:

Comment #7
lauriiiNote: the scope of this issue should be limited to local videos, i.e. we should not add support for OEmbed (Youtube / Vimeo) here.
Comment #8
effulgentsia commented"FE implementation" is ambiguous, so re-titling this issue to clarify its scope. #3534601: Add a Video prop type to the Code Component editor; requires adding `file` as default `StaticPropSource`, `FileWidget` support and various infrastructure improvements is a separate FE issue for the video prop that's a completely separate scope.
Comment #9
wim leersThis MR looks pretty far along, and the new
ui/tests/e2e/media-video-prop.cy.jsis passing! 🥳xb_test_video_fixture_install(): much of that could be just exported config instead; which would make this usable in recipes, too (and which would then benefit Playwright tests in the future).But since the
MediaandFileentities must be created this way, I think it's reasonable and pragmatic 👍So: RTBC. If you can address 2+3 and get CI to green, let's merge 👍
Comment #10
bnjmnm#9.2
I grabbed these videos from Pexels, which specifies they are free to use (although I should point out no specific license is mentioned). Also note I reduced the dimensions and frame rate of the videos before adding to provide a smaller file size.
Comment #11
wim leersWFM 👍
Comment #12
bnjmnmComment #13
bnjmnmIt seems like the mechanism that accounts for an image not yet having a value hasn't been applied to video. I added an intentionally failing e2e test that reproduces the steps.
To Reproduce: Add video component to layout, then update the Display Width field before adding a video
(This doesn't have to be the display width field - it can be any field in a component instance form with a video prop)
Component failed to render, check logs for more detail.in the previewThere's one scenario where this won't happen: If the prop is optional and a video has been added then removed. In this instance, the empty video will not result in an error because of the way removed media items are handled on optional props. The request no longer attempts to send the default value and instead sends empty ones
(The above is with a temporarily altered Video component so the video prop is not required)
Comment #14
bnjmnmUnassigning myself so a B.E. dev can have a look at #13
Comment #15
effulgentsia commentedI think @larowlan would have some insight into #13. Seems like our handling of "use this example value that's already the prop shape but isn't a Media reference" for images should also work for videos, but apparently something about it isn't.
Comment #17
larowlanGot to the bottom of this and it was quite tricky
The difference between image and video is shown here in the shape matching
\Drupal\experience_builder\Hook\ShapeMatchingHooks::getFieldTypePropsIf you look at the src expression on both of them, you will see that its largely identical.
So why doesn't our fallback to default values work for video?
Well its purely by coincidence that the
Imagealso hasalt,widthandheightWhen we try to evaluate these expressions in
\Drupal\experience_builder\Plugin\ExperienceBuilder\ComponentSource\GeneratedFieldExplicitInputUxComponentSourceBase::clientModelToInputbecause there's no entity found, we end up in thecatchblock that falls back to the default value.But this doesn't happen for Video. But why?
Because Image shape match contains three
ReferenceFieldTypePropExpressions that wrapFieldPropExpressions but Video only contains one that wrapsReferenceFieldPropExpressionAnd if we look into the evaluator it has this code
so the
$expr instanceof ReferenceFieldPropExpressioncode here means that for Video, theOutOfRangeExceptionis never thrown and hence the default value handling doesn't work.To fix this, I added a new option to
ReferenceFieldPropExpression, anisRequiredflag. I would like @wim leers to confirm my approach here as I'm not totally sure about USV (although I'm not really making use of USV to track the required flag).Once I add that and check for it, it works as expected. You can find that change in this commit
Comment #18
bnjmnm👏 to @larowlan for tracking that down. Assigning to @wim-leers here to reflect the existing assignment in the MR to get a +1 on that backend solution.
Comment #19
wim leersApparently it is a deep back-end/shape matching bug that @bnjmnm's e2e test coverage uncovered here 🤯
While the purpose was ensuring the worked as expected, it actually largely did (which I already expected given how I didn't have to change a single thing to video-selection-from-Media-Library work — see #5), except that infrastructure broke it. 👻
EDIT: cross-posted with @bnjmnm 😅
Comment #20
wim leersFound one more scenario that hits a bug that causes the
sdc.experience_builder.videocomponent to fail to render:Steps to reproduce:
Videocomponent/xb/api/v0/config/componentfor this component contains:target_id=2) but do not enter a display width, the client will send:This renders fine.
Note how
display_width's raw widget value is passed:value: "", which matches<input data-drupal-selector="edit-xb-component-props-189b4371-3fc7-4b4e-bb98-e5fe9a4c291d-display-width-0-value" data-form-id="component_inputs_form" type="number" id="edit-xb-component-props-189b4371-3fc7-4b4e-bb98-e5fe9a4c291d-display-width-0-value" name="xb_component_props[189b4371-3fc7-4b4e-bb98-e5fe9a4c291d][display_width][0][value]" step="1" min="1" placeholder="" class="_root_1or6m_1 form-number" value>Component failed to render, check logs for more detail.fallback.… which looks an awful lot like client-side transforms aren't being applied. Which … they aren't, because they're absent from the API response in step 1 — for every component 😅
Ah … but … it's #3515629: FieldWidget's XB transforms must be bubbled by the Field Widget rendering to inform the client that made it so, and moved that to
#attached['xb-transforms']+ respecting that in\Drupal\experience_builder\Render\MainContent\XBTemplateRenderer::renderResponse().To be determined where the root cause of that lies, but this is unfortunately reproducibly broken. The e2e test can and should be expanded to remove the video, check that it renders, then re-add it and continue the remainder of the test (where it sets display width 190 etc).
From a https://en.wikipedia.org/wiki/Robustness_principle POV, the server-side should gracefully handle invalid values received by the client that the field type cannot make sense of (
FieldItemListInterface::filterEmptyItems()), so … adding a work-around for the above problem, and triggering a deprecation error, to allow us to figure us out the root cause afterbeta1👍Comment #21
wim leersSo after the crazy #20 detour, time to properly answer @larowlan's #17:
FieldObjectPropsExpression, which itself usesReferenceFieldPropExpression. This is totally possible to make work: I got it to green.ReferenceFieldTypePropExpression, even though for data integrity reasons, it's already required that aStaticPropSourceis non-empty (seeassert($field_item_list->count() === 1);in\Drupal\experience_builder\PropSource\StaticPropSource::isMinimalRepresentation()). This will require widespread changes.code is positively ancient — I never expected it to survive to this day: it was a prototype to throw away/refactor! 😅 It dates back to >14 months ago, before we even were using the issue queue and MRs.
and not
ℹ︎entity_reference␟{src↝entity␜*␜entity:media:baby_videos|vacation_videos␝field_media_video_file|field_media_video_file_1␞␟entity␜*␜entity:file␝uri␞␟url}So … trying a completely different approach: rather than modifying our
StructuredDataPropExpressionInterfaces themselves, with not only LOTS of changes throughout the codebase, but also makes everyhook_storage_prop_shape_alter()implementation more brittle. Furthermore … it'd require changing that hook, because it currently does not distinguish between required or not! That'd also mean potentially doubling everyCandidateStorablePropShape: once for required, once for optional.Turns out … that works too 😊 commit + update a few calls I missed = green, and I'll be able to revert lots of (most?) changes.
💡 All this led to the lightbulb moment that that code I quoted in point 3 above is truly positively ancient and should be generally applying, rather than special-casing
ReferenceFieldPropExpression. Just did that, and then spent (too much) time figuring out the 2 failures: it was because of optional props with examples that needDefaultRelativeUrlPropSource… 😬 made that much more explicit.That was green, so finally reverted all the prop expression changes: https://git.drupalcode.org/project/experience_builder/-/merge_requests/1...
All green, more explicit, less change (if we'd have had to push this to completion, then all version hashes would change too, not to mention the last point), thoroughly manually tested.
I'm RTBC'ing and merging this as soon as it's green, because it A) makes @bnjmnm's new e2e test pass, B) it's totally fine for @larowlan to want to do a follow-up MR, C) it's totally fine for @bnjmnm to add the test coverage for #20 in a follow-up MR.
Comment #22
wim leersComment #24
wim leersComment #25
wim leers@larowlan in chat:
Yay, that answers — would still be nice to see happen 😊
Comment #26
neha_bawankar commentedTested changes on branch
0.x, following scenarios :Scenario
Result
Status
Comment #27
wim leersThanks for the detailed report!
This is a known problem. The preview then does not match (width 30) the entered value (0), which then post-publish indeed results in something the author did not see in the preview. The issue to change that: #3530795: [needs design] Invalid prop errors should be detailed in Component preview; otherwise the preview LIES 😱.
Same for the other.
Comment #29
nagwani commentedRemoving the beta-blocker tag as discused with Alex.