- Issue created by @larowlan
- 🇫🇷France pdureau Paris
"tightly bundled to an SDC" may be the issue here.
As much as I like SDC components, they are UI / design thingies not CMS / building thingies. It is better to manipulate blocks & layout plugins, not directly SDC components, and some of them (I hope most of them) will be direct conversion from SDC components.
I have already posted this image in an other issue and warned about the coupling risk for the project:
https://www.drupal.org/project/experience_builder/issues/3454173#comment... 📌 Media Library integration (includes introducing a new main content renderer/`_wrapper_format`) Fixed
Not everything in a design system is a component
Let's look a bit forward. On our way to extends the design systems coverage of Drupal, we will meet other UI "artefacts" which are renderable in HTML, but which are not UI components.
2 examples:
- grid/layout systems: Very similar to components indeed, template-based too. So today they are implemented with SDC components, but it still be a different UI beast, often defined separately in upstream documentation. The model is a bit different too, instead of slots & props we have:
- regions: looks like slots, but they can have a dynamic number of them which is not possible (and not wished) for UI components
- container options (gutters ? fluid?)
- regions options, would be "props of slots" ?? with different value by slot, also context sensitive, with different value by viewport
- icons: what is defined (the iconset) is not what is renderered (the icon), the main part of the definition is the discovery handler: do I zone a bitmap? do i look for SVG in a folder? do i parse a font? the the model and the renderable are different:
- they have no slots but they may have settings (like "props")
- a renderable will look like that: {#type: "icon", "#iconset": "foo", "#icon": "bar" } with optional settings
- the rendering follow a dual mechanism: direct inclusion which depends of the discovery handler: unicode point, SVG markup, IMG HTML Element... or "calls", which may leverage Twig or not
We are only at the beginning of our design system journey. Do we want to introduce a specific tight coupling each time? Or do we want to manipulate known CMS objects without caring about their implemented design origin?
- grid/layout systems: Very similar to components indeed, template-based too. So today they are implemented with SDC components, but it still be a different UI beast, often defined separately in upstream documentation. The model is a bit different too, instead of slots & props we have:
- Assigned to lauriii
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
@lauriii wrote in Slack that he also images layout plugins become available in XB. But that's not listed in the product requirements. It is sort of implied by
39. Layout Builder migration
though.@lauriii, I'm curious if you could provide more color/context than what you said in Drupal Slack (which will be nearly impossible to find later anyway)? 🙏
@pdureau I'm confused why you bring "icons" into this discussion. That seems to be a much lower level thing — a design system artifact as you described it a few weeks ago. Do you consider that "another component type"? 🤔 (@lauriii can probably help clarify this too.)
- 🇫🇮Finland lauriii Finland
@pdureau I would imagine this issue is to remove that tight coupling so that we can have other concepts like Blocks exposed in the Experience Builder. 😊 This was documented in the product requirements with the following user story:
As a builder, I can place and render blocks and fields rendered via Twig if they are exposed to the page builder as components. Blocks and fields defined in Twig should be able to render both in the preview, and the end-user facing page. This is to enable backwards compatibility with code that already exist in contrib and custom modules.
@Wim Leers We don't have a separate product requirement for layout components. We discussed them as part of the default design system and style guide discussion. What we discussed was that by default, Experience Builder would provide a single section/grid component which can be configured into different shapes. The grid system itself including columns, gutters, container options (i.e. fluid vs fixed) is configured in the style guide. This component is mainly targeted at the builder persona, which they could use to configure into different shapes as patterns and no-code components.
Exposing Layout Plugins themselves as @Wim Leers guessed has more to do with legacy support. We could discover there are valid use cases for Layout Plugins in this new paradigm but I'm not aware of any at the moment.
- Issue was unassigned.
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
The grid system itself including columns, gutters, container options (i.e. fluid vs fixed) is configured in the style guide.
I don't remember discussing this. Where is that written? 🤔
@lauriii: Which component types do you currently think to make sense?
Everyone: please add to the table I just added to the issue summary! 🙏
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
To be able to use field formatters in XB, we could go with either Layout Builder's block-centric approach (
\Drupal\layout_builder\Plugin\Block\FieldBlock
) or just use field formatters directly (which would still allow for an easy upgrade path) and should help UX/performance scalability challenges (see ✨ Add the notion of a 'configured layout builder block' to solve a number of content-editor and performance pain points Active ). - 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
To achieve the great UX that XB aims for, including "direct manipulation" of visible pieces (see 📌 Implement endpoint for realtime preview Active ) without imposing additional work on the component developer (regardless of "component type", name TBD), it is necessary to be able to automatically infer which (Twig) template input connects to which component input (for SDC: "props").
For example: for
sdc_test:my-cta
SDC, that would mean that the visible part of its template<a {{ attributes }} href="{{ href }}"> {{ text }} </a>
connects to the
text
prop.That requires connecting the component's template's AST (see #3453690-10: [META] Real-time preview: supporting back-end infrastructure → ) to the component's inputs. For an SDC this is fairly straightforward.
This may not be possible (or relevant!) for all component types though: For e.g. a block it may not be possible to do that: the
SystemMenuBlock
block plugin only accepts settings for defining how/what subset of the menu to render, so none of the "component's inputs" are directly visible in the template. - 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
While working on this + 🌱 [META] Configuration management: define needed config entity types Active , I stumbled upon an aspect in the product requirements that is confusing, so opened an issue to get a clarification from @lauriii, the product owner: 📌 Clarify "components" vs "elements" vs "patterns" Active .
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
I'm working on some API design here to allow us to support these things
- Merge request !68Draft: #3454519 Add notion of source and tree storage plugins and a component repository. → (Closed) created by larowlan
- Status changed to Needs review
10 months ago 3:43am 25 June 2024 - 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
I've scaffolded some rough code to break the coupling between SDC and components into the branch as follows:
Adds two new plugin types as follows:
- Component Source plugin
- Component Storage plugin
Component source plugin
This decouples the component config entity and component tree from SDC components.
There's a SingleDirectoryComponent implementation that all the existing logic moves to
Adds two additional implementations as follows:- Layout - this will support layouts for a bridge to layout builder
- Blocks - this will support blocks (e.g. views, menus) as well as a bridge to layout builder
Paves the way for:
- Theme builder component - we can create a content-entity here (e.g with fields js, css, twig, props, slots) and build components from the DB based on that
- Paragraphs support - could be in contrib or a sub-module
Component storage plugin
Decouples the component tree loading from the component tree field.
There's an implementation for ComponentTreeItem that holds the existing logic
Starts to scaffold a layout builder version in a sub-module that in could possible be a BC layer for layout builder (I'll keep going on this).
Also opens door to:- storage of default values (e.g. equivalent to LB defaults).
- additional view modes in separate fields (something LB can't do)
- paragraphs support for legacy
- 🇺🇸United States effulgentsia
If I'm reading this right, this MR introduces the concept of a "component", that can contain props and slots, but is decoupled from SDCs, and therefore can forward those props and slots to a different source plugin, such as blocks and layouts. What does this enable or make better than what you'd be able to achieve by implementing a "block" SDC or "layout" SDC that performs that forwarding? If we already have the concept of SDCs, why introduce yet another concept of a "component"?
#2 gives some examples of where
props
andslots
might be an insufficient data model, but I'm not clear how this MR resolves that.I guess from my perspective, what's important about SDCs isn't the SD part (though that part is nice for ergonomics) but the props and slots part.
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
@effulgentsia can you elaborate some more on how we could achieve that?
The SDC plugin manager is not like other plugin manager in core in that it doesn't support derivatives OR fire an alter hook.
This means there is no way to dynamically declare SDC plugins/components. This is by design, looking in the comments in the manager it says only directory based components are supported. If that's the case then the only way we could make SDC components for blocks would be to manually create them. This would mean something like twig tweak's `drupal_block` function in core. This effectively makes these components hidden from site builders. The other alternative is we swap out the plugin manager and add support for dynamic plugins. (There's also a third option, dynamically write components to disk, but that won't work on secure hosting where the file system is read-only outside the files folders - e.g. skpr amongst others). That's even before we start thinking about theme-builder created components.Another approach is to flip the script and make blocks the canonical thing - we have prior art for blocks that wrap SDC (sdc blocks, component blocks modules) but blocks don't support slots, so they're out.
Layouts do support blocks and props - but it feels like forcing a round peg in a square hole.
Hence this approach - a new component definition interface and repository. It means we can have components from things other than SDC folders on disk.
- 🇺🇸United States effulgentsia
The SDC plugin manager is not like other plugin manager in core in that it doesn't support derivatives OR fire an alter hook.
This means there is no way to dynamically declare SDC plugins/components. This is by designOh right, I forgot about that. I think what we should do then is either:
- Create a contrib module separate from XB that replaces/decorates the SDC plugin manager in order to allow PHP-defined SDCs, or
- Create a contrib module separate from XB that defines an abstract "component" concept that can be rendered by SDCs or other things, similar to this MR.
Then hopefully whichever of the above we choose can make its way into core eventually.
The pro of #1 is that modules that have already begun to standardize on SDCs, like https://www.drupal.org/project/sdc_display → , can work without change with not-on-disk components.
I guess the con of #1 is then the "SD" part of the "SDC" name becomes less accurate.
I'm concerned about XB defining its own component concept, and a bunch of other modules each defining their own component concept. What I prefer about #1 is that the SDC concept is already in core and has the shape we want (except perhaps if @pdureau's comment #2 is foreshadowing that XB will need to work with components that need things that can't be cleanly represented with props and slots, but I'm not clear yet on how those specific examples will relate to XB).
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
I think my preference would be to add support in core for programmatically declared components.
I'll open an issue for it. - Assigned to wim leers
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
I intend to review @larowlan's MR first thing on Monday :)
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Note that I do not think this is in the critical path for 🌱 Milestone 0.1.0: Experience Builder Demo Active , but it would be awesome if we can get this in place before then for sure — we'll need it for 🌱 Milestone 0.2.0: Experience Builder-rendered nodes Active , because without it the data model would be very much incomplete.
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
I had to focus on other things today. ( 📌 Add component instance edit form to contextual panel RTBC is a major step forward. #3450586-26: [META] Early phase back-end work coordination → is now conveying again what needs to happen in the short term.)
I'll review tomorrow. Sorry for the delay.
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
@Wim Leers I think we should have a chat about this first. I think there's a quite a few things in it that could be split out on their own. There's also some changes needed in relation to discussion with @effulgentsia above.
Tried messaging on slack to arrange a call.
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
About to meet with @larowlan — but wanted to make sure I processed everything said on this issue ahead of our meeting in a few minutes 😊
@effulgentsia in #13 and @larowlan in #14: Variable # of slots (the "grids" example provided by @pdureau in #2) is a limitation of SDCs. It's also something that @lauriii has identified as one of the biggest risks of this project: the fact that we don't have a full sense yet of what missing features and technical limitations in Single-Directory Components that XB needs resolved. We know about component variants ( ✨ Introduce component variants to SDC Active ), about variable # of slots (the "accordion", "image gallery", etc. use cases — no issue yet AFAIK), but what else?@larowlan in #14: we have a PoC branch (built by @tedbow) that decorates the existing SDC plugin manager, to prove that XB could add support for "config-defined SDCs" (in addition to the default of "code/directory-defined SDCs")
I guess the con of #1 is then the "SD" part of the "SDC" name becomes less accurate.
— @effulgentsia in #15
I'm less concerned about this consequence: every "non-directory SDC" could be converted into an SDC, exported, if you will. That's actually a literal product requirement of Experience Builder:
63. Shared components
's user story says exactly that!@larowlan in #16: Did you already open that issue?
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
@larowlan just walked me through the changes in the MR attached to this issue. He identified 5 areas, each of which can be split into their own issue/MR:
- 👍 Removing the tight coupling between a single SDC and XB's
Component
config entity based on the ID (this was an intentionally simplistic choice in 📌 "Developer-created components": mark which SDCs should be exposed in XB Fixed ), to both allow >1 config per component (not sure about this, because @lauriii IIRC indicated there should only be one set of default values per component, I can see both sides) as well as allowing non-SDC "components" - 👍 Allowing non-SDC "components" is made possible through new infrastructure (see
ComponentSourceInterface
and friends, and in particular theBlockComponent
component source plugin for a very interesting example). @larowlan was interested/glad to see the PoC branch I linked in #21, and we concluded that for now we'd replace theplugin.manager.sdc
service in XB (so: choosing #15.1, not #15.2 as in the current MR), but we eventually would want to see that in core. But ahead of it (hopefully) being in core (which would need the support from SDC maintainer @e0ipso), it'd make sense to validate that in contrib.
So: the concrete implementation in the current MR would change to become more akin to what's in the PoC branch, but the concepts in the MR would remain. - 👍 Typed PHP objects in lieu of an array-based structure returned by
SdcController::layout()
(seeComponentLeaf(Interface)
and friends) would make the tree structure better defined, and would unblock a Just-in-Time approach of loading e.g. Layout Builder into the Experience Builder UI, which in turn enables a smooth, gradual adoption/transition from Layout Builder to Experience Builder. - 👍 Building on top of point 3, we'd also need to allow for multiple possible places to store component trees: they may originate from more places than just an XB field (for example:
LayoutBuilderSectionComponentTreeStorage
), which is how the JIT loading becomes possible (using . Besides transitioning from Layout Builder, it would also enable the use case of defining multiple component trees (one per view mode — by makingComponentFieldTreeStorage
aware of the render context). - 👍 To allow for that, it must become optional to have a
Component
config entity defined for every component, because when JIT-loading the component tree from a Layout Builder field (seeComponentDefinitionRepository
, those config entities would not exist. This is exactly the direction we were already going in with 📌 Support complex SDC prop shapes: introduce (Storable)PropShape to compute field type storage settings Fixed : that too is working towards makingComponent
config entities optional.
We didn't delve into the concrete implementation details of any of these, but they all would represent significant steps forward towards meeting the product requirements.
I'm super excited about the changes @larowlan is proposing here. Especially because in every of the 5 areas, he's bringing in relevant pieces of his vast real-world experience with Layout Builder, wanting to avoid the scalability problems he experienced there. 🙏🙏🥳🚀
(For example, we also discussed the need for per-slot restrictions on which components would be allowed, which is possible in Layout Builder using https://www.drupal.org/project/layout_builder_restrictions → , but that module has scalability issues because the "tags" are not built in. That validates @lauriii's thinking to make that an inherent part — see #21.4.)
- 👍 Removing the tight coupling between a single SDC and XB's
- Issue was unassigned.
- Assigned to larowlan
- Status changed to Needs work
9 months ago 8:21am 17 July 2024 - 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Clarifying issue status: conveying that @larowlan is working on next steps 😊
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Finally fully caught up on everything that happened in the issue queue since June 20 noon — you opened 📌 Experiment: Adapt existing layout builder storage model instead of starting fresh Postponed: needs info just as I'd left for vacation. 😄
I think the draft MR here (https://git.drupalcode.org/project/experience_builder/-/merge_requests/68 is essentially a subsequent concrete iteration of the proposal over at #3456064, @larowlan?
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
larowlan → changed the visibility of the branch 3454519-pluggable-storage-components to hidden.
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
Created those issues and a bonus one as children of this one.
I need to do some security team tasks tomorrow, but if I get through those I'll start on some of these as well.Used the pnx²b 😉 tag and flagged with colleagues as well.
- Assigned to f.mazeikis
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
The issue summary needs to be expanded with at least Layout Plugins, probably also Paragraphs?
I took a stab at expanding it with:
- one new row:
LayoutInterface
- one new column:
More needed.
- one new row:
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Interesting observation: the first column are all existing plugin types, but one is more special than others…
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Tying this to my detailed analysis for Blocks at #3462241-8: Decorate the SDC plugin manager and allow components defined in code → .
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
FYI: 📌 Make Block config entities fully validatable Fixed landed July 22, which means supporting Blocks in XB is much more feasible now. IMHO XB should support only block plugins whose config schema is fully validatable, because only then can we be confident that a block placed in an XB component tree will work reliably (prior to that, a block plugin's block settings is quite often just … a dumping ground).
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
IMHO 📌 Prepare for multiple component types: ComponentTreeStructure should contain Component config entity IDs, not SDC IDs Fixed is the inevitable first step — regardless of whether we do 📌 [later phase] [PP-2] Prepare for multiple component types: prefix Component config entity IDs with `sdc` Postponed or not. Together with @abhisekmazumdar, I got that to green, so … consider this officially started 🤓
- 🇬🇧United Kingdom longwave UK
After reviewing the IS and considering the comments and code provided here, I think @larowlan's approach is valid.
We could try to repurpose SDCs so they can wrap blocks or layouts, but this doesn't conceptually appear to be the right thing to do - SDCs are self contained single directory components by definition, so expanding them with features beyond is scope creep.
We could try to use blocks everywhere and wrap SDCs in blocks, but then we run into the slots issue, and would have to extend blocks so they support slots in some way.
What we are trying to do here is map props/values and slots/components into (at least) three things that are conceptually different (SDCs, blocks, layouts). This is effectively a translation layer and as such should be entirely standalone from the sources and targets of the translation; therefore I think this is the correct direction for this problem.
Also re #2 and the mention of icons, ✨ Add an icon management API Active is a future proposal but eventually we could end up with icons as yet another component type alongside SDCs and blocks?
- 🇫🇷France pdureau Paris
We could try to use blocks everywhere and wrap SDCs in blocks
That is the way to go in my opinion. You can have a look on UI Patterns 2 implementation:
- a block plugin: ComponentBlock
- a deriver: ComponentBlock
but then we run into the slots issue, and would have to extend blocks so they support slots in some way.
Which slots issue? Blocks doesn't have to knows about slots themselves, they just have to wrap a component which will know about slots.
Using the Render API, everything is supposed to nest nicely:
[ '#theme' => 'block', 'content' => [ '#type' => 'component', '#component' => 'example:button', '#slots' => [ 'label' => [ '#type' => 'text_format', '#title' => 'Body', '#format' => 'full_html', '#default_value' => '<p>The quick brown fox jumped over the lazy dog.</p>', ] ] ] ]
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
The first step towards decoupling XB from SDC just landed: 📌 Prepare for multiple component types: ComponentTreeStructure should contain Component config entity IDs, not SDC IDs Fixed . 🥳
@pdureau in #35
Interesting! I suspect you're looking at blocks through a very particular lens here: as a mechanism for rendering. (Although you'd still have to do extra work to avoid the
block.html.twig
wrapping markup to appear around every SDC.) Because:That is the way to go in my opinion.
vs
Which slots issue? Blocks doesn't have to knows about slots themselves, they just have to wrap a component which will know about slots.
is a contradiction from an Experience Builder point of view AFAICT 😅
The reason blocks not knowing about slots being a problem is because we're talking about what the right abstraction layer would be for XB to deal with all components the same way, regardless of component type/source (SDC, Block, Layout …). Since blocks don't have slots, they are unable to decorate/wrap SDCs and still provide access to critical information.
- 🇬🇧United Kingdom f.mazeikis Brighton
I've created #3475584 📌 Add support for Blocks as Components Active to start working on "Blocks as Components" requirement. It's based on @larowan work started in MR68 (closed). It's limited scope, focusing only on blocks for now and using the "Component Source Plugin" approach, as per #12 🌱 [META] Support component types other than SDC Needs work .
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Another step landed: 📌 [later phase] [PP-2] Prepare for multiple component types: prefix Component config entity IDs with `sdc` Postponed . Component config entity IDs are now present in the client-side data model, instead of SDC plugin IDs. Next up: 📌 Add support for Blocks as Components Active .
- 🇺🇸United States Kristen Pol Santa Cruz, CA, USA
We discussed this a couple of days ago at
📌 XB migration meeting 31 March 2025 8:30pm to 9:30pm UTC Active
and at DrupalCon Altanta.
Can we explicitly add Paragraphs to the issue summary list at this point?
- 🇺🇸United States Kristen Pol Santa Cruz, CA, USA
Add Paragraphs to list in issue summary, but with TBD placeholders as we are sorting things out.
I suppose we need a Layout Blocks item as well per @larowlan's slides but I'll check with him.