-
Notifications
You must be signed in to change notification settings - Fork 6.8k
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
feat: add experimental drag-drop package #11864
Conversation
3d4aa8d
to
3e401e7
Compare
* @param fromIndex Starting index of the item. | ||
* @param toIndex Index to which the item should be moved. | ||
*/ | ||
export function moveItemInArray(array: any[], fromIndex: number, toIndex: number): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can use a generic here instead of any
for the array? I would just prefer to avoid any where possible personally, though since the typing never leaves this function, I suppose its not crucial.
moveItemInArray<T>(array: T[], fromIndex: number, toIndex: number): void {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, it would be better to have a generic
import {dispatchMouseEvent, dispatchTouchEvent} from '@angular/cdk/testing'; | ||
import {CdkDrag} from './drag'; | ||
import {CdkDragDrop} from './drag-events'; | ||
import { moveItemInArray } from './drag-utils'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove extra spacing around symbol
|
||
constructor( | ||
/** Element that the draggable is attached to. */ | ||
public element: ElementRef<HTMLElement>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this meant to be public but not internal (_
prefixed)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left it public so people can use the element to add custom styling while it's being dragged.
ngAfterContentInit() { | ||
// TODO: doesn't handle (pun intended) the handle being destroyed | ||
const element = (this._handle ? this._handle.element : this.element).nativeElement; | ||
element.addEventListener('mousedown', this._pointerDown); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it looks like these event listeners are not cleaned up with a removeEventListener
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They're not, but presumably they live for the lifetime of the directive since they're bound either on the host or the handle which is inside the host.
|
||
if (this.dropContainer) { | ||
const element = this.element.nativeElement; | ||
const preview = this._preview = this._createPreviewElement(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than the multiple assignment here, should _createPreviewElement
also assign its output to this._preview
?
It could be thought of as setupPreviewElement
rather than just creating. I think this especially makes sense since _createPreviewElement
already has side effects of creating the refs needed for the preview.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is more of a personal preference. I prefer not to have functions initialize properties like this since it isn't very transparent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree w/ Kristiyan
} | ||
|
||
/** Point on the page or within an element. */ | ||
interface Point { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This same interface is created and used in flexible-connected-position-strategy.ts
, perhaps it should be moved to a common place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided to duplicate it since it's fairly small.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed that it's trivial enough to not bother finding a common place for it, which would necessitate it being part of a public API
3e401e7
to
4b5602d
Compare
Addressed the current feedback @josephperrott. |
|
||
/** Event emitted when the user moves an item into a new drop container. */ | ||
export interface CdkDragEnter<T> { | ||
/** Container from which the user has a removed an item. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is accidentally using the same comments as CdkDragExit
/** Index of the item when it was picked up. */ | ||
previousIndex: number; | ||
/** Current index of the item. */ | ||
currentIndex: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do dragged items have to inherently have an index?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The drop event only fires on items inside a drop zone which ensures that they have an index.
/** Handle that can be used to drag and CdkDrag instance. */ | ||
@Directive({ | ||
selector: '[cdkDragHandle]', | ||
host: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a TODO
here for a11y treatment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have it on my list, I just haven't added any extra APIs to facilitate it (e.g. we need something pick up and swap items programmatically).
* @param fromIndex Starting index of the item. | ||
* @param toIndex Index to which the item should be moved. | ||
*/ | ||
export function moveItemInArray(array: any[], fromIndex: number, toIndex: number): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, it would be better to have a generic
/** Coordinates on the page at which the user picked up the element. */ | ||
private _pickupPositionOnPage: Point; | ||
|
||
/** CSS `transform` applied to the element when it isn't being dragged. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expand this comment to explain why there's a passive transform applied when the element isn't being dragged?
/** | ||
* Drops an item into this container. | ||
* @param item Item being dropped into the container. | ||
* @param currentIndex Index at which the item should be inserted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar question as above: could you have a dropzone without indices? E.g., you have free-floating draggables that can only be placed within certain regions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that makes sense. If you wanted a region with a bunch of freely-draggable items, you'd just place them in something that isn't a CdkDrop
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking about free-drag with constraints. I see those constraints as having two manifestations: blocking you from moving into/out of some element entirely, or "cancelling" a drop if it's in a disallowed area. I do think it is reasonable for that to be done with a different directive than cdkDrop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I was thinking either a directive or a straight-up @Input
that accepts an ElementRef
, although that could be problematic for components with an implicit exportAs
.
import {CdkDrag} from './drag'; | ||
|
||
/** @docs-private */ | ||
export interface CdkDropContainer<T = any> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts on DropContainer
vs. DropZone
or DropRegion
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with DropZone, I just needed a name that isn't CdkDrop
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't worry about changing it now; I'm not strongly attached to any of them. I'll sleep on it.
@ContentChild(CdkDragPlaceholder) _placeholderTemplate: CdkDragPlaceholder; | ||
|
||
/** Emits when the user starts dragging the item. */ | ||
@Output() started = new EventEmitter<CdkDragStart>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Output('cdkDragStarted') started
and similar for other outputs since this is an attribute selector directive
* Other draggable containers that this container is connected | ||
* to and into which the container's items can be transferred. | ||
*/ | ||
@Input('connectedTo') siblings: CdkDrop[] = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's a little confusing for the input and the property to be so different
@@ -0,0 +1,38 @@ | |||
<div class="list"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Andrew has been pushing for is to stop adding demos that only live in demo-app/
and instead always embed something from the examples, since it forced us to flesh those out. Not necessary for this PR, but would be nice to do.
4b5602d
to
4b7b740
Compare
Addressed the latest set of feedback. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
3740c18
to
4a40f9a
Compare
@crisbeto Please rebase when you have a chance |
Adds an initial version of the `drag-drop` module to `cdk-experimental` with support for the following: * Dragging an element on its own. * Dragging an element using a handle. * Sorting an element within a drop zone. * Moving an element between drop zones. * Touch and mouse support. * Custom template for the preview element. * Custom template for the placeholder element. * Animation support for the preview. Demo: https://material-cb7ec.firebaseapp.com/drag-drop Relates to angular#8963.
4a40f9a
to
d3aaa18
Compare
Rebased @josephperrott. |
@josephperrott, @crisbeto, do you know when this feature will be included in a release? |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Adds an initial version of the
drag-drop
module tocdk-experimental
with support for the following:Demo: https://material-cb7ec.firebaseapp.com/drag-drop
Relates to #8963.
Note: this is still missing a lot of unit tests. I'll continue adding them to this branch or open a follow-up PR. Also will continue adding features, docs and a11y guidelines in follow-ups.