@webalternatif/js-core 1.6.3 → 1.6.4

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.
Files changed (57) hide show
  1. package/README.md +3 -3
  2. package/dist/cjs/Mouse.js +6 -1
  3. package/dist/cjs/Translator.js +7 -1
  4. package/dist/cjs/array.js +5 -35
  5. package/dist/cjs/dom.js +817 -208
  6. package/dist/cjs/eventDispatcher.js +6 -1
  7. package/dist/cjs/index.js +6 -13
  8. package/dist/cjs/is.js +44 -1
  9. package/dist/cjs/math.js +56 -31
  10. package/dist/cjs/traversal.js +1 -2
  11. package/dist/cjs/utils.js +155 -38
  12. package/dist/esm/Mouse.js +7 -1
  13. package/dist/esm/Translator.js +7 -1
  14. package/dist/esm/array.js +4 -35
  15. package/dist/esm/dom.js +816 -206
  16. package/dist/esm/eventDispatcher.js +7 -1
  17. package/dist/esm/index.js +7 -8
  18. package/dist/esm/is.js +43 -0
  19. package/dist/esm/math.js +58 -32
  20. package/dist/esm/traversal.js +1 -2
  21. package/dist/esm/utils.js +156 -39
  22. package/dist/umd/Translator.umd.js +1 -0
  23. package/dist/umd/dom.umd.js +1 -0
  24. package/dist/umd/eventDispatcher.umd.js +1 -0
  25. package/dist/umd/mouse.umd.js +1 -0
  26. package/dist/umd/webf.umd.js +1 -0
  27. package/docs/array.md +41 -8
  28. package/docs/dom.md +1063 -269
  29. package/docs/is.md +244 -0
  30. package/docs/math.md +87 -7
  31. package/docs/mouse.md +43 -0
  32. package/docs/translator.md +14 -14
  33. package/docs/traversal.md +16 -16
  34. package/docs/utils.md +173 -20
  35. package/package.json +10 -4
  36. package/src/Mouse.js +73 -0
  37. package/src/Translator.js +148 -0
  38. package/src/array.js +136 -0
  39. package/src/dom.js +1553 -0
  40. package/src/eventDispatcher.js +118 -0
  41. package/src/index.js +106 -0
  42. package/src/is.js +201 -0
  43. package/src/math.js +113 -0
  44. package/src/onOff.js +313 -0
  45. package/src/random.js +38 -0
  46. package/src/string.js +662 -0
  47. package/src/stringPrototype.js +16 -0
  48. package/src/traversal.js +236 -0
  49. package/src/utils.js +242 -0
  50. package/types/Translator.d.ts +6 -5
  51. package/types/array.d.ts +0 -1
  52. package/types/dom.d.ts +763 -204
  53. package/types/index.d.ts +22 -21
  54. package/types/is.d.ts +3 -0
  55. package/types/math.d.ts +6 -5
  56. package/types/utils.d.ts +4 -4
  57. package/types/i18n.d.ts +0 -4
package/dist/esm/dom.js CHANGED
@@ -4,82 +4,74 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
4
4
  function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
5
5
  function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
6
6
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
7
- import { isArray, isArrayLike, isObject, isPlainObject, isString } from './is.js';
7
+ import { isArray, isArrayLike, isDocument, isFunction, isPlainObject, isString, isWindow } from './is.js';
8
8
  import { camelCase } from './string.js';
9
9
  import { each, foreach, map } from './traversal.js';
10
10
  import { inArray } from './array.js';
11
11
  import { on, off, __resetCustomEventsForTests } from './onOff.js';
12
12
  var cssNumber = ['animationIterationCount', 'aspectRatio', 'borderImageSlice', 'columnCount', 'flexGrow', 'flexShrink', 'fontWeight', 'gridArea', 'gridColumn', 'gridColumnEnd', 'gridColumnStart', 'gridRow', 'gridRowEnd', 'gridRowStart', 'lineHeight', 'opacity', 'order', 'orphans', 'scale', 'widows', 'zIndex', 'zoom', 'fillOpacity', 'floodOpacity', 'stopOpacity', 'strokeMiterlimit', 'strokeOpacity'];
