Impossible to drop a component into an empty column of the two

Created on 21 August 2024, 29 days ago
Updated 12 September 2024, 7 days ago

Overview

Once πŸ› Cannot place or drag child components Fixed is fixed, dragging-and-dropping child components works well πŸ‘

But what doesn't work yet with that done, is dragging a child component into an empty slot:

Proposed resolution

  • Update ComponentTreeHydrated::getValue() to include the default slot value for an SDC in its hydrated representation.
  • Update ComponentTreeHydrated::toRenderable() to override the default slot value (see prior point) in case the slot contain component instances. If it does not contain component instances, convert it to a renderable array using the same strategy that πŸ› SDC ComponentElement: Transform slots scalar values to #plain_text instead of throwing an exception Fixed introduced.
  • Expanded test coverage.

User interface changes

πŸ› Bug report
Status

Fixed

Component

Page builder

Created by

πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @Wim Leers
  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί
  • Assigned to Wim Leers
  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    Paired with @jessebaker, he let me know what's needed:

    1. slots without components placed in them MUST contain <div class="sortable-list" data-xb-uuid="%s" data-xb-type="%s"></div> for it to be presented as a slot in the UI
    2. slots without components placed in them BUT with default content (i.e. some markup) must wrap that default content in that same markup, to allow overriding that default content

    On it.

  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    SDC default slot value woes

    Turns out that SDC does not support:

    1. setting [#slots][$slot_name] = [] β†’ you'll get: Drupal\Core\Render\Component\Exception\InvalidComponentDataException: Unable to render component "experience_builder:two_column". A render array or a scalar is expected for the slot "column_one" when using the render element with the "#slots" property in Drupal\Core\Render\Element\ComponentElement->generateComponentTemplate() (line 118 of core/lib/Drupal/Core/Render/Element/ComponentElement.php).
    2. setting [$slots[$slot_name] = [#prefix => …, #suffix => …] β†’ you'll get only the prefix + suffix

    But it does support not specifying any value at all for a slot, then it'll happily use the default.

    IOW: I cannot wrap the default value of a slot (using #prefix + #suffix) β€” doing so causes the default value to disappear 😬

    Investigation

    So I investigated, to understand how to respect the SDC metadata for the two-column component that @ctrlADel added in πŸ“Œ Introduce an example set of representative SDC components; transition from "component list" to "component tree" Fixed :

      column_one:
        title: Column One
        description: The contents of the first column.
        # @todo can_be_dropzone: true
        examples:
          - <p>This is column 1 content</p>
        # @todo this should be a dropzone
      column_two:
        title: Column Two
        description: The contents of the second column.
        # @todo can_be_dropzone: true
        examples:
          - <p>This is column 2 content</p>
        # @todo this should be a dropzone
    

    And discovered that two-column.twig du:

    <div {{ attributes }}>
        {% if block('column_one') %}
          <div class="column-one width-{{ width }}">
            {% block column_one %}
              The contents of the one column.
            {% endblock %}
          </div>
        {% endif %}
    
        {% if block('column_two') %}
          <div class="column-two width-{{ 100-width }}">
            {% block column_two %}
              The contents of the two column.
            {% endblock %}
          </div>
        {% endif %}
    </div>
    

    … as you can see, the Twig template duplicates the sample content. That is where the default was coming from: from the Twig template not the SDC metadata! πŸ˜…

    Now that I understand that, I can continue figuring out a solution.

  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    TIL #slotsAlter, while discovering #5.

    πŸ› The test coverage in \Drupal\KernelTests\Components\ComponentRenderTest::checkRenderElementAlters() is incorrect. It suggests you can choose which slot to alter, but you cannot: it alters the *value* of one slot at a time. (Unlike #propsAlter, which alters all props at the same time, just as the name + test logic suggests.)

    Hopefully that won't block this issue; because fixing that core bug would come with nasty BC break consequences.

  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί
  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί
  • πŸ‡¬πŸ‡§United Kingdom jessebaker

    I've given @balintbrews as much context about this issue as I can so hopefully he can assist with anything you need next week.

  • Assigned to balintk
  • Status changed to Needs review 24 days ago
  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    t

  • πŸ‡­πŸ‡ΊHungary balintk

    balintbrews β†’ made their first commit to this issue’s fork.

  • πŸ‡­πŸ‡ΊHungary balintk

    This looks great, and it's very close! I noticed that you're able to drag the default content, and place it even outside of its slot.

    I pushed a fix for that, but we need to be able to target the default content somehow, so I propose that we wrap it in markup with a class named xb-internal-component-example. (Feel free to rename it if you have a better idea or if you think we can simplify it.) Would you mind adjusting the rendering logic accordingly?

    I also added code to prevent inserting a component above the example β€” this way we avoid having the example content move up and down, which may suggests that it stays in place even after a component is added.

  • Status changed to Needs work 24 days ago
  • πŸ‡­πŸ‡ΊHungary balintk
  • Status changed to Needs review 23 days ago
  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    Great observation!

    If I hack that together without writing code:

    diff --git a/components/containers/two_column/two_column.component.yml b/components/containers/two_column/two_column.component.yml
    index 4ba49c11..149b9bb2 100644
    --- a/components/containers/two_column/two_column.component.yml
    +++ b/components/containers/two_column/two_column.component.yml
    @@ -18,7 +18,7 @@ slots:
         title: Column One
         description: The contents of the first column.
         examples:
    -      - <p>This is column 1 content</p>
    +      - <p class="xb-internal-component-example">This is column 1 content</p>
       column_two:
         title: Column Two
         description: The contents of the second column.
    

    … then it looks like this:

    … which makes me wonder: wouldn't it be better if:

    • the entire column becomes the drop target? (i.e. the existing markup is overlaid with the gray diagonal lines that indicate a drop target)
    • … which removes the need for the before vs after distinction
    • … and would remove the "jumping" of the component just after dropping it

    Assuming you'd agree that's a good idea, I implemented something different instead: annotated the div.sortable-list wrapper with data-xb-slot-is-empty when it contains no components:

    WDYT? 😊

  • πŸ‡­πŸ‡ΊHungary balintk

    I like that idea! I played exactly with that last night after pushing my code, but deemed it too complex to do. I took a fresh look today and managed to implement it.

    Towards the end of the gif you can see that we could tweak the sensitivity of the drop target boundaries, but I thought that could be part of a more comprehensive round of UI improvements, so I didn't spend time with that. The same goes for making the entire slot the "ghost element" and not only the fixed size that's used everywhere.

    What do you think?

  • Assigned to Wim Leers
  • πŸ‡­πŸ‡ΊHungary balintk
  • Assigned to balintk
  • Status changed to Needs work 23 days ago
  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    +1!

    But currently the display: none is causing a somewhat jarring experience IMHO: it causes the drop zone to disappear mid-drag-and-drop, which even makes it unreachable if you drop it back in the original location:

  • πŸ‡­πŸ‡ΊHungary balintk

    Okay, this does need more work. I can see two problems:

    1. When dragging an item over a slot, it's very easy to trigger another slot's drop zone. Not only it is too easy, it's unexpected, and we should probably consider it a bug as opposed to how I generously described it as something to tweak. πŸ™‚
    2. While there is code in my latest commit that restores the visibility of the examples, it clearly doesn't always work. I couldn't quite figure out how to reproduce, but I was able to reproduce by playing around, and it's also visible on your screen capture.

    The first problem can be somewhat temporarily mitigated by doing what I did initially: leaving the example in place and only allowing to drop something below it. If we do this, the second problem goes away for now. Then we can open a follow-up issue to address the problem properly, then re-introduce hiding the example content.

    Or we can try to address everything in this issue. I'm happy either way! @Wim Leers, let me know how you prefer to proceed.

  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί
    1. So: when needing to "fly over" some slots to get to the "intended destination slot", we trigger unintended things. Is that what you mean?

      If correct: I think that could be a fine follow-up issue. That's a weakness that this MR reveals, it doesn't introduce it?

      i.e. I expected to be able to drag onto any part of the left columnin #18, instead of only the comparatively tiny target at the top.

    2. AFAICT it's really just the need to revert the display: none if the drag-and-drop action was canceled (i.e. if the dragged sortable is restored to its original position).
  • πŸ‡­πŸ‡ΊHungary balintk
    1. Both are correct: good rewording of the problem, and yes, this is something the changes emphasize, but it's certainly not new. I'll create a follow-up issue. I will mention increasing the drop target for slots β€” I already had some code experimenting with that. Also worth mentioning that πŸ› Retain the space consumed by a component when it's being dragged Fixed is also a nice improvement over what we're experiencing here.
    2. Nice! This is something I somehow missed testing! Based on your description I was able to fix the problem.

  • Assigned to Wim Leers
  • Status changed to Needs review 22 days ago
  • πŸ‡­πŸ‡ΊHungary balintk
  • Issue was unassigned.
  • Status changed to RTBC 22 days ago
  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    LGTM! I can't merge this though β€” it needs approval from both back-end and front-end folks 😊 Signaling that this is ready for final review by marking RTBC.

  • Assigned to tedbow
  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    Let's first get @tedbow to review the changes to ComponentTreeHydrated(Test).

  • First commit to issue fork.
  • Issue was unassigned.
  • πŸ‡ΊπŸ‡ΈUnited States tedbow Ithaca, NY, USA

    Looks good. I did my one suggestions

  • Assigned to bnjmnm
  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    Back-end pieces are in place. Now needs front-end sign-off to land πŸ€“

  • πŸ‡ΊπŸ‡ΈUnited States tedbow Ithaca, NY, USA

    Looks good. Thanks for the changes @Wim Leers

  • Assigned to hooroomoo
  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί
  • Issue was unassigned.
  • πŸ‡ΊπŸ‡ΈUnited States bnjmnm Ann Arbor, MI

    Reviewed FE only and approved as the FE person in the MR.

  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    πŸ₯³ Thank you!

  • Pipeline finished with Skipped
    21 days ago
    #268394
  • Status changed to Fixed 21 days ago
  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί
  • πŸ‡ΊπŸ‡ΈUnited States Kristen Pol Santa Cruz, CA, USA

    Rather than reopen this, Lauri said I should follow up in new issue so...

    πŸ› Adding a component with slots does not register the slots as children Fixed

  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024