Problem/Motivation

Right-click a component that sits at the root and has a slot, then choose Duplicate: the copy lands inside the component's own first slot, not next to it.

The contextual menu works out where a paste or a duplicate lands with ContextualMenu.getSlotData(). Its third case, "the target is a container with its own slot", exists for Paste: it offers that slot as the destination. Duplicate reuses the same result. A root node has no parent, so data-slot-node-id falls back to the node itself, and the request names the node as its own parent.

The keyboard shortcut is right. For mod+d, keyboard.js takes the closest slot wrapper around the node, and the root when there is none. The two paths disagree.

ApiActionsController::paste() already carries a @todo about it. The "Contextual duplicate and remove" Playwright test does not see it: it counts components at any depth, and a copy nested in the slot still makes two.

With a Button component the copy is a button inside a button, which breaks the builder page: #3627001: Invalid HTML nesting in the Canvas takes the contextual menu and the messages out of the builder.

Steps to reproduce

  1. Open a builder and drop a component with a slot at the root.
  2. Right-click it and choose Duplicate.
  3. Open the Navigator: the copy is a child of the original.

Seen on a pattern preset builder whose root is a UI Suite Bootstrap Button.

Proposed resolution

  • Duplicate resolves its target as mod+d does: the slot the node lives in, or the root when it has none. The third case of getSlotData() stays for Paste.
  • The menu and the shortcut share one resolution, so they cannot disagree again.
  • The Playwright test asserts the copy is a sibling: two components at the root, none nested.

In a pattern preset builder the root takes one node. Duplicating its root then answers "There is no room left here", from #3626659: Paste, duplicate and preset insert end in a server error when the target is full or gone.

Remaining tasks

At the root, paste() attaches at position 0 whatever position it is sent, so a root copy lands first, not after the original. Decide whether that is fixed here or in a follow-up.

User interface changes

The copy appears next to the original.

API changes

None.

Data model changes

None.

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

mogtofu33 created an issue. See original summary.

mogtofu33’s picture

Issue summary: View changes

  • mogtofu33 committed be0e1336 on 1.0.x
    fix: #3627000 Duplicate from the contextual menu lands next to the node...
mogtofu33’s picture

Assigned: mogtofu33 » Unassigned
Status: Active » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.