docs(drag-drop): add docs and live examples (#12794)

Adds live examples and a readme for the CDK drag&drop.
This commit is contained in:
Kristiyan Kostadinov
2018-08-25 17:19:58 +02:00
committed by Jeremy Elbourn
parent e5e5b68a93
commit c8ae9fdea2
23 changed files with 616 additions and 1 deletions
+118 -1
View File
@@ -1 +1,118 @@
# TODO
The `@angular/cdk/drag-drop` module provides you with a way to easily and declaratively create
drag-and-drop interfaces, with support for free dragging, sorting within a list, transferring items
between lists, animations, touch devices, custom drag handles, previews, and placeholders,
in addition to horizontal lists and locking along an axis.
### Getting started
Start by importing `DragDropModule` into the `NgModule` where you want to use drag-and-drop
features. You can now add the `cdkDrag` directive to elements to make them draggable. When
outside of a `<cdk-drop>` element, draggable elements can be freely moved around the page.
You can add `<cdk-drop>` elements to constrain where elements may be dropped.
<!-- example(cdk-drag-drop-overview) -->
### Reordering lists
Adding `<cdk-drop>` around a set of `cdkDrag` elements groups the draggables into a
reorderable collection. Items will automatically rearrange as an element moves. Note
that this will *not* update your data model; you can listen to the `dropped` event to
update the data model once the user finishes dragging.
<!-- example(cdk-drag-drop-sorting) -->
### Transferring items between lists
The `<cdk-drop>` component supports transferring dragged items between connected drop zones.
You can connect one or more `<cdk-drop>` instances together by setting the `connectedTo`
property.
<!-- example(cdk-drag-drop-connected-sorting) -->
Note that `connectedTo` works both with a direct reference to another `<cdk-drop>`, or by
referencing the `id` of another drop container:
```html
<!-- This is valid -->
<cdk-drop #listOne [connectedTo]="[listTwo]"></cdk-drop>
<cdk-drop #listTwo [connectedTo]="[listOne]"></cdk-drop>
<!-- This is valid as well -->
<cdk-drop id="list-one" [connectedTo]="['list-two']"></cdk-drop>
<cdk-drop id="list-two" [connectedTo]="['list-one']"></cdk-drop>
```
### Attaching data
You can associate some arbitrary data with both `cdkDrag` and `<cdk-drop>` by setting
`cdkDragData` or `data`, respectively. Events fired from both directives include this data,
allowing you to easily identify the origin of the drag or drop interaction.
```html
<cdk-drop [data]="list" *ngFor="let list of lists" (dropped)="drop($event)">
<div cdkDrag [cdkDragData]="item" *ngFor="let item of list"></div>
</cdk-drop>
```
### Styling
The `cdkDrag` and `<cdk-drop>` directive include only those styles strictly necessary for
functionality. The application can then customize the elements by styling CSS classes added
by the directives:
| Selector | Description |
|---------------------|--------------------------------------------------------------------------|
| `.cdk-drop` | Corresponds to the `<cdk-drop>` container. |
| `.cdk-drag` | Corresponds to a `cdkDrag` instance. |
| `.cdk-drag-preview` | This is the element that will be rendered next to the user's cursor as they're dragging an item in a sortable list. By default the element looks exactly like the element that is being dragged. |
| `.cdk-drag-placeholder` | This is element that will be shown instead of the real element as it's being dragged inside a `<cdk-drop>`. By default this will look exactly like the element that is being sorted. |
| `.cdk-drop-dragging` | A class that is added to `<cdk-drop>` while the user is dragging an item. |
### Animations
The drag-and-drop module supports animations both while sorting an element inside a list, as well as
animating it from the position that the user dropped it to its final place in the list. To set up
your animations, you have to define a `transition` that targets the `transform` property. The
following classes can be used for animations:
* `.cdk-drag` - If you add a `transition` to this class, it'll animate as the user is sorting
through a list.
* `.cdk-drag-animating` - This class is added to a `cdkDrag` when the user has stopped dragging.
If you add a `transition` to it, the CDK will animate the element from its drop position to
the final position inside the `<cdk-drop>` container.
Example animations:
```css
/* Animate items as they're being sorted. */
.cdk-drop-dragging .cdk-drag {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
/* Animate an item that has been dropped. */
.cdk-drag-animating {
transition: transform 300ms cubic-bezier(0, 0, 0.2, 1);
}
```
### Customizing the drag area using a handle
By default, the user can drag the entire `cdkDrag` element to move it around. If you want to
restrict the user to only be able to do so using a handle element, you can do it by adding the
`cdkDragHandle` directive to an element inside of `cdkDrag`. Note that you can have as many
`cdkDragHandle` elements as you want:
<!-- example(cdk-drag-drop-handle) -->
### Customizing the drag preview
When a `cdkDrag` element is picked up, it will create a preview element visible while dragging.
By default, this will be a clone of the original element positioned next to the user's cursor.
This preview can be customized, though, by providing a custom template via `*cdkDragPreview`:
<!-- example(cdk-drag-drop-custom-preview) -->
### List orientation
The `cdk-drop` component assumes that lists are vertical by default. This can be
changed by setting the `orientation` property to `"horizontal".
<!-- example(cdk-drag-drop-horizontal-sorting) -->
### Restricting movement along an axis
By default, `cdkDrag` allows free movement in all directions. To restrict dragging to a
specific axis, you can set `cdkDragLockAxis` on `cdkDrag` or `lockAxis` on `<cdk-drop>`
to either `"x"` or `"y"`.
<!-- example(cdk-drag-drop-axis-lock) -->
@@ -0,0 +1,22 @@
.box {
width: 200px;
height: 200px;
border: solid 1px #ccc;
cursor: move;
display: inline-flex;
justify-content: center;
align-items: center;
background: #fff;
border-radius: 4px;
margin-right: 25px;
transition: box-shadow 200ms cubic-bezier(0, 0, 0.2, 1);
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),
0 2px 2px 0 rgba(0, 0, 0, 0.14),
0 1px 5px 0 rgba(0, 0, 0, 0.12);
}
.box:active {
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
@@ -0,0 +1,7 @@
<div class="box" cdkDragLockAxis="y" cdkDrag>
I can only be dragged up/down
</div>
<div class="box" cdkDragLockAxis="x" cdkDrag>
I can only be dragged left/right
</div>
@@ -0,0 +1,11 @@
import {Component} from '@angular/core';
/**
* @title Drag&Drop position locking
*/
@Component({
selector: 'cdk-drag-drop-axis-lock-example',
templateUrl: 'cdk-drag-drop-axis-lock-example.html',
styleUrls: ['cdk-drag-drop-axis-lock-example.css'],
})
export class CdkDragDropAxisLockExample {}
@@ -0,0 +1,53 @@
.container {
width: 400px;
max-width: 100%;
margin: 0 25px 25px 0;
display: inline-block;
vertical-align: top;
}
.list {
border: solid 1px #ccc;
min-height: 60px;
background: white;
border-radius: 4px;
overflow: hidden;
display: block;
}
.box {
padding: 20px 10px;
border-bottom: solid 1px #ccc;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
cursor: move;
background: white;
font-size: 14px;
}
.cdk-drag-preview {
box-sizing: border-box;
border-radius: 4px;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
.cdk-drag-placeholder {
opacity: 0;
}
.cdk-drag-animating {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
.box:last-child {
border: none;
}
.list.cdk-drop-dragging .box:not(.cdk-drag-placeholder) {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
@@ -0,0 +1,16 @@
<div class="container">
<h2>To do</h2>
<cdk-drop #todoList [data]="todo" [connectedTo]="[doneList]" class="list" (dropped)="drop($event)">
<div class="box" *ngFor="let item of todo" cdkDrag>{{item}}</div>
</cdk-drop>
</div>
<div class="container">
<h2>Done</h2>
<cdk-drop #doneList [data]="done" [connectedTo]="[todoList]" class="list" (dropped)="drop($event)">
<div class="box" *ngFor="let item of done" cdkDrag>{{item}}</div>
</cdk-drop>
</div>
@@ -0,0 +1,38 @@
import {Component} from '@angular/core';
import {CdkDragDrop, moveItemInArray, transferArrayItem} from '@angular/cdk/drag-drop';
/**
* @title Drag&Drop connected sorting
*/
@Component({
selector: 'cdk-drag-drop-connected-sorting-example',
templateUrl: 'cdk-drag-drop-connected-sorting-example.html',
styleUrls: ['cdk-drag-drop-connected-sorting-example.css'],
})
export class CdkDragDropConnectedSortingExample {
todo = [
'Get to work',
'Pick up groceries',
'Go home',
'Fall asleep'
];
done = [
'Get up',
'Brush teeth',
'Take a shower',
'Check e-mail',
'Walk dog'
];
drop(event: CdkDragDrop<string[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
transferArrayItem(event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex);
}
}
}
@@ -0,0 +1,47 @@
.list {
width: 500px;
max-width: 100%;
border: solid 1px #ccc;
min-height: 60px;
display: block;
background: white;
border-radius: 4px;
overflow: hidden;
}
.box {
padding: 20px 10px;
border-bottom: solid 1px #ccc;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
cursor: move;
background: white;
font-size: 14px;
}
.cdk-drag-preview {
box-sizing: border-box;
border-radius: 4px;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
.cdk-drag-placeholder {
opacity: 0;
}
.cdk-drag-animating {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
.box:last-child {
border: none;
}
.list.cdk-drop-dragging .box:not(.cdk-drag-placeholder) {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
@@ -0,0 +1,6 @@
<cdk-drop class="list" (dropped)="drop($event)">
<div class="box" *ngFor="let movie of movies" cdkDrag>
{{movie.title}}
<img *cdkDragPreview [src]="movie.poster" [alt]="movie.title">
</div>
</cdk-drop>
@@ -0,0 +1,53 @@
import {Component} from '@angular/core';
import {CdkDragDrop, moveItemInArray} from '@angular/cdk/drag-drop';
/**
* @title Drag&Drop custom preview
*/
@Component({
selector: 'cdk-drag-drop-custom-preview-example',
templateUrl: 'cdk-drag-drop-custom-preview-example.html',
styleUrls: ['cdk-drag-drop-custom-preview-example.css'],
})
export class CdkDragDropCustomPreviewExample {
// tslint:disable:max-line-length
movies = [
{
title: 'Episode I - The Phantom Menace',
poster: 'https://upload.wikimedia.org/wikipedia/en/4/40/Star_Wars_Phantom_Menace_poster.jpg'
},
{
title: 'Episode II - Attack of the Clones',
poster: 'https://upload.wikimedia.org/wikipedia/en/3/32/Star_Wars_-_Episode_II_Attack_of_the_Clones_%28movie_poster%29.jpg'
},
{
title: 'Episode III - Revenge of the Sith',
poster: 'https://upload.wikimedia.org/wikipedia/en/9/93/Star_Wars_Episode_III_Revenge_of_the_Sith_poster.jpg'
},
{
title: 'Episode IV - A New Hope',
poster: 'https://upload.wikimedia.org/wikipedia/en/8/87/StarWarsMoviePoster1977.jpg'
},
{
title: 'Episode V - The Empire Strikes Back',
poster: 'https://upload.wikimedia.org/wikipedia/en/3/3c/SW_-_Empire_Strikes_Back.jpg'
},
{
title: 'Episode VI - Return of the Jedi',
poster: 'https://upload.wikimedia.org/wikipedia/en/b/b2/ReturnOfTheJediPoster1983.jpg'
},
{
title: 'Episode VII - The Force Awakens',
poster: 'https://upload.wikimedia.org/wikipedia/en/a/a2/Star_Wars_The_Force_Awakens_Theatrical_Poster.jpg'
},
{
title: 'Episode VIII - The Last Jedi',
poster: 'https://upload.wikimedia.org/wikipedia/en/7/7f/Star_Wars_The_Last_Jedi.jpg'
}
];
// tslint:enable:max-line-length
drop(event: CdkDragDrop<{title: string, poster: string}[]>) {
moveItemInArray(this.movies, event.previousIndex, event.currentIndex);
}
}
@@ -0,0 +1,32 @@
.box {
width: 200px;
height: 200px;
padding: 10px;
box-sizing: border-box;
border: solid 1px #ccc;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
background: #fff;
border-radius: 4px;
position: relative;
transition: box-shadow 200ms cubic-bezier(0, 0, 0.2, 1);
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),
0 2px 2px 0 rgba(0, 0, 0, 0.14),
0 1px 5px 0 rgba(0, 0, 0, 0.12);
}
.box:active {
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
.handle {
position: absolute;
top: 10px;
right: 10px;
color: #ccc;
cursor: move;
}
@@ -0,0 +1,10 @@
<div class="box" cdkDrag>
I can only be dragged using the handle
<div class="handle" cdkDragHandle>
<svg width="24px" fill="currentColor" viewBox="0 0 24 24">
<path d="M10 9h4V6h3l-5-5-5 5h3v3zm-1 1H6V7l-5 5 5 5v-3h3v-4zm14 2l-5-5v3h-3v4h3v3l5-5zm-9 3h-4v3H7l5 5 5-5h-3v-3z"></path>
<path d="M0 0h24v24H0z" fill="none"></path>
</svg>
</div>
</div>
@@ -0,0 +1,11 @@
import {Component} from '@angular/core';
/**
* @title Drag&Drop with a handle
*/
@Component({
selector: 'cdk-drag-drop-handle-example',
templateUrl: 'cdk-drag-drop-handle-example.html',
styleUrls: ['cdk-drag-drop-handle-example.css'],
})
export class CdkDragDropHandleExample {}
@@ -0,0 +1,50 @@
.list {
width: 1000px;
max-width: 100%;
border: solid 1px #ccc;
min-height: 60px;
display: flex;
flex-direction: row;
background: white;
border-radius: 4px;
overflow: hidden;
}
.box {
padding: 20px 10px;
border-right: solid 1px #ccc;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
cursor: move;
background: white;
font-size: 14px;
flex-grow: 1;
flex-basis: 0;
}
.cdk-drag-preview {
box-sizing: border-box;
border-radius: 4px;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
.cdk-drag-placeholder {
opacity: 0;
}
.cdk-drag-animating {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
.box:last-child {
border: none;
}
.list.cdk-drop-dragging .box:not(.cdk-drag-placeholder) {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
@@ -0,0 +1,3 @@
<cdk-drop orientation="horizontal" class="list" (dropped)="drop($event)">
<div class="box" *ngFor="let timePeriod of timePeriods" cdkDrag>{{timePeriod}}</div>
</cdk-drop>
@@ -0,0 +1,24 @@
import {Component} from '@angular/core';
import {CdkDragDrop, moveItemInArray} from '@angular/cdk/drag-drop';
/**
* @title Drag&Drop horizontal sorting
*/
@Component({
selector: 'cdk-drag-drop-horizontal-sorting-example',
templateUrl: 'cdk-drag-drop-horizontal-sorting-example.html',
styleUrls: ['cdk-drag-drop-horizontal-sorting-example.css'],
})
export class CdkDragDropHorizontalSortingExample {
timePeriods = [
'Bronze age',
'Iron age',
'Middle ages',
'Early modern period',
'Long nineteenth century'
];
drop(event: CdkDragDrop<string[]>) {
moveItemInArray(this.timePeriods, event.previousIndex, event.currentIndex);
}
}
@@ -0,0 +1,21 @@
.box {
width: 200px;
height: 200px;
border: solid 1px #ccc;
cursor: move;
display: flex;
justify-content: center;
align-items: center;
background: #fff;
border-radius: 4px;
transition: box-shadow 200ms cubic-bezier(0, 0, 0.2, 1);
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),
0 2px 2px 0 rgba(0, 0, 0, 0.14),
0 1px 5px 0 rgba(0, 0, 0, 0.12);
}
.box:active {
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
@@ -0,0 +1,3 @@
<div class="box" cdkDrag>
Drag me around
</div>
@@ -0,0 +1,11 @@
import {Component} from '@angular/core';
/**
* @title Basic Drag&Drop
*/
@Component({
selector: 'cdk-drag-drop-overview-example',
templateUrl: 'cdk-drag-drop-overview-example.html',
styleUrls: ['cdk-drag-drop-overview-example.css'],
})
export class CdkDragDropOverviewExample {}
@@ -0,0 +1,47 @@
.list {
width: 500px;
max-width: 100%;
border: solid 1px #ccc;
min-height: 60px;
display: block;
background: white;
border-radius: 4px;
overflow: hidden;
}
.box {
padding: 20px 10px;
border-bottom: solid 1px #ccc;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
cursor: move;
background: white;
font-size: 14px;
}
.cdk-drag-preview {
box-sizing: border-box;
border-radius: 4px;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
.cdk-drag-placeholder {
opacity: 0;
}
.cdk-drag-animating {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
.box:last-child {
border: none;
}
.list.cdk-drop-dragging .box:not(.cdk-drag-placeholder) {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
@@ -0,0 +1,3 @@
<cdk-drop class="list" (dropped)="drop($event)">
<div class="box" *ngFor="let movie of movies" cdkDrag>{{movie}}</div>
</cdk-drop>
@@ -0,0 +1,27 @@
import {Component} from '@angular/core';
import {CdkDragDrop, moveItemInArray} from '@angular/cdk/drag-drop';
/**
* @title Drag&Drop sorting
*/
@Component({
selector: 'cdk-drag-drop-sorting-example',
templateUrl: 'cdk-drag-drop-sorting-example.html',
styleUrls: ['cdk-drag-drop-sorting-example.css'],
})
export class CdkDragDropSortingExample {
movies = [
'Episode I - The Phantom Menace',
'Episode II - Attack of the Clones',
'Episode III - Revenge of the Sith',
'Episode IV - A New Hope',
'Episode V - The Empire Strikes Back',
'Episode VI - Return of the Jedi',
'Episode VII - The Force Awakens',
'Episode VIII - The Last Jedi'
];
drop(event: CdkDragDrop<string[]>) {
moveItemInArray(this.movies, event.previousIndex, event.currentIndex);
}
}
+3
View File
@@ -4,6 +4,7 @@ import {ScrollingModule} from '@angular/cdk/scrolling';
import {A11yModule} from '@angular/cdk/a11y';
import {CdkTableModule} from '@angular/cdk/table';
import {CdkTreeModule} from '@angular/cdk/tree';
import {DragDropModule} from '@angular/cdk/drag-drop';
import {
MatAutocompleteModule, MatBadgeModule, MatBottomSheetModule, MatButtonModule,
MatButtonToggleModule, MatCardModule, MatCheckboxModule, MatChipsModule, MatDatepickerModule,
@@ -19,6 +20,7 @@ import {
A11yModule,
CdkTableModule,
CdkTreeModule,
DragDropModule,
MatAutocompleteModule,
MatBadgeModule,
MatBottomSheetModule,
@@ -60,6 +62,7 @@ import {
A11yModule,
CdkTableModule,
CdkTreeModule,
DragDropModule,
MatAutocompleteModule,
MatBadgeModule,
MatBottomSheetModule,