[ACS-10259] Add an option to reorder rows with keyboard (#11548)

* [ACS-10259] Datatable add drag&drop keyboard integration

* [ACS-10259] Add option to reorder rows via keyboard

* [ACS-10259] Add proper focus handling
This commit is contained in:
Michal Kinas
2026-01-22 12:02:45 +01:00
committed by GitHub
parent 096ead8648
commit 5cdcd97201
3 changed files with 87 additions and 1 deletions
@@ -464,6 +464,8 @@ Learn more about styling your datatable: [Customizing the component's styles](#c
## Details ## Details
This component supports rows reordering via keyboard. To enable it first set `enableDragRows` to `true`, focus any selected row and use shift + ArrowUp/ArrowDown combination to reorder selected row.
### Supplying data for the table ### Supplying data for the table
The column layout and row data are supplied to the table using an object that implements the The column layout and row data are supplied to the table using an object that implements the
@@ -1824,6 +1824,62 @@ describe('Accessibility', () => {
expect(focusTrap.destroy).toHaveBeenCalled(); expect(focusTrap.destroy).toHaveBeenCalled();
expect(dataTable.focusTrap).toBeNull(); expect(dataTable.focusTrap).toBeNull();
}); });
it('should support drag&drop with shift + arrow keys', () => {
dataTable.showHeader = ShowHeaderMode.Never;
dataTable.enableDragRows = true;
const dataRows = [{ name: 'test1' }, { name: 'test2' }, { name: 'test3' }, { name: 'test4' }];
dataTable.data = new ObjectDataTableAdapter([], [new ObjectDataColumn({ key: 'name' })]);
const keyDownEvent = new KeyboardEvent('keyup', {
code: 'ArrowDown',
key: 'ArrowDown',
keyCode: 40
} as KeyboardEventInit);
dataTable.ngOnChanges({
rows: new SimpleChange(null, dataRows, false)
});
fixture.detectChanges();
dataTable.ngAfterViewInit();
const rowElement = testingUtils.getAllByCSS('.adf-datatable-body .adf-datatable-row')[0];
testingUtils.setDebugElement(rowElement);
testingUtils.clickByCSS('.adf-datatable-cell');
fixture.debugElement.nativeElement.dispatchEvent(keyDownEvent);
fixture.detectChanges();
spyOn(dataTable.dragDropped, 'emit').and.callThrough();
const shiftDownEvent = new KeyboardEvent('keyup', {
code: 'ArrowDown',
key: 'ArrowDown',
shiftKey: true,
keyCode: 40
} as KeyboardEventInit);
fixture.debugElement.nativeElement.dispatchEvent(shiftDownEvent);
fixture.detectChanges();
expect(dataTable.dragDropped.emit).toHaveBeenCalledWith({ previousIndex: -1, currentIndex: 0 });
testingUtils.clickByCSS('.adf-datatable-cell');
fixture.debugElement.nativeElement.dispatchEvent(keyDownEvent);
fixture.debugElement.nativeElement.dispatchEvent(keyDownEvent);
fixture.detectChanges();
const shiftUpEvent = new KeyboardEvent('keyup', {
code: 'ArrowUp',
key: 'ArrowUp',
shiftKey: true,
keyCode: 38
} as KeyboardEventInit);
fixture.debugElement.nativeElement.dispatchEvent(shiftUpEvent);
fixture.detectChanges();
expect(dataTable.dragDropped.emit).toHaveBeenCalledWith({ previousIndex: 1, currentIndex: 0 });
});
}); });
describe('Drag&Drop column header', () => { describe('Drag&Drop column header', () => {
@@ -342,7 +342,35 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
@HostListener('keyup', ['$event']) @HostListener('keyup', ['$event'])
onKeydown(event: KeyboardEvent): void { onKeydown(event: KeyboardEvent): void {
this.keyManager.onKeydown(event); if (event.shiftKey && this.enableDragRows) {
switch (event.key) {
case 'ArrowUp': {
if (this.keyManager.activeItemIndex > 1) {
this.dragDropped.emit({
previousIndex: this.keyManager.activeItemIndex - 1,
currentIndex: this.keyManager.activeItemIndex - 2
});
setTimeout(() => {
this.keyManager.setActiveItem(this.keyManager.activeItemIndex - 1);
});
}
break;
}
case 'ArrowDown': {
if (this.keyManager.activeItemIndex < this.rowsList.length - 1) {
this.dragDropped.emit({ previousIndex: this.keyManager.activeItemIndex - 1, currentIndex: this.keyManager.activeItemIndex });
setTimeout(() => {
this.keyManager.setActiveItem(this.keyManager.activeItemIndex + 1);
});
}
break;
}
default:
break;
}
} else {
this.keyManager.onKeydown(event);
}
} }
constructor( constructor(