0
# Utilities
1
2
Collection of DOM manipulation and helper functions for advanced integrations and custom implementations.
3
4
## Capabilities
5
6
### Event Management
7
8
Utilities for attaching and removing event listeners with cross-browser compatibility.
9
10
```javascript { .api }
11
/**
12
* Add event listener to element
13
* @param el - Target element
14
* @param event - Event name
15
* @param fn - Event handler function
16
*/
17
Sortable.utils.on(el: HTMLElement, event: string, fn: Function): void;
18
19
/**
20
* Remove event listener from element
21
* @param el - Target element
22
* @param event - Event name
23
* @param fn - Event handler function
24
*/
25
Sortable.utils.off(el: HTMLElement, event: string, fn: Function): void;
26
```
27
28
**Usage Examples:**
29
30
```javascript
31
const { on, off } = Sortable.utils;
32
33
function handleClick(evt) {
34
console.log('Element clicked:', evt.target);
35
}
36
37
// Add event listener
38
on(document.getElementById('myButton'), 'click', handleClick);
39
40
// Remove event listener
41
off(document.getElementById('myButton'), 'click', handleClick);
42
43
// Handle multiple events
44
const events = ['mousedown', 'touchstart'];
45
events.forEach(event => on(element, event, handleStart));
46
```
47
48
### CSS Manipulation
49
50
Utilities for getting and setting CSS properties and classes.
51
52
```javascript { .api }
53
/**
54
* Get or set CSS property on element
55
* @param el - Target element
56
* @param prop - CSS property name
57
* @param value - CSS property value (omit to get current value)
58
* @returns Current property value when getting
59
*/
60
Sortable.utils.css(el: HTMLElement, prop: string, value?: string): string | void;
61
62
/**
63
* Toggle CSS class on element
64
* @param el - Target element
65
* @param name - Class name
66
* @param state - Force state (true=add, false=remove, undefined=toggle)
67
*/
68
Sortable.utils.toggleClass(el: HTMLElement, name: string, state?: boolean): void;
69
```
70
71
**Usage Examples:**
72
73
```javascript
74
const { css, toggleClass } = Sortable.utils;
75
76
// Get CSS property
77
const width = css(element, 'width'); // '200px'
78
79
// Set CSS property
80
css(element, 'background-color', 'red');
81
css(element, 'transform', 'translateX(100px)');
82
83
// Toggle class
84
toggleClass(element, 'active'); // Toggle
85
toggleClass(element, 'selected', true); // Force add
86
toggleClass(element, 'hidden', false); // Force remove
87
```
88
89
### Element Searching
90
91
Utilities for finding and querying DOM elements.
92
93
```javascript { .api }
94
/**
95
* Find elements within a context
96
* @param ctx - Context element to search within
97
* @param tagName - Tag name to search for
98
* @param iterator - Optional iterator function for filtering
99
* @returns Array of matching elements
100
*/
101
Sortable.utils.find(ctx: HTMLElement, tagName: string, iterator?: Function): HTMLElement[];
102
103
/**
104
* Check if element matches selector
105
* @param el - Element to test
106
* @param selector - CSS selector
107
* @returns Whether element matches selector
108
*/
109
Sortable.utils.is(el: HTMLElement, selector: string): boolean;
110
111
/**
112
* Find closest ancestor matching selector
113
* @param el - Starting element
114
* @param selector - CSS selector
115
* @param ctx - Context element (search boundary)
116
* @returns Closest matching ancestor or null
117
*/
118
Sortable.utils.closest(el: HTMLElement, selector: string, ctx?: HTMLElement): HTMLElement | null;
119
```
120
121
**Usage Examples:**
122
123
```javascript
124
const { find, is, closest } = Sortable.utils;
125
126
// Find all divs within container
127
const divs = find(container, 'div');
128
129
// Find draggable items with custom filter
130
const draggableItems = find(container, '*', (el) => {
131
return !el.classList.contains('no-drag');
132
});
133
134
// Check if element matches selector
135
if (is(element, '.sortable-item')) {
136
console.log('Element is sortable item');
137
}
138
139
// Find closest sortable container
140
const sortableContainer = closest(draggedElement, '.sortable-list');
141
```
142
143
### Element Manipulation
144
145
Utilities for cloning, positioning, and measuring elements.
146
147
```javascript { .api }
148
/**
149
* Clone an element
150
* @param el - Element to clone
151
* @returns Cloned element
152
*/
153
Sortable.utils.clone(el: HTMLElement): HTMLElement;
154
155
/**
156
* Get element index within parent
157
* @param el - Target element
158
* @param selector - Optional selector to filter siblings
159
* @returns Element index
160
*/
161
Sortable.utils.index(el: HTMLElement, selector?: string): number;
162
163
/**
164
* Get child element at specific index
165
* @param el - Parent element
166
* @param childNum - Child index
167
* @param options - Options object with draggable selector
168
* @returns Child element at index
169
*/
170
Sortable.utils.getChild(el: HTMLElement, childNum: number, options?: { draggable?: string }): HTMLElement;
171
```
172
173
**Usage Examples:**
174
175
```javascript
176
const { clone, index, getChild } = Sortable.utils;
177
178
// Clone element
179
const clonedElement = clone(originalElement);
180
document.body.appendChild(clonedElement);
181
182
// Get element index
183
const elementIndex = index(element); // Position among all siblings
184
const draggableIndex = index(element, '.draggable'); // Position among draggable siblings
185
186
// Get specific child
187
const firstChild = getChild(container, 0);
188
const firstDraggable = getChild(container, 0, { draggable: '.sortable-item' });
189
```
190
191
### Object and Function Utilities
192
193
Utilities for object manipulation and function optimization.
194
195
```javascript { .api }
196
/**
197
* Extend target object with source objects
198
* @param dst - Target object
199
* @param src - Source objects
200
* @returns Extended target object
201
*/
202
Sortable.utils.extend(dst: object, ...src: object[]): object;
203
204
/**
205
* Throttle function calls
206
* @param fn - Function to throttle
207
* @param ms - Throttle interval in milliseconds
208
* @returns Throttled function
209
*/
210
Sortable.utils.throttle(fn: Function, ms: number): Function;
211
```
212
213
**Usage Examples:**
214
215
```javascript
216
const { extend, throttle } = Sortable.utils;
217
218
// Extend objects
219
const config = extend({}, defaultOptions, userOptions);
220
221
// Throttle expensive operations
222
const expensiveOperation = throttle(() => {
223
console.log('This only runs once every 100ms');
224
updateComplexUI();
225
}, 100);
226
227
// Call frequently, but execution is throttled
228
window.addEventListener('scroll', expensiveOperation);
229
```
230
231
### Async Utilities
232
233
Utilities for scheduling and managing asynchronous operations.
234
235
```javascript { .api }
236
/**
237
* Schedule function for next tick
238
* @param fn - Function to schedule
239
* @returns Ticket ID for cancellation
240
*/
241
Sortable.utils.nextTick(fn: Function): number;
242
243
/**
244
* Cancel scheduled function
245
* @param id - Ticket ID from nextTick
246
*/
247
Sortable.utils.cancelNextTick(id: number): void;
248
```
249
250
**Usage Examples:**
251
252
```javascript
253
const { nextTick, cancelNextTick } = Sortable.utils;
254
255
// Schedule for next tick
256
const ticketId = nextTick(() => {
257
console.log('This runs on next tick');
258
updateUI();
259
});
260
261
// Cancel if needed
262
if (shouldCancel) {
263
cancelNextTick(ticketId);
264
}
265
266
// Common pattern for DOM updates
267
nextTick(() => {
268
// DOM changes are batched and applied efficiently
269
element.style.transform = 'translateX(100px)';
270
element.classList.add('moved');
271
});
272
```
273
274
### Direction Detection
275
276
Utility for detecting sort direction in containers.
277
278
```javascript { .api }
279
/**
280
* Detect sort direction of container
281
* @param el - Container element
282
* @returns Direction string ('horizontal' or 'vertical')
283
*/
284
Sortable.utils.detectDirection(el: HTMLElement): string;
285
```
286
287
**Usage Examples:**
288
289
```javascript
290
const { detectDirection } = Sortable.utils;
291
292
// Detect container direction
293
const direction = detectDirection(container);
294
console.log('Container direction:', direction); // 'horizontal' or 'vertical'
295
296
// Use in custom logic
297
if (detectDirection(container) === 'horizontal') {
298
setupHorizontalScrolling();
299
} else {
300
setupVerticalScrolling();
301
}
302
```
303
304
### Internal Property Access
305
306
Utility for accessing Sortable's internal property key.
307
308
```javascript { .api }
309
/**
310
* Internal property key used to store Sortable instances on elements
311
*/
312
Sortable.utils.expando: string;
313
```
314
315
**Usage Examples:**
316
317
```javascript
318
const { expando } = Sortable.utils;
319
320
// Access sortable instance directly (advanced usage)
321
const sortableInstance = element[expando];
322
323
if (sortableInstance) {
324
console.log('Element has sortable instance:', sortableInstance);
325
}
326
```
327
328
## Complete Utils Interface
329
330
```javascript { .api }
331
interface SortableUtils {
332
// Event management
333
on(el: HTMLElement, event: string, fn: Function): void;
334
off(el: HTMLElement, event: string, fn: Function): void;
335
336
// CSS manipulation
337
css(el: HTMLElement, prop: string, value?: string): string | void;
338
toggleClass(el: HTMLElement, name: string, state?: boolean): void;
339
340
// Element searching
341
find(ctx: HTMLElement, tagName: string, iterator?: Function): HTMLElement[];
342
is(el: HTMLElement, selector: string): boolean;
343
closest(el: HTMLElement, selector: string, ctx?: HTMLElement): HTMLElement | null;
344
345
// Element manipulation
346
clone(el: HTMLElement): HTMLElement;
347
index(el: HTMLElement, selector?: string): number;
348
getChild(el: HTMLElement, childNum: number, options?: { draggable?: string }): HTMLElement;
349
350
// Object and function utilities
351
extend(dst: object, ...src: object[]): object;
352
throttle(fn: Function, ms: number): Function;
353
354
// Async utilities
355
nextTick(fn: Function): number;
356
cancelNextTick(id: number): void;
357
358
// Direction detection
359
detectDirection(el: HTMLElement): string;
360
361
// Internal property access
362
expando: string;
363
}
364
```
365
366
## Advanced Usage Patterns
367
368
### Custom Sortable Implementation
369
370
Using utilities to build custom drag-and-drop functionality:
371
372
```javascript
373
const { on, off, css, closest, throttle } = Sortable.utils;
374
375
class CustomDragDrop {
376
constructor(element) {
377
this.element = element;
378
this.items = [];
379
this.init();
380
}
381
382
init() {
383
on(this.element, 'mousedown', this.handleMouseDown.bind(this));
384
this.handleMouseMove = throttle(this.handleMouseMove.bind(this), 16);
385
}
386
387
handleMouseDown(evt) {
388
const item = closest(evt.target, '.draggable-item', this.element);
389
if (!item) return;
390
391
this.draggedItem = item;
392
css(item, 'opacity', '0.5');
393
394
on(document, 'mousemove', this.handleMouseMove);
395
on(document, 'mouseup', this.handleMouseUp.bind(this));
396
}
397
398
handleMouseMove(evt) {
399
if (!this.draggedItem) return;
400
css(this.draggedItem, 'transform', `translate(${evt.clientX}px, ${evt.clientY}px)`);
401
}
402
403
handleMouseUp() {
404
if (this.draggedItem) {
405
css(this.draggedItem, 'opacity', '');
406
css(this.draggedItem, 'transform', '');
407
this.draggedItem = null;
408
}
409
410
off(document, 'mousemove', this.handleMouseMove);
411
off(document, 'mouseup', this.handleMouseUp);
412
}
413
}
414
```
415
416
### Framework Integration Helper
417
418
Using utilities to integrate with UI frameworks:
419
420
```javascript
421
const { on, off, nextTick } = Sortable.utils;
422
423
class ReactSortableHelper {
424
static attachToRef(ref, options, onOrderChange) {
425
if (!ref.current) return null;
426
427
const sortable = Sortable.create(ref.current, {
428
...options,
429
onEnd: (evt) => {
430
nextTick(() => {
431
// Ensure React state updates after DOM changes
432
const newOrder = sortable.toArray();
433
onOrderChange(newOrder);
434
});
435
436
options.onEnd && options.onEnd(evt);
437
}
438
});
439
440
return sortable;
441
}
442
443
static detachFromRef(sortable) {
444
if (sortable) {
445
sortable.destroy();
446
}
447
}
448
}
449
```