### Install DragDoll and Dependencies via npm
Source: https://github.com/niklasramo/dragdoll/blob/main/docs/docs/getting-started.md
This command installs DragDoll and its core dependencies (Eventti, Tikki, Mezr) using npm, suitable for Node.js projects and bundler-based web development.
```bash
npm install dragdoll eventti tikki mezr
```
--------------------------------
### Configure DragDoll Dependencies with Import Map in Browser
Source: https://github.com/niklasramo/dragdoll/blob/main/docs/docs/getting-started.md
This HTML snippet demonstrates how to set up an import map to load DragDoll and its dependencies directly from CDN for browser-based projects, enabling ES module imports without a build step.
```html
```
--------------------------------
### Initialize Draggable with Sensors - TypeScript Example
Source: https://github.com/niklasramo/dragdoll/blob/main/docs/docs/draggable.md
Demonstrates how to import and instantiate the Draggable class, providing it with PointerSensor and KeyboardSensor instances and configuring which elements to move. This example sets up a basic draggable element.
```ts
import { PointerSensor, KeyboardSensor, Draggable } from 'dragdoll';
const element = document.querySelector('.draggable') as HTMLElement;
const pointerSensor = new PointerSensor(element);
const keyboardSensor = new KeyboardSensor(element);
const draggable = new Draggable([pointerSensor, keyboardSensor], {
elements: () => [element],
});
```
--------------------------------
### Create a Draggable Element with Multiple Sensors in TypeScript
Source: https://github.com/niklasramo/dragdoll/blob/main/docs/docs/getting-started.md
This TypeScript example demonstrates how to make an HTML element draggable using DragDoll. It shows the instantiation of PointerSensor and KeyboardSensor, combining them into a single Draggable instance, and managing the element's movement based on various input events. It also includes the necessary steps to clean up resources by destroying the sensors and draggable instance when no longer needed.
```typescript
import { PointerSensor, KeyboardSensor, Draggable } from 'dragdoll';
// Let's assume that you have this element in DOM and you want to drag it
// around.
const element = document.querySelector('.draggable') as HTMLElement;
// First we need to instantiate a new PointerSensor for the element, which
// listens to DOM events and emits drag events for us to listen to. This does
// not yet make the element move.
const pointerSensor = new PointerSensor(element);
// Let's also create a keyboard sensor, which listens to keyboard events and
// emits drag events for us to listen to.
const keyboardSensor = new KeyboardSensor(element);
// Next, let's make the element move based on the events the PointerSensor
// and KeyboardSensor are emitting. Note that you can feed multiple sensors to
// a single draggable instance.
const draggable = new Draggable([pointerSensor, keyboardSensor], {
// Here we need to provide a function which returns an array of all the
// elements that we want to move around based on the provided sensor's
// events. In this case we just want to move the element which we are
// monitoring.
elements: () => [element],
});
// Now you should be able to drag the element around using mouse, touch or
// keyboard.
// When you're done with your dragging needs you can destroy the sensors and
// draggable.
draggable.destroy();
pointerSensor.destroy();
keyboardSensor.destroy();
```
--------------------------------
### KeyboardSensor Basic Usage Example
Source: https://github.com/niklasramo/dragdoll/blob/main/docs/docs/keyboard-sensor.md
Demonstrates how to import, instantiate, and use the KeyboardSensor and Draggable classes to listen for keyboard events and control an element's drag behavior. It shows event listeners for drag start, move, end, and cancel, and how to integrate the sensor with a Draggable instance.
```ts
import { KeyboardSensor, Draggable } from 'dragdoll';
// Create a keyboard sensor instance that listens to keydown events and starts
// emitting drag events when the provided element is focused and a start key
// (enter or space) is pressed.
const element = document.querySelector('.draggable') as HTMLElement;
const keyboardSensor = new KeyboardSensor(element);
// Listen to drag events.
keyboardSensor.on('start', (e) => console.log('drag started', e));
keyboardSensor.on('move', (e) => console.log('drag move', e));
keyboardSensor.on('end', (e) => console.log('drag ended', e));
keyboardSensor.on('cancel', (e) => console.log('drag canceled', e));
// Use the sensor to move an element.
const draggable = new Draggable([keyboardSensor], {
elements: () => [element],
});
```
--------------------------------
### KeyboardMotionSensor Basic Usage Example
Source: https://github.com/niklasramo/dragdoll/blob/main/docs/docs/keyboard-motion-sensor.md
Demonstrates how to import, instantiate, and use KeyboardMotionSensor to listen for drag events ('start', 'move', 'end', 'cancel', 'tick') and integrate it with a Draggable instance for controlling element movement.
```ts
import { KeyboardMotionSensor, Draggable } from 'dragdoll';
// Create a keyboard motion sensor instance that listens to keydown events and
// starts emitting drag events when the provided element is focused and a start
// key is pressed.
const element = document.querySelector('.draggable') as HTMLElement;
const sensor = new KeyboardMotionSensor(element);
// Listen to drag events.
sensor.on('start', (e) => console.log('drag started', e));
sensor.on('move', (e) => console.log('drag move', e));
sensor.on('end', (e) => console.log('drag ended', e));
sensor.on('cancel', (e) => console.log('drag canceled', e));
sensor.on('tick', () => console.log('tick'));
// Use the sensor to move an element.
const draggable = new Draggable([sensor], {
elements: () => [element]
});
```
--------------------------------
### Example Usage of createTouchDelayPredicate with Draggable
Source: https://github.com/niklasramo/dragdoll/blob/main/docs/docs/draggable-helpers.md
This example demonstrates how to integrate `createTouchDelayPredicate` into a `Draggable` instance. It shows the setup with `PointerSensor` and `KeyboardSensor`, and how to configure `touchDelay` and `fallback` options for custom drag start logic. This helper is experimental and may not work reliably, especially with scroll prevention on touch devices or within iframes.
```ts
import { Draggable, PointerSensor, KeyboardSensor, createTouchDelayPredicate } from 'draggable';
const element = document.querySelector('.draggable') as HTMLElement;
const pointerSensor = new PointerSensor(element);
const keyboardSensor = new KeyboardSensor(element);
const draggable = new Draggable([pointerSensor, keyboardSensor], {
elements: () => [element],
startPredicate: createTouchDelayPredicate({
// The amount of time in milliseconds to wait before trying to start
// dragging after the user has touched the pointer sensor element.
touchDelay: 200,
fallback: (data) => {
// Here you can decide what to do with the other sensors' events.
// For example, if you are using the keyboard sensor and pointer sensor
// together and user uses both the keyboard and the pointer at the same
// time, you can decide the logic for keyboard events here (when should
// the dragging start).
console.log(data);
return true;
}
})
});
```
--------------------------------
### DragDoll Development Environment Setup Commands
Source: https://github.com/niklasramo/dragdoll/blob/main/CONTRIBUTING.md
This section outlines the essential `npm` commands required to set up and manage the DragDoll development environment. These commands facilitate building, formatting, linting, and testing the project locally.
```Shell
npm ci
```
```Shell
npm run build
```
```Shell
npm run format
```
```Shell
npm run lint
```
```Shell
npm run test
```
```Shell
npm run test-local
```
--------------------------------
### BaseSensor Protected Method: _start
Source: https://github.com/niklasramo/dragdoll/blob/main/docs/docs/base-sensor.md
Initiates the drag process internally and emits a drag 'start' event with the provided data. This method is intended for use by extending classes to control the drag flow.
```ts
// Type
type _start = (data: { type: 'start'; x: number; y: number }) => void;
```
```ts
// Usage
baseSensor._start({ type: 'start', x: 100, y: 200 });
```
--------------------------------
### BaseMotionSensor Methods
Source: https://github.com/niklasramo/dragdoll/blob/main/docs/docs/base-motion-sensor.md
Documents the `on` method of `BaseMotionSensor`, detailing its type signature, parameters, return value, and an example of its usage for event listening.
```APIDOC
on: (
type: 'start' | 'move' | 'cancel' | 'end' | 'destroy' | 'tick',
listener: (
e:
| {
type: 'start' | 'move' | 'end' | 'cancel';
x: number;
y: number;
}
| {
type: 'tick';
time: number;
deltaTime: number;
}
| {
type: 'destroy';
},
) => void,
listenerId?: ListenerId,
) => ListenerId;
type ListenerId = null | string | number | symbol | Function | Object;
// Usage
baseMotionSensor.on('start', (e) => {
console.log('start', e);
});
// Adds a listener to a sensor event. Returns a listener id, which can be used to remove this specific listener. By default this will always be a symbol unless manually provided.
```
--------------------------------
### Draggable Element with Center-to-Pointer Alignment (Dragdoll)
Source: https://github.com/niklasramo/dragdoll/blob/main/docs/docs/examples.md
This example demonstrates how to implement a draggable element using the 'dragdoll' library. It configures a custom 'positionModifier' to align the dragged element's center with the pointer's position at the start of the drag. The snippet includes TypeScript logic for draggable setup, HTML structure for the element, and CSS for styling and layout.
```ts
import { Draggable, PointerSensor, KeyboardMotionSensor } from 'dragdoll';
const element = document.querySelector('.draggable') as HTMLElement;
const pointerSensor = new PointerSensor(element);
const keyboardSensor = new KeyboardMotionSensor(element);
const draggable = new Draggable([pointerSensor, keyboardSensor], {
elements: () => [element],
positionModifiers: [
(change, { drag, item, phase }) => {
// Align the dragged element so that the pointer
// is in the center of the element.
if (
// Only apply the alignment on the start phase.
phase === 'start' &&
// Only apply the alignment for the pointer sensor.
drag.sensor instanceof PointerSensor &&
// Only apply the alignment for the primary drag element.
drag.items[0].element === item.element
) {
const { clientRect } = item;
const { x, y } = drag.startEvent;
const targetX = clientRect.x + clientRect.width / 2;
const targetY = clientRect.y + clientRect.height / 2;
change.x = x - targetX;
change.y = y - targetY;
}
return change;
},
],
onStart: () => {
element.classList.add('dragging');
},
onEnd: () => {
element.classList.remove('dragging');
},
});
```
```html
Draggable - Center To Pointer
```
```css
body {
width: 100%;
height: 100%;
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: center;
align-content: center;
gap: 10px 10px;
}
.card.draggable {
position: relative;
flex-grow: 0;
flex-shrink: 0;
}
```
```css
:root {
--bg-color: #111;
--color: rgba(255, 255, 245, 0.86);
--theme-color: #ff5555;
--card-color: rgba(0, 0, 0, 0.7);
--card-bgColor: var(--theme-color);
--card-color--focus: var(--card-color);
--card-bgColor--focus: #db55ff;
--card-color--drag: var(--card-color);
--card-bgColor--drag: #55ff9c;
}
* {
box-sizing: border-box;
}
html {
height: 100%;
background: var(--bg-color);
color: var(--color);
background-size: 40px 40px;
background-image: linear-gradient(to right, rgba(255, 255, 255, 0.1) 1px, transparent 1px),
linear-gradient(to bottom, rgba(255, 255, 255, 0.1) 1px, transparent 1px);
}
body {
margin: 0;
overflow: hidden;
}
.card {
display: flex;
justify-content: center;
align-items: center;
width: 100px;
height: 100px;
}
```
--------------------------------
### onStart Callback Type
Source: https://github.com/niklasramo/dragdoll/blob/main/docs/docs/draggable.md
A callback function invoked at the end of the drag start phase. This phase handles applying the initial positions to the dragged elements, setting up frozen styles, and performing any other initial DOM write operations. This callback is executed immediately after any 'start' events added via the 'on' method.
```ts
type onStart = (drag: DraggableDrag, draggable: Draggable) => void;
```
--------------------------------
### KeyboardMotionSensor updateSettings Method API
Source: https://github.com/niklasramo/dragdoll/blob/main/docs/docs/keyboard-motion-sensor.md
Type definition and usage example for the `updateSettings` method. This method allows for dynamic modification of the sensor's configuration. Only the provided options will be updated.
```APIDOC
updateSettings(options?: Partial): void;
Usage:
keyboardMotionSensor.updateSettings({
startPredicate: () => {
if (Math.random() > 0.5) {
return { x: 0, y: 0 };
}
}
});
```
--------------------------------
### onPrepareStart Callback Type
Source: https://github.com/niklasramo/dragdoll/blob/main/docs/docs/draggable.md
A callback function invoked at the end of the drag start preparation phase. In this phase, draggable item instances are created, initial positions are computed, and all necessary DOM reading for the drag start is completed. This callback is executed immediately after any 'preparestart' events added via the 'on' method.
```ts
type onPrepareStart = (drag: DraggableDrag, draggable: Draggable) => void;
```
--------------------------------
### DraggableSettings Type - startPredicate Property
Source: https://github.com/niklasramo/dragdoll/blob/main/docs/docs/draggable.md
Defines the `startPredicate` function within `DraggableSettings`. This function determines whether a drag operation should begin. It receives data about the draggable, sensor, and event, returning `true` to start, `false` to prevent, or `undefined` to defer the decision.
```APIDOC
type startPredicate = (data: {
draggable: Draggable;
sensor: Sensor;
event: SensorStartEvent | SensorMoveEvent;
}) => boolean | undefined;
Description:
A function that determines if drag should start or not. Each sensor has its own predicate state. If one sensor's predicate resolves, others are rejected.
Return:
- true: Resolve predicate and start drag.
- false: Reject predicate and prevent drag.
- undefined: Keep pending, try again after next 'move' event.
Default: () => true
```
--------------------------------
### Basic PointerSensor and Draggable Usage in TypeScript
Source: https://github.com/niklasramo/dragdoll/blob/main/docs/docs/pointer-sensor.md
Demonstrates how to create a `PointerSensor` instance, listen to its drag events (`start`, `move`, `end`, `cancel`), and integrate it with a `Draggable` instance to move a DOM element.
```ts
import { PointerSensor, Draggable } from 'dragdoll';
// Create a pointer sensor instance which tracks pointer/touch/mouse events in
// window and emits drag events.
const pointerSensor = new PointerSensor(window);
// Listen to events.
pointerSensor.on('start', (e) => console.log('drag started', e));
pointerSensor.on('move', (e) => console.log('drag move', e));
pointerSensor.on('end', (e) => console.log('drag ended', e));
pointerSensor.on('cancel', (e) => console.log('drag canceled', e));
// Use the sensor to move an element.
const dragElement = document.querySelector('.dragElement');
const draggable = new Draggable([pointerSensor], {
elements: () => [dragElement],
});
```
--------------------------------
### Configure DragDoll for Multiple Element Dragging
Source: https://github.com/niklasramo/dragdoll/blob/main/docs/docs/examples.md
This example demonstrates how to set up DragDoll to enable dragging multiple HTML elements concurrently. It initializes `Draggable` instances for each element, using `PointerSensor` and `KeyboardMotionSensor`, and configures the `elements` callback to return the current element along with all other draggable elements. The `onStart` and `onEnd` callbacks manage a 'dragging' class for visual feedback.
```ts
import { Draggable, PointerSensor, KeyboardMotionSensor } from 'dragdoll';
const draggableElements = [...document.querySelectorAll('.draggable')] as HTMLElement[];
draggableElements.forEach((element) => {
const otherElements = draggableElements.filter((el) => el !== element);
const pointerSensor = new PointerSensor(element);
const keyboardSensor = new KeyboardMotionSensor(element);
const draggable = new Draggable([pointerSensor, keyboardSensor], {
elements: () => {
return [element, ...otherElements];
},
startPredicate: () => {
return !element.classList.contains('dragging');
},
onStart: (drag) => {
drag.items.forEach((item) => {
item.element.classList.add('dragging');
});
},
onEnd: (drag) => {
drag.items.forEach((item) => {
item.element.classList.remove('dragging');
});
}
});
});
```
```html
Draggable - Multiple Elements