ngx-virtual-dnd 3.1.2 → 3.2.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -32
- package/fesm2022/ngx-virtual-dnd.mjs +826 -161
- package/fesm2022/ngx-virtual-dnd.mjs.map +1 -1
- package/package.json +4 -4
- package/types/ngx-virtual-dnd.d.ts +114 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ngx-virtual-dnd",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0-alpha.0",
|
|
4
4
|
"description": "A performant drag-and-drop library for Angular that works seamlessly with virtual scrolling",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
|
22
|
-
"url": "git+https://github.com/gultyayev/
|
|
22
|
+
"url": "git+https://github.com/gultyayev/ngx-virtual-dnd.git"
|
|
23
23
|
},
|
|
24
|
-
"homepage": "https://github.com/gultyayev/
|
|
24
|
+
"homepage": "https://github.com/gultyayev/ngx-virtual-dnd#readme",
|
|
25
25
|
"bugs": {
|
|
26
|
-
"url": "https://github.com/gultyayev/
|
|
26
|
+
"url": "https://github.com/gultyayev/ngx-virtual-dnd/issues"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
29
|
"@angular/common": "^21.0.0 || ^22.0.0",
|
|
@@ -59,7 +59,7 @@ interface DragState {
|
|
|
59
59
|
grabOffset: GrabOffset | null;
|
|
60
60
|
/** Position when drag started (for axis locking) */
|
|
61
61
|
initialPosition: CursorPosition | null;
|
|
62
|
-
/** Axis to
|
|
62
|
+
/** Axis to freeze ('x' = X frozen → vertical-only, 'y' = Y frozen → horizontal-only) */
|
|
63
63
|
lockAxis: 'x' | 'y' | null;
|
|
64
64
|
/** Whether this is a keyboard-initiated drag */
|
|
65
65
|
isKeyboardDrag: boolean;
|
|
@@ -116,6 +116,31 @@ interface DropEvent {
|
|
|
116
116
|
/** Information about where the item is going */
|
|
117
117
|
destination: DropDestination;
|
|
118
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Event emitted by a droppable each time the placeholder moves within it during a drag,
|
|
121
|
+
* i.e. whenever items are displaced. Useful for haptic feedback on every step.
|
|
122
|
+
*
|
|
123
|
+
* Indexes use the same convention as `DropEvent.destination.index` (the insertion index
|
|
124
|
+
* the item would get if dropped now). Not emitted for the placeholder's initial position
|
|
125
|
+
* at drag start, nor when the placeholder leaves this droppable.
|
|
126
|
+
*/
|
|
127
|
+
interface PlaceholderMoveEvent {
|
|
128
|
+
/** Unique identifier for the dragged item */
|
|
129
|
+
draggableId: string;
|
|
130
|
+
/** ID of the droppable container the item originated from */
|
|
131
|
+
sourceDroppableId: string;
|
|
132
|
+
/** ID of the droppable the placeholder moved within */
|
|
133
|
+
droppableId: string;
|
|
134
|
+
/**
|
|
135
|
+
* Previous insertion index in this droppable, or `null` when the placeholder just entered
|
|
136
|
+
* it from elsewhere. For the first move in the source list this is the item's own index.
|
|
137
|
+
*/
|
|
138
|
+
previousIndex: number | null;
|
|
139
|
+
/** New insertion index in this droppable */
|
|
140
|
+
currentIndex: number;
|
|
141
|
+
/** Optional user-provided data associated with the dragged item */
|
|
142
|
+
data?: unknown;
|
|
143
|
+
}
|
|
119
144
|
/**
|
|
120
145
|
* Event emitted when a drag operation ends (including cancel).
|
|
121
146
|
*/
|
|
@@ -124,13 +149,22 @@ interface DragEndEvent {
|
|
|
124
149
|
draggableId: string;
|
|
125
150
|
/** ID of the droppable container the item originated from */
|
|
126
151
|
droppableId: string;
|
|
127
|
-
/**
|
|
152
|
+
/**
|
|
153
|
+
* Whether the drag was actively cancelled (Escape key). Releasing over no valid
|
|
154
|
+
* target (outside any droppable, or over a disabled droppable) is NOT a cancel —
|
|
155
|
+
* it reports `cancelled: false` with `destinationIndex: null`. Branch on
|
|
156
|
+
* `destinationIndex === null` to detect "no drop occurred".
|
|
157
|
+
*/
|
|
128
158
|
cancelled: boolean;
|
|
129
159
|
/** Optional user-provided data associated with the item */
|
|
130
160
|
data?: unknown;
|
|
131
161
|
/** Original 0-indexed position in source list (for cancel announcements) */
|
|
132
162
|
sourceIndex: number;
|
|
133
|
-
/**
|
|
163
|
+
/**
|
|
164
|
+
* Final 0-indexed insertion position, or `null` when there is no valid drop target —
|
|
165
|
+
* a cancelled drag, a release outside every droppable, or a release over a disabled
|
|
166
|
+
* droppable. A non-null value pairs with a `DropEvent` on the destination.
|
|
167
|
+
*/
|
|
134
168
|
destinationIndex: number | null;
|
|
135
169
|
}
|
|
136
170
|
/**
|
|
@@ -302,6 +336,37 @@ interface VdndVirtualViewport {
|
|
|
302
336
|
*/
|
|
303
337
|
declare const VDND_VIRTUAL_VIEWPORT: InjectionToken<VdndVirtualViewport>;
|
|
304
338
|
|
|
339
|
+
/**
|
|
340
|
+
* Animation settings for drag-and-drop lists.
|
|
341
|
+
*/
|
|
342
|
+
interface VdndAnimationConfig {
|
|
343
|
+
/**
|
|
344
|
+
* Duration (ms) of the slide animation played when items are displaced by the
|
|
345
|
+
* placeholder during a drag. `0` disables the animation.
|
|
346
|
+
* @default 200
|
|
347
|
+
*/
|
|
348
|
+
shiftDuration?: number;
|
|
349
|
+
/**
|
|
350
|
+
* CSS easing function for the shift animation.
|
|
351
|
+
* @default 'cubic-bezier(0.2, 0, 0, 1)'
|
|
352
|
+
*/
|
|
353
|
+
shiftEasing?: string;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Opt-in animation configuration. When provided, items displaced by the placeholder
|
|
357
|
+
* slide into their new position instead of jumping. Resolved through the element
|
|
358
|
+
* injector, so it can be provided app-wide or per component subtree.
|
|
359
|
+
*
|
|
360
|
+
* The animation is skipped when the user prefers reduced motion. Values are read each
|
|
361
|
+
* time an animation starts, so getters can toggle the animation at runtime.
|
|
362
|
+
*
|
|
363
|
+
* @example
|
|
364
|
+
* ```typescript
|
|
365
|
+
* providers: [{ provide: VDND_ANIMATION_CONFIG, useValue: { shiftDuration: 200 } }]
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
368
|
+
declare const VDND_ANIMATION_CONFIG: InjectionToken<VdndAnimationConfig>;
|
|
369
|
+
|
|
305
370
|
/**
|
|
306
371
|
* Central service for managing drag-and-drop state.
|
|
307
372
|
* Uses signals for reactive state management.
|
|
@@ -317,6 +382,8 @@ declare class DragStateService {
|
|
|
317
382
|
#private;
|
|
318
383
|
/** Whether the last drag was cancelled (for droppable to check before emitting drop) */
|
|
319
384
|
readonly wasCancelled: _angular_core.Signal<boolean>;
|
|
385
|
+
/** Snapshot captured synchronously before the last drag reset. */
|
|
386
|
+
readonly endedDragState: _angular_core.Signal<DragState | null>;
|
|
320
387
|
/** Whether a drag operation is in progress */
|
|
321
388
|
readonly isDragging: _angular_core.Signal<boolean>;
|
|
322
389
|
/** The currently dragged item, or null */
|
|
@@ -430,6 +497,25 @@ declare class PositionCalculatorService {
|
|
|
430
497
|
* scroll event has not yet fired but the container has already moved.
|
|
431
498
|
*/
|
|
432
499
|
invalidateDroppableRects(): void;
|
|
500
|
+
/**
|
|
501
|
+
* Re-query the candidate droppable *list* for the active session and re-read their
|
|
502
|
+
* rects. Unlike {@link invalidateDroppableRects} (which only refreshes rects), this
|
|
503
|
+
* picks up droppables added or removed since the snapshot was captured at drag start —
|
|
504
|
+
* the frozen candidate list is otherwise blind to mid-drag mounts/unmounts.
|
|
505
|
+
*
|
|
506
|
+
* Safe to call when no session is active (no-op).
|
|
507
|
+
*/
|
|
508
|
+
refreshCandidates(): void;
|
|
509
|
+
/**
|
|
510
|
+
* Signal that the set of droppables for `groupName` may have changed (a droppable
|
|
511
|
+
* registered or unregistered mid-drag). Defers the actual re-query to the next
|
|
512
|
+
* hit-test — where a removed element is already gone from the DOM and a newly added
|
|
513
|
+
* one has its data attributes applied — keeping this notification path cheap.
|
|
514
|
+
*
|
|
515
|
+
* Called by {@link DroppableDirective} lifecycle hooks. No-op when the active session
|
|
516
|
+
* belongs to a different group or no session is active.
|
|
517
|
+
*/
|
|
518
|
+
notifyCandidatesChanged(groupName: string): void;
|
|
433
519
|
/**
|
|
434
520
|
* Find the droppable element at a given point.
|
|
435
521
|
*
|
|
@@ -538,8 +624,14 @@ declare class PositionCalculatorService {
|
|
|
538
624
|
findAdjacentDroppable(currentDroppableId: string, direction: 'left' | 'right', groupName: string): {
|
|
539
625
|
element: HTMLElement;
|
|
540
626
|
id: string;
|
|
541
|
-
itemCount: number;
|
|
542
627
|
} | null;
|
|
628
|
+
/**
|
|
629
|
+
* Whether the droppable with the given ID is currently disabled. A droppable that cannot
|
|
630
|
+
* be found is reported as disabled (treat missing as not a valid target). Used to
|
|
631
|
+
* revalidate a keyboard drag's active target at drop time, since it may have been disabled
|
|
632
|
+
* after the drag navigated into it.
|
|
633
|
+
*/
|
|
634
|
+
isDroppableDisabledById(id: string): boolean;
|
|
543
635
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<PositionCalculatorService, never>;
|
|
544
636
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<PositionCalculatorService>;
|
|
545
637
|
}
|
|
@@ -550,7 +642,7 @@ declare class PositionCalculatorService {
|
|
|
550
642
|
interface AutoScrollConfig {
|
|
551
643
|
/** Distance from edge to start scrolling (in pixels) */
|
|
552
644
|
threshold: number;
|
|
553
|
-
/** Maximum scroll speed
|
|
645
|
+
/** Maximum scroll speed in pixels per 60fps frame (about 16.67ms) */
|
|
554
646
|
maxSpeed: number;
|
|
555
647
|
/** Whether to accelerate scroll based on distance from edge */
|
|
556
648
|
accelerate: boolean;
|
|
@@ -1075,8 +1167,10 @@ declare class VirtualSortableListComponent<T> {
|
|
|
1075
1167
|
constrainToContainer: _angular_core.InputSignal<boolean>;
|
|
1076
1168
|
/** Emits when an item is dropped on this list */
|
|
1077
1169
|
drop: _angular_core.OutputEmitterRef<DropEvent>;
|
|
1170
|
+
/** Emits each time the placeholder moves within this list (every item displacement) */
|
|
1171
|
+
placeholderMove: _angular_core.OutputEmitterRef<PlaceholderMoveEvent>;
|
|
1078
1172
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<VirtualSortableListComponent<any>, never>;
|
|
1079
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<VirtualSortableListComponent<any>, "vdnd-sortable-list", never, { "droppableId": { "alias": "droppableId"; "required": true; "isSignal": true; }; "group": { "alias": "group"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": true; "isSignal": true; }; "itemHeight": { "alias": "itemHeight"; "required": true; "isSignal": true; }; "dynamicItemHeight": { "alias": "dynamicItemHeight"; "required": false; "isSignal": true; }; "itemIdFn": { "alias": "itemIdFn"; "required": true; "isSignal": true; }; "itemTemplate": { "alias": "itemTemplate"; "required": true; "isSignal": true; }; "trackByFn": { "alias": "trackByFn"; "required": false; "isSignal": true; }; "droppableData": { "alias": "droppableData"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "containerHeight": { "alias": "containerHeight"; "required": false; "isSignal": true; }; "overscan": { "alias": "overscan"; "required": false; "isSignal": true; }; "autoScrollEnabled": { "alias": "autoScrollEnabled"; "required": false; "isSignal": true; }; "autoScrollConfig": { "alias": "autoScrollConfig"; "required": false; "isSignal": true; }; "constrainToContainer": { "alias": "constrainToContainer"; "required": false; "isSignal": true; }; }, { "drop": "drop"; }, never, never, true, never>;
|
|
1173
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<VirtualSortableListComponent<any>, "vdnd-sortable-list", never, { "droppableId": { "alias": "droppableId"; "required": true; "isSignal": true; }; "group": { "alias": "group"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": true; "isSignal": true; }; "itemHeight": { "alias": "itemHeight"; "required": true; "isSignal": true; }; "dynamicItemHeight": { "alias": "dynamicItemHeight"; "required": false; "isSignal": true; }; "itemIdFn": { "alias": "itemIdFn"; "required": true; "isSignal": true; }; "itemTemplate": { "alias": "itemTemplate"; "required": true; "isSignal": true; }; "trackByFn": { "alias": "trackByFn"; "required": false; "isSignal": true; }; "droppableData": { "alias": "droppableData"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "containerHeight": { "alias": "containerHeight"; "required": false; "isSignal": true; }; "overscan": { "alias": "overscan"; "required": false; "isSignal": true; }; "autoScrollEnabled": { "alias": "autoScrollEnabled"; "required": false; "isSignal": true; }; "autoScrollConfig": { "alias": "autoScrollConfig"; "required": false; "isSignal": true; }; "constrainToContainer": { "alias": "constrainToContainer"; "required": false; "isSignal": true; }; }, { "drop": "drop"; "placeholderMove": "placeholderMove"; }, never, never, true, never>;
|
|
1080
1174
|
}
|
|
1081
1175
|
|
|
1082
1176
|
/**
|
|
@@ -1285,7 +1379,12 @@ declare class DraggableDirective implements OnInit, OnDestroy {
|
|
|
1285
1379
|
* Set to 0 for immediate drag (default behavior).
|
|
1286
1380
|
*/
|
|
1287
1381
|
dragDelay: _angular_core.InputSignal<number>;
|
|
1288
|
-
/**
|
|
1382
|
+
/**
|
|
1383
|
+
* Lock dragging by freezing one axis. The value names the axis that stays
|
|
1384
|
+
* fixed: `'x'` freezes the X coordinate (vertical-only movement), `'y'`
|
|
1385
|
+
* freezes the Y coordinate (horizontal-only movement). `null` allows free
|
|
1386
|
+
* movement. Note: this is the opposite of Angular CDK's `cdkDragLockAxis`.
|
|
1387
|
+
*/
|
|
1289
1388
|
lockAxis: _angular_core.InputSignal<"x" | "y" | null>;
|
|
1290
1389
|
/** Emits when drag starts */
|
|
1291
1390
|
dragStart: _angular_core.OutputEmitterRef<DragStartEvent>;
|
|
@@ -1368,6 +1467,11 @@ declare class DroppableDirective implements OnDestroy {
|
|
|
1368
1467
|
constrainToContainer: _angular_core.InputSignal<boolean>;
|
|
1369
1468
|
/** Emits when an item is dropped on this droppable */
|
|
1370
1469
|
drop: _angular_core.OutputEmitterRef<DropEvent>;
|
|
1470
|
+
/**
|
|
1471
|
+
* Emits each time the placeholder moves within this droppable during a drag
|
|
1472
|
+
* (every item displacement) — e.g. to trigger haptic feedback.
|
|
1473
|
+
*/
|
|
1474
|
+
placeholderMove: _angular_core.OutputEmitterRef<PlaceholderMoveEvent>;
|
|
1371
1475
|
/** Whether this droppable is currently being targeted */
|
|
1372
1476
|
readonly isActive: _angular_core.Signal<boolean>;
|
|
1373
1477
|
/** The current placeholder ID when this droppable is active */
|
|
@@ -1391,7 +1495,7 @@ declare class DroppableDirective implements OnDestroy {
|
|
|
1391
1495
|
*/
|
|
1392
1496
|
getScrollHeight(): number;
|
|
1393
1497
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DroppableDirective, never>;
|
|
1394
|
-
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<DroppableDirective, "[vdndDroppable]", never, { "vdndDroppable": { "alias": "vdndDroppable"; "required": true; "isSignal": true; }; "vdndDroppableGroup": { "alias": "vdndDroppableGroup"; "required": false; "isSignal": true; }; "vdndDroppableData": { "alias": "vdndDroppableData"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "autoScrollEnabled": { "alias": "autoScrollEnabled"; "required": false; "isSignal": true; }; "autoScrollConfig": { "alias": "autoScrollConfig"; "required": false; "isSignal": true; }; "constrainToContainer": { "alias": "constrainToContainer"; "required": false; "isSignal": true; }; }, { "drop": "drop"; }, never, never, true, never>;
|
|
1498
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<DroppableDirective, "[vdndDroppable]", never, { "vdndDroppable": { "alias": "vdndDroppable"; "required": true; "isSignal": true; }; "vdndDroppableGroup": { "alias": "vdndDroppableGroup"; "required": false; "isSignal": true; }; "vdndDroppableData": { "alias": "vdndDroppableData"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "autoScrollEnabled": { "alias": "autoScrollEnabled"; "required": false; "isSignal": true; }; "autoScrollConfig": { "alias": "autoScrollConfig"; "required": false; "isSignal": true; }; "constrainToContainer": { "alias": "constrainToContainer"; "required": false; "isSignal": true; }; }, { "drop": "drop"; "placeholderMove": "placeholderMove"; }, never, never, true, never>;
|
|
1395
1499
|
}
|
|
1396
1500
|
|
|
1397
1501
|
/**
|
|
@@ -1700,5 +1804,5 @@ declare function insertAt<T>(list: T[], item: T, index: number): T[];
|
|
|
1700
1804
|
*/
|
|
1701
1805
|
declare function removeAt<T>(list: T[], index: number): T[];
|
|
1702
1806
|
|
|
1703
|
-
export { AutoScrollService, ContentHeaderDirective, DragPlaceholderComponent, DragPreviewComponent, DragStateService, DraggableDirective, DroppableDirective, DroppableGroupDirective, DynamicHeightStrategy, END_OF_LIST, ElementCloneService, FixedHeightStrategy, INITIAL_DRAG_STATE, KeyboardDragService, OverlayContainerService, PlaceholderComponent, PositionCalculatorService, ScrollableDirective, VDND_GROUP_TOKEN, VDND_SCROLL_CONTAINER, VDND_VIRTUAL_VIEWPORT, VirtualContentComponent, VirtualForDirective, VirtualScrollContainerComponent, VirtualSortableListComponent, VirtualViewportComponent, applyMove, insertAt, isNoOpDrop, moveItem, removeAt, reorderItems };
|
|
1704
|
-
export type { AutoScrollConfig, CursorPosition, DragEndEvent, DragPreviewContext, DragStartEvent, DragState, DraggedItem, DropDestination, DropEvent, DropSource, GrabOffset, PlaceholderContext, VdndGroupContext, VdndScrollContainer, VdndVirtualViewport, VirtualForContext, VirtualScrollItemContext, VirtualScrollStrategy };
|
|
1807
|
+
export { AutoScrollService, ContentHeaderDirective, DragPlaceholderComponent, DragPreviewComponent, DragStateService, DraggableDirective, DroppableDirective, DroppableGroupDirective, DynamicHeightStrategy, END_OF_LIST, ElementCloneService, FixedHeightStrategy, INITIAL_DRAG_STATE, KeyboardDragService, OverlayContainerService, PlaceholderComponent, PositionCalculatorService, ScrollableDirective, VDND_ANIMATION_CONFIG, VDND_GROUP_TOKEN, VDND_SCROLL_CONTAINER, VDND_VIRTUAL_VIEWPORT, VirtualContentComponent, VirtualForDirective, VirtualScrollContainerComponent, VirtualSortableListComponent, VirtualViewportComponent, applyMove, insertAt, isNoOpDrop, moveItem, removeAt, reorderItems };
|
|
1808
|
+
export type { AutoScrollConfig, CursorPosition, DragEndEvent, DragPreviewContext, DragStartEvent, DragState, DraggedItem, DropDestination, DropEvent, DropSource, GrabOffset, PlaceholderContext, PlaceholderMoveEvent, VdndAnimationConfig, VdndGroupContext, VdndScrollContainer, VdndVirtualViewport, VirtualForContext, VirtualScrollItemContext, VirtualScrollStrategy };
|