Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug(CdkDragDrop): preview position is incorrect when inside of a popover using translate #28889

Closed
1 task
JeffMosaic opened this issue Apr 16, 2024 · 7 comments · Fixed by #28945
Closed
1 task
Assignees
Labels
area: cdk/drag-drop P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent

Comments

@JeffMosaic
Copy link

Is this a regression?

  • Yes, this behavior used to work in the previous version

The previous version in which this bug was not present was

No response

Description

Currently if you are using cdk drag with a preview attached to its parent, and the parent is inside of a popover type element that uses absolute positioning and translate transformation then the preview artifact appears in the wrong location.

This appears to be happening because the fixed position is unable to break out of its container due to a parent element having a transform property attached. Based on MDN this appears to be the expected behavior.

Switching to use the global cdkDragPreviewContainer position works around this issue but then breaks styling because the preview element is removed from the DOM structure controlling style.

Reproduction

StackBlitz link: https://stackblitz.com/edit/stackblitz-starters-1zhux8?file=src%2Fmain.ts
Steps to reproduce:

  1. Click on one of the items
  2. Start dragging

Expected Behavior

Preview element should be at the same position as the mouse pointer

Actual Behavior

Preview element is several pixels to the right and bottom on the cursor.

Environment

  • Angular: ^17.2.0
  • CDK/Material: ^17.3.4
  • Browser(s): Chrome (maybe others)
  • Operating System (e.g. Windows, macOS, Ubuntu): macOS (probably others)
@JeffMosaic JeffMosaic added the needs triage This issue needs to be triaged by the team label Apr 16, 2024
@crisbeto
Copy link
Member

I think that this is a duplicate of #28864. I have it my TODO to add a note for transform being problematic.

@JeffMosaic
Copy link
Author

@crisbeto It does look like this is a duplicate of that issue. I agree that browser vendors have not given cdk a good way to solve this problem. Unfortunately to apply the workaround of attaching to body would result in breaking the cascade and requires the consumer of this API to do its own set of hacks to apply what would otherwise be inherited styles.

@crisbeto
Copy link
Member

Would it be an option to put a container for the inside the list and then have the preview be projected into it? Something like

<div cdkDropList>
  <div style="position: fixed; top: 0; bottom: 0; left: 0; right: 0;" #previewContainer></div>
  <div cdkDrag [cdkDragPreviewContainer]="previewContainer"></div>
</div>

@JeffMosaic
Copy link
Author

I appreciate the attempted workaround but all of the content in question is inside of a popover type element that positions itself using fixed and transform. Because of this and the way the spec is written for fixed positioning I do not think there is a straight-forward way to break the container out of being constrained.

From MDN

Fixed positioning is similar to absolute positioning, with the exception that the element's containing block is the initial containing block established by the viewport, unless any ancestor has transform, perspective, or filter property set to something other than none (see CSS Transforms Spec), which then causes that ancestor to take the place of the elements containing block

It is possible I am misunderstanding the provided workaround but how interpreted it was the following

<!-- does the fixed position + transform thing to position itself on screen -->
<my-popover-element>
    <!-- sets up some desired styles that are to be inherited -->
    <div cdkDropList>
        <!-- Unfortunately this is constrained to the bounds of my-popover-element because of its use of transform -->
        <div style="position: fixed; top: 0; bottom: 0; left: 0; right: 0;" #previewContainer></div>
        <div cdkDrag [cdkDragPreviewContainer]="previewContainer"></div>
    </div>
</my-popover-element>

The only options I see in this case are the following

  1. Consumer of cdk uses global positioning (default option) and manually applies styles using a class or some other selector pattern
  2. Consumer of cdk finds a parent that is outside of the transform element which in my case is the entire element that has styles I would like to inherit
  3. cdkDrag's preview is updated to handle this case by walking the DOM tree finding if this set of rules applies and then offsetting its transform by the position of the problematic parent element.

I must admit none of these options sound great.

@crisbeto
Copy link
Member

The example is more or less what I was imagining. I was also thinking if it wouldn't be possible to put the transform on something else that's not a parent of the preview container, but I realize that it might be tricky.

And yeah, it's unfortunate that this is the way they implemented the stacking context for fixed elements... I think the only viable workaround would be to create a native popover element dynamically (e.g. <dialog>), project the preview into it and then destroy that element.

@crisbeto
Copy link
Member

I'll reopen this so we can try to use native popovers for the preview element.

@crisbeto crisbeto reopened this Apr 18, 2024
@crisbeto crisbeto added P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent area: cdk/drag-drop and removed needs triage This issue needs to be triaged by the team labels Apr 18, 2024
crisbeto added a commit to crisbeto/material2 that referenced this issue Apr 24, 2024
…preview

Wraps the preview element in a native popover which allows it to always be rendered on top of everything and to avoid issues when the parent element has a `transform`.

Fixes angular#28889.
@crisbeto crisbeto self-assigned this Apr 24, 2024
crisbeto added a commit that referenced this issue Apr 24, 2024
…preview

Wraps the preview element in a native popover which allows it to always be rendered on top of everything and to avoid issues when the parent element has a `transform`.

Fixes #28889.
crisbeto added a commit that referenced this issue Apr 24, 2024
…preview

Wraps the preview element in a native popover which allows it to always be rendered on top of everything and to avoid issues when the parent element has a `transform`.

Fixes #28889.

(cherry picked from commit 7cd3f02)
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators May 25, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: cdk/drag-drop P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants