Skip to content

Commit eccac65

Browse files
committed
kanban board without first-drag jitters, just Firefox jitters
1 parent bbe1439 commit eccac65

15 files changed

+319
-215
lines changed

packages/angular-skyhook-card-list/src/card-list.component.ts

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ import {
4444
</ng-template>
4545
4646
<ng-container *ngLet="placeholderIndex$|async as phi">
47-
<ng-container *ngLet="cardOver$|async as cardOver">
47+
<ng-container *ngLet="placeholderOver$|async as cardOver">
48+
<ng-container *ngLet="selfOver$|async as selfOver">
4849
4950
<div [dropTarget]="target" [dropTargetType]="type" [class]="containerClass"
5051
[ngStyle]="{ display: 'flex', flexDirection: horizontal ? 'row' : 'column' }">
@@ -56,22 +57,23 @@ import {
5657
[type]="type"
5758
[listId]="listId"
5859
[horizontal]="horizontal"
59-
(hover)="onHover($event)"
60-
(begin)="begin($event)"
60+
(hover)="hoverOnCard($event)"
61+
(begin)="cardBeganDragging($event)"
6162
[template]="cardRendererTemplates.first"
6263
[ngStyle]="{ order: i >= phi ? i + 1 : i }"
6364
>
6465
</skyhook-card-renderer>
6566
66-
<ng-container *ngIf="cardOver">
67-
<div *ngLet="item$|async as item" [ngStyle]="{ order: phi }">
67+
<ng-container *ngIf="selfOver && (cardOver || isEmpty)">
68+
<div *ngIf="item$|async as item" [ngStyle]="{ order: phi }">
6869
<ng-container *ngTemplateOutlet="placeholderTemplates.first; context: { $implicit: item }">
6970
</ng-container>
7071
</div>
7172
</ng-container>
7273
7374
</div>
7475
76+
</ng-container>
7577
</ng-container>
7678
</ng-container>
7779
`
@@ -80,7 +82,8 @@ export class CardListComponent implements OnDestroy, AfterContentInit {
8082
@Input() listId: any = Math.random();
8183
@Input() horizontal = false;
8284

83-
@Input() cards: Data[];
85+
@Input() cards: Array<Data> | Iterable<Data>;
86+
8487
@Output() dropped = new EventEmitter<DropEvent>();
8588

8689
@Input() type = ItemTypes.CARD;
@@ -95,22 +98,27 @@ export class CardListComponent implements OnDestroy, AfterContentInit {
9598
drop: monitor => {
9699
const drag = monitor.getItem() as DraggedItem;
97100
this.dropEmit$.next(drag);
98-
this.placeholder$.next({ index: 0, size: { width: 0, height: 0 } });
101+
this.placeholder$.next({ over: false, index: 0, size: { width: 0, height: 0 } });
99102
}
100103
});
101104

102-
cardOver$ = this.target.listen(m => m.isOver({ shallow: false }));
105+
selfOver$ = this.target.listen(m => m.isOver({ shallow: false }));
103106
item$ = this.target.listen(m => m.getItem());
104107

105108
dropEmit$ = new Subject<DraggedItem>();
106109
placeholder$ = new BehaviorSubject({
110+
over: false,
107111
index: 0,
108112
size: { width: 0, height: 0 }
109113
});
110114
placeholderIndex$: Observable<number> = this.placeholder$.pipe(
111115
map(p => p.index),
112116
distinctUntilChanged()
113117
);
118+
placeholderOver$: Observable<boolean> = this.placeholder$.pipe(
119+
map(p => p.over),
120+
distinctUntilChanged()
121+
);
114122

115123
constructor(private dnd: SkyhookDndService) {
116124
this.dropEmit$
@@ -140,16 +148,17 @@ export class CardListComponent implements OnDestroy, AfterContentInit {
140148
});
141149
}
142150

143-
private begin({ id, index, size }: BeginEvent) {
144-
this.placeholder$.next({ index, size });
151+
private cardBeganDragging({ id, index, size }: BeginEvent) {
152+
this.placeholder$.next({ index, size, over: true });
145153
}
146154

147-
private onHover(evt: HoverEvent) {
155+
private hoverOnCard(evt: HoverEvent) {
148156
let dim = this.horizontal
149157
? evt.hover.size.width
150158
: evt.hover.size.height;
151159
const targetCentre = evt.hover.start + dim / 2.0;
152160
this.placeholder$.next({
161+
over: true,
153162
index:
154163
evt.mouse < targetCentre
155164
? evt.hover.index
@@ -158,6 +167,21 @@ export class CardListComponent implements OnDestroy, AfterContentInit {
158167
});
159168
}
160169

170+
/** @ignore
171+
* Returns isEmpty, whether it's an immutable List or an array
172+
*/
173+
private get isEmpty() {
174+
if (typeof this.cards["isEmpty"] === 'function') {
175+
// it's immutable
176+
return this.cards["isEmpty"]();
177+
} else if (typeof this.cards["length"] === 'number') {
178+
// it's an array
179+
return (this.cards as Array<Data>).length === 0;
180+
} else {
181+
return false;
182+
}
183+
}
184+
161185
ngAfterContentInit() {
162186
if (this.placeholderTemplates.length !== 1) {
163187
throw new Error("must have exactly one cardPlaceholder template");

packages/angular-skyhook-card-list/src/card-renderer.component.ts

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,6 @@ import { BehaviorSubject, Subscription } from "rxjs";
3333
import { Size } from "./size";
3434
import { Observable } from "rxjs";
3535

36-
// for html5 dnd
37-
let emptyImage: HTMLImageElement;
38-
function getEmptyImage() {
39-
if (!emptyImage) {
40-
emptyImage = new Image();
41-
emptyImage.src =
42-
"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
43-
}
44-
return emptyImage;
45-
}
46-
4736
// TODO: render target box at full width (vertical) or full height (horiz)
4837

4938
@Component({
@@ -134,7 +123,7 @@ export class CardRendererComponent implements OnInit, OnDestroy {
134123
constructor(
135124
private dnd: SkyhookDndService,
136125
private cdr: ChangeDetectorRef
137-
) {}
126+
) { }
138127

139128
private rect() {
140129
const rect = (this.sizingDiv
@@ -170,8 +159,6 @@ export class CardRendererComponent implements OnInit, OnDestroy {
170159
this.isDragging = d;
171160
this.cdr.markForCheck();
172161
});
173-
const img = getEmptyImage() as HTMLImageElement;
174-
this.source.connectDragPreview(img);
175162
}
176163

177164
ngOnChanges() {

packages/examples/package.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,9 @@
2727
"angular-skyhook-card-list": "^0.0.2",
2828
"angular-skyhook-multi-backend": "^1.0.3",
2929
"core-js": "^2.5.4",
30-
"dnd-multi-backend": "^3.1.0",
3130
"faker": "^4.1.0",
3231
"immutability-helper": "^2.7.0",
33-
"react-dnd-html5-backend": "^2.5.3",
3432
"react-dnd-mouse-backend": "^0.1.1",
35-
"react-dnd-touch-backend": "^0.3.15",
3633
"rxjs": "^6.2.0",
3734
"zone.js": "^0.8.26"
3835
},
@@ -61,4 +58,4 @@
6158
"tslint": "~5.9.1",
6259
"typescript": "~2.7.2"
6360
}
64-
}
61+
}

packages/examples/src/app/kanban/container.component.html

Lines changed: 0 additions & 69 deletions
This file was deleted.

packages/examples/src/app/kanban/container.component.scss

Lines changed: 0 additions & 89 deletions
This file was deleted.

packages/examples/src/app/kanban/index.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,23 @@ import { CommonModule } from "@angular/common";
33
import { UtilityModule } from "../utility.module";
44
import { SkyhookDndModule } from "angular-skyhook";
55
import { RouterModule } from "@angular/router";
6+
import { ReactiveFormsModule } from "@angular/forms";
67
import { SkyhookMultiBackendModule } from "angular-skyhook-multi-backend";
8+
import { SkyhookCardListModule } from "angular-skyhook-card-list";
79

8-
import { KanbanContainerComponent } from "./container.component";
10+
import { KanbanBoardComponent } from "./kanban-board/kanban-board.component";
11+
import { KanbanListComponent } from "./kanban-list/kanban-list.component";
912
import { KanbanCardComponent } from "./card.component";
10-
import { SkyhookCardListModule } from "angular-skyhook-card-list";
11-
import { ReactiveFormsModule } from "@angular/forms";
1213
import { AddCardComponent } from "./add-card.component";
14+
import { TrashCanComponent } from "./trash-can.component";
1315

1416
@NgModule({
1517
declarations: [
16-
KanbanContainerComponent,
18+
KanbanBoardComponent,
19+
KanbanListComponent,
1720
KanbanCardComponent,
18-
AddCardComponent
21+
AddCardComponent,
22+
TrashCanComponent,
1923
],
2024
imports: [
2125
CommonModule,
@@ -25,8 +29,8 @@ import { AddCardComponent } from "./add-card.component";
2529
SkyhookCardListModule,
2630
ReactiveFormsModule,
2731
RouterModule.forChild([
28-
{ path: "", component: KanbanContainerComponent }
32+
{ path: "", component: KanbanBoardComponent }
2933
])
3034
]
3135
})
32-
export class KanbanModule {}
36+
export class KanbanModule { }
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const ItemTypes = {
2+
CARD: "KANBAN_CARD",
3+
LIST: "KANBAN_LIST"
4+
};

0 commit comments

Comments
 (0)