tiny-essentials
Version:
Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.
461 lines (279 loc) โข 12.9 kB
Markdown
# ๐งฒ TinyDragger
TinyDragger enables customizable **drag-and-drop** behavior for HTML elements.
It supports visual proxies, jail boundaries, collision detection, vibration feedback, drop restrictions, and custom events โ all with a lightweight and flexible architecture.
## โจ Features
- ๐ฑ๏ธ Mouse & touch drag support
- ๐ Jail constraints to restrict dragging area
- ๐ฅ Collision detection with other elements
- ๐ Auto-revert to original position
- ๐ฎ Vibration feedback via `navigator.vibrate()`
- ๐ป Visual clone during drag (proxy)
- ๐จ Fully configurable class names
- ๐ฆ Clean destroy method with memory-safe teardown
- ๐ Custom drag and drop events
## ๐ฆ Installation
```js
import TinyDragger from './TinyDragger.js';
```
## ๐งฐ Constructor
```ts
new TinyDragger(targetElement, options?)
```
### Parameters:
| Name | Type | Default | Description |
| --------------- | ------------- | ------------ | --------------------------------- |
| `targetElement` | `HTMLElement` | **required** | The element to enable dragging on |
| `options` | `Object` | `{}` | Optional configuration |
### Options:
| Option | Type | Default | Description |
| ----------------------- | ------------------------------ | ---------------------- | ----------------------------------------------------------- |
| `jail` | `HTMLElement` | `null` | Optional container that restricts movement |
| `collisionByMouse` | `boolean` | `false` | Use mouse position instead of bounding box for collision |
| `classDragging` | `string` | `'dragging'` | Class applied to the clone element |
| `classBodyDragging` | `string` | `'drag-active'` | Class applied to the `<body>` during dragging |
| `classJailDragging` | `string` | `'jail-drag-active'` | Class applied to jail while dragging |
| `classJailDragDisabled` | `string` | `'jail-drag-disabled'` | Class applied to jail when dragging is disabled |
| `classDragCollision` | `string` | `'dragging-collision'` | Class applied to elements when collision is detected |
| `classHidden` | `string` | `'drag-hidden'` | Class used to hide the original element while dragging |
| `lockInsideJail` | `boolean` | `false` | Prevent drag from exceeding jail bounds |
| `dropInJailOnly` | `boolean` | `false` | Prevent drop outside the jail area |
| `multiCollision` | `boolean` | `false` | Enables returning multiple collided elements |
| `vibration` | `VibrationPatterns` or `false` | `false` | Vibration feedback configuration |
| `revertOnDrop` | `boolean` | `false` | Return to original position after dropping |
| `mirrorElem` | `boolean` | `true` | Use a visual clone instead of dragging the original element |
| `defaultZIndex` | `number` | `9999` | Sets the z-index value applied when dragging starts |
## ๐ณ Vibration Patterns
```ts
type VibrationPatterns = {
start: number[] | false,
end: number[] | false,
collide: number[] | false,
move: number[] | false
}
```
## ๐ Public Methods
### `enable()`
๐ Re-enables dragging after being disabled.
### `disable()`
๐ซ Temporarily disables dragging. Still allows re-enabling later.
### `destroy()`
๐ฃ Fully disables the instance, removes event listeners, and clears any DOM state.
### `addCollidable(element: HTMLElement)`
โ Adds an element to the collision tracking list.
๐ Throws if the element is not a valid `HTMLElement`.
### `removeCollidable(element: HTMLElement)`
โ Removes an element from the collision list.
๐ Throws if the element is not a valid `HTMLElement`.
### `setVibrationPattern({ startPattern, endPattern, collidePattern, movePattern })`
๐ณ Updates the vibration patterns used during drag events.
Each pattern must be either `false` or an array of numbers.
### `disableVibration()`
๐ Turns off all vibration feedback.
### `getOffset(event: MouseEvent | Touch): { x: number, y: number }`
๐ Returns the X and Y offset from the event to the top-left corner of the element.
๐ Throws if the event is invalid.
### `getCollidedElementByRect(rect: DOMRect): HTMLElement | null`
๐ฏ Detects if a `DOMRect` collides with any registered collidable elements.
๐ Throws if the rect is invalid.
### `getAllCollidedElementsByRect(rect: DOMRect): HTMLElement[]`
๐ Returns **all elements** currently intersecting the given rectangle. Useful for detecting multiple overlaps when dragging.
๐ Throws if `rect` is not a valid `DOMRect` with numeric `left`, `right`, `top`, and `bottom` properties.
### `getCollidedElement(x: number, y: number): HTMLElement | null`
๐ Detects if the given screen coordinates collide with any tracked element.
๐ Throws if `x` or `y` is not a number.
### `getAllCollidedElements(x: number, y: number): HTMLElement[]`
๐ Detects **all elements** currently under the given screen coordinates. Works well when `collisionByMouse` is enabled.
๐ Throws if `x` or `y` is not a number.
### `getDragging(): boolean`
๐ Returns whether dragging is currently active.
### `getLockInsideJail(): boolean`
๐ Returns whether movement is restricted inside the jail container.
### `setLockInsideJail(value: boolean): void`
โ๏ธ Sets whether movement is restricted inside the jail container.
๐ Throws if `value` is not a boolean.
### `getRevertOnDrop(): boolean`
โฉ๏ธ Returns whether the element should revert to its original position on drop.
### `setRevertOnDrop(value: boolean): void`
โ๏ธ Sets whether the element should revert to its original position on drop.
๐ Throws if `value` is not a boolean.
### `getCollisionByMouse(): boolean`
๐ฑ๏ธ Returns whether collision detection uses mouse position instead of element bounding rectangles.
### `setCollisionByMouse(value: boolean): void`
โ๏ธ Sets whether collision detection uses mouse position instead of element bounding rectangles.
๐ Throws if `value` is not a boolean.
### `getDropInJailOnly(): boolean`
๐ซ Returns whether dropping is restricted inside the jail container.
### `setDropInJailOnly(value: boolean): void`
โ๏ธ Sets whether dropping is restricted inside the jail container.
๐ Throws if `value` is not a boolean.
### `checkDragCollision(event: MouseEvent | Touch): void`
๐ฏ Checks for collision between the drag proxy and registered elements.
๐ฅ Applies or removes the collision class depending on overlap.
๐ณ Triggers vibration if configured.
### `execCollision(event: MouseEvent | Touch): { inJail: boolean; collidedElement: HTMLElement | null }`
๐งฉ Executes collision detection logic based on the drag position and mode.
๐ Uses either the mouse point or the proxy rectangle depending on `collisionByMouse`.
๐ Respects `dropInJailOnly` and jail boundaries.
๐ Returns `{ inJail: false, collidedElement: null }` if dragging is not active.
### `getTarget(): HTMLElement`
๐ฏ Returns the original element being dragged.
### `getJail(): HTMLElement | null`
๐ง Returns the jail container element if one is set.
Returns `null` if no jail is configured.
### `getDragProxy(): HTMLElement | null`
๐ป Returns the current proxy (clone) element being dragged.
Returns `null` if no proxy is active.
### `getLastCollision(): HTMLElement | null`
๐ฅ Returns the last collided element (if any).
### `getCollidables(): HTMLElement[]`
๐งฒ Returns the list of elements that are considered for collision detection.
### `getDragHiddenClass(): string`
๐ Returns the CSS class used to hide the original element during dragging.
### `getClassDragging(): string`
๐ฌ Returns the CSS class applied to the clone while it is being dragged.
### `getClassBodyDragging(): string`
๐ง Returns the CSS class applied to `<body>` when dragging is active.
### `getClassJailDragging(): string`
๐๏ธ Returns the CSS class applied to the jail element while dragging is active.
### `getClassJailDragDisabled(): string`
๐ซ Returns the CSS class applied to the jail when dragging is disabled.
### `getClassDragCollision(): string`
โ ๏ธ Returns the CSS class applied to elements when a collision is detected.
### `getVibrations(): { start: number[] | false, end: number[] | false, collide: number[] | false, move: number[] | false }`
๐ต Returns the full vibration pattern configuration used during dragging.
### `getStartVibration(): number[] | false`
๐ณ Returns the vibration pattern used at the **start** of a drag.
### `getEndVibration(): number[] | false`
๐ด Returns the vibration pattern used at the **end** of a drag.
### `getCollideVibration(): number[] | false`
๐ฏ Returns the vibration pattern used when **colliding** with another element.
### `getMoveVibration(): number[] | false`
๐ถ Returns the vibration pattern used during **movement** while dragging.
### `isEnabled(): boolean`
โ
Returns whether the drag-and-drop functionality is currently enabled.
### `getDefaultZIndex(): number`
๐ฏ Returns the current default `z-index` used when a draggable item is picked up.
### `setDefaultZIndex(newZIndex: number): void`
๐ ๏ธ Sets a new default `z-index` to be used during drag operations.
> Throws `TypeError` if `newZIndex` is not a finite number.
### `isMirrorEnabled(): boolean`
๐ฏ Returns whether the draggable element uses a **mirror** (`true`) or the **original element** (`false`) during dragging.
### `setMirrorEnabled(useMirror: boolean): void`
๐ ๏ธ Defines whether the draggable element should use a **mirror clone** or move the **original element**.
> Throws `TypeError` if `useMirror` is not a boolean.
## ๐ Events
The target element will emit these events:
| Event | Description |
| ---------- | ------------------------------------------------ |
| `drag` | Fired at the beginning of a drag |
| `dragging` | Continuously fired while dragging |
| `drop` | Fired at the end of the drag with collision info |
### Example:
```js
targetEl.addEventListener('drop', (e) => {
console.log('Dropped on:', e.detail.target);
});
```
## ๐ก๏ธ Error Handling
* Throws errors if the constructor options are of invalid types.
* Throws if using destroyed instances (`destroy()` has been called).
* Throws on invalid usage of methods like `addCollidable` or `getOffset`.
## โ
Example
```js
const box = document.getElementById('draggableBox');
const jail = document.getElementById('jailContainer');
const dragger = new TinyDragger(box, {
jail,
lockInsideJail: false,
collisionByMouse: false,
revertOnDrop: false,
vibration: {
start: [30],
move: [5],
collide: [80],
end: [20, 10, 20],
},
});
const dropTarget = document.getElementById('dropArea');
dragger.addCollidable(dropTarget);
box.addEventListener('drop', (e) => {
if (e.detail.target === dropTarget) {
alert('Dropped successfully!');
}
});
```
## ๐งผ Clean-Up
Call `.destroy()` to completely remove drag behavior and all event listeners:
```js
dragger.destroy();
```
## ๐งช Testing & Styling
* ๐จ **Example Stylesheets:**
You can find optional example styles to get started or test layout integration in:
```
dist/v1/css/TinyDraggerExample.css
dist/v1/css/TinyDraggerExample.min.css
```
* ๐งฑ **Test Environment:**
A ready-to-use HTML test page is available at:
```
test/html/TinyDragger
```
This includes practical demos and scenarios to test dragging, collision, jail constraints, and more.
## ๐ง Notes
* Touch support uses the first touch point only.
* Make sure your draggable element has `position: relative` or `absolute` if itโs meant to be positioned manually after drop.