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

cmd+dragging a view / element / component causes unpredictable behaviours based on parent layout mode #69

Closed
maltenuhn opened this issue Jun 9, 2020 · 5 comments · Fixed by #137
Assignees
Labels
Perceived Bug Something that feels broken or like a problem

Comments

@maltenuhn
Copy link
Member

Problem
"I tried moving this div with CMD like you said, but it's not moving"

Root cause
The div in question was in another div, which didn't have a layout type enabled. As a result, it behaved like a flow layout. In a flow layout, at most you can reorder (and not even that if there's a generated element elsewhere in the flow). Otherwise the element stays put until you've moved it out fully. If you're moving it into another flow (or flex) layout, it can give the impression it's still "stuck"

Analysis
In almost any design tool, cmd+drag gives you free-form control over the element you're dragging. We used to do that as well. This meant that you were getting the feedback "I'm moving this thing", with what happens to it (because of layout system etc becoming a separate thing). However, this either regressed or broke. As a consequence, a view inside a flow layout, flex layout, or pinned absolutely, will behave radically differently but with little to nothing on the canvas to tell you that. It also means that during a reparent you get weird or unpredictable behaviours. But most importantly, it gives the impression the editor is "broken", "laggy", "not behaving well".

Proposed solution

  • In legacy we solved this well, through suffering, by not actually reparenting until the element was dropped, and instead showing a placeholder control.
  • If that's not possible, another option is to clone or snapshot the element and move that "wherever the mouse goes", to give the illusion of control. However, that will probably fail on drop
  • To solve that, there is the option of creating a placeholder view (not a control) that is actually being reparented-in-realtime, possibly with similar top level settings

(Please discuss in #feature-layout before implementing a solution)

@balazsbajorics
Copy link
Contributor

(I'm on the phone with Malte)

Spike 1 for a possible solution would be to make sure that we can make a "screenshot" of the dragged element, and only the dragged element (do not include things that are visually below it or over it etc).

@maltenuhn maltenuhn added the Perceived Bug Something that feels broken or like a problem label Jun 10, 2020
@Rheeseyb
Copy link
Contributor

I was just having a look at this to see how simple that proposal would be, and I think this is a bigger problem than that proposal would solve.

So the underlying issue here is that sometimes we don't want the rendered controls to map 1-to-1 with the outcome, and sometimes in those cases we also want the rendered controls to include a version of the thing being updated. So some example cases:

  • Dragging an element that is in a flex container (no change of parent) - the controls should stick to the mouse, but we should show the result of the drag too. In this case having a placeholder rendered in the final location worked nicely. Having a snapshot of the element as part of those controls (and also applying the result in real time to the actual element) means you'll see the element twice, with overlapping occurring in a lot of cases. If we adjusted the opacity that might help, but then what if the thing being dragged already has partial opacity?
  • Dragging an element to re-parent it into a container that changes the layout - very similar situation to the above, but if the re-parent were to trigger the element to disappear completely then having the semi-transparent snapshot in the controls would certainly make it clearer what is happening here
  • Dragging to move (or even resize) an element that has some transforms applied to it - as much as it will be painful to create the controls for this (though we did find a library that would help before), you'd probably want the controls to reflect that transform (something that is being partially wrestled with in Fix/canvas dragging with margin #91 ). In this case it feels like you wouldn't want to see the placeholder result or the snapshot in the controls?

IMO what we had in legacy partially solved the first two (I'd say we should also adjust the opacity of the dragged thing if the result doesn't match the controls 1-to-1), but not the second. Is this worth further discussion before someone undertakes that spike?

@maltenuhn
Copy link
Member Author

maltenuhn commented Jun 11, 2020

I'll fill in some more things from the discussion with @balazsbajorics here, and then separately comment on @Rheeseyb your (super helpful) notes.

The core issue is precisely that dragging gives you two things that are mutually incompatible:

  1. I feel like I'm control of this thing. It doesn't suddenly stop moving (because it's in a flex context) or "go away" (because I'm dragging over a component that supports props.children but doesn't render them by default)

  2. I know what would happen when I let go. If drop this here, it won't end up exactly here, but somewhere else (because it's a flex context, or a flow context). If I drop this there, it won't show up at all (because the component swallows its children). And if I drop this over there, it will transform weirdly.

(1) is direct manipulation, (2) is instant feedback. For design tools, they often go hand in hand, because very few situations will manipulate, transform, hide, or swallow things you're dragging. For us, they diverge - especially with components and styles-that-apply-to-children (transforms, opacity).

However, the solution is on one level quite straightforward, and pretty much what we did previously: show a placeholder and extra controls for (2), show the real element for (1), and after letting go use an animation to make the two converge. -- In theory we could do it the other way 'round (a placeholder that follows the mouse, the real thing moving in and out of containers. We previously didn't do this because (IIRC) of perf concerns.

And: it doesn't need to be perfect. In particular, one of the two does not need to be real or realistic, or even fast - as long as the other is. E.g. Previously we made the placeholder a pink rectangle - almost a "shadow" of the real element - and that worked well because the real element tracked the mouse with very high speed (fueled by our tears of rage, I'm sure you remember / have suppressed this :).

@Rheeseyb Rheeseyb assigned Rheeseyb and unassigned balazsbajorics Jun 11, 2020
@Rheeseyb
Copy link
Contributor

I have a branch with this partially solved (feature/drag-controls-stick-to-cursor), but this requires further experimentation, so I'm going to move this to Triage so we can address this together with other experiments we want to run around canvas controls

@Rheeseyb
Copy link
Contributor

Change of plan. I have opened a PR to cover the work from that branch. We will re-address the remaining issues as part of an upcoming process of experimenting with various canvas controls.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Perceived Bug Something that feels broken or like a problem
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants