snap-dnd 0.1.3 → 0.2.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 +105 -0
- package/dist/behaviors/AutoScroll.d.ts +20 -0
- package/dist/behaviors/ConstraintAxis.d.ts +37 -0
- package/dist/behaviors/SnapGrid.d.ts +38 -0
- package/dist/behaviors/index.d.ts +3 -0
- package/dist/core/DragEngine.d.ts +60 -0
- package/dist/core/DragState.d.ts +67 -0
- package/dist/core/DropZone.d.ts +97 -0
- package/dist/core/Snap.d.ts +85 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/index.d.ts +62 -0
- package/dist/plugins/FileDrop.d.ts +33 -0
- package/dist/plugins/Kanban.d.ts +40 -0
- package/dist/plugins/Sortable.d.ts +33 -0
- package/dist/plugins/index.d.ts +3 -0
- package/dist/sensors/FileSensor.d.ts +51 -0
- package/dist/sensors/PointerSensor.d.ts +79 -0
- package/dist/sensors/index.d.ts +2 -0
- package/dist/snap.core.js +2 -2
- package/dist/snap.core.js.map +7 -0
- package/dist/snap.esm.js +11 -11
- package/dist/snap.esm.js.map +7 -0
- package/dist/snap.umd.js +11 -11
- package/dist/snap.umd.js.map +7 -0
- package/dist/types/index.d.ts +161 -0
- package/dist/utils/BoundsCache.d.ts +54 -0
- package/dist/utils/DataTransfer.d.ts +32 -0
- package/dist/utils/EventEmitter.d.ts +37 -0
- package/dist/utils/ObjectPool.d.ts +38 -0
- package/dist/utils/RAFThrottle.d.ts +39 -0
- package/dist/utils/index.d.ts +5 -0
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -351,6 +351,111 @@ interface DropEvent {
|
|
|
351
351
|
}
|
|
352
352
|
```
|
|
353
353
|
|
|
354
|
+
## Security Considerations
|
|
355
|
+
|
|
356
|
+
Snap is designed with security in mind for enterprise and banking applications.
|
|
357
|
+
|
|
358
|
+
### Built-in Security Features
|
|
359
|
+
|
|
360
|
+
1. **Prototype Pollution Protection**
|
|
361
|
+
- All option merging uses `safeMerge()` which blocks `__proto__`, `constructor`, and `prototype` keys
|
|
362
|
+
|
|
363
|
+
2. **Selector Validation**
|
|
364
|
+
- User-provided CSS selectors are validated before use
|
|
365
|
+
- Blocks potentially dangerous patterns (javascript:, expression(), etc.)
|
|
366
|
+
- Falls back to safe defaults if validation fails
|
|
367
|
+
|
|
368
|
+
3. **Data Attribute Sanitization**
|
|
369
|
+
- Only allowed data attributes are extracted (`data-drag-id`, `data-drag-type`, etc.)
|
|
370
|
+
- Values are sanitized to prevent XSS via HTML tags
|
|
371
|
+
|
|
372
|
+
4. **Banking-Grade File Validation** (FileDrop plugin)
|
|
373
|
+
```javascript
|
|
374
|
+
const snap = new Snap(container).use(new FileDrop({
|
|
375
|
+
secureValidation: true, // Enable strict validation
|
|
376
|
+
validateMagicBytes: true, // Detect extension spoofing
|
|
377
|
+
maxSize: 10 * 1024 * 1024, // 10MB limit
|
|
378
|
+
minSize: 1, // Reject empty files
|
|
379
|
+
maxFiles: 10, // Limit batch uploads
|
|
380
|
+
accept: ['.pdf', '.docx'], // Whitelist extensions
|
|
381
|
+
onValidationError: (errors) => {
|
|
382
|
+
// Handle rejected files
|
|
383
|
+
errors.forEach(({ file, error }) => {
|
|
384
|
+
console.warn(`${file.name}: ${error}`);
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
}));
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Content Security Policy (CSP)
|
|
391
|
+
|
|
392
|
+
Snap requires the following CSP directives:
|
|
393
|
+
|
|
394
|
+
```
|
|
395
|
+
style-src 'unsafe-inline'; /* Required for ghost/placeholder positioning */
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
For strict CSP environments without `unsafe-inline`:
|
|
399
|
+
- Provide your own ghost/placeholder elements via CSS classes
|
|
400
|
+
- Override the default ghost creation using callbacks
|
|
401
|
+
|
|
402
|
+
### Security Best Practices
|
|
403
|
+
|
|
404
|
+
1. **Validate Drop Data**
|
|
405
|
+
```javascript
|
|
406
|
+
onDrop: (e) => {
|
|
407
|
+
// Always validate data from drag operations
|
|
408
|
+
const itemId = e.data.getData('id');
|
|
409
|
+
if (!isValidId(itemId)) return;
|
|
410
|
+
|
|
411
|
+
// Verify user permissions server-side
|
|
412
|
+
await api.moveItem(itemId, e.dropZone.id);
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
2. **Sanitize File Uploads**
|
|
417
|
+
```javascript
|
|
418
|
+
// Always validate files server-side even with client validation
|
|
419
|
+
onFileDrop: async (e) => {
|
|
420
|
+
const formData = new FormData();
|
|
421
|
+
for (const file of e.files) {
|
|
422
|
+
formData.append('files', file);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Server should re-validate file types, scan for malware
|
|
426
|
+
const response = await fetch('/upload', {
|
|
427
|
+
method: 'POST',
|
|
428
|
+
body: formData,
|
|
429
|
+
credentials: 'same-origin'
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
3. **CSRF Protection**
|
|
435
|
+
- Include CSRF tokens in any server requests triggered by drop events
|
|
436
|
+
- Use `credentials: 'same-origin'` for fetch requests
|
|
437
|
+
|
|
438
|
+
4. **Disable in Sensitive Contexts**
|
|
439
|
+
```javascript
|
|
440
|
+
// Disable drag when viewing sensitive data
|
|
441
|
+
if (isViewingSecureDocument) {
|
|
442
|
+
snap.disable();
|
|
443
|
+
}
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### Security Utilities
|
|
447
|
+
|
|
448
|
+
Snap exports security utilities for custom use:
|
|
449
|
+
|
|
450
|
+
```javascript
|
|
451
|
+
import {
|
|
452
|
+
safeMerge, // Prototype pollution-safe object merge
|
|
453
|
+
sanitizeSelector, // Validate CSS selectors
|
|
454
|
+
validateFiles, // Banking-grade file validation
|
|
455
|
+
sanitizeDataValue, // Strip HTML from strings
|
|
456
|
+
} from 'snap-dnd';
|
|
457
|
+
```
|
|
458
|
+
|
|
354
459
|
## Browser Support
|
|
355
460
|
|
|
356
461
|
- Chrome 88+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AutoScroll behavior - scrolls containers when dragging near edges
|
|
3
|
+
*/
|
|
4
|
+
import type { Behavior, DragSession, AutoScrollOptions } from '../types/index.js';
|
|
5
|
+
export declare class AutoScroll implements Behavior {
|
|
6
|
+
name: string;
|
|
7
|
+
private _options;
|
|
8
|
+
private _scrollableAncestors;
|
|
9
|
+
private _rafId;
|
|
10
|
+
private _active;
|
|
11
|
+
constructor(options?: AutoScrollOptions);
|
|
12
|
+
onDragStart(session: DragSession): void;
|
|
13
|
+
onDragMove(session: DragSession): void;
|
|
14
|
+
onDragEnd(): void;
|
|
15
|
+
destroy(): void;
|
|
16
|
+
private _performScroll;
|
|
17
|
+
private _calculateScrollSpeed;
|
|
18
|
+
private _getSpeed;
|
|
19
|
+
private _findScrollableAncestors;
|
|
20
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConstraintAxis behavior - constrain movement to specific axis
|
|
3
|
+
* Note: Basic axis constraint is handled in DragEngine via options.axis
|
|
4
|
+
* This behavior adds additional constraint features like bounds
|
|
5
|
+
*/
|
|
6
|
+
import type { Behavior, DragSession, Axis, Point } from '../types/index.js';
|
|
7
|
+
export interface ConstraintOptions {
|
|
8
|
+
axis?: Axis;
|
|
9
|
+
/** Bounding rectangle to constrain within */
|
|
10
|
+
bounds?: {
|
|
11
|
+
minX?: number;
|
|
12
|
+
maxX?: number;
|
|
13
|
+
minY?: number;
|
|
14
|
+
maxY?: number;
|
|
15
|
+
};
|
|
16
|
+
/** Constrain to parent element bounds */
|
|
17
|
+
containWithinParent?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare class ConstraintAxis implements Behavior {
|
|
20
|
+
name: string;
|
|
21
|
+
private _options;
|
|
22
|
+
private _bounds;
|
|
23
|
+
constructor(options?: ConstraintOptions);
|
|
24
|
+
onDragStart(session: DragSession): void;
|
|
25
|
+
onDragMove(_session: DragSession): void;
|
|
26
|
+
onDragEnd(): void;
|
|
27
|
+
destroy(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Apply constraints to a point
|
|
30
|
+
*/
|
|
31
|
+
constrain(point: Point, origin: Point): Point;
|
|
32
|
+
/**
|
|
33
|
+
* Get current bounds
|
|
34
|
+
*/
|
|
35
|
+
getBounds(): typeof this._bounds;
|
|
36
|
+
private _calculateParentBounds;
|
|
37
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SnapGrid behavior - snaps drag position to a grid
|
|
3
|
+
* Note: This is handled in DragEngine via options.grid
|
|
4
|
+
* This behavior provides additional grid-related features
|
|
5
|
+
*/
|
|
6
|
+
import type { Behavior, DragSession, GridOptions } from '../types/index.js';
|
|
7
|
+
export interface SnapGridOptions extends GridOptions {
|
|
8
|
+
/** Only snap when within threshold of grid line */
|
|
9
|
+
threshold?: number;
|
|
10
|
+
/** Show visual grid guides */
|
|
11
|
+
showGuides?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare class SnapGrid implements Behavior {
|
|
14
|
+
name: string;
|
|
15
|
+
private _options;
|
|
16
|
+
private _guideContainer;
|
|
17
|
+
constructor(options: SnapGridOptions);
|
|
18
|
+
onDragStart(session: DragSession): void;
|
|
19
|
+
onDragMove(_session: DragSession): void;
|
|
20
|
+
onDragEnd(): void;
|
|
21
|
+
destroy(): void;
|
|
22
|
+
/**
|
|
23
|
+
* Snap a point to the grid
|
|
24
|
+
*/
|
|
25
|
+
snap(x: number, y: number): {
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Snap with threshold - only snap when close to grid line
|
|
31
|
+
*/
|
|
32
|
+
snapWithThreshold(x: number, y: number, threshold?: number): {
|
|
33
|
+
x: number;
|
|
34
|
+
y: number;
|
|
35
|
+
};
|
|
36
|
+
private _createGuides;
|
|
37
|
+
private _removeGuides;
|
|
38
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DragEngine orchestrates the drag operation
|
|
3
|
+
* Coordinates between sensors, state, and drop zones
|
|
4
|
+
*/
|
|
5
|
+
import type { SnapOptions, Axis } from '../types/index.js';
|
|
6
|
+
import { DragState } from './DragState.js';
|
|
7
|
+
export interface DragEngineOptions {
|
|
8
|
+
container: HTMLElement | ShadowRoot;
|
|
9
|
+
state: DragState;
|
|
10
|
+
options: SnapOptions;
|
|
11
|
+
getDropZones: () => HTMLElement[];
|
|
12
|
+
getItemData: (element: HTMLElement) => Record<string, unknown> | undefined;
|
|
13
|
+
getItemAxis: (element: HTMLElement) => Axis | undefined;
|
|
14
|
+
}
|
|
15
|
+
export declare class DragEngine {
|
|
16
|
+
private _container;
|
|
17
|
+
private _state;
|
|
18
|
+
private _options;
|
|
19
|
+
private _getDropZones;
|
|
20
|
+
private _getItemData;
|
|
21
|
+
private _getItemAxis;
|
|
22
|
+
private _pointerSensor;
|
|
23
|
+
private _enabled;
|
|
24
|
+
private _ghost;
|
|
25
|
+
private _ghostOffset;
|
|
26
|
+
constructor(engineOptions: DragEngineOptions);
|
|
27
|
+
/**
|
|
28
|
+
* Enable drag engine
|
|
29
|
+
*/
|
|
30
|
+
enable(): void;
|
|
31
|
+
/**
|
|
32
|
+
* Disable drag engine
|
|
33
|
+
*/
|
|
34
|
+
disable(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Check if enabled
|
|
37
|
+
*/
|
|
38
|
+
get isEnabled(): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Update options
|
|
41
|
+
*/
|
|
42
|
+
updateOptions(options: Partial<SnapOptions>): void;
|
|
43
|
+
private _setupListeners;
|
|
44
|
+
private _onPointerDown;
|
|
45
|
+
private _onPointerMove;
|
|
46
|
+
private _onPointerUp;
|
|
47
|
+
private _onPointerCancel;
|
|
48
|
+
private _applyAxisConstraint;
|
|
49
|
+
private _applyGridSnap;
|
|
50
|
+
private _updateDropZone;
|
|
51
|
+
private _createGhost;
|
|
52
|
+
private _updateGhost;
|
|
53
|
+
private _removeGhost;
|
|
54
|
+
private _cleanup;
|
|
55
|
+
private _extractDataAttributes;
|
|
56
|
+
/**
|
|
57
|
+
* Cleanup
|
|
58
|
+
*/
|
|
59
|
+
destroy(): void;
|
|
60
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized drag state management
|
|
3
|
+
* Single source of truth for the current drag session
|
|
4
|
+
*/
|
|
5
|
+
import type { DragSession, Point, StateEvent, Unsubscribe } from '../types/index.js';
|
|
6
|
+
import { EventEmitter } from '../utils/EventEmitter.js';
|
|
7
|
+
interface StateEvents {
|
|
8
|
+
dragstart: DragSession;
|
|
9
|
+
dragmove: DragSession;
|
|
10
|
+
dragend: DragSession;
|
|
11
|
+
dropzoneenter: DragSession;
|
|
12
|
+
dropzoneleave: DragSession;
|
|
13
|
+
drop: DragSession;
|
|
14
|
+
}
|
|
15
|
+
export declare class DragState extends EventEmitter<StateEvents> {
|
|
16
|
+
private _session;
|
|
17
|
+
private _idCounter;
|
|
18
|
+
/**
|
|
19
|
+
* Get current drag session (null if not dragging)
|
|
20
|
+
*/
|
|
21
|
+
get session(): DragSession | null;
|
|
22
|
+
/**
|
|
23
|
+
* Check if currently dragging
|
|
24
|
+
*/
|
|
25
|
+
isDragging(): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Get the element being dragged
|
|
28
|
+
*/
|
|
29
|
+
getActiveElement(): HTMLElement | null;
|
|
30
|
+
/**
|
|
31
|
+
* Get current drop zone
|
|
32
|
+
*/
|
|
33
|
+
getCurrentDropZone(): HTMLElement | null;
|
|
34
|
+
/**
|
|
35
|
+
* Start a new drag session
|
|
36
|
+
*/
|
|
37
|
+
startDrag(element: HTMLElement, origin: Point, initialData?: Record<string, unknown>): DragSession;
|
|
38
|
+
/**
|
|
39
|
+
* Update position during drag
|
|
40
|
+
*/
|
|
41
|
+
updatePosition(point: Point): void;
|
|
42
|
+
/**
|
|
43
|
+
* Set or clear drop zone target
|
|
44
|
+
*/
|
|
45
|
+
setDropTarget(zone: HTMLElement | null): void;
|
|
46
|
+
/**
|
|
47
|
+
* Complete the drag with a drop
|
|
48
|
+
*/
|
|
49
|
+
endDrag(): DragSession | null;
|
|
50
|
+
/**
|
|
51
|
+
* Cancel the current drag
|
|
52
|
+
*/
|
|
53
|
+
cancelDrag(): DragSession | null;
|
|
54
|
+
/**
|
|
55
|
+
* Subscribe to state changes
|
|
56
|
+
*/
|
|
57
|
+
subscribe(event: StateEvent, callback: (session: DragSession) => void): Unsubscribe;
|
|
58
|
+
/**
|
|
59
|
+
* Reset state
|
|
60
|
+
*/
|
|
61
|
+
reset(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Cleanup
|
|
64
|
+
*/
|
|
65
|
+
destroy(): void;
|
|
66
|
+
}
|
|
67
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DropZone manages individual drop target areas
|
|
3
|
+
* Handles hit testing and insertion index calculation
|
|
4
|
+
*/
|
|
5
|
+
import type { DataTransfer, DropZoneOptions } from '../types/index.js';
|
|
6
|
+
export declare class DropZone {
|
|
7
|
+
private _element;
|
|
8
|
+
private _options;
|
|
9
|
+
private _isActive;
|
|
10
|
+
constructor(element: HTMLElement, options?: DropZoneOptions);
|
|
11
|
+
/**
|
|
12
|
+
* The DOM element for this drop zone
|
|
13
|
+
*/
|
|
14
|
+
get element(): HTMLElement;
|
|
15
|
+
/**
|
|
16
|
+
* Whether this zone is currently active (being hovered)
|
|
17
|
+
*/
|
|
18
|
+
get isActive(): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Update options
|
|
21
|
+
*/
|
|
22
|
+
setOptions(options: Partial<DropZoneOptions>): void;
|
|
23
|
+
/**
|
|
24
|
+
* Check if a point is inside this drop zone
|
|
25
|
+
*/
|
|
26
|
+
containsPoint(x: number, y: number): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Check if this zone accepts the given data
|
|
29
|
+
*/
|
|
30
|
+
accepts(data: DataTransfer): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Set active state and add/remove CSS class
|
|
33
|
+
*/
|
|
34
|
+
setActive(active: boolean): void;
|
|
35
|
+
/**
|
|
36
|
+
* Calculate insertion index for sortable behavior
|
|
37
|
+
* Returns the index where an item should be inserted based on position
|
|
38
|
+
*/
|
|
39
|
+
getInsertionIndex(x: number, y: number, itemSelector: string, excludeElement?: HTMLElement): number;
|
|
40
|
+
/**
|
|
41
|
+
* Get closest item to a point (for visual feedback)
|
|
42
|
+
*/
|
|
43
|
+
getClosestItem(x: number, y: number, itemSelector: string, excludeElement?: HTMLElement): {
|
|
44
|
+
element: HTMLElement;
|
|
45
|
+
position: 'before' | 'after';
|
|
46
|
+
} | null;
|
|
47
|
+
/**
|
|
48
|
+
* Force update cached bounds
|
|
49
|
+
*/
|
|
50
|
+
updateBounds(): void;
|
|
51
|
+
/**
|
|
52
|
+
* Cleanup
|
|
53
|
+
*/
|
|
54
|
+
destroy(): void;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* DropZoneManager handles multiple drop zones
|
|
58
|
+
*/
|
|
59
|
+
export declare class DropZoneManager {
|
|
60
|
+
private _zones;
|
|
61
|
+
/**
|
|
62
|
+
* Register a drop zone
|
|
63
|
+
*/
|
|
64
|
+
register(element: HTMLElement, options?: DropZoneOptions): DropZone;
|
|
65
|
+
/**
|
|
66
|
+
* Unregister a drop zone
|
|
67
|
+
*/
|
|
68
|
+
unregister(element: HTMLElement): void;
|
|
69
|
+
/**
|
|
70
|
+
* Get drop zone for an element
|
|
71
|
+
*/
|
|
72
|
+
get(element: HTMLElement): DropZone | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Get all drop zone elements
|
|
75
|
+
*/
|
|
76
|
+
getElements(): HTMLElement[];
|
|
77
|
+
/**
|
|
78
|
+
* Get all drop zones
|
|
79
|
+
*/
|
|
80
|
+
getAll(): DropZone[];
|
|
81
|
+
/**
|
|
82
|
+
* Find drop zone at point
|
|
83
|
+
*/
|
|
84
|
+
findAtPoint(x: number, y: number): DropZone | null;
|
|
85
|
+
/**
|
|
86
|
+
* Clear all drop zones
|
|
87
|
+
*/
|
|
88
|
+
clear(): void;
|
|
89
|
+
/**
|
|
90
|
+
* Update all bounds (e.g., after scroll/resize)
|
|
91
|
+
*/
|
|
92
|
+
updateAllBounds(): void;
|
|
93
|
+
/**
|
|
94
|
+
* Cleanup
|
|
95
|
+
*/
|
|
96
|
+
destroy(): void;
|
|
97
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snap - Main entry point for the drag and drop library
|
|
3
|
+
* Coordinates all subsystems and provides the public API
|
|
4
|
+
*/
|
|
5
|
+
import type { SnapOptions, SnapInstance, ItemOptions, DropZoneOptions, Plugin, Behavior } from '../types/index.js';
|
|
6
|
+
export declare class Snap implements SnapInstance {
|
|
7
|
+
private _container;
|
|
8
|
+
private _options;
|
|
9
|
+
private _state;
|
|
10
|
+
private _engine;
|
|
11
|
+
private _dropZoneManager;
|
|
12
|
+
private _imperativeDraggables;
|
|
13
|
+
private _imperativeDropZones;
|
|
14
|
+
private _plugins;
|
|
15
|
+
private _behaviors;
|
|
16
|
+
private _observer;
|
|
17
|
+
private _refreshScheduled;
|
|
18
|
+
private _scrollHandler;
|
|
19
|
+
private _resizeHandler;
|
|
20
|
+
constructor(container: HTMLElement | ShadowRoot, options?: SnapOptions);
|
|
21
|
+
/**
|
|
22
|
+
* Current options
|
|
23
|
+
*/
|
|
24
|
+
get options(): SnapOptions;
|
|
25
|
+
/**
|
|
26
|
+
* Enable drag and drop
|
|
27
|
+
*/
|
|
28
|
+
enable(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Disable drag and drop
|
|
31
|
+
*/
|
|
32
|
+
disable(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Cleanup and destroy instance
|
|
35
|
+
*/
|
|
36
|
+
destroy(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Re-scan for declarative elements (call after DOM changes)
|
|
39
|
+
*/
|
|
40
|
+
refresh(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Register a draggable element imperatively
|
|
43
|
+
*/
|
|
44
|
+
addDraggable(element: HTMLElement, options?: ItemOptions): void;
|
|
45
|
+
/**
|
|
46
|
+
* Unregister a draggable element
|
|
47
|
+
*/
|
|
48
|
+
removeDraggable(element: HTMLElement): void;
|
|
49
|
+
/**
|
|
50
|
+
* Register a drop zone imperatively
|
|
51
|
+
*/
|
|
52
|
+
addDropZone(element: HTMLElement, options?: DropZoneOptions): void;
|
|
53
|
+
/**
|
|
54
|
+
* Unregister a drop zone
|
|
55
|
+
*/
|
|
56
|
+
removeDropZone(element: HTMLElement): void;
|
|
57
|
+
/**
|
|
58
|
+
* Check if currently dragging
|
|
59
|
+
*/
|
|
60
|
+
isDragging(): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Get the element currently being dragged
|
|
63
|
+
*/
|
|
64
|
+
getActiveElement(): HTMLElement | null;
|
|
65
|
+
/**
|
|
66
|
+
* Register a plugin
|
|
67
|
+
*/
|
|
68
|
+
use(plugin: Plugin): this;
|
|
69
|
+
/**
|
|
70
|
+
* Add a behavior
|
|
71
|
+
*/
|
|
72
|
+
addBehavior(behavior: Behavior): this;
|
|
73
|
+
/**
|
|
74
|
+
* Update options dynamically
|
|
75
|
+
*/
|
|
76
|
+
setOptions(options: Partial<SnapOptions>): void;
|
|
77
|
+
private _getDropZones;
|
|
78
|
+
private _getItemData;
|
|
79
|
+
private _getItemAxis;
|
|
80
|
+
private _scanDeclarativeElements;
|
|
81
|
+
private _setupStateListeners;
|
|
82
|
+
private _setupAutoRefresh;
|
|
83
|
+
private _setupScrollResize;
|
|
84
|
+
}
|
|
85
|
+
export default Snap;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snap - A zero-dependency, memory-optimized drag and drop library
|
|
3
|
+
*
|
|
4
|
+
* @example Basic usage with data attributes
|
|
5
|
+
* ```html
|
|
6
|
+
* <div id="container">
|
|
7
|
+
* <div data-draggable>Drag me</div>
|
|
8
|
+
* <div data-droppable>Drop here</div>
|
|
9
|
+
* </div>
|
|
10
|
+
*
|
|
11
|
+
* <script>
|
|
12
|
+
* const snap = new Snap(document.getElementById('container'));
|
|
13
|
+
* </script>
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @example Imperative usage
|
|
17
|
+
* ```javascript
|
|
18
|
+
* const snap = new Snap(container, {
|
|
19
|
+
* onDrop: (e) => console.log('Dropped!', e.element, e.dropZone)
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* snap.addDraggable(myElement, { data: { id: 1 } });
|
|
23
|
+
* snap.addDropZone(myZone, { accepts: ['item'] });
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @example With Lit Element
|
|
27
|
+
* ```javascript
|
|
28
|
+
* class MyComponent extends LitElement {
|
|
29
|
+
* snap;
|
|
30
|
+
*
|
|
31
|
+
* firstUpdated() {
|
|
32
|
+
* this.snap = new Snap(this.shadowRoot, {
|
|
33
|
+
* autoRefresh: true,
|
|
34
|
+
* onDrop: this.handleDrop.bind(this)
|
|
35
|
+
* });
|
|
36
|
+
* }
|
|
37
|
+
*
|
|
38
|
+
* disconnectedCallback() {
|
|
39
|
+
* super.disconnectedCallback();
|
|
40
|
+
* this.snap?.destroy();
|
|
41
|
+
* }
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export { Snap, default } from './core/Snap.js';
|
|
46
|
+
export { DragState } from './core/DragState.js';
|
|
47
|
+
export { DragEngine } from './core/DragEngine.js';
|
|
48
|
+
export { DropZone, DropZoneManager } from './core/DropZone.js';
|
|
49
|
+
export { Sortable } from './plugins/Sortable.js';
|
|
50
|
+
export { Kanban } from './plugins/Kanban.js';
|
|
51
|
+
export { FileDrop, createFileDropZone } from './plugins/FileDrop.js';
|
|
52
|
+
export { AutoScroll } from './behaviors/AutoScroll.js';
|
|
53
|
+
export { SnapGrid } from './behaviors/SnapGrid.js';
|
|
54
|
+
export { ConstraintAxis } from './behaviors/ConstraintAxis.js';
|
|
55
|
+
export { EventEmitter } from './utils/EventEmitter.js';
|
|
56
|
+
export { ObjectPool, pointPool, rectPool } from './utils/ObjectPool.js';
|
|
57
|
+
export { BoundsCache, boundsCache } from './utils/BoundsCache.js';
|
|
58
|
+
export { RAFThrottle, rafThrottle } from './utils/RAFThrottle.js';
|
|
59
|
+
export { SnapDataTransfer } from './utils/DataTransfer.js';
|
|
60
|
+
export { PointerSensor } from './sensors/PointerSensor.js';
|
|
61
|
+
export { FileSensor } from './sensors/FileSensor.js';
|
|
62
|
+
export type { Point, Rect, Axis, Unsubscribe, DragSession, DragPhase, DataTransfer, DragStartEvent, DragMoveEvent, DragEndEvent, DropEvent, DropZoneEnterEvent, DropZoneLeaveEvent, FileDropEvent, SnapOptions, SnapInstance, ItemOptions, DropZoneOptions, AutoScrollOptions, GridOptions, SortableOptions, KanbanOptions, FileDropOptions, Plugin, Behavior, Sensor, } from './types/index.js';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileDrop plugin - enables file drop zones for external files
|
|
3
|
+
*/
|
|
4
|
+
import type { Plugin, SnapInstance, FileDropOptions, FileDropEvent } from '../types/index.js';
|
|
5
|
+
export declare class FileDrop implements Plugin {
|
|
6
|
+
name: string;
|
|
7
|
+
private _snap;
|
|
8
|
+
private _options;
|
|
9
|
+
private _sensor;
|
|
10
|
+
private _onFileDrop;
|
|
11
|
+
constructor(options?: FileDropOptions);
|
|
12
|
+
init(snap: SnapInstance): void;
|
|
13
|
+
destroy(): void;
|
|
14
|
+
/**
|
|
15
|
+
* Set callback for file drop events
|
|
16
|
+
*/
|
|
17
|
+
onFileDrop(callback: (event: FileDropEvent) => void): this;
|
|
18
|
+
/**
|
|
19
|
+
* Update file drop options
|
|
20
|
+
*/
|
|
21
|
+
setOptions(options: Partial<FileDropOptions>): void;
|
|
22
|
+
private _getContainer;
|
|
23
|
+
private _setupEventHandlers;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Simple file drop zone creation helper
|
|
27
|
+
* For basic use cases without full Snap instance
|
|
28
|
+
*/
|
|
29
|
+
export declare function createFileDropZone(element: HTMLElement, options: FileDropOptions & {
|
|
30
|
+
onDrop: (files: File[]) => void;
|
|
31
|
+
onDragEnter?: () => void;
|
|
32
|
+
onDragLeave?: () => void;
|
|
33
|
+
}): () => void;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kanban plugin - enables moving items between multiple containers
|
|
3
|
+
*/
|
|
4
|
+
import type { Plugin, SnapInstance, KanbanOptions } from '../types/index.js';
|
|
5
|
+
export declare class Kanban implements Plugin {
|
|
6
|
+
name: string;
|
|
7
|
+
private _snap;
|
|
8
|
+
private _options;
|
|
9
|
+
private _sourceContainer;
|
|
10
|
+
private _targetContainer;
|
|
11
|
+
private _placeholder;
|
|
12
|
+
private _originalIndex;
|
|
13
|
+
private _currentIndex;
|
|
14
|
+
constructor(options?: KanbanOptions);
|
|
15
|
+
init(snap: SnapInstance): void;
|
|
16
|
+
destroy(): void;
|
|
17
|
+
private _onDragStart;
|
|
18
|
+
private _onDragMove;
|
|
19
|
+
private _onDropZoneEnter;
|
|
20
|
+
private _onDropZoneLeave;
|
|
21
|
+
private _onDragEnd;
|
|
22
|
+
private _createPlaceholder;
|
|
23
|
+
private _movePlaceholder;
|
|
24
|
+
private _calculateInsertionIndex;
|
|
25
|
+
private _getItemCount;
|
|
26
|
+
private _animateItems;
|
|
27
|
+
private _cleanup;
|
|
28
|
+
/**
|
|
29
|
+
* Get source container during drag
|
|
30
|
+
*/
|
|
31
|
+
getSourceContainer(): HTMLElement | null;
|
|
32
|
+
/**
|
|
33
|
+
* Get target container during drag
|
|
34
|
+
*/
|
|
35
|
+
getTargetContainer(): HTMLElement | null;
|
|
36
|
+
/**
|
|
37
|
+
* Get current insertion index
|
|
38
|
+
*/
|
|
39
|
+
getCurrentIndex(): number;
|
|
40
|
+
}
|