13
-
14
- /**
15
- * @param {any} o
16
- * @returns {boolean}
17
- */
18
- export var isWindow = function isWindow(o) {
19
- return !!o && o === o.window;
20
- };
21
-
22
- /**
23
- * @param {any} o
24
- * @returns {boolean}
25
- */
26
- export var isDocument = function isDocument(o) {
27
- return !!o && o.nodeType === 9;
28
- };
29
-
30
- /**
31
- * @param {any} o
32
- * @returns {boolean}
33
- */
34
- export var isDomElement = function isDomElement(o) {
35
- return isObject(o) && o instanceof HTMLElement;
36
- };
37
-
38
- /**
39
- * @param {Element} el
40
- * @param {string} cssRule
41
- * @returns {string}
42
- */
43
- export var getStyle = function getStyle(el, cssRule) {
44
- if (!isDomElement(el)) {
45
- return '';
46
- }
47
- if (window.getComputedStyle) {
48
- var computedStyle = window.getComputedStyle(el, null);
49
- return computedStyle.getPropertyValue(cssRule) || computedStyle[camelCase(cssRule)] || '';
50
- }
51
- return el.style[camelCase(cssRule)] || '';
52
- };
53
13
  var dom = {
54
14
  /**
55
- * @param {Element} el
56
- * @param {string} [selector]
57
- * @returns {NodeList|Element[]}
15
+ * Returns the direct children of an element.
16
+ * If a selector is provided, only children matching the selector are returned.
17
+ *
18
+ * @example
19
+ * // <ul id="list"><li class="a"></li><li class="b"></li></ul>
20
+ * const list = document.getElementById('list')
21
+ *
22
+ * dom.children(list) // [[<li class="a">], [<li class="b">]]
23
+ * dom.children(list, '.a') // [<li class="a">]
24
+ *
25
+ * @param {Element} el - Parent element
26
+ * @param {string} [selector] - Optional CSS selector to filter direct children
27
+ * @returns {Element[]} Direct children, optionally filtered
58
28
  */
59
29
  children: function children(el, selector) {
60
- return selector ? this.find(el, ":scope > ".concat(selector)) : el.children;
30
+ return selector ? this.find(el, ":scope > ".concat(selector)) : Array.from(el.children);
61
31
  },
62
32
  /**
63
- * @param {Element} el
64
- * @param {string} [selector]
65
- * @returns {Element|null}
33
+ * Returns the first direct child of an element matching `selector`.
34
+ *
35
+ * @example
36
+ * // <ul id="list"><li class="a"></li><li class="b"></li></ul>
37
+ * const list = document.getElementById('list')
38
+ *
39
+ * dom.child(list) // <li class="a">
40
+ * dom.child(list, '.b') // <li class="b">
41
+ * dom.child(list, '.c') // null
42
+ *
43
+ * @param {Element} el - Parent element
44
+ * @param {string} [selector] - Optional CSS selector to filter direct children
45
+ * @returns {Element|null} - The first matching direct child, or null if none found
66
46
  */
67
47
  child: function child(el, selector) {
68
48
  return this.first(this.children(el, selector));
69
49
  },
70
50
  /**
71
- * @param {Element|Document|string} refEl
72
- * @param {string|Element|NodeList|Array<Element>} [selector]
73
- * @returns {Element}
74
- */
75
- findOne: function findOne(refEl, selector) {
76
- var _this$find$;
77
- return (_this$find$ = this.find(refEl, selector)[0]) !== null && _this$find$ !== void 0 ? _this$find$ : null;
78
- },
79
- /**
80
- * @param {Element|Document|string} refEl
81
- * @param {string|Element|NodeList|Array<Element>} [selector]
82
- * @returns {Element[]}
51
+ * Finds elements based on a selector or a collection
52
+ *
53
+ * If only one argument is provided, the search is performed from `document`.
54
+ *
55
+ * The `selector` can be:
56
+ * - a CSS selector string
57
+ * - a single Element
58
+ * - a NodeList or array-like collection of Elements
59
+ *
60
+ * @example
61
+ * dom.find('.item') // All elements matching .item in document
62
+ *
63
+ * const container = document.getElementById('box')
64
+ * dom.find(container, '.item') // All .item inside #box
65
+ *
66
+ * const el = document.querySelector('.item')
67
+ * dom.find(container, el) // [el] if inside container, otherwise []
68
+ *
69
+ * const list = document.querySelectorAll('.item')
70
+ * dom.find(container, list) // Only those inside container
71
+ *
72
+ * @param {Element|Document|DocumentFragment|string} refEl - Reference element or selector (if used alone)
73
+ * @param {string|Element|NodeList|Array<Element>} [selector] - What to find
74
+ * @returns {Element[]} - An array of matched elements
83
75
  */
84
76
  find: function find(refEl, selector) {
85
77
  if (undefined === selector) {
@@ -104,29 +96,80 @@ var dom = {
104
96
  }
105
97
  },
106
98
  /**
107
- * @param {Element|string} el
108
- * @param {string} data
109
- * @param {string} [value]
110
- * @returns {Element|null}
99
+ * Finds the first element matching a selector or collection.
100
+ *
101
+ * Behaves like `dom.find` but returns only the first matched element.
102
+ * Returns `null` if no element matches.
103
+ *
104
+ * @param {Element|Document|DocumentFragment|string} refEl - Reference element or selector (if used alone)
105
+ * @param {string|Element|NodeList|Array<Element>} [selector] - What to find
106
+ * @returns {Element|null} - The first matched Element, or null if none found
111
107
  */
112
- findOneByData: function findOneByData(el, data, value) {
113
- var _this$findByData$;
114
- return (_this$findByData$ = this.findByData(el, data, value)[0]) !== null && _this$findByData$ !== void 0 ? _this$findByData$ : null;
108
+ findOne: function findOne(refEl, selector) {
109
+ var _this$find$;
110
+ return (_this$find$ = this.find(refEl, selector)[0]) !== null && _this$find$ !== void 0 ? _this$find$ : null;
115
111
  },
116
112
  /**
117
- * @param {Element|string} el
118
- * @param {string} data
119
- * @param {string} [value]
120
- * @returns {Element[]}
113
+ * Finds elements by a data-* attribute.
114
+ *
115
+ * If `value` is provided, only elements with an exact matching value are returned.
116
+ * If `value` is omitted, all elements having the data attribute are returned.
117
+ *
118
+ * @example
119
+ * // <div data-user-id="42"></div>
120
+ *
121
+ * dom.findByData(document, 'user-id') // all elements with [data-user-id]
122
+ * dom.findByData(document, 'user-id', '42') // elements with [data-user-id="42"]
123
+ *
124
+ * @param {Element|Document|string} el - Reference element or selector (if used alone)
125
+ * @param {string} data - The data-* key without the "data-" prefix
126
+ * @param {string} [value] - Optional value to match exactly
127
+ * @returns {Element[]} - Matching elements
121
128
  */
122
129
  findByData: function findByData(el, data, value) {
123
- var escapeValue = CSS.escape(value);
130
+ if (undefined === value) return this.find(el, "[data-".concat(data, "]"));
131
+ var escapeValue = CSS.escape(value + '');
124
132
  return this.find(el, "[data-".concat(data, "=\"").concat(escapeValue, "\"]"));
125
133
  },
126
134
  /**
127
- * @param {Element|NodeList|Array<Element>} el
128
- * @param {string} className
129
- * @returns {Element|NodeList|Array<Element>}
135
+ * Finds the first element matching a data-* attribute.
136
+ *
137
+ * If `value` is provided, returns the first element whose data attribute
138
+ * exactly matches the given value. If omitted, returns the first element
139
+ * that has the data attribute.
140
+ *
141
+ * @example
142
+ * // <div data-user-id="42"></div>
143
+ *
144
+ * dom.findOneByData(document, 'user-id') // first element with [data-user-id]
145
+ * dom.findOneByData(document, 'user-id', '42') // element with [data-user-id="42"]
146
+ * dom.findOneByData(document, 'user-id', '99') // null
147
+ *
148
+ * @param {Element|Document|string} el - Reference element or selector (if used alone)
149
+ * @param {string} data - The data-* key without the "data-" prefix
150
+ * @param {string} [value] - Optional value to match exactly
151
+ * @returns {Element|null} The first matching element, or null if none found
152
+ */
153
+ findOneByData: function findOneByData(el, data, value) {
154
+ var _this$findByData$;
155
+ return (_this$findByData$ = this.findByData(el, data, value)[0]) !== null && _this$findByData$ !== void 0 ? _this$findByData$ : null;
156
+ },
157
+ /**
158
+ * Adds one or more CSS classes to one or multiple elements.
159
+ *
160
+ * Multiple classes can be provided as a space-separated string.
161
+ * Accepts a single Element, a NodeList, or an array of Elements.
162
+ *
163
+ * @example
164
+ * const el = document.querySelector('#box')
165
+ * dom.addClass(el, 'active')
166
+ *
167
+ * const items = document.querySelectorAll('.item')
168
+ * dom.addClass(items, 'selected active')
169
+ *
170
+ * @param {Element|NodeList|Element[]} el - Element(s) to update
171
+ * @param {string} className - One or more class names separated by spaces
172
+ * @returns {Element|NodeList|Element[]} The original input
130
173
  */
131
174
  addClass: function addClass(el, className) {
132
175
  if (!className) return el;
@@ -143,12 +186,24 @@ var dom = {
143
186
  return el;
144
187
  },
145
188
  /**
146
- * @param {Element|NodeList|Array<Element>} el
147
- * @param {string} className
148
- * @returns {Element|NodeList|Array<Element>}
189
+ * Removes one or more CSS classes from one or multiple elements.
190
+ *
191
+ * Multiple classes can be provided as a space-separated string.
192
+ * Accepts a single Element, a NodeList, or an array of Elements.
193
+ *
194
+ * @example
195
+ * const el = document.querySelector('#box')
196
+ * dom.removeClass(el, 'active')
197
+ *
198
+ * const items = document.querySelectorAll('.item')
199
+ * dom.removeClass(items, 'selected highlighted')
200
+ *
201
+ * @param {Element|NodeList|Array<Element>} el - Element(s) to update
202
+ * @param {string} className - One or more class names separated by spaces
203
+ * @returns {Element|NodeList|Array<Element>} The original input
149
204
  */
150
205
  removeClass: function removeClass(el, className) {
151
- if (!className) return;
206
+ if (!className) return el;
152
207
  var classNames = className.split(' ').map(function (c) {
153
208
  return c.trim();
154
209
  }).filter(Boolean);
@@ -162,10 +217,24 @@ var dom = {
162
217
  return el;
163
218
  },
164
219
  /**
165
- * @param {Element} el
166
- * @param {string} classNames
167
- * @param {boolean} [force]
168
- * @returns {Element}
220
+ * Toggles one or more CSS classes on an element.
221
+ *
222
+ * Multiple classes can be provided as a space-separated string.
223
+ * If `force` is provided, it explicitly adds (`true`) or removes (`false`)
224
+ * the class instead of toggling it.
225
+ *
226
+ * @example
227
+ * const el = document.querySelector('#box')
228
+ *
229
+ * dom.toggleClass(el, 'active') // toggles "active"
230
+ * dom.toggleClass(el, 'a b') // toggles both classes
231
+ * dom.toggleClass(el, 'active', true) // ensures "active" is present
232
+ * dom.toggleClass(el, 'active', false) // ensures "active" is removed
233
+ *
234
+ * @param {Element} el - Element to update
235
+ * @param {string} classNames - One or more class names separated by spaces
236
+ * @param {boolean} [force] - Optional force flag passed to classList.toggle
237
+ * @returns {Element} The element
169
238
  */
170
239
  toggleClass: function toggleClass(el, classNames, force) {
171
240
  foreach(classNames.split(' ').map(function (c) {
@@ -176,9 +245,22 @@ var dom = {
176
245
  return el;
177
246
  },
178
247
  /**
179
- * @param {Element} el
180
- * @param {string} classNames
181
- * @returns {boolean}
248
+ * Checks whether an element has all the given CSS classes.
249
+ *
250
+ * Multiple classes can be provided as a space-separated string.
251
+ * Returns `true` only if the element contains every class.
252
+ *
253
+ * @example
254
+ * // <div class="box active large"></div>
255
+ *
256
+ * dom.hasClass(el, 'active') // true
257
+ * dom.hasClass(el, 'active large') // true
258
+ * dom.hasClass(el, 'active missing') // false
259
+ * dom.hasClass(el, '') // false
260
+ *
261
+ * @param {Element} el - Element to test
262
+ * @param {string} classNames - One or more class names separated by spaces
263
+ * @returns {boolean} - `true` if the element has all the classes
182
264
  */
183
265
  hasClass: function hasClass(el, classNames) {
184
266
  if (!classNames) return false;
@@ -186,18 +268,25 @@ var dom = {
186
268
  foreach(classNames.split(' ').map(function (c) {
187
269
  return c.trim();
188
270
  }).filter(Boolean), function (c) {
189
- if (el.classList.contains(c)) {
190
- return true;
191
- }
271
+ if (inArray(c, Array.from(el.classList))) return;
192
272
  foundClasses = false;
193
273
  return false;
194
274
  });
195
275
  return foundClasses;
196
276
  },
197
277
  /**
198
- * @param {Node} node
199
- * @param {...(Node|string)} children
200
- * @returns {Node}
278
+ * Appends one or more children to a node.
279
+ *
280
+ * Children can be DOM nodes or HTML strings.
281
+ *
282
+ * @example
283
+ * const box = document.createElement('div')
284
+ * dom.append(box, document.createElement('span'))
285
+ * dom.append(box, '<b>Hello</b>', '<i>world</i>')
286
+ *
287
+ * @param {Node} node - The parent node
288
+ * @param {...(Node|string)} children - Nodes or HTML strings to append
289
+ * @returns {Node} The parent node
201
290
  */
202
291
  append: function append(node) {
203
292
  var _this = this;
@@ -213,9 +302,21 @@ var dom = {
213
302
  return node;
214
303
  },
215
304
  /**
216
- * @param {Node} node
217
- * @param {...(Node|string)} children
218
- * @returns {Node}
305
+ * Prepends one or more children to a node.
306
+ *
307
+ * Children can be DOM nodes or HTML strings.
308
+ * HTML strings are converted to nodes using `dom.create`.
309
+ * When multiple children are provided, their original order is preserved.
310
+ *
311
+ * @example
312
+ * const box = document.createElement('div')
313
+ *
314
+ * dom.prepend(box, document.createElement('span'))
315
+ * dom.prepend(box, '<b>Hello</b>', '<i>world</i>')
316
+ *
317
+ * @param {Node} node - The parent node
318
+ * @param {...(Node|string)} children - Nodes or HTML strings to prepend
319
+ * @returns {Node} - The parent node
219
320
  */
220
321
  prepend: function prepend(node) {
221
322
  var _this2 = this;
@@ -231,7 +332,7 @@ var dom = {
231
332
  return node;
232
333
  },
233
334
  /**
234
- * @param {Element|NodeList|Array<Element>|string} els
335
+ * @param {Element|NodeList|Element[]|string} els
235
336
  * @returns {void}
236
337
  */
237
338
  remove: function remove() {
@@ -252,9 +353,24 @@ var dom = {
252
353
  });
253
354
  },
254
355
  /**
255
- * @param {Element} el
256
- * @param {string|Element} [selector]
257
- * @returns {Element|null}
356
+ * Returns the closest ancestor of an element matching a selector or a specific element.
357
+ *
358
+ * If a DOM element is provided as `selector`, the function walks up the DOM
359
+ * tree and returns it if found among the ancestors (or the element itself).
360
+ * If a CSS selector string is provided, it delegates to `Element.closest()`.
361
+ * If `selector` is omitted, the element itself is returned.
362
+ *
363
+ * @example
364
+ * const item = document.querySelector('.item')
365
+ * const container = document.querySelector('.container')
366
+ *
367
+ * dom.closest(item, '.container') // container
368
+ * dom.closest(item, container) // container
369
+ * dom.closest(item) // item
370
+ *
371
+ * @param {Element} el - The starting element
372
+ * @param {string|Element} [selector] - CSS selector or specific ancestor element
373
+ * @returns {Element|null} - The matching ancestor, or null if none found
258
374
  */
259
375
  closest: function closest(el, selector) {
260
376
  if (selector instanceof Element) {
@@ -274,9 +390,22 @@ var dom = {
274
390
  return el.closest(selector);
275
391
  },
276
392
  /**
277
- * @param {Element} el
278
- * @param {string} [selector]
279
- * @returns {Element|null}
393
+ * Returns the next sibling element of a node.
394
+ *
395
+ * If a selector is provided, the next sibling is returned only if it matches
396
+ * the selector. This function does not search beyond the immediate sibling.
397
+ *
398
+ * @example
399
+ * // <div class="a"></div><div class="b"></div><div class="c"></div>
400
+ * const a = document.querySelector('.a')
401
+ *
402
+ * dom.next(a) // <div class="b">
403
+ * dom.next(a, '.b') // <div class="b">
404
+ * dom.next(a, '.c') // null
405
+ *
406
+ * @param {Element} el - Reference element
407
+ * @param {string|null} [selector] - CSS selector to filter the sibling
408
+ * @returns {Element|null} - The next sibling element, or null if not found/matching
280
409
  */
281
410
  next: function next(el) {
282
411
  var selector = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
@@ -288,9 +417,22 @@ var dom = {
288
417
  return null;
289
418
  },
290
419
  /**
291
- * @param {Element} el
292
- * @param {string|null} [selector]
293
- * @returns {Element|null}
420
+ * Returns the previous sibling element of a node.
421
+ *
422
+ * If a selector is provided, the previous sibling is returned only if it matches
423
+ * the selector. This function does not search beyond the immediate sibling.
424
+ *
425
+ * @example
426
+ * // <div class="a"></div><div class="b"></div><div class="c"></div>
427
+ * const c = document.querySelector('.c')
428
+ *
429
+ * dom.prev(c) // <div class="b">
430
+ * dom.prev(c, '.b') // <div class="b">
431
+ * dom.prev(c, '.a') // null
432
+ *
433
+ * @param {Element} el - Reference element
434
+ * @param {string|null} [selector] - CSS selector to filter the sibling
435
+ * @returns {Element|null} - The previous sibling element, or null if not found/matching
294
436
  */
295
437
  prev: function prev(el) {
296
438
  var selector = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
@@ -302,9 +444,21 @@ var dom = {
302
444
  return null;
303
445
  },
304
446
  /**
305
- * @param {Element} el
306
- * @param {string} [selector]
307
- * @returns {Element[]}
447
+ * Returns all following sibling elements of a node.
448
+ *
449
+ * If a selector is provided, only siblings matching the selector are included.
450
+ * Traversal continues through all next siblings in document order.
451
+ *
452
+ * @example
453
+ * // <div class="a"></div><div class="b"></div><div class="c"></div>
454
+ * const a = document.querySelector('.a')
455
+ *
456
+ * dom.nextAll(a) // [<div class="b">, <div class="c">]
457
+ * dom.nextAll(a, '.c') // [<div class="c">]
458
+ *
459
+ * @param {Element} el - Reference element
460
+ * @param {string} [selector] - CSS selector to filter siblings
461
+ * @returns {Element[]} - Array of matching following siblings
308
462
  */
309
463
  nextAll: function nextAll(el, selector) {
310
464
  var siblings = [];
@@ -318,9 +472,21 @@ var dom = {
318
472
  return siblings;
319
473
  },
320
474
  /**
321
- * @param {Element} el
322
- * @param {string} [selector]
323
- * @returns {Element[]}
475
+ * Returns all preceding sibling elements of a node.
476
+ *
477
+ * If a selector is provided, only siblings matching the selector are included.
478
+ * Traversal continues through all previous siblings in reverse document order.
479
+ *
480
+ * @example
481
+ * // <div class="a"></div><div class="b"></div><div class="c"></div>
482
+ * const c = document.querySelector('.c')
483
+ *
484
+ * dom.prevAll(c) // [<div class="b">, <div class="a">]
485
+ * dom.prevAll(c, '.a') // [<div class="a">]
486
+ *
487
+ * @param {Element} el - Reference element
488
+ * @param {string} [selector] - CSS selector to filter siblings
489
+ * @returns {Element[]} - Array of matching preceding siblings
324
490
  */
325
491
  prevAll: function prevAll(el, selector) {
326
492
  var siblings = [];
@@ -334,9 +500,42 @@ var dom = {
334
500
  return siblings;
335
501
  },
336
502
  /**
337
- * @param {Element} el
338
- * @param {Element|string} selector
339
- * @returns {Element[]}
503
+ * Returns the index of a node among its preceding siblings.
504
+ *
505
+ * If a selector is provided, only matching siblings are considered.
506
+ *
507
+ * @example
508
+ * // <div class="a"></div><div class="b"></div><div class="c"></div>
509
+ * const c = document.querySelector('.c')
510
+ *
511
+ * dom.index(a) // 0
512
+ * dom.index(c) // 2
513
+ * dom.prevAll(c, '.a') // 1
514
+ *
515
+ * @param {Element} el - Reference element
516
+ * @param {string} [selector] - CSS selector to filter siblings
517
+ * @returns {number} - The index of `el`
518
+ */
519
+ index: function index(el, selector) {
520
+ return this.prevAll(el, selector).length;
521
+ },
522
+ /**
523
+ * Returns all following sibling elements until a matching element is reached.
524
+ *
525
+ * Traversal stops before the first sibling that matches the given selector
526
+ * or equals the provided element. That matching element is not included.
527
+ *
528
+ * @example
529
+ * // <div class="a"></div><div class="b"></div><div class="c"></div><div class="d"></div>
530
+ * const a = document.querySelector('.a')
531
+ * const d = document.querySelector('.d')
532
+ *
533
+ * dom.nextUntil(a, '.d') // [<div class="b">, <div class="c">]
534
+ * dom.nextUntil(a, d) // [<div class="b">, <div class="c">]
535
+ *
536
+ * @param {Element} el - Reference element
537
+ * @param {Element|string} selector - CSS selector or element to stop at
538
+ * @returns {Element[]} - Array of siblings until the stop condition
340
539
  */
341
540
  nextUntil: function nextUntil(el, selector) {
342
541
  var selectorIsElement = false;
@@ -354,9 +553,23 @@ var dom = {
354
553
  return list;
355
554
  },
356
555
  /**
357
- * @param {Element} el
358
- * @param {Element|string} selector
359
- * @returns {Element[]}
556
+ * Returns all preceding sibling elements until a matching element is reached.
557
+ *
558
+ * Traversal stops before the first sibling that matches the given selector
559
+ * or equals the provided element. That matching element is not included.
560
+ *
561
+ * @example
562
+ * // <div class="a"></div><div class="b"></div><div class="c"></div><div class="d"></div>
563
+ *
564
+ * const d = document.querySelector('.d')
565
+ * const a = document.querySelector('.a')
566
+ *
567
+ * dom.prevUntil(d, '.a') // [<div class="c">, <div class="b">]
568
+ * dom.prevUntil(d, a) // [<div class="c">, <div class="b">]
569
+ *
570
+ * @param {Element} el - Reference element
571
+ * @param {Element|string} selector - CSS selector or element to stop at
572
+ * @returns {Element[]} - Array of siblings until the stop condition
360
573
  */
361
574
  prevUntil: function prevUntil(el, selector) {
362
575
  var selectorIsElement = false;
@@ -374,9 +587,22 @@ var dom = {
374
587
  return list;
375
588
  },
376
589
  /**
377
- * @param {Element} el
378
- * @param {Element} wrappingElement
379
- * @returns {Element}
590
+ * Wraps an element inside another element.
591
+ *
592
+ * If the wrapping element is not already in the DOM, it is inserted
593
+ * just before the target element. The target element is then appended
594
+ * inside the wrapper.
595
+ *
596
+ * @example
597
+ * const el = document.querySelector('.item')
598
+ * const wrapper = document.createElement('div')
599
+ *
600
+ * dom.wrap(el, wrapper)
601
+ * // <div><div class="item"></div></div>
602
+ *
603
+ * @param {Element} el - The element to wrap
604
+ * @param {Element} wrappingElement - The wrapper element
605
+ * @returns {Element} - The original wrapped element
380
606
  */
381
607
  wrap: function wrap(el, wrappingElement) {
382
608
  if (!wrappingElement.isConnected) {
@@ -386,10 +612,21 @@ var dom = {
386
612
  return el;
387
613
  },
388
614
  /**
389
- * @param {Element} el
390
- * @param {string} name
391
- * @param {*} [value]
392
- * @returns {Element|*}
615
+ * Gets, sets, or removes an attribute on an element.
616
+ *
617
+ * - If `value` is omitted, returns the attribute value (or null if not present).
618
+ * - If `value` is `null`, the attribute is removed.
619
+ * - Otherwise, the attribute is set to the provided value.
620
+ *
621
+ * @example
622
+ * dom.attr(el, 'id') // "my-id"
623
+ * dom.attr(el, 'title', 'Hello') // sets title="Hello"
624
+ * dom.attr(el, 'disabled', null) // removes the attribute
625
+ *
626
+ * @param {Element} el - Target element
627
+ * @param {string} name - Attribute name
628
+ * @param {string|null} [value] - Value to set, or null to remove
629
+ * @returns {Element|string|null} - The attribute value when reading, otherwise the element
393
630
  */
394
631
  attr: function attr(el, name, value) {
395
632
  if (undefined === value) return el.getAttribute(name);
@@ -401,10 +638,24 @@ var dom = {
401
638
  return el;
402
639
  },
403
640
  /**
404
- * @param {Element} el
405
- * @param {string} name
406
- * @param {*} [value]
407
- * @returns {*|Element}
641
+ * Gets or sets a property directly on a DOM element.
642
+ *
643
+ * Unlike `dom.attr`, this interacts with the live DOM property,
644
+ * not the HTML attribute.
645
+ *
646
+ * - If `value` is omitted, returns the property value.
647
+ * - Otherwise, sets the property.
648
+ *
649
+ * @example
650
+ * dom.prop(input, 'checked') // true/false
651
+ * dom.prop(input, 'checked', true) // checks the checkbox
652
+ *
653
+ * dom.prop(img, 'src') // full resolved URL
654
+ *
655
+ * @param {Element} el - Target element
656
+ * @param {string} name - Property name
657
+ * @param {any} [value] - Value to set
658
+ * @returns {*|Element} - The property value when reading, otherwise the element
408
659
  */
409
660
  prop: function prop(el, name, value) {
410
661
  if (undefined === value) {
@@ -414,9 +665,18 @@ var dom = {
414
665
  return el;
415
666
  },
416
667
  /**
417
- * @param {Element} el
418
- * @param {string} [html]
419
- * @returns {Element|string}
668
+ * Gets or sets the HTML content of an element.
669
+ *
670
+ * - If `html` is omitted, returns the element's current `innerHTML`.
671
+ * - Otherwise, replaces the element's content with the provided HTML string.
672
+ *
673
+ * @example
674
+ * dom.html(el) // "<span>Hello</span>"
675
+ * dom.html(el, '<b>Hi</b>') // sets inner HTML
676
+ *
677
+ * @param {Element} el - Target element
678
+ * @param {string} [html] - HTML string to set
679
+ * @returns {Element|string} The HTML string when reading, otherwise the element
420
680
  */
421
681
  html: function html(el, _html) {
422
682
  if (undefined === _html) return el.innerHTML;
@@ -424,9 +684,18 @@ var dom = {
424
684
  return el;
425
685
  },
426
686
  /**
427
- * @param {Element} el
428
- * @param {string} [text]
429
- * @returns {Element|string}
687
+ * Gets or sets the text content of an element.
688
+ *
689
+ * - If `text` is omitted, returns the element's visible text (`innerText`).
690
+ * - Otherwise, replaces the element's text content.
691
+ *
692
+ * @example
693
+ * dom.text(el) // "Hello world"
694
+ * dom.text(el, 'New text') // sets visible text content
695
+ *
696
+ * @param {Element} el - Target element
697
+ * @param {string} [text] - Text to set
698
+ * @returns {Element|string} - The text when reading, otherwise the element
430
699
  */
431
700
  text: function text(el, _text) {
432
701
  if (undefined === _text) return el.innerText;
@@ -434,20 +703,43 @@ var dom = {
434
703
  return el;
435
704
  },
436
705
  /**
437
- * @param {Element} el
438
- * @returns {Element}
706
+ * Hides an element by setting `display: none`, while preserving its original display value.
707
+ *
708
+ * The original computed `display` value is stored internally so it can be
709
+ * restored later (typically by the corresponding `show()` method).
710
+ *
711
+ * @example
712
+ * dom.hide(el) // element becomes hidden
713
+ *
714
+ * @param {Element} el - Element to hide
715
+ * @returns {Element} The element
439
716
  */
440
717
  hide: function hide(el) {
441
718
  if (undefined === this.data(el, '__display__')) {
442
- var display = getComputedStyle(el).display;
719
+ var display = '';
720
+ if (isFunction(window.getComputedStyle)) {
721
+ display = window.getComputedStyle(el).display;
722
+ } else {
723
+ display = el.style.display;
724
+ }
443
725
  this.data(el, '__display__', display);
444
726
  }
445
727
  el.style.display = 'none';
446
728
  return el;
447
729
  },
448
730
  /**
449
- * @param {Element} el
450
- * @returns {Element}
731
+ * Shows an element by restoring its original `display` value.
732
+ *
733
+ * If the element was previously hidden using `hide`, its original
734
+ * computed display value is restored. Otherwise, the inline `display`
735
+ * style is simply removed.
736
+ *
737
+ * @example
738
+ * dom.hide(el)
739
+ * dom.show(el) // element becomes visible again with its original display
740
+ *
741
+ * @param {Element} el - Element to show
742
+ * @returns {Element} - The element
451
743
  */
452
744
  show: function show(el) {
453
745
  var dataDisplay = this.data(el, '__display__');
@@ -460,17 +752,47 @@ var dom = {
460
752
  return el;
461
753
  },
462
754
  /**
463
- * @param {Element} el
464
- * @returns {Element}
755
+ * Toggles the visibility of an element using `dom.hide` and `dom.show`.
756
+ *
757
+ * The visibility state is determined from the computed display value,
758
+ * not only the inline style.
759
+ *
760
+ * @example
761
+ * dom.toggle(el) // hides if visible, shows if hidden
762
+ *
763
+ * @param {Element} el - Element to toggle
764
+ * @returns {Element} - The element
465
765
  */
466
766
  toggle: function toggle(el) {
467
- return 'none' === el.style.display ? this.show(el) : this.hide(el);
767
+ return 'none' === this.css(el, 'display') ? this.show(el) : this.hide(el);
468
768
  },
469
769
  /**
470
- * @param {Element} el
471
- * @param {Object<string, string>|string} name
472
- * @param {string} [value]
473
- * @returns {Element|DOMStringMap}
770
+ * Gets, sets, or removes data-* attributes on an element.
771
+ *
772
+ * - If called with no arguments, returns the element's `dataset`.
773
+ * - If `name` is an object, sets multiple data entries.
774
+ * - If `value` is omitted, returns the value of the data key.
775
+ * - If `value` is `null`, removes the data attribute.
776
+ * - Otherwise, sets the data value.
777
+ *
778
+ * Keys can be provided in camelCase (`userId`) or kebab-case with `data-` prefix (`data-user-id`).
779
+ *
780
+ * @example
781
+ * dom.data(el) // DOMStringMap of all data attributes
782
+ *
783
+ * dom.data(el, 'userId') // value of data-user-id
784
+ * dom.data(el, 'userId', '42') // sets data-user-id="42"
785
+ *
786
+ * dom.data(el, 'data-role', 'admin') // also works
787
+ *
788
+ * dom.data(el, { userId: '42', role: 'admin' }) // sets multiple values
789
+ *
790
+ * dom.data(el, 'userId', null) // removes data-user-id
791
+ *
792
+ * @param {Element} el - Target element
793
+ * @param {Object<string, string>|string} [name] - Data key or object of key/value pairs
794
+ * @param {string|null} [value] - Value to set, or null to remove
795
+ * @returns {Element|DOMStringMap|string|undefined} - Dataset, value, or element
474
796
  */
475
797
  data: function data(el, name, value) {
476
798
  var _this4 = this;
@@ -487,34 +809,69 @@ var dom = {
487
809
  var key = camelCase(isAttr ? (name + '').replace(/^data-/, '') : name + '');
488
810
  if (undefined === value) return el.dataset[key];
489
811
  if (null === value) {
490
- this.removeData(el, key);
812
+ delete el.dataset[key];
491
813
  return el;
492
814
  }
493
815
  el.dataset[key] = value;
494
816
  return el;
495
817
  },
496
818
  /**
497
- * @param {Element} el
498
- * @param {string} name
499
- * @returns {Element|*}
819
+ * Removes a data-* attribute from an element.
820
+ *
821
+ * The key can be provided in camelCase, kebab-case, or with the `data-` prefix.
822
+ *
823
+ * @example
824
+ * dom.removeData(el, 'userId') // removes data-user-id
825
+ * dom.removeData(el, 'user-id') // removes data-user-id
826
+ * dom.removeData(el, 'data-role') // removes data-role
827
+ *
828
+ * @param {Element} el - Target element
829
+ * @param {string} name - Data key to remove
830
+ * @returns {Element} - The element
500
831
  */
501
832
  removeData: function removeData(el, name) {
502
- var key = camelCase((name + '').replace(/^data-/, ''));
503
- delete el.dataset[key];
504
- return el;
833
+ return this.data(el, name, null);
505
834
  },
506
835
  /**
507
- * @param {HTMLElement} el
508
- * @param {Object<string, string>|string} style
509
- * @param {string} [value]
510
- * @returns {Element}
836
+ * Gets or sets CSS styles on an element.
837
+ *
838
+ * - If `style` is a string and `value` is omitted, returns the computed style value.
839
+ * - If `style` is a string and `value` is provided, sets the style.
840
+ * - If `style` is an object, sets multiple styles at once.
841
+ *
842
+ * handles :
843
+ * - camelCase and kebab-case properties
844
+ * - CSS custom properties (`--var`)
845
+ * - Adding `px` to numeric values where appropriate
846
+ *
847
+ * @example
848
+ * dom.css(el, 'color') // "rgb(255, 0, 0)"
849
+ * dom.css(el, 'background-color', 'blue')
850
+ * dom.css(el, 'width', 200) // sets "200px"
851
+ *
852
+ * dom.css(el, {
853
+ * width: 100,
854
+ * height: 50,
855
+ * backgroundColor: 'red'
856
+ * })
857
+ *
858
+ * dom.css(el, '--my-var', '10px') // CSS custom property
859
+ *
860
+ * @param {HTMLElement} el - Target element
861
+ * @param {Object<string, string|number>|string} style - CSS property or object of properties
862
+ * @param {string|number} [value] - Value to set
863
+ * @returns {Element|string} - The style value when reading, otherwise the element
511
864
  */
512
865
  css: function css(el, style, value) {
513
866
  var _this5 = this;
514
867
  if (isString(style)) {
515
868
  var prop = style.startsWith('--') ? style : camelCase(style);
516
869
  if (undefined === value) {
517
- return getStyle(el, prop);
870
+ if (window.getComputedStyle) {
871
+ var computedStyle = window.getComputedStyle(el, null);
872
+ return computedStyle.getPropertyValue(style) || computedStyle[camelCase(style)] || '';
873
+ }
874
+ return el.style[camelCase(style)] || '';
518
875
  }
519
876
  if (prop.startsWith('--')) {
520
877
  el.style.setProperty(prop, String(value));
@@ -530,10 +887,22 @@ var dom = {
530
887
  return el;
531
888
  },
532
889
  /**
533
- * @param {Element} el
534
- * @param {string} selectorClosest
535
- * @param {string} selectorFind
536
- * @returns {Array<Element>}
890
+ * Finds elements matching a selector inside the closest ancestor
891
+ * that matches another selector.
892
+ *
893
+ * First finds the closest ancestor of `el` matching `selectorClosest`,
894
+ * then searches inside it for elements matching `selectorFind`.
895
+ *
896
+ * @example
897
+ * // <div class="card"><button class="btn"></button><span class="label"></span></div>
898
+ *
899
+ * dom.closestFind(button, '.card', '.label')
900
+ * // => finds .label inside the closest .card ancestor
901
+ *
902
+ * @param {Element} el - Starting element
903
+ * @param {string} selectorClosest - Selector used to find the closest ancestor
904
+ * @param {string} selectorFind - Selector used to find elements inside that ancestor
905
+ * @returns {Element[]} - Array of matched elements, or empty array if none found
537
906
  */
538
907
  closestFind: function closestFind(el, selectorClosest, selectorFind) {
539
908
  var closest = this.closest(el, selectorClosest);
@@ -543,10 +912,22 @@ var dom = {
543
912
  return [];
544
913
  },
545
914
  /**
546
- * @param {Element} el
547
- * @param {string} selectorClosest
548
- * @param {string} selectorFindOne
549
- * @returns {Element|null}
915
+ * Finds the first element matching a selector inside the closest ancestor
916
+ * that matches another selector.
917
+ *
918
+ * First finds the closest ancestor of `el` matching `selectorClosest`,
919
+ * then searches inside it for the first element matching `selectorFindOne`.
920
+ *
921
+ * @example
922
+ * // <div class="card"><button class="btn"></button><span class="label"></span></div>
923
+ *
924
+ * dom.closestFindOne(button, '.card', '.label')
925
+ * // => finds the first .label inside the closest .card ancestor
926
+ *
927
+ * @param {Element} el - Starting element
928
+ * @param {string} selectorClosest - Selector used to find the closest ancestor
929
+ * @param {string} selectorFindOne - Selector used to find a single element inside that ancestor
930
+ * @returns {Element|null} - The matched element, or null if none found
550
931
  */
551
932
  closestFindOne: function closestFindOne(el, selectorClosest, selectorFindOne) {
552
933
  var closest = this.closest(el, selectorClosest);
@@ -556,8 +937,18 @@ var dom = {
556
937
  return null;
557
938
  },
558
939
  /**
559
- * @param {NodeList|Element|Array<Element>} nodeList
560
- * @returns {Element|null}
940
+ * Returns the first element from a collection or the element itself.
941
+ *
942
+ * Accepts a single Element, a NodeList, or an array of Elements.
943
+ * Returns `null` if the collection is empty.
944
+ *
945
+ * @example
946
+ * dom.first(document.querySelectorAll('.item')) // first .item
947
+ * dom.first([el1, el2]) // el1
948
+ * dom.first(el) // el
949
+ *
950
+ * @param {NodeList|Element|Element[]} nodeList - Collection or single element
951
+ * @returns {Element|null} - The first element, or null if none found
561
952
  */
562
953
  first: function first(nodeList) {
563
954
  var _Array$from$;
@@ -565,8 +956,17 @@ var dom = {
565
956
  return (_Array$from$ = Array.from(nodeList)[0]) !== null && _Array$from$ !== void 0 ? _Array$from$ : null;
566
957
  },
567
958
  /**
568
- * @param {NodeList|Array<Element>} nodeList
569
- * @returns {Element|null}
959
+ * Returns the last element from a collection or the element itself.
960
+ *
961
+ * Accepts a NodeList or an array of Elements.
962
+ * Returns `null` if the collection is empty.
963
+ *
964
+ * @example
965
+ * dom.last(document.querySelectorAll('.item')) // last .item
966
+ * dom.last([el1, el2]) // el2
967
+ *
968
+ * @param {NodeList|Element|Element[]} nodeList - Collection or single element
969
+ * @returns {Element|null} - The last element, or null if none found
570
970
  */
571
971
  last: function last(nodeList) {
572
972
  var _arr;
@@ -575,8 +975,20 @@ var dom = {
575
975
  return (_arr = arr[arr.length - 1]) !== null && _arr !== void 0 ? _arr : null;
576
976
  },
577
977
  /**
578
- * @param {string} html
579
- * @returns {Element|DocumentFragment|null}
978
+ * Creates DOM node(s) from a tag name or an HTML string.
979
+ *
980
+ * - If a simple tag name is provided (e.g. `"div"`), a new element is created.
981
+ * - If an HTML string is provided, it is parsed using a `<template>` element.
982
+ * - If the HTML contains a single root element, that element is returned.
983
+ * - If multiple root nodes are present, a `DocumentFragment` is returned.
984
+ *
985
+ * @example
986
+ * dom.create('div') // <div></div>
987
+ * dom.create('<span>Hello</span>') // <span>Hello</span>
988
+ * dom.create('<li>One</li><li>Two</li>') // DocumentFragment containing both <li>
989
+ *
990
+ * @param {string} html - Tag name or HTML string
991
+ * @returns {Element|DocumentFragment|null} - Created node(s), or null if input is invalid
580
992
  */
581
993
  create: function create(html) {
582
994
  if (!isString(html)) return null;
@@ -595,9 +1007,22 @@ var dom = {
595
1007
  return frag.cloneNode(true);
596
1008
  },
597
1009
  /**
598
- * @param {NodeList|Array<Element>} nodeList
599
- * @param {number} [index=0]
600
- * @returns {Element|null}
1010
+ * Returns the element at a given index from a collection.
1011
+ *
1012
+ * Supports negative indexes to count from the end of the list.
1013
+ * Returns `null` if the index is out of bounds.
1014
+ *
1015
+ * @example
1016
+ * const items = document.querySelectorAll('.item')
1017
+ *
1018
+ * dom.eq(items, 0) // first element
1019
+ * dom.eq(items, 2) // third element
1020
+ * dom.eq(items, -1) // last element
1021
+ * dom.eq(items, -2) // second to last
1022
+ *
1023
+ * @param {NodeList|Element[]} nodeList - Collection of elements
1024
+ * @param {number} [index=0] - Index of the element (can be negative)
1025
+ * @returns {Element|null} - The element at the given index, or null if not found
601
1026
  */
602
1027
  eq: function eq(nodeList) {
603
1028
  var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
@@ -609,9 +1034,18 @@ var dom = {
609
1034
  return nodeList[index];
610
1035
  },
611
1036
  /**
612
- * @param {Element} el
613
- * @param {Element|string} newEl
614
- * @returns {Element|null}
1037
+ * Inserts a new element or HTML string immediately after a reference element.
1038
+ *
1039
+ * If `newEl` is a string, it is converted to a node using `dom.create`.
1040
+ * Returns the inserted node, or `null` if the reference element has no parent.
1041
+ *
1042
+ * @example
1043
+ * dom.after(el, '<span>New</span>')
1044
+ * dom.after(el, document.createElement('div'))
1045
+ *
1046
+ * @param {Element} el - Reference element
1047
+ * @param {Element|string} newEl - Element or HTML string to insert
1048
+ * @returns {Element|DocumentFragment|null} - The inserted node, or null if insertion failed
615
1049
  */
616
1050
  after: function after(el, newEl) {
617
1051
  if (!el.parentElement) return null;
@@ -621,9 +1055,18 @@ var dom = {
621
1055
  return el.parentElement.insertBefore(newEl, el.nextElementSibling);
622
1056
  },
623
1057
  /**
624
- * @param {Element} el
625
- * @param {Element|string} newEl
626
- * @returns {Element|null}
1058
+ * Inserts a new element or HTML string immediately before a reference element.
1059
+ *
1060
+ * If `newEl` is a string, it is converted to a node using `dom.create`.
1061
+ * Returns the inserted node, or `null` if the reference element has no parent.
1062
+ *
1063
+ * @example
1064
+ * dom.before(el, '<span>New</span>')
1065
+ * dom.before(el, document.createElement('div'))
1066
+ *
1067
+ * @param {Element} el - Reference element
1068
+ * @param {Element|string} newEl - Element or HTML string to insert
1069
+ * @returns {Element|DocumentFragment|null} - The inserted node, or null if insertion failed
627
1070
  */
628
1071
  before: function before(el, newEl) {
629
1072
  if (!el.parentElement) return null;
@@ -633,8 +1076,13 @@ var dom = {
633
1076
  return el.parentElement.insertBefore(newEl, el);
634
1077
  },
635
1078
  /**
636
- * @param {Element} el
637
- * @returns {Element}
1079
+ * Removes all child nodes from an element.
1080
+ *
1081
+ * @example
1082
+ * dom.empty(el) // el now has no children
1083
+ *
1084
+ * @param {Element} el - Element to clear
1085
+ * @returns {Element} - The element
638
1086
  */
639
1087
  empty: function empty(el) {
640
1088
  while (el.firstChild) {
@@ -643,23 +1091,45 @@ var dom = {
643
1091
  return el;
644
1092
  },
645
1093
  /**
646
- * @param {Element|NodeList|Array<Element>} el
647
- * @param {string|Element} selector
648
- * @return {Array<Element>}
1094
+ * Filters a collection of elements by excluding those matching a selector
1095
+ * or a specific element.
1096
+ *
1097
+ * Accepts a single Element, a NodeList, or an array of Elements.
1098
+ * If `selector` is a string, elements matching it are excluded.
1099
+ * If `selector` is an Element, that exact element is excluded.
1100
+ *
1101
+ * @example
1102
+ * const items = document.querySelectorAll('.item')
1103
+ *
1104
+ * dom.not(items, '.active') // all .item elements except those with .active
1105
+ * dom.not(items, someElement) // all elements except that specific one
1106
+ *
1107
+ * dom.not(el, '.hidden') // returns [] if el matches, otherwise [el]
1108
+ *
1109
+ * @param {Element|NodeList|Element[]} el - Element(s) to filter
1110
+ * @param {string|Element} selector - CSS selector or element to exclude
1111
+ * @returns {Element[]} - Filtered array of elements
649
1112
  */
650
1113
  not: function not(el, selector) {
651
1114
  var elements = el instanceof Element ? [el] : Array.from(el);
652
1115
  var selectorIsString = isString(selector);
653
1116
  return elements.filter(function (e) {
654
- // if (!(e instanceof Element)) return false
655
-
656
1117
  return selectorIsString ? !e.matches(selector) : e !== selector;
657
1118
  });
658
1119
  },
659
1120
  /**
660
- * @param {Element} elem1
661
- * @param {Element} elem2
662
- * @returns {boolean}
1121
+ * Checks whether two elements visually collide (overlap) in the viewport.
1122
+ *
1123
+ * Returns `true` if their rectangles intersect.
1124
+ *
1125
+ * @example
1126
+ * if (dom.collide(box1, box2)) {
1127
+ * console.log('Elements overlap')
1128
+ * }
1129
+ *
1130
+ * @param {Element} elem1 - First element
1131
+ * @param {Element} elem2 - Second element
1132
+ * @returns {boolean} - `true` if the elements overlap, otherwise false
663
1133
  */
664
1134
  collide: function collide(elem1, elem2) {
665
1135
  var rect1 = elem1.getBoundingClientRect();
@@ -667,25 +1137,49 @@ var dom = {
667
1137
  return rect1.x < rect2.x + rect2.width && rect1.x + rect1.width > rect2.x && rect1.y < rect2.y + rect2.height && rect1.y + rect1.height > rect2.y;
668
1138
  },
669
1139
  /**
670
- * @param {Element} el
671
- * @param {string|Element} selector
1140
+ * Checks whether an element matches a selector or is equal to another element.
1141
+ *
1142
+ * If `selector` is a string, uses `Element.matches()`.
1143
+ * If `selector` is an Element, checks strict equality.
1144
+ *
1145
+ * @example
1146
+ * dom.matches(el, '.active') // true if el has class "active"
1147
+ * dom.matches(el, otherEl) // true if el === otherEl
1148
+ *
1149
+ * @param {Element} el - Element to test
1150
+ * @param {string|Element} selector - CSS selector or element to compare
1151
+ * @returns {boolean} - `true` if the element matches, otherwise false
672
1152
  */
673
1153
  matches: function matches(el, selector) {
674
1154
  if (!el) return false;
675
1155
  return selector instanceof Element ? selector === el : el.matches(selector);
676
1156
  },
677
1157
  /**
678
- * @param {Element} el
679
- * @param {Element} child
680
- * @param {Element} oldChild
1158
+ * Replaces a child node of an element with another node.
1159
+ *
1160
+ * @example
1161
+ * dom.replaceChild(parent, newEl, oldEl)
1162
+ *
1163
+ * @param {Element} el - Parent element
1164
+ * @param {Element} child - New child node
1165
+ * @param {Element} oldChild - Existing child node to replace
1166
+ * @returns {Element} - The replaced node
681
1167
  */
682
1168
  replaceChild: function replaceChild(el, child, oldChild) {
683
1169
  return el.replaceChild(child, oldChild);
684
1170
  },
685
1171
  /**
686
- * @param {Element} el
687
- * @param {NodeList|Array<Element>|string[]} children
688
- * @returns {Element}
1172
+ * Replaces all children of an element with new nodes or HTML strings.
1173
+ *
1174
+ * Strings are converted to DOM nodes using `dom.create`.
1175
+ *
1176
+ * @example
1177
+ * dom.replaceChildren(el, '<span>A</span>', '<span>B</span>')
1178
+ * dom.replaceChildren(el, document.createElement('div'))
1179
+ *
1180
+ * @param {Element} el - Target element
1181
+ * @param {...(Element|string)} children - New children to insert
1182
+ * @returns {Element} - The element
689
1183
  */
690
1184
  replaceChildren: function replaceChildren(el) {
691
1185
  var _this6 = this;
@@ -703,8 +1197,19 @@ var dom = {
703
1197
  return el;
704
1198
  },
705
1199
  /**
706
- * @param {Element|Document|Window} el
707
- * @returns {{top: number, left: number}}
1200
+ * Returns the page offset of an element, document, or window.
1201
+ *
1202
+ * - For `window`, returns the current scroll position.
1203
+ * - For `document`, returns the scroll position of the root element.
1204
+ * - For an element, returns its position relative to the top-left of the page.
1205
+ *
1206
+ * @example
1207
+ * dom.offset(window) // { top: scrollY, left: scrollX }
1208
+ * dom.offset(document) // { top: scrollTop, left: scrollLeft }
1209
+ * dom.offset(el) // position of el relative to the page
1210
+ *
1211
+ * @param {Element|Document|Window} el - Target element, document, or window
1212
+ * @returns {{top: number, left: number}} - The offset relative to the page
708
1213
  */
709
1214
  offset: function offset(el) {
710
1215
  if (isWindow(el)) {
@@ -726,8 +1231,24 @@ var dom = {
726
1231
  };
727
1232
  },
728
1233
  /**
729
- * @param {Node} el
730
- * @returns {boolean}
1234
+ * Checks whether a node is inside an editable context.
1235
+ *
1236
+ * Returns true if the element itself, or one of its ancestors,
1237
+ * is an editable form control or has `contenteditable="true"`.
1238
+ * Text nodes are automatically resolved to their parent element.
1239
+ *
1240
+ * @example
1241
+ * dom.isEditable(inputEl) // true
1242
+ * dom.isEditable(textareaEl) // true
1243
+ * dom.isEditable(selectEl) // true
1244
+ *
1245
+ * dom.isEditable(divWithContentEditable) // true
1246
+ * dom.isEditable(spanInsideContentEditable) // true
1247
+ *
1248
+ * dom.isEditable(document.body) // false
1249
+ *
1250
+ * @param {Node} el - Node to test
1251
+ * @returns {boolean} True if the node is in an editable context
731
1252
  */
732
1253
  isEditable: function isEditable(el) {
733
1254
  var _el;
@@ -736,8 +1257,16 @@ var dom = {
736
1257
  return inArray(el.tagName, ['INPUT', 'TEXTAREA', 'SELECT']) || el.isContentEditable || !!this.closest(el, '[contenteditable="true"]');
737
1258
  },
738
1259
  /**
739
- * @param {Node} node
740
- * @returns {boolean}
1260
+ * Checks whether a node is currently attached to the main document.
1261
+ *
1262
+ * @example
1263
+ * dom.isInDOM(el) // true if element is in the document
1264
+ *
1265
+ * const frag = document.createDocumentFragment()
1266
+ * dom.isInDOM(frag) // false
1267
+ *
1268
+ * @param {Node} node - Node to test
1269
+ * @returns {boolean} - `true` if the node is attached to the document
741
1270
  */
742
1271
  isInDOM: function isInDOM(node) {
743
1272
  if (!(node instanceof Node)) return false;
@@ -746,7 +1275,82 @@ var dom = {
746
1275
  });
747
1276
  return root === document;
748
1277
  },
1278
+ /**
1279
+ * Attaches one or more event listeners to an element, document, or window.
1280
+ *
1281
+ * Supports:
1282
+ * - Multiple events (space-separated)
1283
+ * - Event namespaces (e.g. "click.menu")
1284
+ * - Event delegation via CSS selector
1285
+ * - Custom events
1286
+ *
1287
+ * Custom Events :
1288
+ *
1289
+ * The following custom events are available:
1290
+ *
1291
+ * `longtap`
1292
+ * Fired when the user presses and holds on an element for a short duration
1293
+ * (useful for touch interfaces and long-press interactions).
1294
+ *
1295
+ * `dbltap`
1296
+ * Fired when the user performs a quick double tap on touch devices.
1297
+ *
1298
+ * These events are automatically enabled the first time they are used.
1299
+ *
1300
+ * @example
1301
+ * // Simple binding
1302
+ * dom.on(button, 'click', (ev) => {})
1303
+ *
1304
+ * // Multiple events
1305
+ * dom.on(input, 'focus blur', handler)
1306
+ *
1307
+ * // Namespaced event
1308
+ * dom.on(button, 'click.menu', handler)
1309
+ *
1310
+ * // Delegated event
1311
+ * dom.on(list, 'click', '.item', (ev) => {})
1312
+ *
1313
+ * // With options
1314
+ * dom.on(window, 'scroll', handler, { passive: true })
1315
+ *
1316
+ * @example
1317
+ * dom.on(el, 'longtap', handler)
1318
+ * dom.on(el, 'dbltap', handler)
1319
+ *
1320
+ * @param {Element|Document|Window} el - Element to bind the listener to
1321
+ * @param {string} events - Space-separated list of events (optionally namespaced)
1322
+ * @param {string|function} [selector] - CSS selector for delegation, or handler if no delegation
1323
+ * @param {function|AddEventListenerOptions|boolean} [handler] - Event handler
1324
+ * @param {AddEventListenerOptions|boolean} [options] - Native event listener options
1325
+ * @returns {Element} - The element
1326
+ */
749
1327
  on: on,
1328
+ /**
1329
+ * Removes event listeners previously attached with `dom.on`.
1330
+ *
1331
+ * You can remove listeners by:
1332
+ * - Event type
1333
+ * - Namespace
1334
+ * - Handler reference
1335
+ * - Selector (for delegated events)
1336
+ * - Options
1337
+ *
1338
+ * If no event is provided, all listeners on the element are removed.
1339
+ *
1340
+ * @example
1341
+ * dom.off(button, 'click')
1342
+ * dom.off(button, 'click.menu')
1343
+ * dom.off(button, 'click', handler)
1344
+ * dom.off(list, 'click', '.item', handler)
1345
+ * dom.off(button) // removes all listeners
1346
+ *
1347
+ * @param {Element|Document|Window} el - Element to unbind listeners from
1348
+ * @param {string} [events] - Space-separated events (optionally namespaced)
1349
+ * @param {string|function} [selector] - Delegation selector or handler
1350
+ * @param {function|AddEventListenerOptions|boolean} [handler] - Specific handler to remove
1351
+ * @param {AddEventListenerOptions|boolean} [options] - Listener options to match
1352
+ * @returns {Element} - The element
1353
+ */
750
1354
  off: off
751
1355
  };
752
1356
 
@@ -756,4 +1360,10 @@ if ('test' === process.env.NODE_ENV) {
756
1360
  __resetCustomEventsForTests();
757
1361
  };
758
1362
  }
759
- export default dom;
1363
+ export default dom;
1364
+
1365
+ /* istanbul ignore next */
1366
+ if ('undefined' !== typeof window) {
1367
+ window.webf = window.webf || {};
1368
+ window.webf.dom = dom;
1369
+ }