Skip to content

Commit

Permalink
refactor(cdk/drag-drop): simplify sort strategy interface
Browse files Browse the repository at this point in the history
Simplifies the interface for sort strategies to avoid the unnecessary generics that were put in place to avoid circular imports.
  • Loading branch information
crisbeto committed Jun 8, 2024
1 parent fffb92d commit 65348eb
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 51 deletions.
14 changes: 10 additions & 4 deletions src/cdk/drag-drop/drop-list-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export class DropListRef<T = any> {
private _parentPositions: ParentPositionTracker;

/** Strategy being used to sort items within the list. */
private _sortStrategy: DropListSortStrategy<DragRef>;
private _sortStrategy: DropListSortStrategy;

/** Cached `DOMRect` of the drop list. */
private _domRect: DOMRect | undefined;
Expand Down Expand Up @@ -187,6 +187,9 @@ export class DropListRef<T = any> {
/** Initial value for the element's `scroll-snap-type` style. */
private _initialScrollSnap: string;

/** Direction of the list's layout. */
private _direction: Direction = 'ltr';

constructor(
element: ElementRef<HTMLElement> | HTMLElement,
private _dragDropRegistry: DragDropRegistry<DragRef, DropListRef>,
Expand Down Expand Up @@ -332,7 +335,10 @@ export class DropListRef<T = any> {

/** Sets the layout direction of the drop list. */
withDirection(direction: Direction): this {
this._sortStrategy.direction = direction;
this._direction = direction;
if (this._sortStrategy instanceof SingleAxisSortStrategy) {
this._sortStrategy.direction = direction;
}
return this;
}

Expand All @@ -353,7 +359,7 @@ export class DropListRef<T = any> {
withOrientation(orientation: 'vertical' | 'horizontal'): this {
// TODO(crisbeto): eventually we should be constructing the new sort strategy here based on
// the new orientation. For now we can assume that it'll always be `SingleAxisSortStrategy`.
(this._sortStrategy as SingleAxisSortStrategy<DragRef>).orientation = orientation;
(this._sortStrategy as SingleAxisSortStrategy).orientation = orientation;
return this;
}

Expand Down Expand Up @@ -455,7 +461,7 @@ export class DropListRef<T = any> {
[verticalScrollDirection, horizontalScrollDirection] = getElementScrollDirections(
element as HTMLElement,
position.clientRect,
this._sortStrategy.direction,
this._direction,
pointerX,
pointerY,
);
Expand Down
33 changes: 9 additions & 24 deletions src/cdk/drag-drop/sorting/drop-list-sort-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,31 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Direction} from '@angular/cdk/bidi';
import type {DragRef} from '../drag-ref';

/**
* Function that is used to determine whether an item can be sorted into a particular index.
* @docs-private
*/
export type SortPredicate<T> = (index: number, item: T) => boolean;

/**
* Item that can be sorted within `DropListSortStrategy`. This is a limited representation of
* `DragRef` used to avoid circular dependencies. It is intended to only be used within
* `DropListSortStrategy`.
* @docs-private
*/
export interface DropListSortStrategyItem {
isDragging(): boolean;
getPlaceholderElement(): HTMLElement;
getRootElement(): HTMLElement;
_sortFromLastPointerPosition(): void;
getVisibleElement(): HTMLElement;
}

/**
* Strategy used to sort and position items within a drop list.
* @docs-private
*/
export interface DropListSortStrategy<T extends DropListSortStrategyItem> {
direction: Direction;
start(items: readonly T[]): void;
export interface DropListSortStrategy {
start(items: readonly DragRef[]): void;
sort(
item: T,
item: DragRef,
pointerX: number,
pointerY: number,
pointerDelta: {x: number; y: number},
): {previousIndex: number; currentIndex: number} | null;
enter(item: T, pointerX: number, pointerY: number, index?: number): void;
withItems(items: readonly T[]): void;
withSortPredicate(predicate: SortPredicate<T>): void;
enter(item: DragRef, pointerX: number, pointerY: number, index?: number): void;
withItems(items: readonly DragRef[]): void;
withSortPredicate(predicate: SortPredicate<DragRef>): void;
reset(): void;
getActiveItemsSnapshot(): readonly T[];
getItemIndex(item: T): number;
getActiveItemsSnapshot(): readonly DragRef[];
getItemIndex(item: DragRef): number;
updateOnScroll(topDifference: number, leftDifference: number): void;
}
41 changes: 18 additions & 23 deletions src/cdk/drag-drop/sorting/single-axis-sort-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,8 @@ import {DragDropRegistry} from '../drag-drop-registry';
import {moveItemInArray} from '../drag-utils';
import {combineTransforms} from '../dom/styling';
import {adjustDomRect, getMutableClientRect, isInsideClientRect} from '../dom/dom-rect';
import {
DropListSortStrategy,
DropListSortStrategyItem,
SortPredicate,
} from './drop-list-sort-strategy';
import {DropListSortStrategy, SortPredicate} from './drop-list-sort-strategy';
import type {DragRef} from '../drag-ref';

/**
* Entry in the position cache for draggable items.
Expand All @@ -39,21 +36,19 @@ interface CachedItemPosition<T> {
* Items are reordered using CSS transforms which allows for sorting to be animated.
* @docs-private
*/
export class SingleAxisSortStrategy<T extends DropListSortStrategyItem>
implements DropListSortStrategy<T>
{
export class SingleAxisSortStrategy implements DropListSortStrategy {
/** Function used to determine if an item can be sorted into a specific index. */
private _sortPredicate: SortPredicate<T>;
private _sortPredicate: SortPredicate<DragRef>;

/** Cache of the dimensions of all the items inside the container. */
private _itemPositions: CachedItemPosition<T>[] = [];
private _itemPositions: CachedItemPosition<DragRef>[] = [];

/**
* Draggable items that are currently active inside the container. Includes the items
* that were there at the start of the sequence, as well as any items that have been dragged
* in, but haven't been dropped yet.
*/
private _activeDraggables: T[];
private _activeDraggables: DragRef[];

/** Direction in which the list is oriented. */
orientation: 'vertical' | 'horizontal' = 'vertical';
Expand All @@ -63,7 +58,7 @@ export class SingleAxisSortStrategy<T extends DropListSortStrategyItem>

constructor(
private _element: HTMLElement | ElementRef<HTMLElement>,
private _dragDropRegistry: DragDropRegistry<T, unknown>,
private _dragDropRegistry: DragDropRegistry<DragRef, unknown>,
) {}

/**
Expand All @@ -72,7 +67,7 @@ export class SingleAxisSortStrategy<T extends DropListSortStrategyItem>
* overlap with the swapped item after the swapping occurred.
*/
private _previousSwap = {
drag: null as T | null,
drag: null as DragRef | null,
delta: 0,
overlaps: false,
};
Expand All @@ -81,7 +76,7 @@ export class SingleAxisSortStrategy<T extends DropListSortStrategyItem>
* To be called when the drag sequence starts.
* @param items Items that are currently in the list.
*/
start(items: readonly T[]) {
start(items: readonly DragRef[]) {
this.withItems(items);
}

Expand All @@ -92,7 +87,7 @@ export class SingleAxisSortStrategy<T extends DropListSortStrategyItem>
* @param pointerY Position of the item along the Y axis.
* @param pointerDelta Direction in which the pointer is moving along each axis.
*/
sort(item: T, pointerX: number, pointerY: number, pointerDelta: {x: number; y: number}) {
sort(item: DragRef, pointerX: number, pointerY: number, pointerDelta: {x: number; y: number}) {
const siblings = this._itemPositions;
const newIndex = this._getItemIndexFromPointerPosition(item, pointerX, pointerY, pointerDelta);

Expand Down Expand Up @@ -172,7 +167,7 @@ export class SingleAxisSortStrategy<T extends DropListSortStrategyItem>
* @param index Index at which the item entered. If omitted, the container will try to figure it
* out automatically.
*/
enter(item: T, pointerX: number, pointerY: number, index?: number): void {
enter(item: DragRef, pointerX: number, pointerY: number, index?: number): void {
const newIndex =
index == null || index < 0
? // We use the coordinates of where the item entered the drop
Expand All @@ -183,7 +178,7 @@ export class SingleAxisSortStrategy<T extends DropListSortStrategyItem>
const activeDraggables = this._activeDraggables;
const currentIndex = activeDraggables.indexOf(item);
const placeholder = item.getPlaceholderElement();
let newPositionReference: T | undefined = activeDraggables[newIndex];
let newPositionReference: DragRef | undefined = activeDraggables[newIndex];

// If the item at the new position is the same as the item that is being dragged,
// it means that we're trying to restore the item to its initial position. In this
Expand Down Expand Up @@ -229,13 +224,13 @@ export class SingleAxisSortStrategy<T extends DropListSortStrategyItem>
}

/** Sets the items that are currently part of the list. */
withItems(items: readonly T[]): void {
withItems(items: readonly DragRef[]): void {
this._activeDraggables = items.slice();
this._cacheItemPositions();
}

/** Assigns a sort predicate to the strategy. */
withSortPredicate(predicate: SortPredicate<T>): void {
withSortPredicate(predicate: SortPredicate<DragRef>): void {
this._sortPredicate = predicate;
}

Expand All @@ -262,12 +257,12 @@ export class SingleAxisSortStrategy<T extends DropListSortStrategyItem>
* Gets a snapshot of items currently in the list.
* Can include items that we dragged in from another list.
*/
getActiveItemsSnapshot(): readonly T[] {
getActiveItemsSnapshot(): readonly DragRef[] {
return this._activeDraggables;
}

/** Gets the index of a specific item. */
getItemIndex(item: T): number {
getItemIndex(item: DragRef): number {
// Items are sorted always by top/left in the cache, however they flow differently in RTL.
// The rest of the logic still stands no matter what orientation we're in, however
// we need to invert the array when determining the index.
Expand Down Expand Up @@ -351,7 +346,7 @@ export class SingleAxisSortStrategy<T extends DropListSortStrategyItem>
*/
private _getSiblingOffsetPx(
currentIndex: number,
siblings: CachedItemPosition<T>[],
siblings: CachedItemPosition<DragRef>[],
delta: 1 | -1,
) {
const isHorizontal = this.orientation === 'horizontal';
Expand Down Expand Up @@ -410,7 +405,7 @@ export class SingleAxisSortStrategy<T extends DropListSortStrategyItem>
* @param delta Direction in which the user is moving their pointer.
*/
private _getItemIndexFromPointerPosition(
item: T,
item: DragRef,
pointerX: number,
pointerY: number,
delta?: {x: number; y: number},
Expand Down

0 comments on commit 65348eb

Please sign in to comment.