johnpicozzi → credited ctrladel → .
ctrladel → made their first commit to this issue’s fork.
Tried out the interactions on with the current branch and found a few oddities/areas that could be improved. An overall issue I encountered is that it wasn't clear where things could be dropped because there's not a great indicator to tell where valid drop zones are for slots vs a component vs two components next to each other
- It's confusing that reordering and dropping into a slot have the same styles. I would expect the slot to highlight in someway if a component is going to be placed in it
- When dropping a component into a closed slot it'd probably be better if that slot opened when a component is placed in it
- Hovering over a closed slot should open it so I can drop a component deeper into the tree without having to open it first
- ( end-with-slot.mp4 → )Things get twitchy when trying to drag a component into a slot or to the end of a list when there is an expanded component containing a slot at the end of the list
- ( expanded-no-move.mp4 → )It's hard to tell if an expanded component will be placed in the same spot because the indicator appears at the bottom of the expanded tree for the component
- ( move-far.mp4 → )With an expanded tree the indicator can unexpectedly jump quite far down because it's the closest drop target
- ( general-weirdness.mp4 → )There's some general weirdness with the indicator jumping around
- The placement indicator isn't visible when it is before/after a selected component
Looks good to me.
The section previews are actually rendering correctly but are being pushed outside of the tooltip by "undefined" text which was the preview trying to include the css/js header/js footer. css, js_header, and js_footer weren't defined in the component definition which caused the include statements to ultimately be 'undefined' instead of an html string.
{
"id": "fakeSection2",
"name": "Fake Section 2",
"layoutModel": {
"layout": {
"nodeType": "root",
"name": "root",
"uuid": "root",
"children": [
{
"uuid": "abcde",
"nodeType": "component",
"type": "experience_builder:two_column",
"children": [
{
"uuid": "two-column-uuid-slot-column_one",
"name": "column_one",
"nodeType": "slot",
"children": [
{
"uuid": "fghij",
"nodeType": "component",
"type": "experience_builder:my-hero",
"children": []
}
]
},
{
"uuid": "two-column-uuid-slot-column_two",
"name": "column_two",
"nodeType": "slot",
"children": [
{
"uuid": "klmno",
"nodeType": "component",
"type": "experience_builder:my-hero",
"children": []
}
]
}
]
}
]
},
"model": {
"abcde": {
"width": 50,
"name": "Two column"
},
"fghij": {
"heading": "A hero in slot 1!",
"subheading": "This text was defined in the section.",
"cta1": "Yes",
"cta2": "No",
"cta1href": "https://drupal.org",
"cta2href": "https://google.com",
"name": "Hero"
},
"klmno": {
"heading": "A hero in slot 2!",
"subheading": "Text saved in the section",
"cta1": "Up",
"cta2": "Down",
"cta1href": "https://drupal.org",
"cta2href": "https://google.com",
"name": "Hero"
}
}
},
"default_markup": "<h1 style=\"background: black; color: white;\">TODO</h1>"
}
ctrladel → made their first commit to this issue’s fork.
Took a look at this at the Barcelona contrib day. Found and fixed a bug with the logic for the keyboard shortcuts so copy/paste actually works now.
I don't think reusing duplicateNode is going to be the right approach or at least it does not fully cover all the needed functionality. To be able to copy components between different nodes the component needs to be placed on the system clipboard and the json inserted into the tree. With the current approach it looks like we're only copying/pasting the component from app state.
ctrladel → made their first commit to this issue’s fork.
Images fall into the weird category of being both an element and a component. They should be individually placeable within slots or on a page but are also a fundamental building block of other components.
it has a single prop, also called "image", so the component looks like a meaningless wrapper around this single prop
I've found this to be a good way to future proof component definitions, it appears like a meaningless wrapper until there's a need to add another prop that is not directly an attribute of the image.
it doesn't use the expected attributes object
Attributes has always felt like an SDC antipattern that was included only to ease the integration with Drupal. This image use case is a great example of how a Drupal render array ends up having significant undefined impacts on the rendering of the component. An image component schema that fully defines/handles all the various ways to render an image as an html element would be way better then relying on whatever is in the attributes object but would be challenging with how much of an image's format/style is currently done in Drupal's render layer.
This issue is also making me wonder if part of the scope of 🌱 [META] Support component types other than SDC Needs work should be allowing media(and other entities?) to be placed directly in XB using view modes.
Wim Leers → credited ctrlADel → .
hestenet → credited ctrlADel → .
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
volkswagenchick → credited ctrlADel → .
I don't have any specific feedback on which library is best, react router has generally done everything I've needed.
We'll want to make sure there's a good path for integrating Drupal's translations with whatever option is chosen. I've had challenges in the past making sure small SPA type components are able to effectively use Drupal's translations. From what I've found interface translations are heavily dependent on Drupal's html responses either through the initial page response or ajax responses rendering twig or using Drupal.t() in javascript which is dependent on drupalSettings being populated with the initial page response or an ajax response. This poses a challenge when you want to get the translated title for a pop up or component edit pane that is only rendered from JS without requiring an html request to Drupal.
I don't understand why e.g. the first authoring form in the diagram has a yellow "Add Component to Slot 1" on the right-hand side: shouldn't that be on the left-hand side of "the forms"? Or what is the meaning of the layout of the different boxes in each "Forms" box?
The form's aren't laid out in any specific order, it's just a collection of forms(based on my opinion) that show how different modeling approaches change the amount of options an author could have and how many forms they'd have to interact with to create a component.
I see 5 different approaches, but I don't see specified who defines them, nor where. For example, the second example component (labeled "Components for layout and content"): who defined at what time that there is an "Image component" in the yellow drop zone/slot? Is it the SDC author? Is it the Site Builder? Where is that information stored?
In this case the components shown beside the Authoring Forms show a fully authored component. So a user with authoring permissions authored a side by side component with those values using the forms associated to that model. How forms are composed, where they are composed, and how an SDC definition can change from SDC definition -> embedded in a component -> field mapping -> being displayed to an author is probably worthy of it's own diagram.
In our past discussions, we said that field formatters must be available early. If so, we must be able to express them. If so, exposing them as field blocks probably makes sense? It’d make the upgrade path easy too. OTOH, doesn’t that inherit all scalability problems? We could also make field formatters a distinct “component type” or “renderable” (name TBD), which seems to make things simpler?
I'd be interested to understand more about the motivation here. Field formatters as we know them in Drupal(ones that output html) go against the concept of components only being passed structured values that they then place in their html.
What if there's a prop that you don't want content creators to be able to modify?
The internals of the component should not be editable when the component is being used. When the component is being used, it's only possible to modify props of the component, and insert components to the slots of the component.
This warrants more discussion. IMO components composed of other components should definitely be able to compose their forms by passing thru props and customizing what props are available on the authoring form otherwise we end up in the same situation various Drupal approaches and Acquia Site Studio have where every usage of a component in another component requires redefining fields on the parent form so they can be mapped from the parent to the child.
Back to the main question for this issue component vs element vs pattern. +1 to @laurii's take that elements are just a type of simple component. Expanding on the similar but different concepts touched on in the issue description for how components will be created/placed on a page. I've seen 3 main types of components that authors want to place:
- : These are the components that will most commonly be placed in XB by authors, you place them on a given page and that's the only place they'll ever need to be rendered.
- : These are components that are globally available, managed by site builders or by privileged authors they exist so that the same content can be placed on many different pages and when the content changes all the pages using the component show the newest content. This concept is implemented in core by blocks where reusable blocks can be placed in layout builder and in paragraphs through the paragraphs_library submodule.
- : These are what are being called patterns in this issue(not a huge fan of the patterns name btw). This is a set of components that have been authored either on an XB page or a separate pattern creation page and saved by a site builder or author to either the site or author's personal library of "patterns". These saved patterns are then available for the author to place when creating a page with XB but unlike reusable components that is a self contained reference to a component pattern components end up on the page as a preconfigured set of standalone components that have no concept of what their parent pattern is. Tossing out alternative names to pattern these could also be called stencils, templates, or blueprints. This is implemented for layout builder by https://www.drupal.org/project/section_library → and not sure if paragraphs has an equivalent.
@larowlan one of the benefits of using structurizr's DSL from is that it's really easy to generate and keep in sync smaller diagrams that are easier to digest and if you put the code in the previewer at https://structurizr.com/dsl it's really easy to zoom in/out on specific areas. I'm not particularly attached to structurizr but am a fan of the concepts behind c4 that encourage diagramming systems at multiple levels of detail so people can more easily onboard.
@wimleers I know these diagrams are early drafts but it looks like XB.dsl is missing Senior Developers as a person and Code Defined components that live alongside Config Defined components.
Redid the diagrams and updated the issue description to include @laurii's feedback and other feedback from Drupalcon discussions. Also with talk of this being referenced from the project page I changed the color scheme to be more accessible.
Changes
- Added the concept of an open, restricted, and closed slot. Restricted slots can be restricted by types of components that can be placed or the total number of components that can be placed within the slot. Closed slots help to clarify the functionality of embedded slots. When using a two column component for layout the side by side component may want to populate one column slot with known components through the side by side form(closing the slot) while leaving the other column free for any component to be placed in(open slot)
- Added a few more variations of how the side by side component could be built with slots.
- Added more descriptive text around the models and what "flexibility" means in the context of the diagram.
- Split the diagram into two images one for models and another for forms.
- Removed the different types of form approaches since the direction for XB appears to be using a sidebar. These were replaced with my ideas of what forms would be needed based on how a component is modeled.
Another possible home for the ADRs is the project's gitlab wiki. I think it's available to our poejcts but not sure if our unique contrib flow would work well with them. Gitlab does create a new repo just for the wiki, all changes to wiki are recorded as commits, and it supports markdown so overall sounds like it could work?
Wim Leers → credited ctrlADel → .
2.How can we load the Media Library within the Experience Builder (which is a React SPA)? (Frontend)
I've managed to decouple(ish) Entity Browser in the RJSF module, it still depends on some drupalSettings values so it's not fully decoupled. Never explored doing it for Media Library because Entity Browser did a good enough job for my needs and could be used for any entity type. Linking in case it's helpful. https://git.drupalcode.org/project/rjsf/-/tree/1.0.x/modules/rjsf_entity...
griffynh → credited ctrlADel → .
@pdureau this branch/MR was created before there was a 0.x and there were some previous components pulled from SDC at the top level which it looks like you reviewed. I just rebased the MR onto 0.x so now the only example components are the ones in the experience_builder_example_components submodule, would be great to get your thoughts on those.
Knowing that XB will likely require some changes to SDC schemas and that there are many features that need to be built on top of the schemas the overall goal here is to provide a diverse set of example implementation approaches to ensure that XB doesn't unintentionally limit how components can be built/used. A smaller set of example components also has the benefit of being easier to update and adjust as extra settings are added/removed from the schema. The full design system implementations you mentioned will be great to use as a more thorough test once XB is a bit better defined.
Would be interested to know If there are any common component structures/approaches you use that are missing from the examples and what would be a good example we could use to add them in.
ctrlADel → changed the visibility of the branch experience_builder-3446722-2 to hidden.
I wrote the https://www.drupal.org/project/rjsf → module to do this and was successful using it to implement component based authoring for several sites but after talking with Wim at Drupalcon there are a number of limitations that made me think it wouldn't be the best path forward for XB.
When it comes to forms there's really 3 different parts, the data model(schema), the view(form display), and the current data. JSON Schema does a really good job at defining the data model but has no concepts to define how a prop should display in a form. All the various JSON Schema form generators add on their own layer of properties and keys to the schema to allow defining how props should be displayed which potentially makes the XB JSON Schema less portable to other JSON Schema tools. If we were to adopt a form generator for XB we'd need to consider:
- If the library is extensible enough to meet all our needs, including allowing contrib to provide an arbitrary number widgets, from my work with RJSF it's good but is complex to make extensible for contrib.
- If the library's license is compatible with Drupal. RJSF is licensed under Apache-2.0 which as far as I understand is not compatible with GPL making distributing it with core difficult
- How developers(and non developers) would discover the various plugin widgets available and how they map to schema structures
- When defining a component meant to be used across multiple sites how do you know which components are available or denote a dependency? What happens when a widget defined the schema isn't available?
- How difficult it would be to reimplement and maintain two versions of core and contrib field widgets. We'd need both a PHP version and a JS version.
- Which schema are we storing? The schema for the content being collected or the schema for the content being rendered. Often the content when authored has a different structure then the template needs to render. Think a button link component, the target URL for is often an entity reference where we need to collect and store the entity reference from the form but the component template expects a url string.
- How would validation work? Most of these form generators have a built in client side set of validation that runs against the schema but Drupal's validation is much more extensive and would likely have to happen server side then need to be sent back to the form in some way.
I'm a fan of generated forms from schema and think that XB should have some amount of functionality to allow authoring of a component straight from the schema without additional configuration but overall after seeing that it's possible I'm a much bigger fan of reusing our existing field system and mapping known/validated content field structures to json schema props. Even if it means we have relatively ugly fields and forms to begin with. This approach lets JSON Schema do what it's good at which is define the structure of the props needed to render the component while allowing Drupal to do one of the things it's best at which is collecting and providing structured content to templates.
griffynh → credited ctrlADel → .
tekNorah → credited ctrlADel → .
Can you give it another try? I pushed a fix for the width issue, looks like something I broke while doing clean up before opening the MR.
ctrlADel → created an issue.
Just a note on the components in 📌 Introduce an example set of representative SDC components; transition from "component list" to "component tree" Fixed . They are very much intended as a place to test and experiment with the config/data structures experience builder will need. They may serve as a good starting point for some of the default components but definitely are not meant to be included as defaults.
ctrlADel → created an issue.
ctrlADel → created an issue.
lauriii → credited ctrlADel → .
Overall in favor of moving layout builder field storage from serialized php to json. Being able to easily read field values and query them would be great. Since the layout builder value is already exported to yaml for display mode configs it seems like it should be an easy jump to store it as json in the database.
An additional approach to the ones mentioned in #15:
Plain old plugin blocks
In this approach each component is represented as a plugin block in layout builder using the block's form to author the block within layout builder and then stored in the layout builder field along with the block's plugin id. This avoids the revisioning and proliferation of entities that come with paragraphs or content blocks. Downside is that the block and authoring form need to be defined in code(currently) with Form API. Since we have to use form API this results in losing access to an interface to configure the form/display and you can't use many use contrib modules that only provide fields and not form elements.
I've had pretty good success with this approach using an in house SDC like schema definition system and generated forms from schema using RJSF →
That works if you have one image gallery with multiple images. What happens if you want two image galleries?
With a component first approach you'd define two components an Image Gallery component to store multiple images and then a Two Gallery component with two slots where each slot would contain a Simple Gallery.
Other thoughts:
Perhaps a bit off topic for this issue but since the discussion is happening here I feel like there could be room for a whole new component entity type in addition to config and content entities. The definining characteristics of a component entity would be
- built in support for props aka fields
- built in support for slots aka drop zones/sections/regions that contain other components
- built in support to template/layout props and slots
- provides a way to restrict slots to only allow certain components
- is stored as a singular json blob
- Either one or both of:
- can gracefully handle when a saved json blob does not match the entities prop/slot structure
- leverages a working entity usage system so update hooks can reliably update json blobs when the component structure changes
- isn't a standalone authorable entity but is instead assumed to live within a config or content entity
- provides a way to transform prop values before passing them to a template(a reference field stores the entity id but in the component you always need a value from the entity like the title)
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
volkswagenchick → credited ctrlADel → .
I helped with Matt's globbing at Drupal's second best camp
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
This was included in the Alpha 2 release.
- Facet settings were added to the endpoint response using an event subscriber
- Facet settings were reviewed and some support for settings that apply to all facets was added
- Facet configuration from the API is preferred over the facet config provided by attributes, unless preferAttributes is present in a components attributes
Would this also postpone nice to have features for using cookie based auth to make requests? I agree in a fully decoupled scenario JWTs make a lot more sense but when looking to progressively decouple part of the admin interface cookie support is nice. Since a user logs in via Drupal to access the admin portion of the site anyways they typically will already have a cookie that can be used.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.
ctrlADel → created an issue.