@splendidlabz/utils 1.10.0 → 1.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/dom/events.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * @typedef {Object} EventListener
3
3
  * @property {Element} node - The DOM element to attach the event listener to
4
4
  * @property {string} event - The event type (e.g., 'click', 'keydown')
5
- * @property {Function} handler - The event handler function
5
+ * @property {EventListenerOrEventListenerObject} handler - The event handler function
6
6
  */
7
7
 
8
8
  /**
@@ -1,4 +1,4 @@
1
- import { splitUnit } from '../lib/index.js'
1
+ import { splitUnit } from '../lib/numbers/index.js'
2
2
 
3
3
  export function getUnit(value) {
4
4
  const [, unit] = splitUnit(value)
@@ -5,8 +5,8 @@ import { useObserverMethodOnTarget } from './observer.js'
5
5
  /**
6
6
  * Creates and manages a ResizeObserver instance to monitor size changes of a target element.
7
7
  *
8
- * @param {Element|Window|NodeList|Element[]} target - The element(s) to observe.
9
- * - If window is provided, document.body will be observed instead.
8
+ * @param {Element|Window|Document|NodeList|Element[]} target - The element(s) to observe.
9
+ * - If window or document is provided, document.documentElement will be observed instead.
10
10
  * - If NodeList or Array of elements is provided, all elements will be observed.
11
11
  * @param {Object} options - Configuration options for the resize observer
12
12
  * @param {boolean} [options.observe=true] - Whether to start observing immediately. If false, the observer won't be created.
@@ -39,13 +39,15 @@ export function resizeObserver(target, options) {
39
39
  const { callback, ...opts } = options
40
40
  const observer = new ResizeObserver(observerFn)
41
41
 
42
- if (target === window) target = document.body
42
+ if (target === window || target === document)
43
+ target = document.documentElement
43
44
  useObserverMethodOnTarget(target, observer, 'observe', opts)
44
45
 
45
46
  function observerFn(entries) {
46
47
  for (const entry of entries) {
47
48
  if (callback) callback({ entry, entries, observer })
48
- else dispatchEvent(target, 'resize-obs', { entry, entries, observer })
49
+ else
50
+ dispatchEvent(entry.target, 'resize-obs', { entry, entries, observer })
49
51
  }
50
52
  }
51
53
 
@@ -18,9 +18,24 @@ const defaultOptions = {
18
18
  * @property {Function} [onEnterThreshold] - Called when entering threshold zone
19
19
  */
20
20
 
21
+ /**
22
+ * @param {Element | Document | Window} node
23
+ * @returns {Element}
24
+ */
25
+ function getScrollElement(node) {
26
+ if (
27
+ node === document ||
28
+ node === window ||
29
+ node === document.documentElement
30
+ ) {
31
+ return document.documentElement
32
+ }
33
+ return /** @type {Element} */ (node)
34
+ }
35
+
21
36
  /**
22
37
  * Scroll Observer - Optimized for performance
23
- * @param {Element} node - The element to observe scroll events on
38
+ * @param {Element | Document | Window} node - The element to observe scroll events on
24
39
  * @param {ScrollObserverOptions} [options] - Configuration options
25
40
  */
