From dc37330842c3c29cdf56e738a91eb6ed1a3f9bf6 Mon Sep 17 00:00:00 2001 From: Brian Kimball Date: Thu, 5 Nov 2020 22:06:42 -0500 Subject: [PATCH 01/13] feat(lib): use inject to pass container reference to selectableItem --- .../src/lib/select-container.component.ts | 45 ++++++++++--------- .../src/lib/select-item.directive.ts | 12 ++++- 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/projects/ngx-drag-to-select/src/lib/select-container.component.ts b/projects/ngx-drag-to-select/src/lib/select-container.component.ts index 55cdea3..2926297 100644 --- a/projects/ngx-drag-to-select/src/lib/select-container.component.ts +++ b/projects/ngx-drag-to-select/src/lib/select-container.component.ts @@ -15,6 +15,7 @@ import { PLATFORM_ID, Inject, AfterContentInit, + InjectionToken, } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; @@ -68,6 +69,8 @@ import { } from './utils'; import { KeyboardEventsService } from './keyboard-events.service'; +export const DTS_SELECT_CONTAINER = new InjectionToken('SelectContainerComponent'); + @Component({ selector: 'dts-select-container', exportAs: 'dts-select-container', @@ -84,6 +87,7 @@ import { KeyboardEventsService } from './keyboard-events.service'; > `, styleUrls: ['./select-container.component.scss'], + providers: [{ provide: DTS_SELECT_CONTAINER, useExisting: SelectContainerComponent }], }) export class SelectContainerComponent implements AfterViewInit, OnDestroy, AfterContentInit { host: SelectContainerHost; @@ -262,8 +266,12 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After this._selectableItems = this.$selectableItems.toArray(); } + updateSelectableItems() { + this._selectableItems = Array.from(this._registry); //this.$selectableItems.toArray(); + } + selectAll() { - this.$selectableItems.forEach((item) => { + this._selectableItems.forEach((item) => { this._selectItem(item); }); } @@ -281,14 +289,26 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After } clearSelection() { - this.$selectableItems.forEach((item) => { + this._selectableItems.forEach((item) => { this._deselectItem(item); }); } + _registry: Set = new Set(); + + register(item: SelectItemDirective) { + this._registry.add(item); + this.updateSelectableItems(); + } + unregister(item: SelectItemDirective) { + this._registry.delete(item); + this.updateSelectableItems(); + this._removeItem(item, this.selectedItems); + } + update() { this._calculateBoundingClientRect(); - this.$selectableItems.forEach((item) => item.calculateBoundingClientRect()); + this._selectableItems.forEach((item) => item.calculateBoundingClientRect()); } ngOnDestroy() { @@ -335,21 +355,6 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After break; } }); - - // Update the container as well as all selectable items if the list has changed - this.$selectableItems.changes - .pipe(withLatestFrom(this._selectedItems$), observeOn(asyncScheduler), takeUntil(this.destroy$)) - .subscribe(([items, selectedItems]: [QueryList, any[]]) => { - const newList = items.toArray(); - this._selectableItems = newList; - const removedItems = selectedItems.filter((item) => !newList.includes(item.value)); - - if (removedItems.length) { - removedItems.forEach((item) => this._removeItem(item, selectedItems)); - } - - this.update(); - }); } private _observeBoundingRectChanges() { @@ -446,7 +451,7 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After return; } - this.$selectableItems.forEach((item, index) => { + this._selectableItems.forEach((item, index) => { const itemRect = item.getBoundingClientRect(); const withinBoundingBox = inBoundingBox(mousePoint, itemRect); @@ -509,7 +514,7 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After private _selectItems(event: Event) { const selectionBox = calculateBoundingClientRect(this.$selectBox.nativeElement); - this.$selectableItems.forEach((item, index) => { + this._selectableItems.forEach((item, index) => { if (this._isExtendedSelection(event)) { this._extendedSelectionMode(selectionBox, item, event); } else { diff --git a/projects/ngx-drag-to-select/src/lib/select-item.directive.ts b/projects/ngx-drag-to-select/src/lib/select-item.directive.ts index 168cd4d..fd54620 100644 --- a/projects/ngx-drag-to-select/src/lib/select-item.directive.ts +++ b/projects/ngx-drag-to-select/src/lib/select-item.directive.ts @@ -10,9 +10,13 @@ import { Renderer2, OnInit, HostBinding, + Optional, + SkipSelf, + OnDestroy, } from '@angular/core'; import { DragToSelectConfig, BoundingBox } from './models'; +import { DTS_SELECT_CONTAINER, SelectContainerComponent } from './select-container.component'; import { CONFIG } from './tokens'; import { calculateBoundingClientRect } from './utils'; @@ -25,7 +29,7 @@ export const SELECT_ITEM_INSTANCE = Symbol(); class: 'dts-select-item', }, }) -export class SelectItemDirective implements OnInit, DoCheck { +export class SelectItemDirective implements OnInit, DoCheck, OnDestroy { private _boundingClientRect: BoundingBox | undefined; selected = false; @@ -41,18 +45,24 @@ export class SelectItemDirective implements OnInit, DoCheck { constructor( @Inject(CONFIG) private config: DragToSelectConfig, @Inject(PLATFORM_ID) private platformId: Object, + @Inject(DTS_SELECT_CONTAINER) @Optional() @SkipSelf() public container: SelectContainerComponent, private host: ElementRef, private renderer: Renderer2 ) {} ngOnInit() { this.nativeElememnt[SELECT_ITEM_INSTANCE] = this; + this.container.register(this); } ngDoCheck() { this.applySelectedClass(); } + ngOnDestroy() { + this.container.unregister(this); + } + toggleRangeStart() { this.rangeStart = !this.rangeStart; } From 1f14bd31beedfc5f8b4b74cca213893354963909 Mon Sep 17 00:00:00 2001 From: Brian Kimball Date: Sat, 7 Nov 2020 21:52:43 -0500 Subject: [PATCH 02/13] docs: added nested directive demo with drag and drop refactor: removed dead code from change and fixed circular dependency caused by DI --- projects/ngx-drag-to-select/src/lib/models.ts | 7 ++ .../src/lib/select-container.component.ts | 14 ++-- .../src/lib/select-item.directive.ts | 7 +- projects/ngx-drag-to-select/src/lib/tokens.ts | 4 +- src/app/app.component.html | 32 ++++++--- src/app/app.module.ts | 11 +++ src/app/dragndrop/dragndrop.component.html | 9 +++ src/app/dragndrop/dragndrop.component.scss | 20 ++++++ src/app/dragndrop/dragndrop.component.ts | 14 ++++ .../task-list/task-list.component.html | 19 +++++ .../task-list/task-list.component.scss | 69 +++++++++++++++++++ .../task-list/task-list.component.ts | 61 ++++++++++++++++ src/app/dragndrop/task/task.component.html | 4 ++ src/app/dragndrop/task/task.component.scss | 8 +++ src/app/dragndrop/task/task.component.ts | 14 ++++ 15 files changed, 271 insertions(+), 22 deletions(-) create mode 100644 src/app/dragndrop/dragndrop.component.html create mode 100644 src/app/dragndrop/dragndrop.component.scss create mode 100644 src/app/dragndrop/dragndrop.component.ts create mode 100644 src/app/dragndrop/task-list/task-list.component.html create mode 100644 src/app/dragndrop/task-list/task-list.component.scss create mode 100644 src/app/dragndrop/task-list/task-list.component.ts create mode 100644 src/app/dragndrop/task/task.component.html create mode 100644 src/app/dragndrop/task/task.component.scss create mode 100644 src/app/dragndrop/task/task.component.ts diff --git a/projects/ngx-drag-to-select/src/lib/models.ts b/projects/ngx-drag-to-select/src/lib/models.ts index 4122c2f..582da6d 100644 --- a/projects/ngx-drag-to-select/src/lib/models.ts +++ b/projects/ngx-drag-to-select/src/lib/models.ts @@ -1,3 +1,4 @@ +import { ComponentType } from '@angular/cdk/portal'; import { Observable } from 'rxjs'; import { SelectItemDirective } from './select-item.directive'; @@ -62,3 +63,9 @@ export enum Action { Delete, None, } + +export interface SelectContainer { + selectedItems: T[]; + register(item: T): void; + unregister(item: T): void; +} diff --git a/projects/ngx-drag-to-select/src/lib/select-container.component.ts b/projects/ngx-drag-to-select/src/lib/select-container.component.ts index 2926297..9455dd3 100644 --- a/projects/ngx-drag-to-select/src/lib/select-container.component.ts +++ b/projects/ngx-drag-to-select/src/lib/select-container.component.ts @@ -53,6 +53,7 @@ import { UpdateActions, PredicateFn, BoundingBox, + SelectContainer, } from './models'; import { AUDIT_TIME, NO_SELECT_CLASS } from './constants'; @@ -68,8 +69,7 @@ import { hasMinimumSize, } from './utils'; import { KeyboardEventsService } from './keyboard-events.service'; - -export const DTS_SELECT_CONTAINER = new InjectionToken('SelectContainerComponent'); +import { DTS_SELECT_CONTAINER } from './tokens'; @Component({ selector: 'dts-select-container', @@ -89,7 +89,8 @@ export const DTS_SELECT_CONTAINER = new InjectionToken styleUrls: ['./select-container.component.scss'], providers: [{ provide: DTS_SELECT_CONTAINER, useExisting: SelectContainerComponent }], }) -export class SelectContainerComponent implements AfterViewInit, OnDestroy, AfterContentInit { +export class SelectContainerComponent + implements AfterViewInit, OnDestroy, AfterContentInit, SelectContainer { host: SelectContainerHost; selectBoxStyles$: Observable>; selectBoxClasses$: Observable<{ [key: string]: boolean }>; @@ -97,9 +98,6 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After @ViewChild('selectBox', { static: true }) private $selectBox: ElementRef; - @ContentChildren(SelectItemDirective, { descendants: true }) - private $selectableItems: QueryList; - @Input() selectedItems: any; @Input() selectOnDrag = true; @Input() disabled = false; @@ -263,11 +261,11 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After } ngAfterContentInit() { - this._selectableItems = this.$selectableItems.toArray(); + // removed query list, maybe remove this too } updateSelectableItems() { - this._selectableItems = Array.from(this._registry); //this.$selectableItems.toArray(); + this._selectableItems = Array.from(this._registry); } selectAll() { diff --git a/projects/ngx-drag-to-select/src/lib/select-item.directive.ts b/projects/ngx-drag-to-select/src/lib/select-item.directive.ts index fd54620..bccc1c5 100644 --- a/projects/ngx-drag-to-select/src/lib/select-item.directive.ts +++ b/projects/ngx-drag-to-select/src/lib/select-item.directive.ts @@ -15,9 +15,8 @@ import { OnDestroy, } from '@angular/core'; -import { DragToSelectConfig, BoundingBox } from './models'; -import { DTS_SELECT_CONTAINER, SelectContainerComponent } from './select-container.component'; -import { CONFIG } from './tokens'; +import { DragToSelectConfig, BoundingBox, SelectContainer } from './models'; +import { CONFIG, DTS_SELECT_CONTAINER } from './tokens'; import { calculateBoundingClientRect } from './utils'; export const SELECT_ITEM_INSTANCE = Symbol(); @@ -45,7 +44,7 @@ export class SelectItemDirective implements OnInit, DoCheck, OnDestroy { constructor( @Inject(CONFIG) private config: DragToSelectConfig, @Inject(PLATFORM_ID) private platformId: Object, - @Inject(DTS_SELECT_CONTAINER) @Optional() @SkipSelf() public container: SelectContainerComponent, + @Inject(DTS_SELECT_CONTAINER) @Optional() @SkipSelf() public container: SelectContainer, private host: ElementRef, private renderer: Renderer2 ) {} diff --git a/projects/ngx-drag-to-select/src/lib/tokens.ts b/projects/ngx-drag-to-select/src/lib/tokens.ts index 6e3122b..429828f 100644 --- a/projects/ngx-drag-to-select/src/lib/tokens.ts +++ b/projects/ngx-drag-to-select/src/lib/tokens.ts @@ -1,5 +1,7 @@ +import { ComponentType } from '@angular/cdk/portal'; import { InjectionToken } from '@angular/core'; -import { DragToSelectConfig } from './models'; +import { DragToSelectConfig, SelectContainer } from './models'; export const CONFIG = new InjectionToken('DRAG_TO_SELECT_CONFIG'); export const USER_CONFIG = new InjectionToken('USER_CONFIG'); +export const DTS_SELECT_CONTAINER = new InjectionToken>('SelectContainerComponent'); diff --git a/src/app/app.component.html b/src/app/app.component.html index 70c95fe..b8908b8 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -4,11 +4,15 @@

Keyboard Shortcuts

- + + + - + + + @@ -21,9 +25,8 @@

Select on Drag Disable - Disable Range Selection + Disable Range Selection + Select Mode Select with Shortcut @@ -43,8 +46,7 @@

[disabled]="disable" [disableRangeSelection]="disableRangeSelection" [selectOnDrag]="selectOnDrag" - [selectWithShortcut]="selectWithShortcut" - > + [selectWithShortcut]="selectWithShortcut"> {{ document.name }} @@ -69,7 +71,19 @@

Mobile Demo SOURCE

-
+
+ +
+ + +
+

+ Drag & Drop Demo SOURCE +

+ + +
- + \ No newline at end of file diff --git a/src/app/app.module.ts b/src/app/app.module.ts index a7bcc84..0333950 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -9,6 +9,9 @@ import { MatChipsModule } from '@angular/material/chips'; import { MatTabsModule } from '@angular/material/tabs'; import { MatIconModule } from '@angular/material/icon'; import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; + +import { DragDropModule } from '@angular/cdk/drag-drop'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @@ -19,6 +22,9 @@ import { AppComponent } from './app.component'; import { FooterComponent } from './footer/footer.component'; import { HeaderComponent } from './header/header.component'; import { PhoneComponent } from './phone/phone.component'; +import { DragNDropComponent } from './dragndrop/dragndrop.component'; +import { TaskComponent } from './dragndrop/task/task.component'; +import { TaskListComponent } from './dragndrop/task-list/task-list.component'; import { KeyComponent, @@ -36,6 +42,8 @@ const MATERIAL_MODULES = [ MatTabsModule, MatIconModule, MatButtonModule, + MatCardModule, + DragDropModule, ]; @NgModule({ @@ -49,6 +57,9 @@ const MATERIAL_MODULES = [ FooterComponent, HeaderComponent, PhoneComponent, + DragNDropComponent, + TaskComponent, + TaskListComponent, ], imports: [ BrowserModule.withServerTransition({ appId: 'demo-app' }), diff --git a/src/app/dragndrop/dragndrop.component.html b/src/app/dragndrop/dragndrop.component.html new file mode 100644 index 0000000..b766471 --- /dev/null +++ b/src/app/dragndrop/dragndrop.component.html @@ -0,0 +1,9 @@ + +
+ + + + + +
+
\ No newline at end of file diff --git a/src/app/dragndrop/dragndrop.component.scss b/src/app/dragndrop/dragndrop.component.scss new file mode 100644 index 0000000..4497a6f --- /dev/null +++ b/src/app/dragndrop/dragndrop.component.scss @@ -0,0 +1,20 @@ +.list-wrapper { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 1rem; + min-height: 400px; +} + +.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); +} diff --git a/src/app/dragndrop/dragndrop.component.ts b/src/app/dragndrop/dragndrop.component.ts new file mode 100644 index 0000000..e444307 --- /dev/null +++ b/src/app/dragndrop/dragndrop.component.ts @@ -0,0 +1,14 @@ +import { Component } from '@angular/core'; +import { CdkDragDrop, CdkDragStart, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop'; + +@Component({ + selector: 'app-dragndrop', + templateUrl: './dragndrop.component.html', + styleUrls: ['./dragndrop.component.scss'], +}) +export class DragNDropComponent { + todo = ['Next Task', 'Very Important Item', 'Open Ticket #1', 'Open Ticket #2', 'Not Important Task']; + doing = ['High Priority Task', 'In Progress Item']; + done = ['Completed Item']; + selectedItems: any[] = []; +} diff --git a/src/app/dragndrop/task-list/task-list.component.html b/src/app/dragndrop/task-list/task-list.component.html new file mode 100644 index 0000000..f432a2f --- /dev/null +++ b/src/app/dragndrop/task-list/task-list.component.html @@ -0,0 +1,19 @@ +

{{title}}

+ +
+ +
+ {{ selected }} +
+
+ {{ selected }} +
+
+
\ No newline at end of file diff --git a/src/app/dragndrop/task-list/task-list.component.scss b/src/app/dragndrop/task-list/task-list.component.scss new file mode 100644 index 0000000..ba84a72 --- /dev/null +++ b/src/app/dragndrop/task-list/task-list.component.scss @@ -0,0 +1,69 @@ +:host { + background-color: #ebecf0; + border-radius: 3px; + box-sizing: border-box; + display: flex; + flex-direction: column; + max-height: 100%; + position: relative; + white-space: normal; +} + +.list-header { + padding: 0.5rem; +} + +.list-cards { + margin: 0 4px; + padding: 0 4px; + display: grid; + grid-template-columns: 1fr; + grid-auto-rows: min-content; + gap: 0.4rem; + height: -webkit-fill-available; +} + +.list-cards.cdk-drop-list-dragging app-task:not(.cdk-drag-placeholder) { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} + +:host(.item-dragging) { + ::ng-deep { + mat-card.selected:not(.cdk-drag-placeholder) { + opacity: 0.3; + } + } +} + +.drag-placeholder-container { + display: flex; + flex-flow: column; + gap: 0.5rem; + mat-card { + opacity: 0.5; + } +} + +.drag-preview-container { + gap: 0.5rem; + position: relative; + + mat-card { + position: absolute; + width: 200px; + top: -10px; + left: -25px; + } + mat-card:nth-child(2) { + left: -40px; + top: -10px; + transform: rotate(-1deg); + z-index: -1; + } + mat-card:nth-child(3) { + top: -5px; + left: -20px; + transform: rotate(1deg); + z-index: -2; + } +} diff --git a/src/app/dragndrop/task-list/task-list.component.ts b/src/app/dragndrop/task-list/task-list.component.ts new file mode 100644 index 0000000..4848dd5 --- /dev/null +++ b/src/app/dragndrop/task-list/task-list.component.ts @@ -0,0 +1,61 @@ +import { CdkDragStart, CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop'; +import { ThrowStmt } from '@angular/compiler'; +import { Component, HostBinding, Inject, Input, Optional, SkipSelf } from '@angular/core'; +import { DTS_SELECT_CONTAINER } from 'projects/ngx-drag-to-select/src/lib/tokens'; +import { SelectContainerComponent } from 'projects/ngx-drag-to-select/src/public_api'; + +@Component({ + selector: 'app-task-list', + styleUrls: ['./task-list.component.scss'], + templateUrl: './task-list.component.html', +}) +export class TaskListComponent { + @Input() title = 'Tasks'; + @Input() tasks = []; + + @HostBinding('class.item-dragging') + dragging = false; + + constructor(@Inject(DTS_SELECT_CONTAINER) @Optional() @SkipSelf() public container: SelectContainerComponent) {} + + dragStarted(ev: CdkDragStart, index: number): void { + this.dragging = !!ev.source._dragRef; + this.container.selectItems((item) => { + return item === this.tasks[index]; + }); + } + + dragEnded(): void { + this.dragging = null; + } + + dropped(event: CdkDragDrop): void { + this.dragging = null; + const indices = this.container.selectedItems.map((it) => event.previousContainer.data.findIndex((i) => it === i)); + indices.sort().reverse(); + indices.forEach((idx) => { + this.tasks.splice(idx, 1); + }); + + setTimeout(() => this.container.clearSelection()); + } + + drop(event: CdkDragDrop) { + const indices = this.container.selectedItems.map((it) => event.previousContainer.data.findIndex((i) => it === i)); + console.log('Selected', indices); + + const spliceIntoIndex = event.currentIndex; + this.tasks.splice(spliceIntoIndex, 0, ...this.container.selectedItems); + + this.container.update(); + // if (event.previousContainer === event.container) { + // for (const item of this.container.selectedItems) { + // moveItemInArray(event.container.data, event.previousIndex, event.currentIndex); + // } + // } else { + // for (const item of this.container.selectedItems) { + // transferArrayItem(event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex); + // } + // } + } +} diff --git a/src/app/dragndrop/task/task.component.html b/src/app/dragndrop/task/task.component.html new file mode 100644 index 0000000..4ca1a8a --- /dev/null +++ b/src/app/dragndrop/task/task.component.html @@ -0,0 +1,4 @@ + + {{ item }} + \ No newline at end of file diff --git a/src/app/dragndrop/task/task.component.scss b/src/app/dragndrop/task/task.component.scss new file mode 100644 index 0000000..3d2d13e --- /dev/null +++ b/src/app/dragndrop/task/task.component.scss @@ -0,0 +1,8 @@ +:host { + height: min-content; +} +mat-card { + &.selected { + border: 1px solid blue; + } +} diff --git a/src/app/dragndrop/task/task.component.ts b/src/app/dragndrop/task/task.component.ts new file mode 100644 index 0000000..b6fe6c0 --- /dev/null +++ b/src/app/dragndrop/task/task.component.ts @@ -0,0 +1,14 @@ +import { Component, Inject, Input, Optional, SkipSelf } from '@angular/core'; +import { SelectContainerComponent } from 'projects/ngx-drag-to-select/src/public_api'; +import { DTS_SELECT_CONTAINER } from 'projects/ngx-drag-to-select/src/lib/tokens'; + +@Component({ + selector: 'app-task', + styleUrls: ['./task.component.scss'], + templateUrl: './task.component.html', +}) +export class TaskComponent { + @Input() item = ''; + // @Input() selectedItems = []; + constructor(@Inject(DTS_SELECT_CONTAINER) @Optional() @SkipSelf() public container: SelectContainerComponent) {} +} From 104eeb6c133ef04776d7c80722631e5b1f7b0742 Mon Sep 17 00:00:00 2001 From: Brian Kimball Date: Sat, 7 Nov 2020 22:09:39 -0500 Subject: [PATCH 03/13] style: fixed lint error for member ordering --- .../ngx-drag-to-select/src/lib/select-container.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/ngx-drag-to-select/src/lib/select-container.component.ts b/projects/ngx-drag-to-select/src/lib/select-container.component.ts index 9455dd3..6c6f295 100644 --- a/projects/ngx-drag-to-select/src/lib/select-container.component.ts +++ b/projects/ngx-drag-to-select/src/lib/select-container.component.ts @@ -129,6 +129,8 @@ export class SelectContainerComponent private _newRangeStart = false; private _lastRangeSelection: Map = new Map(); + private _registry: Set = new Set(); + constructor( @Inject(PLATFORM_ID) private platformId: Object, private shortcuts: ShortcutService, @@ -292,8 +294,6 @@ export class SelectContainerComponent }); } - _registry: Set = new Set(); - register(item: SelectItemDirective) { this._registry.add(item); this.updateSelectableItems(); From a7d0a23300b2f38a31783f7230cbc6a5685f653c Mon Sep 17 00:00:00 2001 From: Brian Kimball Date: Sun, 8 Nov 2020 08:06:40 -0500 Subject: [PATCH 04/13] docs: added new section to README --- README.md | 16 ++++++++++++++++ .../dragndrop/task-list/task-list.component.ts | 3 +-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9282776..8cf8a4b 100644 --- a/README.md +++ b/README.md @@ -554,6 +554,22 @@ Here we listen for `scroll` on the `div` and call `container.update()` in case t In order not to kill the performance, because the `scroll` event is called many many times, you may want to **throttle** it to only call `update` every 16ms or so. +### Does the `selectItem` directive need to be a direct child of the `dts-select-container`? + +As of version `4.1.0`, an injetion token is used to pass the SelectContainerComponent parent to the directive. You can use this in any component nested within the `dts-select-container`. + +```javascript +import { DTS_SELECT_CONTAINER } from 'ngx-drag-to-select'; + +@Component({...}) +export class TaskListComponent { + constructor( + @Inject(DTS_SELECT_CONTAINER) @Optional() + public container: SelectContainerComponent) {} +``` + +You can see an example of the this in the [drag and drop example](https://github.com/d3lm/ngx-drag-to-select/blob/master/src/app/dragndrop). You can see that the `[selectItem]` directive is set in `app-task` component and the `dts-select-container` is in the `drag-n-drop` component. + ## Want to contribute? If you want to file a bug, contribute some code, or improve our documentation, read up on our [contributing guidelines](CONTRIBUTING.md) and [code of conduct](CODE_OF_CONDUCT.md), and check out [open issues](/issues). diff --git a/src/app/dragndrop/task-list/task-list.component.ts b/src/app/dragndrop/task-list/task-list.component.ts index 4848dd5..7ee1479 100644 --- a/src/app/dragndrop/task-list/task-list.component.ts +++ b/src/app/dragndrop/task-list/task-list.component.ts @@ -1,5 +1,4 @@ -import { CdkDragStart, CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop'; -import { ThrowStmt } from '@angular/compiler'; +import { CdkDragStart, CdkDragDrop } from '@angular/cdk/drag-drop'; import { Component, HostBinding, Inject, Input, Optional, SkipSelf } from '@angular/core'; import { DTS_SELECT_CONTAINER } from 'projects/ngx-drag-to-select/src/lib/tokens'; import { SelectContainerComponent } from 'projects/ngx-drag-to-select/src/public_api'; From 70e97a1cdadc7798412d6c9c894d3e745e47abdd Mon Sep 17 00:00:00 2001 From: Brian Kimball Date: Sun, 8 Nov 2020 21:25:43 -0500 Subject: [PATCH 05/13] docs(lib): added section to readme about components capturing events test(app): added cypress test for new example demo --- README.md | 6 +- cypress/integration/drag-and-drop.spec.ts | 80 +++++++++++++++++++ cypress/support/utils.ts | 16 ++++ .../src/lib/select-container.component.ts | 5 +- src/app/app.component.html | 2 +- src/app/dragndrop/dragndrop.component.html | 8 +- .../task-list/task-list.component.scss | 2 +- .../task-list/task-list.component.ts | 4 +- src/app/dragndrop/task/task.component.html | 4 +- src/app/dragndrop/task/task.component.ts | 8 +- 10 files changed, 119 insertions(+), 16 deletions(-) create mode 100644 cypress/integration/drag-and-drop.spec.ts diff --git a/README.md b/README.md index 8cf8a4b..2e9de6e 100644 --- a/README.md +++ b/README.md @@ -568,7 +568,11 @@ export class TaskListComponent { public container: SelectContainerComponent) {} ``` -You can see an example of the this in the [drag and drop example](https://github.com/d3lm/ngx-drag-to-select/blob/master/src/app/dragndrop). You can see that the `[selectItem]` directive is set in `app-task` component and the `dts-select-container` is in the `drag-n-drop` component. +You can see an example of the this in the [drag and drop example](https://github.com/d3lm/ngx-drag-to-select/blob/master/src/app/dragndrop). You can see that the `[selectItem]` directive is set in `app-task` component and the `dts-select-container` is in the `dragndrop` component. + +### Why is my `selectItem` directive not selecting why I click on it? + +If you are using the `selectItem` within a nested component then your mousedown/up events might being captured by another directive or component in your code. For example if you are using this libary with Angular CDK's DragDropModule, the mouse events are captured by the `cdkDrag` directive, [see here](https://github.com/angular/components/pull/19674). ## Want to contribute? diff --git a/cypress/integration/drag-and-drop.spec.ts b/cypress/integration/drag-and-drop.spec.ts new file mode 100644 index 0000000..ea90f16 --- /dev/null +++ b/cypress/integration/drag-and-drop.spec.ts @@ -0,0 +1,80 @@ +import { DEFAULT_CONFIG } from '../../projects/ngx-drag-to-select/src/lib/config'; + +import { + disableSelection, + disableSelectOnDrag, + enableSelectMode, + getDesktopExample, + getDoingList, + getDragAndDropExample, + getTodoList, + shouldBeInvisible, + shouldBeVisible, + toggleItem, +} from '../support/utils'; + +const SELECTED_CLASS = DEFAULT_CONFIG.selectedClass; + +describe('Drag And Drop', () => { + beforeEach(() => { + cy.visit('/'); + }); + + describe('Select on Drag', () => { + it('should start new selection', () => { + getDragAndDropExample().within(() => { + getTodoList() + .dispatch('mousedown', 'topLeft', { button: 0 }) + .getSelectItem(2) + .dispatch('mousemove') + .dispatch('mouseup'); + + cy.get('.selected').should('have.length', 3); + }); + }); + + it('should drag to new list', () => { + getDragAndDropExample().within(() => { + getTodoList() + // Select First 3 items in list + .dispatch('mousedown', 'topLeft', { button: 0 }) + .getSelectItem(2) + .dispatch('mousemove') + .dispatch('mouseup') + // Click on second item + .getSelectItem(1) + .dispatch('mousedown', { button: 0 }) + // Drag to Select Item in other list + .getSelectItem(5) + .wait(16) + .dispatch('mousemove') + .dispatch('mousemove') + .dispatch('mouseup'); + + getDoingList().within(() => { + cy.get('app-task').should('have.length', 5); + }); + }); + }); + + it('should reorder within list', () => { + getDragAndDropExample().within(() => { + getTodoList() + .dispatch('mousedown', 'bottomRight', { button: 0 }) + .getSelectItem(2) + .dispatch('mousemove') + .dispatch('mouseup') + .getSelectItem(3) + .dispatch('mousedown', { button: 0 }) + .getSelectItem(0) + .wait(16) + .dispatch('mousemove') + .dispatch('mousemove') + .dispatch('mouseup'); + + cy.get('app-task').eq(0).should('contain', 'Open Ticket #1'); + cy.get('app-task').eq(1).should('contain', 'Open Ticket #2'); + }); + }); + }); +}); diff --git a/cypress/support/utils.ts b/cypress/support/utils.ts index 5f2e640..fc12cb8 100644 --- a/cypress/support/utils.ts +++ b/cypress/support/utils.ts @@ -28,6 +28,10 @@ export const getMobileExample = () => { return cy.get('[data-cy="mobile"]'); }; +export const getDragAndDropExample = () => { + return cy.get('[data-cy="drag-and-drop"]'); +}; + export const getSelectCount = () => { return cy.get('[data-cy="select-count"]'); }; @@ -48,6 +52,18 @@ export const getClearButton = () => { return cy.get('[data-cy="clearSelection"]'); }; +export const getTodoList = () => { + return cy.get('[data-cy="todo-list"]'); +}; + +export const getDoingList = () => { + return cy.get('[data-cy="doing-list"]'); +}; + +export const getDoneList = () => { + return cy.get('[data-cy="done-list"]'); +}; + export const disableSelectOnDrag = () => { return cy.get('[data-cy="selectOnDrag"]').click(); }; diff --git a/projects/ngx-drag-to-select/src/lib/select-container.component.ts b/projects/ngx-drag-to-select/src/lib/select-container.component.ts index 6c6f295..9c9a658 100644 --- a/projects/ngx-drag-to-select/src/lib/select-container.component.ts +++ b/projects/ngx-drag-to-select/src/lib/select-container.component.ts @@ -8,14 +8,11 @@ import { Renderer2, ViewChild, NgZone, - ContentChildren, - QueryList, HostBinding, AfterViewInit, PLATFORM_ID, Inject, AfterContentInit, - InjectionToken, } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; @@ -33,7 +30,6 @@ import { share, withLatestFrom, distinctUntilChanged, - observeOn, startWith, concatMapTo, first, @@ -398,6 +394,7 @@ export class SelectContainerComponent } private _onMouseDown(event: MouseEvent) { + console.log('Mouse Down'); if (this.shortcuts.disableSelection(event) || this.disabled) { return; } diff --git a/src/app/app.component.html b/src/app/app.component.html index b8908b8..679d520 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -76,7 +76,7 @@

-
+

Drag & Drop Demo SOURCE diff --git a/src/app/dragndrop/dragndrop.component.html b/src/app/dragndrop/dragndrop.component.html index b766471..7c44eea 100644 --- a/src/app/dragndrop/dragndrop.component.html +++ b/src/app/dragndrop/dragndrop.component.html @@ -1,9 +1,9 @@ - +
- - - + + +
\ No newline at end of file diff --git a/src/app/dragndrop/task-list/task-list.component.scss b/src/app/dragndrop/task-list/task-list.component.scss index ba84a72..23030ba 100644 --- a/src/app/dragndrop/task-list/task-list.component.scss +++ b/src/app/dragndrop/task-list/task-list.component.scss @@ -30,7 +30,7 @@ :host(.item-dragging) { ::ng-deep { mat-card.selected:not(.cdk-drag-placeholder) { - opacity: 0.3; + display: none; //opacity: 0.3; } } } diff --git a/src/app/dragndrop/task-list/task-list.component.ts b/src/app/dragndrop/task-list/task-list.component.ts index 7ee1479..52e8ee2 100644 --- a/src/app/dragndrop/task-list/task-list.component.ts +++ b/src/app/dragndrop/task-list/task-list.component.ts @@ -15,7 +15,7 @@ export class TaskListComponent { @HostBinding('class.item-dragging') dragging = false; - constructor(@Inject(DTS_SELECT_CONTAINER) @Optional() @SkipSelf() public container: SelectContainerComponent) {} + constructor(@Inject(DTS_SELECT_CONTAINER) @Optional() public container: SelectContainerComponent) {} dragStarted(ev: CdkDragStart, index: number): void { this.dragging = !!ev.source._dragRef; @@ -46,7 +46,7 @@ export class TaskListComponent { const spliceIntoIndex = event.currentIndex; this.tasks.splice(spliceIntoIndex, 0, ...this.container.selectedItems); - this.container.update(); + setTimeout(() => this.container.update()); // if (event.previousContainer === event.container) { // for (const item of this.container.selectedItems) { // moveItemInArray(event.container.data, event.previousIndex, event.currentIndex); diff --git a/src/app/dragndrop/task/task.component.html b/src/app/dragndrop/task/task.component.html index 4ca1a8a..423ac50 100644 --- a/src/app/dragndrop/task/task.component.html +++ b/src/app/dragndrop/task/task.component.html @@ -1,4 +1,6 @@ + data-cy="selected-item" + [dtsSelectItem]="item" + (click)="select()"> {{ item }} \ No newline at end of file diff --git a/src/app/dragndrop/task/task.component.ts b/src/app/dragndrop/task/task.component.ts index b6fe6c0..b2279c9 100644 --- a/src/app/dragndrop/task/task.component.ts +++ b/src/app/dragndrop/task/task.component.ts @@ -9,6 +9,10 @@ import { DTS_SELECT_CONTAINER } from 'projects/ngx-drag-to-select/src/lib/tokens }) export class TaskComponent { @Input() item = ''; - // @Input() selectedItems = []; - constructor(@Inject(DTS_SELECT_CONTAINER) @Optional() @SkipSelf() public container: SelectContainerComponent) {} + constructor(@Inject(DTS_SELECT_CONTAINER) @Optional() public container: SelectContainerComponent) {} + + select() { + this.container.clearSelection(); + this.container.selectItems((it) => it === this.item); + } } From 2b28e38e1b748f4f617375ea70a285a6819b7f01 Mon Sep 17 00:00:00 2001 From: Brian Kimball Date: Mon, 9 Nov 2020 11:30:55 -0500 Subject: [PATCH 06/13] fix(lib): new Token was not export with the public api --- projects/ngx-drag-to-select/src/public_api.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/projects/ngx-drag-to-select/src/public_api.ts b/projects/ngx-drag-to-select/src/public_api.ts index e1d010e..aab3305 100644 --- a/projects/ngx-drag-to-select/src/public_api.ts +++ b/projects/ngx-drag-to-select/src/public_api.ts @@ -5,3 +5,4 @@ export * from './lib/drag-to-select.module'; export * from './lib/select-container.component'; export * from './lib/select-item.directive'; +export { DTS_SELECT_CONTAINER } from './lib/tokens'; From 1e70169c9f2a1c9e4a1268cb0c66b326919facac Mon Sep 17 00:00:00 2001 From: Brian Kimball Date: Tue, 10 Nov 2020 19:14:09 -0500 Subject: [PATCH 07/13] refactor(app): renamed drag-and-drop docs: updated grammar --- README.md | 15 ++-- projects/ngx-drag-to-select/src/lib/models.ts | 3 +- .../src/lib/select-container.component.ts | 10 +-- projects/ngx-drag-to-select/src/lib/tokens.ts | 3 +- src/app/app.component.html | 4 +- src/app/app.module.ts | 8 +-- src/app/dragndrop/dragndrop.component.html | 9 --- src/app/dragndrop/dragndrop.component.scss | 20 ------ src/app/dragndrop/dragndrop.component.ts | 14 ---- .../task-list/task-list.component.html | 19 ----- .../task-list/task-list.component.scss | 69 ------------------- .../task-list/task-list.component.ts | 60 ---------------- src/app/dragndrop/task/task.component.html | 6 -- src/app/dragndrop/task/task.component.scss | 8 --- src/app/dragndrop/task/task.component.ts | 18 ----- 15 files changed, 19 insertions(+), 247 deletions(-) delete mode 100644 src/app/dragndrop/dragndrop.component.html delete mode 100644 src/app/dragndrop/dragndrop.component.scss delete mode 100644 src/app/dragndrop/dragndrop.component.ts delete mode 100644 src/app/dragndrop/task-list/task-list.component.html delete mode 100644 src/app/dragndrop/task-list/task-list.component.scss delete mode 100644 src/app/dragndrop/task-list/task-list.component.ts delete mode 100644 src/app/dragndrop/task/task.component.html delete mode 100644 src/app/dragndrop/task/task.component.scss delete mode 100644 src/app/dragndrop/task/task.component.ts diff --git a/README.md b/README.md index 2e9de6e..4ecf343 100644 --- a/README.md +++ b/README.md @@ -554,25 +554,26 @@ Here we listen for `scroll` on the `div` and call `container.update()` in case t In order not to kill the performance, because the `scroll` event is called many many times, you may want to **throttle** it to only call `update` every 16ms or so. -### Does the `selectItem` directive need to be a direct child of the `dts-select-container`? +### Does the `dtsSelectItem` directive need to be a direct child of the `dts-select-container`? -As of version `4.1.0`, an injetion token is used to pass the SelectContainerComponent parent to the directive. You can use this in any component nested within the `dts-select-container`. +As of version `4.1.0`, an injection token is used to pass the `SelectContainerComponent` parent to the directive. You can use this in any component nested within the `dts-select-container`. -```javascript +```ts import { DTS_SELECT_CONTAINER } from 'ngx-drag-to-select'; @Component({...}) export class TaskListComponent { constructor( @Inject(DTS_SELECT_CONTAINER) @Optional() - public container: SelectContainerComponent) {} + public container: SelectContainerComponent + ) {} ``` -You can see an example of the this in the [drag and drop example](https://github.com/d3lm/ngx-drag-to-select/blob/master/src/app/dragndrop). You can see that the `[selectItem]` directive is set in `app-task` component and the `dts-select-container` is in the `dragndrop` component. +You can find an example of this in the [drag and drop example](https://github.com/d3lm/ngx-drag-to-select/blob/master/src/app/dragndrop). -### Why is my `selectItem` directive not selecting why I click on it? +### Why is my `dtsSelectItem` directive not selecting when I click on it? -If you are using the `selectItem` within a nested component then your mousedown/up events might being captured by another directive or component in your code. For example if you are using this libary with Angular CDK's DragDropModule, the mouse events are captured by the `cdkDrag` directive, [see here](https://github.com/angular/components/pull/19674). +If you are using the `dtsSelectItem` within a nested component then your mousedown/up events might being captured by another directive or component in your code. For example if you are using this libary with Angular CDK's DragDropModule, the mouse events are captured by the `cdkDrag` directive, [see here](https://github.com/angular/components/pull/19674). ## Want to contribute? diff --git a/projects/ngx-drag-to-select/src/lib/models.ts b/projects/ngx-drag-to-select/src/lib/models.ts index 582da6d..5ebf228 100644 --- a/projects/ngx-drag-to-select/src/lib/models.ts +++ b/projects/ngx-drag-to-select/src/lib/models.ts @@ -1,4 +1,3 @@ -import { ComponentType } from '@angular/cdk/portal'; import { Observable } from 'rxjs'; import { SelectItemDirective } from './select-item.directive'; @@ -69,3 +68,5 @@ export interface SelectContainer { register(item: T): void; unregister(item: T): void; } + +export type ComponentType = new (...args: any[]) => T; diff --git a/projects/ngx-drag-to-select/src/lib/select-container.component.ts b/projects/ngx-drag-to-select/src/lib/select-container.component.ts index 9c9a658..177e321 100644 --- a/projects/ngx-drag-to-select/src/lib/select-container.component.ts +++ b/projects/ngx-drag-to-select/src/lib/select-container.component.ts @@ -12,7 +12,6 @@ import { AfterViewInit, PLATFORM_ID, Inject, - AfterContentInit, } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; @@ -38,7 +37,7 @@ import { import { SelectItemDirective, SELECT_ITEM_INSTANCE } from './select-item.directive'; import { ShortcutService } from './shortcut.service'; -import { createSelectBox, whenSelectBoxVisible, distinctKeyEvents } from './operators'; +import { createSelectBox, whenSelectBoxVisible } from './operators'; import { Action, @@ -85,8 +84,7 @@ import { DTS_SELECT_CONTAINER } from './tokens'; styleUrls: ['./select-container.component.scss'], providers: [{ provide: DTS_SELECT_CONTAINER, useExisting: SelectContainerComponent }], }) -export class SelectContainerComponent - implements AfterViewInit, OnDestroy, AfterContentInit, SelectContainer { +export class SelectContainerComponent implements AfterViewInit, OnDestroy, SelectContainer { host: SelectContainerHost; selectBoxStyles$: Observable>; selectBoxClasses$: Observable<{ [key: string]: boolean }>; @@ -258,10 +256,6 @@ export class SelectContainerComponent } } - ngAfterContentInit() { - // removed query list, maybe remove this too - } - updateSelectableItems() { this._selectableItems = Array.from(this._registry); } diff --git a/projects/ngx-drag-to-select/src/lib/tokens.ts b/projects/ngx-drag-to-select/src/lib/tokens.ts index 429828f..87d3856 100644 --- a/projects/ngx-drag-to-select/src/lib/tokens.ts +++ b/projects/ngx-drag-to-select/src/lib/tokens.ts @@ -1,6 +1,5 @@ -import { ComponentType } from '@angular/cdk/portal'; import { InjectionToken } from '@angular/core'; -import { DragToSelectConfig, SelectContainer } from './models'; +import { DragToSelectConfig, SelectContainer, ComponentType } from './models'; export const CONFIG = new InjectionToken('DRAG_TO_SELECT_CONFIG'); export const USER_CONFIG = new InjectionToken('USER_CONFIG'); diff --git a/src/app/app.component.html b/src/app/app.component.html index 679d520..04eb728 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -79,10 +79,10 @@

Drag & Drop Demo SOURCE + href="https://github.com/d3lm/ngx-drag-to-select/blob/master/src/app/drag-and-drop">SOURCE

- +
diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 0333950..e0b8e68 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -22,9 +22,9 @@ import { AppComponent } from './app.component'; import { FooterComponent } from './footer/footer.component'; import { HeaderComponent } from './header/header.component'; import { PhoneComponent } from './phone/phone.component'; -import { DragNDropComponent } from './dragndrop/dragndrop.component'; -import { TaskComponent } from './dragndrop/task/task.component'; -import { TaskListComponent } from './dragndrop/task-list/task-list.component'; +import { DragAndDropComponent } from './drag-and-drop/drag-and-drop.component'; +import { TaskComponent } from './drag-and-drop/task/task.component'; +import { TaskListComponent } from './drag-and-drop/task-list/task-list.component'; import { KeyComponent, @@ -57,7 +57,7 @@ const MATERIAL_MODULES = [ FooterComponent, HeaderComponent, PhoneComponent, - DragNDropComponent, + DragAndDropComponent, TaskComponent, TaskListComponent, ], diff --git a/src/app/dragndrop/dragndrop.component.html b/src/app/dragndrop/dragndrop.component.html deleted file mode 100644 index 7c44eea..0000000 --- a/src/app/dragndrop/dragndrop.component.html +++ /dev/null @@ -1,9 +0,0 @@ - -
- - - - - -
-
\ No newline at end of file diff --git a/src/app/dragndrop/dragndrop.component.scss b/src/app/dragndrop/dragndrop.component.scss deleted file mode 100644 index 4497a6f..0000000 --- a/src/app/dragndrop/dragndrop.component.scss +++ /dev/null @@ -1,20 +0,0 @@ -.list-wrapper { - display: grid; - grid-template-columns: 1fr 1fr 1fr; - gap: 1rem; - min-height: 400px; -} - -.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); -} diff --git a/src/app/dragndrop/dragndrop.component.ts b/src/app/dragndrop/dragndrop.component.ts deleted file mode 100644 index e444307..0000000 --- a/src/app/dragndrop/dragndrop.component.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Component } from '@angular/core'; -import { CdkDragDrop, CdkDragStart, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop'; - -@Component({ - selector: 'app-dragndrop', - templateUrl: './dragndrop.component.html', - styleUrls: ['./dragndrop.component.scss'], -}) -export class DragNDropComponent { - todo = ['Next Task', 'Very Important Item', 'Open Ticket #1', 'Open Ticket #2', 'Not Important Task']; - doing = ['High Priority Task', 'In Progress Item']; - done = ['Completed Item']; - selectedItems: any[] = []; -} diff --git a/src/app/dragndrop/task-list/task-list.component.html b/src/app/dragndrop/task-list/task-list.component.html deleted file mode 100644 index f432a2f..0000000 --- a/src/app/dragndrop/task-list/task-list.component.html +++ /dev/null @@ -1,19 +0,0 @@ -

{{title}}

- -
- -
- {{ selected }} -
-
- {{ selected }} -
-
-
\ No newline at end of file diff --git a/src/app/dragndrop/task-list/task-list.component.scss b/src/app/dragndrop/task-list/task-list.component.scss deleted file mode 100644 index 23030ba..0000000 --- a/src/app/dragndrop/task-list/task-list.component.scss +++ /dev/null @@ -1,69 +0,0 @@ -:host { - background-color: #ebecf0; - border-radius: 3px; - box-sizing: border-box; - display: flex; - flex-direction: column; - max-height: 100%; - position: relative; - white-space: normal; -} - -.list-header { - padding: 0.5rem; -} - -.list-cards { - margin: 0 4px; - padding: 0 4px; - display: grid; - grid-template-columns: 1fr; - grid-auto-rows: min-content; - gap: 0.4rem; - height: -webkit-fill-available; -} - -.list-cards.cdk-drop-list-dragging app-task:not(.cdk-drag-placeholder) { - transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); -} - -:host(.item-dragging) { - ::ng-deep { - mat-card.selected:not(.cdk-drag-placeholder) { - display: none; //opacity: 0.3; - } - } -} - -.drag-placeholder-container { - display: flex; - flex-flow: column; - gap: 0.5rem; - mat-card { - opacity: 0.5; - } -} - -.drag-preview-container { - gap: 0.5rem; - position: relative; - - mat-card { - position: absolute; - width: 200px; - top: -10px; - left: -25px; - } - mat-card:nth-child(2) { - left: -40px; - top: -10px; - transform: rotate(-1deg); - z-index: -1; - } - mat-card:nth-child(3) { - top: -5px; - left: -20px; - transform: rotate(1deg); - z-index: -2; - } -} diff --git a/src/app/dragndrop/task-list/task-list.component.ts b/src/app/dragndrop/task-list/task-list.component.ts deleted file mode 100644 index 52e8ee2..0000000 --- a/src/app/dragndrop/task-list/task-list.component.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { CdkDragStart, CdkDragDrop } from '@angular/cdk/drag-drop'; -import { Component, HostBinding, Inject, Input, Optional, SkipSelf } from '@angular/core'; -import { DTS_SELECT_CONTAINER } from 'projects/ngx-drag-to-select/src/lib/tokens'; -import { SelectContainerComponent } from 'projects/ngx-drag-to-select/src/public_api'; - -@Component({ - selector: 'app-task-list', - styleUrls: ['./task-list.component.scss'], - templateUrl: './task-list.component.html', -}) -export class TaskListComponent { - @Input() title = 'Tasks'; - @Input() tasks = []; - - @HostBinding('class.item-dragging') - dragging = false; - - constructor(@Inject(DTS_SELECT_CONTAINER) @Optional() public container: SelectContainerComponent) {} - - dragStarted(ev: CdkDragStart, index: number): void { - this.dragging = !!ev.source._dragRef; - this.container.selectItems((item) => { - return item === this.tasks[index]; - }); - } - - dragEnded(): void { - this.dragging = null; - } - - dropped(event: CdkDragDrop): void { - this.dragging = null; - const indices = this.container.selectedItems.map((it) => event.previousContainer.data.findIndex((i) => it === i)); - indices.sort().reverse(); - indices.forEach((idx) => { - this.tasks.splice(idx, 1); - }); - - setTimeout(() => this.container.clearSelection()); - } - - drop(event: CdkDragDrop) { - const indices = this.container.selectedItems.map((it) => event.previousContainer.data.findIndex((i) => it === i)); - console.log('Selected', indices); - - const spliceIntoIndex = event.currentIndex; - this.tasks.splice(spliceIntoIndex, 0, ...this.container.selectedItems); - - setTimeout(() => this.container.update()); - // if (event.previousContainer === event.container) { - // for (const item of this.container.selectedItems) { - // moveItemInArray(event.container.data, event.previousIndex, event.currentIndex); - // } - // } else { - // for (const item of this.container.selectedItems) { - // transferArrayItem(event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex); - // } - // } - } -} diff --git a/src/app/dragndrop/task/task.component.html b/src/app/dragndrop/task/task.component.html deleted file mode 100644 index 423ac50..0000000 --- a/src/app/dragndrop/task/task.component.html +++ /dev/null @@ -1,6 +0,0 @@ - - {{ item }} - \ No newline at end of file diff --git a/src/app/dragndrop/task/task.component.scss b/src/app/dragndrop/task/task.component.scss deleted file mode 100644 index 3d2d13e..0000000 --- a/src/app/dragndrop/task/task.component.scss +++ /dev/null @@ -1,8 +0,0 @@ -:host { - height: min-content; -} -mat-card { - &.selected { - border: 1px solid blue; - } -} diff --git a/src/app/dragndrop/task/task.component.ts b/src/app/dragndrop/task/task.component.ts deleted file mode 100644 index b2279c9..0000000 --- a/src/app/dragndrop/task/task.component.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Component, Inject, Input, Optional, SkipSelf } from '@angular/core'; -import { SelectContainerComponent } from 'projects/ngx-drag-to-select/src/public_api'; -import { DTS_SELECT_CONTAINER } from 'projects/ngx-drag-to-select/src/lib/tokens'; - -@Component({ - selector: 'app-task', - styleUrls: ['./task.component.scss'], - templateUrl: './task.component.html', -}) -export class TaskComponent { - @Input() item = ''; - constructor(@Inject(DTS_SELECT_CONTAINER) @Optional() public container: SelectContainerComponent) {} - - select() { - this.container.clearSelection(); - this.container.selectItems((it) => it === this.item); - } -} From 464791cbb85ec3de046565d1523aed9e060b74e0 Mon Sep 17 00:00:00 2001 From: Brian Kimball Date: Tue, 10 Nov 2020 19:14:53 -0500 Subject: [PATCH 08/13] refactor(app): forgot to add new files --- .../drag-and-drop.component.html | 7 ++ .../drag-and-drop.component.scss | 20 ++++++ .../drag-and-drop/drag-and-drop.component.ts | 13 ++++ .../task-list/task-list.component.html | 19 +++++ .../task-list/task-list.component.scss | 69 +++++++++++++++++++ .../task-list/task-list.component.ts | 60 ++++++++++++++++ .../drag-and-drop/task/task.component.html | 6 ++ .../drag-and-drop/task/task.component.scss | 8 +++ src/app/drag-and-drop/task/task.component.ts | 18 +++++ 9 files changed, 220 insertions(+) create mode 100644 src/app/drag-and-drop/drag-and-drop.component.html create mode 100644 src/app/drag-and-drop/drag-and-drop.component.scss create mode 100644 src/app/drag-and-drop/drag-and-drop.component.ts create mode 100644 src/app/drag-and-drop/task-list/task-list.component.html create mode 100644 src/app/drag-and-drop/task-list/task-list.component.scss create mode 100644 src/app/drag-and-drop/task-list/task-list.component.ts create mode 100644 src/app/drag-and-drop/task/task.component.html create mode 100644 src/app/drag-and-drop/task/task.component.scss create mode 100644 src/app/drag-and-drop/task/task.component.ts diff --git a/src/app/drag-and-drop/drag-and-drop.component.html b/src/app/drag-and-drop/drag-and-drop.component.html new file mode 100644 index 0000000..5fde904 --- /dev/null +++ b/src/app/drag-and-drop/drag-and-drop.component.html @@ -0,0 +1,7 @@ + +
+ + + +
+
\ No newline at end of file diff --git a/src/app/drag-and-drop/drag-and-drop.component.scss b/src/app/drag-and-drop/drag-and-drop.component.scss new file mode 100644 index 0000000..4497a6f --- /dev/null +++ b/src/app/drag-and-drop/drag-and-drop.component.scss @@ -0,0 +1,20 @@ +.list-wrapper { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 1rem; + min-height: 400px; +} + +.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); +} diff --git a/src/app/drag-and-drop/drag-and-drop.component.ts b/src/app/drag-and-drop/drag-and-drop.component.ts new file mode 100644 index 0000000..9d81538 --- /dev/null +++ b/src/app/drag-and-drop/drag-and-drop.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-drag-and-drop', + templateUrl: './drag-and-drop.component.html', + styleUrls: ['./drag-and-drop.component.scss'], +}) +export class DragAndDropComponent { + todo = ['Next Task', 'Very Important Item', 'Open Ticket #1', 'Open Ticket #2', 'Not Important Task']; + doing = ['High Priority Task', 'In Progress Item']; + done = ['Completed Item']; + selectedItems: any[] = []; +} diff --git a/src/app/drag-and-drop/task-list/task-list.component.html b/src/app/drag-and-drop/task-list/task-list.component.html new file mode 100644 index 0000000..f432a2f --- /dev/null +++ b/src/app/drag-and-drop/task-list/task-list.component.html @@ -0,0 +1,19 @@ +

{{title}}

+ +
+ +
+ {{ selected }} +
+
+ {{ selected }} +
+
+
\ No newline at end of file diff --git a/src/app/drag-and-drop/task-list/task-list.component.scss b/src/app/drag-and-drop/task-list/task-list.component.scss new file mode 100644 index 0000000..23030ba --- /dev/null +++ b/src/app/drag-and-drop/task-list/task-list.component.scss @@ -0,0 +1,69 @@ +:host { + background-color: #ebecf0; + border-radius: 3px; + box-sizing: border-box; + display: flex; + flex-direction: column; + max-height: 100%; + position: relative; + white-space: normal; +} + +.list-header { + padding: 0.5rem; +} + +.list-cards { + margin: 0 4px; + padding: 0 4px; + display: grid; + grid-template-columns: 1fr; + grid-auto-rows: min-content; + gap: 0.4rem; + height: -webkit-fill-available; +} + +.list-cards.cdk-drop-list-dragging app-task:not(.cdk-drag-placeholder) { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} + +:host(.item-dragging) { + ::ng-deep { + mat-card.selected:not(.cdk-drag-placeholder) { + display: none; //opacity: 0.3; + } + } +} + +.drag-placeholder-container { + display: flex; + flex-flow: column; + gap: 0.5rem; + mat-card { + opacity: 0.5; + } +} + +.drag-preview-container { + gap: 0.5rem; + position: relative; + + mat-card { + position: absolute; + width: 200px; + top: -10px; + left: -25px; + } + mat-card:nth-child(2) { + left: -40px; + top: -10px; + transform: rotate(-1deg); + z-index: -1; + } + mat-card:nth-child(3) { + top: -5px; + left: -20px; + transform: rotate(1deg); + z-index: -2; + } +} diff --git a/src/app/drag-and-drop/task-list/task-list.component.ts b/src/app/drag-and-drop/task-list/task-list.component.ts new file mode 100644 index 0000000..7fcb27c --- /dev/null +++ b/src/app/drag-and-drop/task-list/task-list.component.ts @@ -0,0 +1,60 @@ +import { CdkDragStart, CdkDragDrop } from '@angular/cdk/drag-drop'; +import { Component, HostBinding, Inject, Input, Optional, SkipSelf } from '@angular/core'; +import { DTS_SELECT_CONTAINER } from 'projects/ngx-drag-to-select/src/lib/tokens'; +import { SelectContainerComponent } from 'projects/ngx-drag-to-select/src/public_api'; + +@Component({ + selector: 'app-task-list', + styleUrls: ['./task-list.component.scss'], + templateUrl: './task-list.component.html', +}) +export class TaskListComponent { + @Input() title = 'Tasks'; + @Input() tasks = []; + + @HostBinding('class.item-dragging') + dragging = false; + + constructor(@Inject(DTS_SELECT_CONTAINER) @Optional() public container: SelectContainerComponent) {} + + dragStarted(ev: CdkDragStart, index: number): void { + this.dragging = !!ev.source._dragRef; + this.container.selectItems((item) => { + return item === this.tasks[index]; + }); + } + + dragEnded(): void { + this.dragging = null; + } + + dropped(event: CdkDragDrop): void { + this.dragging = null; + const indices = this.container.selectedItems.map((it) => event.previousContainer.data.findIndex((i) => it === i)); + indices.sort().reverse(); + indices.forEach((idx) => { + this.tasks.splice(idx, 1); + }); + + setTimeout(() => this.container.clearSelection()); + } + + drop(event: CdkDragDrop) { + const indices = this.container.selectedItems.map((it) => event.previousContainer.data.findIndex((i) => it === i)); + console.log('Selected', indices); + + const spliceIntoIndex = event.currentIndex; + this.tasks.splice(spliceIntoIndex, 0, ...this.container.selectedItems); + + /** + * Caution! + * When drop event is within the same drop-list the bounding box of + * drag events might not update to there new positions. Use the + * `update` method from the `SelectContainerComponent` to force the + * bounding boxes to be recalculated. + * This is put behind `setTimeout` because we have to wait until the next + * frame before angular change detection has updated the dom. + * */ + setTimeout(() => this.container.update()); + } +} diff --git a/src/app/drag-and-drop/task/task.component.html b/src/app/drag-and-drop/task/task.component.html new file mode 100644 index 0000000..423ac50 --- /dev/null +++ b/src/app/drag-and-drop/task/task.component.html @@ -0,0 +1,6 @@ + + {{ item }} + \ No newline at end of file diff --git a/src/app/drag-and-drop/task/task.component.scss b/src/app/drag-and-drop/task/task.component.scss new file mode 100644 index 0000000..3d2d13e --- /dev/null +++ b/src/app/drag-and-drop/task/task.component.scss @@ -0,0 +1,8 @@ +:host { + height: min-content; +} +mat-card { + &.selected { + border: 1px solid blue; + } +} diff --git a/src/app/drag-and-drop/task/task.component.ts b/src/app/drag-and-drop/task/task.component.ts new file mode 100644 index 0000000..b2279c9 --- /dev/null +++ b/src/app/drag-and-drop/task/task.component.ts @@ -0,0 +1,18 @@ +import { Component, Inject, Input, Optional, SkipSelf } from '@angular/core'; +import { SelectContainerComponent } from 'projects/ngx-drag-to-select/src/public_api'; +import { DTS_SELECT_CONTAINER } from 'projects/ngx-drag-to-select/src/lib/tokens'; + +@Component({ + selector: 'app-task', + styleUrls: ['./task.component.scss'], + templateUrl: './task.component.html', +}) +export class TaskComponent { + @Input() item = ''; + constructor(@Inject(DTS_SELECT_CONTAINER) @Optional() public container: SelectContainerComponent) {} + + select() { + this.container.clearSelection(); + this.container.selectItems((it) => it === this.item); + } +} From 9b13e1ade242d869bd316db9a7202cb7087cfd97 Mon Sep 17 00:00:00 2001 From: Brian Kimball Date: Wed, 11 Nov 2020 08:57:42 -0500 Subject: [PATCH 09/13] style: updated cypress comments style: update whitespace --- README.md | 1 + cypress/integration/drag-and-drop.spec.ts | 19 ++++--------------- .../src/lib/select-container.component.ts | 1 + 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 4ecf343..09b074d 100644 --- a/README.md +++ b/README.md @@ -567,6 +567,7 @@ export class TaskListComponent { @Inject(DTS_SELECT_CONTAINER) @Optional() public container: SelectContainerComponent ) {} +} ``` You can find an example of this in the [drag and drop example](https://github.com/d3lm/ngx-drag-to-select/blob/master/src/app/dragndrop). diff --git a/cypress/integration/drag-and-drop.spec.ts b/cypress/integration/drag-and-drop.spec.ts index ea90f16..c0ffcd7 100644 --- a/cypress/integration/drag-and-drop.spec.ts +++ b/cypress/integration/drag-and-drop.spec.ts @@ -1,17 +1,6 @@ import { DEFAULT_CONFIG } from '../../projects/ngx-drag-to-select/src/lib/config'; -import { - disableSelection, - disableSelectOnDrag, - enableSelectMode, - getDesktopExample, - getDoingList, - getDragAndDropExample, - getTodoList, - shouldBeInvisible, - shouldBeVisible, - toggleItem, -} from '../support/utils'; +import { getDoingList, getDragAndDropExample, getTodoList } from '../support/utils'; const SELECTED_CLASS = DEFAULT_CONFIG.selectedClass; @@ -36,15 +25,15 @@ describe('Drag And Drop', () => { it('should drag to new list', () => { getDragAndDropExample().within(() => { getTodoList() - // Select First 3 items in list + // select first 3 items in list .dispatch('mousedown', 'topLeft', { button: 0 }) .getSelectItem(2) .dispatch('mousemove') .dispatch('mouseup') - // Click on second item + // click on second item .getSelectItem(1) .dispatch('mousedown', { button: 0 }) - // Drag to Select Item in other list + // drag to SelectItem in other list .getSelectItem(5) .wait(16) .dispatch('mousemove') diff --git a/projects/ngx-drag-to-select/src/lib/select-container.component.ts b/projects/ngx-drag-to-select/src/lib/select-container.component.ts index 177e321..c79e675 100644 --- a/projects/ngx-drag-to-select/src/lib/select-container.component.ts +++ b/projects/ngx-drag-to-select/src/lib/select-container.component.ts @@ -288,6 +288,7 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, Selec this._registry.add(item); this.updateSelectableItems(); } + unregister(item: SelectItemDirective) { this._registry.delete(item); this.updateSelectableItems(); From e98d0b844986f38789d380359ed6a84c59f87ab6 Mon Sep 17 00:00:00 2001 From: Brian Kimball Date: Thu, 12 Nov 2020 10:47:03 -0500 Subject: [PATCH 10/13] refactor(app): moved drag-and-drop above mobile and hides style(app): linting some scss --- src/app/app.component.html | 21 ++++++++++--------- src/app/app.module.ts | 1 - .../task-list/task-list.component.scss | 3 +++ .../drag-and-drop/task/task.component.scss | 5 ++++- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/app/app.component.html b/src/app/app.component.html index 04eb728..9e770ba 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -66,24 +66,25 @@

Meta Information

-
+

- Mobile Demo SOURCE + Drag & Drop Demo + SOURCE

-
- -
+ +
-
+

- Drag & Drop Demo SOURCE + Mobile Demo + SOURCE

- - +
+ +
\ No newline at end of file diff --git a/src/app/app.module.ts b/src/app/app.module.ts index e0b8e68..2f00890 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -10,7 +10,6 @@ import { MatTabsModule } from '@angular/material/tabs'; import { MatIconModule } from '@angular/material/icon'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; - import { DragDropModule } from '@angular/cdk/drag-drop'; import { BrowserModule } from '@angular/platform-browser'; diff --git a/src/app/drag-and-drop/task-list/task-list.component.scss b/src/app/drag-and-drop/task-list/task-list.component.scss index 23030ba..d1210eb 100644 --- a/src/app/drag-and-drop/task-list/task-list.component.scss +++ b/src/app/drag-and-drop/task-list/task-list.component.scss @@ -39,6 +39,7 @@ display: flex; flex-flow: column; gap: 0.5rem; + mat-card { opacity: 0.5; } @@ -54,12 +55,14 @@ top: -10px; left: -25px; } + mat-card:nth-child(2) { left: -40px; top: -10px; transform: rotate(-1deg); z-index: -1; } + mat-card:nth-child(3) { top: -5px; left: -20px; diff --git a/src/app/drag-and-drop/task/task.component.scss b/src/app/drag-and-drop/task/task.component.scss index 3d2d13e..8346b9d 100644 --- a/src/app/drag-and-drop/task/task.component.scss +++ b/src/app/drag-and-drop/task/task.component.scss @@ -1,8 +1,11 @@ :host { height: min-content; } + mat-card { + border: 1px solid transparent; + &.selected { - border: 1px solid blue; + border: 1px solid #2196f3; } } From 563617081a612406d286658bcc42aa60ac0a01a2 Mon Sep 17 00:00:00 2001 From: Brian Kimball Date: Thu, 12 Nov 2020 11:51:19 -0500 Subject: [PATCH 11/13] fix(app): fixed cypress test, error with test --- cypress/integration/drag-and-drop.spec.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cypress/integration/drag-and-drop.spec.ts b/cypress/integration/drag-and-drop.spec.ts index c0ffcd7..8567e5d 100644 --- a/cypress/integration/drag-and-drop.spec.ts +++ b/cypress/integration/drag-and-drop.spec.ts @@ -49,14 +49,13 @@ describe('Drag And Drop', () => { it('should reorder within list', () => { getDragAndDropExample().within(() => { getTodoList() - .dispatch('mousedown', 'bottomRight', { button: 0 }) - .getSelectItem(2) + .dispatch('mousedown', 'topRight', { button: 0 }) + .getSelectItem(1) .dispatch('mousemove') .dispatch('mouseup') - .getSelectItem(3) - .dispatch('mousedown', { button: 0 }) .getSelectItem(0) - .wait(16) + .dispatch('mousedown', 'bottom', { button: 0 }) + .getSelectItem(4) .dispatch('mousemove') .dispatch('mousemove') .dispatch('mouseup'); From 4de8b47b57889aa2418fbb5542fc965c498b5d69 Mon Sep 17 00:00:00 2001 From: Brian Kimball Date: Fri, 13 Nov 2020 21:47:14 -0500 Subject: [PATCH 12/13] fix(app): visual issues with hidden placeholders --- .../task-list/task-list.component.html | 3 +- .../task-list/task-list.component.scss | 8 ++--- .../task-list/task-list.component.ts | 31 ++++++++++++++++--- .../drag-and-drop/task/task.component.html | 1 - .../drag-and-drop/task/task.component.scss | 11 ++++--- 5 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/app/drag-and-drop/task-list/task-list.component.html b/src/app/drag-and-drop/task-list/task-list.component.html index f432a2f..6a726fe 100644 --- a/src/app/drag-and-drop/task-list/task-list.component.html +++ b/src/app/drag-and-drop/task-list/task-list.component.html @@ -8,7 +8,8 @@

{{title}}

+ (cdkDragDropped)="dropped($event)" + [dtsSelectItem]="item">
{{ selected }}
diff --git a/src/app/drag-and-drop/task-list/task-list.component.scss b/src/app/drag-and-drop/task-list/task-list.component.scss index d1210eb..4691402 100644 --- a/src/app/drag-and-drop/task-list/task-list.component.scss +++ b/src/app/drag-and-drop/task-list/task-list.component.scss @@ -28,10 +28,8 @@ } :host(.item-dragging) { - ::ng-deep { - mat-card.selected:not(.cdk-drag-placeholder) { - display: none; //opacity: 0.3; - } + app-task.selected:not(.cdk-drag-placeholder) { + display: none; } } @@ -39,6 +37,8 @@ display: flex; flex-flow: column; gap: 0.5rem; + min-height: 53px; + height: min-content; mat-card { opacity: 0.5; diff --git a/src/app/drag-and-drop/task-list/task-list.component.ts b/src/app/drag-and-drop/task-list/task-list.component.ts index 7fcb27c..f3eadda 100644 --- a/src/app/drag-and-drop/task-list/task-list.component.ts +++ b/src/app/drag-and-drop/task-list/task-list.component.ts @@ -1,5 +1,5 @@ import { CdkDragStart, CdkDragDrop } from '@angular/cdk/drag-drop'; -import { Component, HostBinding, Inject, Input, Optional, SkipSelf } from '@angular/core'; +import { Component, ElementRef, HostBinding, Inject, Input, Optional, SkipSelf } from '@angular/core'; import { DTS_SELECT_CONTAINER } from 'projects/ngx-drag-to-select/src/lib/tokens'; import { SelectContainerComponent } from 'projects/ngx-drag-to-select/src/public_api'; @@ -15,16 +15,40 @@ export class TaskListComponent { @HostBinding('class.item-dragging') dragging = false; - constructor(@Inject(DTS_SELECT_CONTAINER) @Optional() public container: SelectContainerComponent) {} + // CdkDragModule only supports dragging a single dom element + private selectDomRefs: { parent: Node; node: Node }[] = []; + + constructor( + @Inject(DTS_SELECT_CONTAINER) @Optional() public container: SelectContainerComponent, + private element: ElementRef + ) {} dragStarted(ev: CdkDragStart, index: number): void { this.dragging = !!ev.source._dragRef; this.container.selectItems((item) => { return item === this.tasks[index]; }); + + /** + * We remove the selected elements from the DOM, because the + * CdkDragDropModule includes them when reordering even if they. + * are hidden. + **/ + this.selectDomRefs = []; + this.element.nativeElement.querySelectorAll('.selected').forEach((node: Node) => { + this.selectDomRefs.push({ parent: node.parentNode, node }); + node.parentNode.removeChild(node); + }); } dragEnded(): void { + /** + * Add the DOM elements back in because the Angular refs are still + * bound to them. + **/ + this.selectDomRefs.forEach(({ parent, node }) => { + parent.appendChild(node); + }); this.dragging = null; } @@ -40,9 +64,6 @@ export class TaskListComponent { } drop(event: CdkDragDrop) { - const indices = this.container.selectedItems.map((it) => event.previousContainer.data.findIndex((i) => it === i)); - console.log('Selected', indices); - const spliceIntoIndex = event.currentIndex; this.tasks.splice(spliceIntoIndex, 0, ...this.container.selectedItems); diff --git a/src/app/drag-and-drop/task/task.component.html b/src/app/drag-and-drop/task/task.component.html index 423ac50..1a52761 100644 --- a/src/app/drag-and-drop/task/task.component.html +++ b/src/app/drag-and-drop/task/task.component.html @@ -1,6 +1,5 @@ {{ item }} \ No newline at end of file diff --git a/src/app/drag-and-drop/task/task.component.scss b/src/app/drag-and-drop/task/task.component.scss index 8346b9d..4f9f40a 100644 --- a/src/app/drag-and-drop/task/task.component.scss +++ b/src/app/drag-and-drop/task/task.component.scss @@ -1,11 +1,12 @@ :host { - height: min-content; + display: block; + &.selected { + mat-card { + border: 1px solid #2196f3; + } + } } mat-card { border: 1px solid transparent; - - &.selected { - border: 1px solid #2196f3; - } } From 61fda2c69f1c7055066928c356aaf4c026b06bd1 Mon Sep 17 00:00:00 2001 From: Brian Kimball Date: Sun, 15 Nov 2020 21:27:52 -0500 Subject: [PATCH 13/13] style(app): trying to force tests to re-run --- src/app/drag-and-drop/task/task.component.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/drag-and-drop/task/task.component.scss b/src/app/drag-and-drop/task/task.component.scss index 4f9f40a..2b3cb9e 100644 --- a/src/app/drag-and-drop/task/task.component.scss +++ b/src/app/drag-and-drop/task/task.component.scss @@ -1,5 +1,6 @@ :host { display: block; + &.selected { mat-card { border: 1px solid #2196f3;