ngx-virtual-dnd 3.1.1 → 3.1.3
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 +30 -14
- package/fesm2022/ngx-virtual-dnd.mjs +568 -206
- package/fesm2022/ngx-virtual-dnd.mjs.map +1 -1
- package/package.json +4 -4
- package/types/ngx-virtual-dnd.d.ts +50 -8
package/README.md
CHANGED
|
@@ -241,10 +241,13 @@ The preview cannot leave the droppable area, and the placeholder snaps to the ed
|
|
|
241
241
|
Lock dragging to a single axis:
|
|
242
242
|
|
|
243
243
|
```html
|
|
244
|
+
<!-- Lock the Y axis → item moves horizontally only -->
|
|
244
245
|
<div [vdndDraggable]="item.id" lockAxis="y">{{ item.name }}</div>
|
|
245
246
|
```
|
|
246
247
|
|
|
247
|
-
Values: `'x'` (
|
|
248
|
+
Values: `'x'` (X axis locked → **vertical-only** movement), `'y'` (Y axis locked → **horizontal-only** movement), or omit for free movement. The value names the axis that is _frozen_.
|
|
249
|
+
|
|
250
|
+
> **Note:** This is the opposite of Angular CDK's `cdkDragLockAxis`, where `'x'` means _movement is constrained to_ the X axis (horizontal only). Here `'x'` freezes the X axis. Keep this in mind when migrating from CDK.
|
|
248
251
|
|
|
249
252
|
### Drag Threshold & Delay
|
|
250
253
|
|
|
@@ -289,11 +292,11 @@ Configure auto-scroll behavior when dragging near container edges:
|
|
|
289
292
|
/>
|
|
290
293
|
```
|
|
291
294
|
|
|
292
|
-
| Option | Default | Description
|
|
293
|
-
| ------------ | ------- |
|
|
294
|
-
| `threshold` | `50` | Distance from edge (px) to trigger
|
|
295
|
-
| `maxSpeed` | `15` | Maximum scroll speed
|
|
296
|
-
| `accelerate` | `true` | Speed up based on distance from edge
|
|
295
|
+
| Option | Default | Description |
|
|
296
|
+
| ------------ | ------- | ---------------------------------------------- |
|
|
297
|
+
| `threshold` | `50` | Distance from edge (px) to trigger |
|
|
298
|
+
| `maxSpeed` | `15` | Maximum scroll speed in pixels per 60fps frame |
|
|
299
|
+
| `accelerate` | `true` | Speed up based on distance from edge |
|
|
297
300
|
|
|
298
301
|
Set `[autoScrollEnabled]="false"` to disable auto-scroll entirely. These options are available on `VirtualSortableListComponent`, `DroppableDirective`, and `ScrollableDirective`.
|
|
299
302
|
|
|
@@ -320,6 +323,8 @@ Use the `disabled` input to conditionally disable draggables, droppables, or ent
|
|
|
320
323
|
|
|
321
324
|
Disabled draggables get the `vdnd-draggable-disabled` CSS class. Disabled droppables get `vdnd-droppable-disabled`.
|
|
322
325
|
|
|
326
|
+
A disabled droppable is removed from all drag-time candidate sets: pointer hit-testing skips it (the cursor falls through to whatever enabled droppable sits underneath, or none) and keyboard `ArrowLeft`/`ArrowRight` navigation steps over it. Releasing a drag over a disabled droppable fires **no `drop` event**; the `(dragEnd)` event still fires with `cancelled: false` and `destinationIndex: null`, so consumers that pair `drop`/`dragEnd` should treat a `null` `destinationIndex` as "no valid drop target".
|
|
327
|
+
|
|
323
328
|
### Low-Level API
|
|
324
329
|
|
|
325
330
|
For maximum control, use individual components instead of `VirtualSortableListComponent`:
|
|
@@ -446,11 +451,13 @@ export class MyComponent {
|
|
|
446
451
|
}
|
|
447
452
|
|
|
448
453
|
announceEnd(e: DragEndEvent) {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
+
// destinationIndex is null when there is no valid drop target: an Escape cancel,
|
|
455
|
+
// a release outside every droppable, or a release over a disabled droppable.
|
|
456
|
+
if (e.destinationIndex === null) {
|
|
457
|
+
this.announce(`Returned to position ${e.sourceIndex + 1}`);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
this.announce(`Dropped at position ${e.destinationIndex + 1}`);
|
|
454
461
|
}
|
|
455
462
|
}
|
|
456
463
|
```
|
|
@@ -489,13 +496,22 @@ All event types are importable from `ngx-virtual-dnd`.
|
|
|
489
496
|
| `(dragEnd)` | `DragEndEvent` | `DraggableDirective` |
|
|
490
497
|
| `(drop)` | `DropEvent` | `DroppableDirective`, `VirtualSortableListComponent` |
|
|
491
498
|
|
|
492
|
-
`DragEndEvent`
|
|
499
|
+
`DragEndEvent.destinationIndex` is `null` when no drop occurred — an Escape cancel, a release outside every droppable, or a release over a disabled droppable — so branch on `destinationIndex === null` to detect that. The `cancelled` boolean is `true` only for an active Escape cancel.
|
|
493
500
|
|
|
494
501
|
## How It Works
|
|
495
502
|
|
|
496
503
|
Traditional drag-and-drop libraries query sibling DOM elements via `getBoundingClientRect()`. This fails with virtual scrolling because items outside the viewport aren't rendered.
|
|
497
504
|
|
|
498
|
-
This library uses **
|
|
505
|
+
This library uses **geometric hit-testing against a cached rect snapshot**: at drag start it snapshots the candidate droppables of the active group and their bounding rects, then per-pointermove it hit-tests the cursor against those rects (last match in document order wins) and calculates the placeholder position mathematically. Caching the rects avoids the forced layout flush that `document.elementFromPoint()` imposes on the hot drag loop. The snapshot self-heals during the drag: rects are re-read on scroll/resize and when a candidate resizes (via `ResizeObserver`), the candidate **list** is refreshed when a droppable mounts or unmounts mid-drag, and each rect is clipped to its nearest `vdndScrollable` ancestor so a droppable scrolled out of a clipping container is not falsely hit.
|
|
506
|
+
|
|
507
|
+
### Known Limitations
|
|
508
|
+
|
|
509
|
+
Because hit-testing is geometry against cached rects (not live `elementFromPoint`), a few browser-native behaviors are **not** reproduced:
|
|
510
|
+
|
|
511
|
+
- **Occluding overlays** — a modal, toolbar, or other element painted over a droppable does not block a geometric hit; the droppable underneath still resolves as the target.
|
|
512
|
+
- **Stacking contexts / explicit `z-index`** — the "last in document order" tie-break approximates paint order but is not true painter order once `z-index` and stacking contexts are involved. An earlier-in-DOM droppable raised visually on top via `z-index` loses the tie-break to a later sibling.
|
|
513
|
+
|
|
514
|
+
If your layout depends on these, keep overlapping droppables out of the same drag group, or avoid painting interactive overlays across active drop targets during a drag.
|
|
499
515
|
|
|
500
516
|
## Browser Support
|
|
501
517
|
|
|
@@ -517,7 +533,7 @@ npm run e2e # E2E tests
|
|
|
517
533
|
Install a skill to teach AI coding assistants how to integrate this library:
|
|
518
534
|
|
|
519
535
|
```bash
|
|
520
|
-
npx skills add gultyayev/
|
|
536
|
+
npx skills add gultyayev/ngx-virtual-dnd
|
|
521
537
|
```
|
|
522
538
|
|
|
523
539
|
Works with Claude Code, Cursor, Windsurf, GitHub Copilot, and [40+ other agents](https://skills.sh).
|