26
41
  export function scrollObserver(node, options = {}) {
@@ -38,7 +53,7 @@ export function scrollObserver(node, options = {}) {
38
53
  // Determine scroll context once at initialization
39
54
  const isDocumentScroll =
40
55
  node === document || node === window || node === document.documentElement
41
- const scrollElement = isDocumentScroll ? document.documentElement : node
56
+ const scrollElement = getScrollElement(node)
42
57
  const eventTarget = isDocumentScroll ? window : node
43
58
 
44
59
  // Cache DOM references and expensive calculations
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Enhances a form element with spam detection capabilities
3
3
  * @param {HTMLFormElement} form - The form element to enhance
4
- * @param {Object} options - Configuration options
5
- * @param {string} options.honeypotField - Name of the honeypot field (default: 'hp')
6
- * @param {number} options.honeypotDuration - Minimum time in ms for legitimate form fill (default: 2000)
7
- * @returns {Function} Cleanup function to remove listeners and method
4
+ * @param {Object} [options] - Configuration options
5
+ * @param {string} [options.honeypotField] - Name of the honeypot field (default: 'hp')
6
+ * @param {number} [options.honeypotDuration] - Minimum time in ms for legitimate form fill (default: 2000)
7
+ * @returns {void}
8
8
  */
9
9
  export function preventSpam(
10
10
  form,
@@ -25,6 +25,7 @@ export function preventSpam(
25
25
  form.containsSpam = function () {
26
26
  const fillTime = Date.now() - startTime
27
27
  const isTooFast = fillTime < honeypotDuration
28
+ /** @type {HTMLInputElement | null} */
28
29
  const honeypotInput = form.querySelector(`[name="${honeypotField}"]`)
29
30
  const hasHoneypotValue = honeypotInput?.value?.trim()
30
31
  const noInteraction = !hasInteraction
@@ -1,99 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { describe, expect, it } from 'vitest'
3
-
4
- import { createListeners } from './events.js'
5
-
6
- describe('Listeners Factory', _ => {
7
- it('Empty', _ => {
8
- const listeners = createListeners()
9
- expect(listeners.list).toEqual([])
10
- })
11
-
12
- it('Begins with some listeners', _ => {
13
- const node1 = document.createElement('div')
14
- const node2 = document.createElement('p')
15
- const event1 = 'click'
16
- const event2 = 'keydown'
17
- const cb1 = _ => {}
18
- const cb2 = _ => {}
19
-
20
- const listeners = createListeners([
21
- { node: node1, event: event1, handler: cb1 },
22
- { node: node2, event: event2, handler: cb2 },
23
- ])
24
-
25
- expect(listeners.list).toEqual([
26
- { node: node1, event: event1, handler: cb1 },
27
- { node: node2, event: event2, handler: cb2 },
28
- ])
29
- })
30
-
31
- it('Add', _ => {
32
- const node = document.createElement('div')
33
- const event = 'click'
34
- const handler = _ => {
35
- node.setAttribute('clicked', true)
36
- }
37
-
38
- const listeners = createListeners()
39
- listeners.add({ node, event, handler })
40
-
41
- // Ensures the listener was added to the list
42
- expect(listeners.list.length).toBe(1)
43
-
44
- // Ensures the listener works
45
- node.click()
46
- expect(node.getAttribute('clicked')).toBe('true')
47
- })
48
-
49
- it('Remove', _ => {
50
- const node = document.createElement('div')
51
- const event = 'click'
52
- const handler = _ => {
53
- const count = node.getAttribute('count') || 0
54
- node.setAttribute('count', count + 1)
55
- }
56
-
57
- const listener = { node, event, handler }
58
- const listeners = createListeners([listener])
59
-
60
- node.click()
61
- expect(node.getAttribute('count')).toBe('1')
62
-
63
- listeners.remove(listener)
64
-
65
- // Ensures listener has been removed
66
- node.click()
67
-
68
- expect(listeners.list.length).toBe(0)
69
- expect(node.getAttribute('count')).toBe('1')
70
- })
71
-
72
- it('Clears all listeners from', _ => {
73
- const node1 = document.createElement('div')
74
- const node2 = document.createElement('p')
75
- const event1 = 'click'
76
- const event2 = 'click'
77
- const cb1 = _ => {
78
- node1.setAttribute('clicked', true)
79
- }
80
- const cb2 = _ => {
81
- node2.setAttribute('clicked', true)
82
- }
83
-
84
- const listeners = createListeners([
85
- { node: node1, event: event1, handler: cb1 },
86
- { node: node2, event: event2, handler: cb2 },
87
- ])
88
-
89
- listeners.clear()
90
- expect(listeners.list).toEqual([])
91
-
92
- // Ensures none of the listeners work anymore
93
- node1.click()
94
- node2.click()
95
-
96
- expect(node1.getAttribute('clicked')).toBe(null)
97
- expect(node2.getAttribute('clicked')).toBe(null)
98
- })
99
- })