From ed7451aeb7c1a138ad8b42c16ddf6c651198d720 Mon Sep 17 00:00:00 2001 From: Philip Odermatt Date: Tue, 29 Nov 2022 23:57:03 +0100 Subject: [PATCH] feat(lib): add input for intersection mode This commit adds a new `@Input()` property `intersectionMode` to the `SelectContainerComponent` that allows to modify if items' bounding boxes need to be fully included in the select box or (by default) if bounding boxes need to intersect. --- cypress/integration/dragging.spec.ts | 22 +++++++++++++++++++ cypress/support/utils.ts | 9 ++++++++ .../src/lib/select-container.component.ts | 15 +++++++++++-- projects/ngx-drag-to-select/src/lib/utils.ts | 9 ++++++++ src/app/app.component.html | 16 +++++++++++--- src/app/app.component.ts | 1 + src/app/app.module.ts | 2 ++ 7 files changed, 69 insertions(+), 5 deletions(-) diff --git a/cypress/integration/dragging.spec.ts b/cypress/integration/dragging.spec.ts index 7a1e220..81f59e0 100644 --- a/cypress/integration/dragging.spec.ts +++ b/cypress/integration/dragging.spec.ts @@ -5,6 +5,7 @@ import { disableSelectOnDrag, enableSelectMode, getDesktopExample, + setDragIntersectionMode, shouldBeInvisible, shouldBeVisible, toggleItem, @@ -460,4 +461,25 @@ describe('Dragging', () => { }); }); }); + + describe('intersection mode "included"', () => { + beforeEach(() => { + setDragIntersectionMode('included'); + }); + + it('should only select items that have their bounding box fully included in the select box', () => { + getDesktopExample().within(() => { + cy.getSelectItem(0) + .dispatch('mousedown', { button: 0 }) + .getSelectItem(11) + .dispatch('mousemove') + .as('end') + .getSelectBox() + .then(shouldBeVisible) + .shouldSelect([6, 7]) + .get('@end') + .dispatch('mouseup'); + }); + }); + }); }); diff --git a/cypress/support/utils.ts b/cypress/support/utils.ts index e046644..d25da94 100644 --- a/cypress/support/utils.ts +++ b/cypress/support/utils.ts @@ -76,6 +76,15 @@ export const enableSelectWithShortcut = () => { return cy.get('[data-cy="selectWithShortcut"]').click(); }; +export const setDragIntersectionMode = (mode: 'intersection' | 'included') => { + return cy + .get('[data-cy="intersectionMode"]') + .click() + .then(() => { + cy.get(`.cdk-overlay-container .mat-select-panel-wrap .mat-option-text:contains("${mode}")`).click(); + }); +}; + export const selectAll = () => { return getSelectAllButton().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 9b4c764..14631d4 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 @@ -65,6 +65,7 @@ import { getRelativeMousePosition, getMousePosition, hasMinimumSize, + boxIncluded, } from './utils'; import { KeyboardEventsService } from './keyboard-events.service'; @@ -102,6 +103,10 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After @Input() disableRangeSelection = false; @Input() selectMode = false; @Input() selectWithShortcut = false; + /** + * Configure if an items' bounding box needs to intersect or to be fully included in the select box. + */ + @Input() intersectionMode: 'intersection' | 'included' = 'intersection'; @Input() @HostBinding('class.dts-custom') @@ -538,7 +543,10 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After } private _normalSelectionMode(selectBox: BoundingBox, item: SelectItemDirective, event: Event) { - const inSelection = boxIntersects(selectBox, item.getBoundingClientRect()); + const inSelection = + this.intersectionMode === 'intersection' + ? boxIntersects(selectBox, item.getBoundingClientRect()) + : boxIncluded(selectBox, item.getBoundingClientRect()); const shouldAdd = inSelection && !item.selected && !this.shortcuts.removeFromSelection(event); @@ -554,7 +562,10 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After } private _extendedSelectionMode(selectBox, item: SelectItemDirective, event: Event) { - const inSelection = boxIntersects(selectBox, item.getBoundingClientRect()); + const inSelection = + this.intersectionMode === 'intersection' + ? boxIntersects(selectBox, item.getBoundingClientRect()) + : boxIncluded(selectBox, item.getBoundingClientRect()); const shoudlAdd = (inSelection && !item.selected && !this.shortcuts.removeFromSelection(event) && !this._tmpItems.has(item)) || diff --git a/projects/ngx-drag-to-select/src/lib/utils.ts b/projects/ngx-drag-to-select/src/lib/utils.ts index dcb5470..0307526 100644 --- a/projects/ngx-drag-to-select/src/lib/utils.ts +++ b/projects/ngx-drag-to-select/src/lib/utils.ts @@ -55,6 +55,15 @@ export const boxIntersects = (boxA: BoundingBox, boxB: BoundingBox) => { ); }; +export const boxIncluded = (boxA: BoundingBox, boxB: BoundingBox) => { + return ( + boxA.left <= boxB.left && + boxA.left + boxA.width >= boxB.left + boxB.width && + boxA.top <= boxB.top && + boxA.top + boxA.height >= boxB.top + boxB.height + ); +}; + export const calculateBoundingClientRect = (element: HTMLElement): BoundingBox => { return element.getBoundingClientRect(); }; diff --git a/src/app/app.component.html b/src/app/app.component.html index 8929b47..81ed236 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -30,6 +30,14 @@

Select Mode Select with Shortcut + + Intersection Mode + + intersection + included + + +