@splendidlabz/utils 1.9.1 → 1.10.1

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 (35) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cjs/dom/actions/index.cjs +75 -73
  3. package/dist/cjs/dom/actions/masonry.cjs +4 -2
  4. package/dist/cjs/dom/actions/prefer-horizontal-scroll.cjs +24 -24
  5. package/dist/cjs/dom/actions/sticky.cjs +4 -2
  6. package/dist/cjs/dom/font-size.cjs +9 -3
  7. package/dist/cjs/dom/index.cjs +81 -66
  8. package/dist/cjs/dom/observers/index.cjs +24 -17
  9. package/dist/cjs/dom/observers/resize-observer.cjs +4 -2
  10. package/dist/cjs/dom/observers/scroll-observer.cjs +24 -17
  11. package/dist/esm/dom/actions/index.js +75 -73
  12. package/dist/esm/dom/actions/masonry.js +4 -2
  13. package/dist/esm/dom/actions/prefer-horizontal-scroll.js +24 -24
  14. package/dist/esm/dom/actions/sticky.js +4 -2
  15. package/dist/esm/dom/font-size.js +8 -3
  16. package/dist/esm/dom/index.js +80 -66
  17. package/dist/esm/dom/observers/index.js +24 -17
  18. package/dist/esm/dom/observers/resize-observer.js +4 -2
  19. package/dist/esm/dom/observers/scroll-observer.js +24 -17
  20. package/dist/types/dom/events.d.cts +2 -2
  21. package/dist/types/dom/font-size.d.cts +3 -2
  22. package/dist/types/dom/index.d.cts +2 -2
  23. package/dist/types/dom/observers/index.d.cts +1 -1
  24. package/dist/types/dom/observers/resize-observer.d.cts +3 -3
  25. package/dist/types/dom/observers/scroll-observer.d.cts +34 -21
  26. package/dist/types/dom/spam-prevention.d.cts +7 -7
  27. package/dist/types/lib/checks.d.cts +1 -1
  28. package/package.json +1 -1
  29. package/src/dom/actions/prefer-horizontal-scroll.js +3 -8
  30. package/src/dom/events.js +1 -1
  31. package/src/dom/font-size.js +9 -4
  32. package/src/dom/observers/resize-observer.js +6 -4
  33. package/src/dom/observers/scroll-observer.js +41 -27
  34. package/src/dom/spam-prevention.js +5 -4
  35. package/src/dom/events.test.js +0 -99
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @splendidlabz/utils
2
2
 
3
+ ## 1.10.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Fix circular references and typescript errors
8
+
9
+ ## 1.10.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 4efacb3: - 6c636877 fix scroll observer
14
+ - 54effb06 add rlh
15
+
3
16
  ## 1.9.1
4
17
 
5
18
  ### Patch Changes
@@ -108,12 +108,14 @@ function useObserverMethodOnTarget(target, observer, method = "observe", options
108
108
  function resizeObserver(target, options) {
109
109
  const { callback, ...opts } = options;
110
110
  const observer = new ResizeObserver(observerFn);
111
- if (target === window) target = document.body;
111
+ if (target === window || target === document)
112
+ target = document.documentElement;
112
113
  useObserverMethodOnTarget(target, observer, "observe", opts);
113
114
  function observerFn(entries) {
114
115
  for (const entry of entries) {
115
116
  if (callback) callback({ entry, entries, observer });
116
- else dispatchEvent(target, "resize-obs", { entry, entries, observer });
117
+ else
118
+ dispatchEvent(entry.target, "resize-obs", { entry, entries, observer });
117
119
  }
118
120
  }
119
121
  return {
@@ -161,58 +163,6 @@ function nativeMasonrySupport(node) {
161
163
  return getComputedStyle(node).gridTemplateRows === "masonry";
162
164
  }
163
165
 
164
- // src/dom/bounding-box.js
165
- function boundingBox(element, { containsPadding = true } = {}) {
166
- const box = element.getBoundingClientRect();
167
- const ret = {};
168
- for (const prop in box) ret[prop] = box[prop];
169
- if (!containsPadding) {
170
- const style = getComputedStyle(element);
171
- const paddingTop = parseFloat(style.paddingTop);
172
- const paddingRight = parseFloat(style.paddingRight);
173
- const paddingBottom = parseFloat(style.paddingBottom);
174
- const paddingLeft = parseFloat(style.paddingLeft);
175
- ret.x = ret.x + paddingLeft;
176
- ret.y = ret.y + paddingTop;
177
- ret.width = ret.width - paddingLeft - paddingRight;
178
- ret.height = ret.height - paddingTop - paddingBottom;
179
- ret.top = ret.top + paddingTop;
180
- ret.bottom = ret.bottom - paddingBottom;
181
- ret.right = ret.right - paddingRight;
182
- ret.left = ret.left + paddingLeft;
183
- }
184
- ret.xCenter = (ret.left + ret.right) / 2;
185
- ret.yCenter = (ret.top + ret.bottom) / 2;
186
- return ret;
187
- }
188
- function boundingBoxRelativeToAncestor({ element, ancestorElement }) {
189
- ancestorElement = ancestorElement || element.parentElement;
190
- const box = boundingBox(element);
191
- const ancestorBox = boundingBox(ancestorElement, {
192
- containsPadding: false
193
- });
194
- return {
195
- top: box.top - ancestorBox.top,
196
- right: box.right - ancestorBox.right,
197
- bottom: box.bottom - ancestorBox.bottom,
198
- left: box.left - ancestorBox.left,
199
- width: box.width,
200
- height: box.height,
201
- xCenter: (box.left + box.right) / 2 - ancestorBox.left,
202
- yCenter: (box.top + box.bottom) / 2 - ancestorBox.top
203
- };
204
- }
205
-
206
- // src/dom/css-vars.js
207
- function getCSSVar(element, prop) {
208
- element = getElement(element);
209
- return getComputedStyle(element).getPropertyValue(prop);
210
- }
211
- function setCSSVar(element, prop, value) {
212
- element = getElement(element);
213
- element.style.setProperty(prop, value);
214
- }
215
-
216
166
  // src/lib/objects/omit-empty.js
217
167
  function omitEmpty(obj, shallow = false) {
218
168
  if (typeof obj !== "object" || obj === null) return obj;
@@ -227,25 +177,14 @@ function omitEmpty(obj, shallow = false) {
227
177
  return result;
228
178
  }
229
179
 
230
- // src/dom/ui/scroll-container.js
231
- function findScrollContainer(element, direction = "both") {
232
- if (!element) return;
233
- let parent = element.parentElement;
234
- while (parent) {
235
- const { overflow, overflowX, overflowY } = getComputedStyle(parent);
236
- if (direction === "both") {
237
- if (overflow.includes("auto") || overflow.includes("scroll"))
238
- return parent;
239
- }
240
- if (direction === "horizontal") {
241
- if (overflowX === "auto" || overflowX === "scroll") return parent;
242
- }
243
- if (direction === "vertical") {
244
- if (overflowY === "auto" || overflowY === "scroll") return parent;
245
- }
246
- parent = parent.parentElement;
247
- }
248
- return document.documentElement;
180
+ // src/dom/css-vars.js
181
+ function getCSSVar(element, prop) {
182
+ element = getElement(element);
183
+ return getComputedStyle(element).getPropertyValue(prop);
184
+ }
185
+ function setCSSVar(element, prop, value) {
186
+ element = getElement(element);
187
+ element.style.setProperty(prop, value);
249
188
  }
250
189
 
251
190
  // src/dom/actions/prefer-horizontal-scroll.js
@@ -334,6 +273,69 @@ function isTrackpad(event) {
334
273
  if (event.wheelDeltaY === event.deltaY * -3) return true;
335
274
  }
336
275
 
276
+ // src/dom/bounding-box.js
277
+ function boundingBox(element, { containsPadding = true } = {}) {
278
+ const box = element.getBoundingClientRect();
279
+ const ret = {};
280
+ for (const prop in box) ret[prop] = box[prop];
281
+ if (!containsPadding) {
282
+ const style = getComputedStyle(element);
283
+ const paddingTop = parseFloat(style.paddingTop);
284
+ const paddingRight = parseFloat(style.paddingRight);
285
+ const paddingBottom = parseFloat(style.paddingBottom);
286
+ const paddingLeft = parseFloat(style.paddingLeft);
287
+ ret.x = ret.x + paddingLeft;
288
+ ret.y = ret.y + paddingTop;
289
+ ret.width = ret.width - paddingLeft - paddingRight;
290
+ ret.height = ret.height - paddingTop - paddingBottom;
291
+ ret.top = ret.top + paddingTop;
292
+ ret.bottom = ret.bottom - paddingBottom;
293
+ ret.right = ret.right - paddingRight;
294
+ ret.left = ret.left + paddingLeft;
295
+ }
296
+ ret.xCenter = (ret.left + ret.right) / 2;
297
+ ret.yCenter = (ret.top + ret.bottom) / 2;
298
+ return ret;
299
+ }
300
+ function boundingBoxRelativeToAncestor({ element, ancestorElement }) {
301
+ ancestorElement = ancestorElement || element.parentElement;
302
+ const box = boundingBox(element);
303
+ const ancestorBox = boundingBox(ancestorElement, {
304
+ containsPadding: false
305
+ });
306
+ return {
307
+ top: box.top - ancestorBox.top,
308
+ right: box.right - ancestorBox.right,
309
+ bottom: box.bottom - ancestorBox.bottom,
310
+ left: box.left - ancestorBox.left,
311
+ width: box.width,
312
+ height: box.height,
313
+ xCenter: (box.left + box.right) / 2 - ancestorBox.left,
314
+ yCenter: (box.top + box.bottom) / 2 - ancestorBox.top
315
+ };
316
+ }
317
+
318
+ // src/dom/ui/scroll-container.js
319
+ function findScrollContainer(element, direction = "both") {
320
+ if (!element) return;
321
+ let parent = element.parentElement;
322
+ while (parent) {
323
+ const { overflow, overflowX, overflowY } = getComputedStyle(parent);
324
+ if (direction === "both") {
325
+ if (overflow.includes("auto") || overflow.includes("scroll"))
326
+ return parent;
327
+ }
328
+ if (direction === "horizontal") {
329
+ if (overflowX === "auto" || overflowX === "scroll") return parent;
330
+ }
331
+ if (direction === "vertical") {
332
+ if (overflowY === "auto" || overflowY === "scroll") return parent;
333
+ }
334
+ parent = parent.parentElement;
335
+ }
336
+ return document.documentElement;
337
+ }
338
+
337
339
  // src/dom/actions/sticky.js
338
340
  function sticky(node, props = {}) {
339
341
  const scrollContainer = findScrollContainer(node);
@@ -91,12 +91,14 @@ function useObserverMethodOnTarget(target, observer, method = "observe", options
91
91
  function resizeObserver(target, options) {
92
92
  const { callback, ...opts } = options;
93
93
  const observer = new ResizeObserver(observerFn);
94
- if (target === window) target = document.body;
94
+ if (target === window || target === document)
95
+ target = document.documentElement;
95
96
  useObserverMethodOnTarget(target, observer, "observe", opts);
96
97
  function observerFn(entries) {
97
98
  for (const entry of entries) {
98
99
  if (callback) callback({ entry, entries, observer });
99
- else dispatchEvent(target, "resize-obs", { entry, entries, observer });
100
+ else
101
+ dispatchEvent(entry.target, "resize-obs", { entry, entries, observer });
100
102
  }
101
103
  }
102
104
  return {
@@ -23,6 +23,20 @@ __export(prefer_horizontal_scroll_exports, {
23
23
  });
24
24
  module.exports = __toCommonJS(prefer_horizontal_scroll_exports);
25
25
 
26
+ // src/lib/objects/omit-empty.js
27
+ function omitEmpty(obj, shallow = false) {
28
+ if (typeof obj !== "object" || obj === null) return obj;
29
+ if (obj instanceof Date) return obj;
30
+ const result = Array.isArray(obj) ? [] : {};
31
+ for (const [key, value] of Object.entries(obj)) {
32
+ if (value === null || value === void 0 || value === "" || typeof value === "object" && !(value instanceof Date) && Object.keys(value).length === 0) {
33
+ continue;
34
+ }
35
+ result[key] = shallow ? value : omitEmpty(value);
36
+ }
37
+ return result;
38
+ }
39
+
26
40
  // src/dom/get-element.js
27
41
  function getElement(selector) {
28
42
  if (!selector) return;
@@ -30,18 +44,6 @@ function getElement(selector) {
30
44
  return document.querySelector(selector);
31
45
  }
32
46
 
33
- // src/dom/events.js
34
- function addListeners(listeners) {
35
- listeners.forEach(({ node, event, handler }) => {
36
- node.addEventListener(event, handler);
37
- });
38
- }
39
- function removeListeners(listeners) {
40
- listeners.forEach(({ node, event, handler }) => {
41
- node.removeEventListener(event, handler);
42
- });
43
- }
44
-
45
47
  // src/dom/css-vars.js
46
48
  function getCSSVar(element, prop) {
47
49
  element = getElement(element);
@@ -52,18 +54,16 @@ function setCSSVar(element, prop, value) {
52
54
  element.style.setProperty(prop, value);
53
55
  }
54
56
 
55
- // src/lib/objects/omit-empty.js
56
- function omitEmpty(obj, shallow = false) {
57
- if (typeof obj !== "object" || obj === null) return obj;
58
- if (obj instanceof Date) return obj;
59
- const result = Array.isArray(obj) ? [] : {};
60
- for (const [key, value] of Object.entries(obj)) {
61
- if (value === null || value === void 0 || value === "" || typeof value === "object" && !(value instanceof Date) && Object.keys(value).length === 0) {
62
- continue;
63
- }
64
- result[key] = shallow ? value : omitEmpty(value);
65
- }
66
- return result;
57
+ // src/dom/events.js
58
+ function addListeners(listeners) {
59
+ listeners.forEach(({ node, event, handler }) => {
60
+ node.addEventListener(event, handler);
61
+ });
62
+ }
63
+ function removeListeners(listeners) {
64
+ listeners.forEach(({ node, event, handler }) => {
65
+ node.removeEventListener(event, handler);
66
+ });
67
67
  }
68
68
 
69
69
  // src/dom/actions/prefer-horizontal-scroll.js
@@ -99,12 +99,14 @@ function useObserverMethodOnTarget(target, observer, method = "observe", options
99
99
  function resizeObserver(target, options) {
100
100
  const { callback, ...opts } = options;
101
101
  const observer = new ResizeObserver(observerFn);
102
- if (target === window) target = document.body;
102
+ if (target === window || target === document)
103
+ target = document.documentElement;
103
104
  useObserverMethodOnTarget(target, observer, "observe", opts);
104
105
  function observerFn(entries) {
105
106
  for (const entry of entries) {
106
107
  if (callback) callback({ entry, entries, observer });
107
- else dispatchEvent(target, "resize-obs", { entry, entries, observer });
108
+ else
109
+ dispatchEvent(entry.target, "resize-obs", { entry, entries, observer });
108
110
  }
109
111
  }
110
112
  return {
@@ -23,6 +23,7 @@ __export(font_size_exports, {
23
23
  getUnit: () => getUnit,
24
24
  lh: () => lh,
25
25
  rem: () => rem,
26
+ rlh: () => rlh,
26
27
  toPx: () => toPx
27
28
  });
28
29
  module.exports = __toCommonJS(font_size_exports);
@@ -41,13 +42,17 @@ function getUnit(value) {
41
42
  const [, unit] = splitUnit(value);
42
43
  return unit;
43
44
  }
45
+ function rem(multiple = 1) {
46
+ const value = parseFloat(getComputedStyle(document.body)["font-size"]);
47
+ return Math.round(value * multiple);
48
+ }
44
49
  function em(element = document.body, multiple = 1) {
45
50
  const value = parseFloat(getComputedStyle(element)["font-size"]);
46
51
  return Math.round(value * multiple);
47
52
  }
48
- function rem(multiple = 1) {
49
- const value = parseFloat(getComputedStyle(document.body)["font-size"]);
50
- return Math.round(value * multiple);
53
+ function rlh(multiple = 1) {
54
+ const lineHeight = parseFloat(getComputedStyle(document.body)["line-height"]);
55
+ return Math.round(lineHeight * multiple);
51
56
  }
52
57
  function lh(element = document.body, multiple = 1) {
53
58
  const lineHeight = getComputedStyle(element)["line-height"];
@@ -70,5 +75,6 @@ function toPx(value, element = null) {
70
75
  getUnit,
71
76
  lh,
72
77
  rem,
78
+ rlh,
73
79
  toPx
74
80
  });
@@ -77,6 +77,7 @@ __export(dom_exports, {
77
77
  rem: () => rem,
78
78
  removeListeners: () => removeListeners,
79
79
  resizeObserver: () => resizeObserver,
80
+ rlh: () => rlh,
80
81
  sanitize: () => sanitize2,
81
82
  scrollObserver: () => scrollObserver,
82
83
  scrollToElement: () => scrollToElement,
@@ -248,12 +249,14 @@ function useObserverMethodOnTarget(target, observer, method = "observe", options
248
249
  function resizeObserver(target, options) {
249
250
  const { callback, ...opts } = options;
250
251
  const observer = new ResizeObserver(observerFn);
251
- if (target === window) target = document.body;
252
+ if (target === window || target === document)
253
+ target = document.documentElement;
252
254
  useObserverMethodOnTarget(target, observer, "observe", opts);
253
255
  function observerFn(entries) {
254
256
  for (const entry of entries) {
255
257
  if (callback) callback({ entry, entries, observer });
256
- else dispatchEvent(target, "resize-obs", { entry, entries, observer });
258
+ else
259
+ dispatchEvent(entry.target, "resize-obs", { entry, entries, observer });
257
260
  }
258
261
  }
259
262
  return {
@@ -301,36 +304,6 @@ function nativeMasonrySupport(node) {
301
304
  return getComputedStyle(node).gridTemplateRows === "masonry";
302
305
  }
303
306
 
304
- // src/lib/numbers/index.js
305
- function splitUnit(string) {
306
- if (typeof string === "number") return [string, null];
307
- const regex = /(-?\d*\.?\d+)\s*([a-z]+)/i;
308
- const match = string.match(regex);
309
- if (match) return [parseFloat(match[1]), match[2]];
310
- return [parseFloat(string), null];
311
- }
312
-
313
- // src/lib/form/sanitize.js
314
- function sanitize(value, options = {}) {
315
- const { sanitizer, ...rest } = options;
316
- if (!sanitizer) throw new Error("sanitizer function is required");
317
- if (typeof value === "string") return sanitizer(value, rest);
318
- if (Array.isArray(value)) return sanitizeArray(value, { sanitizer, ...rest });
319
- if (value && typeof value === "object") {
320
- return Object.fromEntries(
321
- Object.entries(value).map(([key, val]) => [
322
- key,
323
- sanitize(val, { sanitizer, ...rest })
324
- ])
325
- );
326
- }
327
- return value;
328
- }
329
- function sanitizeArray(arr, { sanitizer, ...rest }) {
330
- if (!sanitizer) throw new Error("sanitizer function is required");
331
- return arr.map((item) => sanitize(item, { sanitizer, ...rest }));
332
- }
333
-
334
307
  // src/lib/objects/omit-empty.js
335
308
  function omitEmpty(obj, shallow = false) {
336
309
  if (typeof obj !== "object" || obj === null) return obj;
@@ -345,6 +318,22 @@ function omitEmpty(obj, shallow = false) {
345
318
  return result;
346
319
  }
347
320
 
321
+ // src/dom/css-vars.js
322
+ function getCSSValue(element, prop) {
323
+ return getCSSVar(element, prop);
324
+ }
325
+ function setCSSValue(element, prop, value) {
326
+ setCSSVar(element, prop, value);
327
+ }
328
+ function getCSSVar(element, prop) {
329
+ element = getElement(element);
330
+ return getComputedStyle(element).getPropertyValue(prop);
331
+ }
332
+ function setCSSVar(element, prop, value) {
333
+ element = getElement(element);
334
+ element.style.setProperty(prop, value);
335
+ }
336
+
348
337
  // src/dom/actions/prefer-horizontal-scroll.js
349
338
  var DEFAULT_OPTIONS = {
350
339
  scrollSnapDelay: 1e3
@@ -600,22 +589,6 @@ function setCookie(name, value, days) {
600
589
  document.cookie = name + "=" + (value || "") + expires + "; path=/";
601
590
  }
602
591
 
603
- // src/dom/css-vars.js
604
- function getCSSValue(element, prop) {
605
- return getCSSVar(element, prop);
606
- }
607
- function setCSSValue(element, prop, value) {
608
- setCSSVar(element, prop, value);
609
- }
610
- function getCSSVar(element, prop) {
611
- element = getElement(element);
612
- return getComputedStyle(element).getPropertyValue(prop);
613
- }
614
- function setCSSVar(element, prop, value) {
615
- element = getElement(element);
616
- element.style.setProperty(prop, value);
617
- }
618
-
619
592
  // src/dom/focusable.js
620
593
  function getFocusableElements(container = document.body) {
621
594
  return {
@@ -731,18 +704,31 @@ function Focusable(container = document.body) {
731
704
  return getFocusableElements(container);
732
705
  }
733
706
 
707
+ // src/lib/numbers/index.js
708
+ function splitUnit(string) {
709
+ if (typeof string === "number") return [string, null];
710
+ const regex = /(-?\d*\.?\d+)\s*([a-z]+)/i;
711
+ const match = string.match(regex);
712
+ if (match) return [parseFloat(match[1]), match[2]];
713
+ return [parseFloat(string), null];
714
+ }
715
+
734
716
  // src/dom/font-size.js
735
717
  function getUnit(value) {
736
718
  const [, unit] = splitUnit(value);
737
719
  return unit;
738
720
  }
721
+ function rem(multiple = 1) {
722
+ const value = parseFloat(getComputedStyle(document.body)["font-size"]);
723
+ return Math.round(value * multiple);
724
+ }
739
725
  function em(element = document.body, multiple = 1) {
740
726
  const value = parseFloat(getComputedStyle(element)["font-size"]);
741
727
  return Math.round(value * multiple);
742
728
  }
743
- function rem(multiple = 1) {
744
- const value = parseFloat(getComputedStyle(document.body)["font-size"]);
745
- return Math.round(value * multiple);
729
+ function rlh(multiple = 1) {
730
+ const lineHeight = parseFloat(getComputedStyle(document.body)["line-height"]);
731
+ return Math.round(lineHeight * multiple);
746
732
  }
747
733
  function lh(element = document.body, multiple = 1) {
748
734
  const lineHeight = getComputedStyle(element)["line-height"];
@@ -915,40 +901,44 @@ var defaultOptions2 = {
915
901
  // Float between 0 to 1.
916
902
  tolerance: 0.1,
917
903
  // Float between 0 to 1. Tolerance for event firing
918
- throttle: 16,
919
- // Throttle interval in ms (default: ~60fps)
920
904
  once: false
921
905
  // Only fire threshold callback once
922
906
  };
907
+ function getScrollElement(node) {
908
+ if (node === document || node === window || node === document.documentElement) {
909
+ return document.documentElement;
910
+ }
911
+ return (
912
+ /** @type {Element} */
913
+ node
914
+ );
915
+ }
923
916
  function scrollObserver(node, options = {}) {
924
917
  const { callback, onScrollDown, onScrollUp, onEnterThreshold, ...userOpts } = options;
925
918
  const opts = { ...defaultOptions2, ...userOpts };
926
- const { threshold, tolerance, throttle, once } = opts;
927
- const prevScrollDirection = null;
919
+ const { threshold, tolerance, once } = opts;
920
+ let prevScrollDirection = null;
928
921
  let prevScrollTop = 0;
929
922
  let prevScrollPercent = 0;
930
- let lastThrottleTime = 0;
931
923
  let thresholdFired = false;
932
924
  let rafId = null;
933
- const isDocumentScroll = node === document || node === window;
934
- const scrollElement = isDocumentScroll ? document.documentElement : node;
925
+ const isDocumentScroll = node === document || node === window || node === document.documentElement;
926
+ const scrollElement = getScrollElement(node);
927
+ const eventTarget = isDocumentScroll ? window : node;
935
928
  let cachedScrollHeight = 0;
936
929
  let cachedClientHeight = 0;
937
930
  updateCache();
938
931
  const cacheObserver = resizeObserver(scrollElement, {
939
932
  callback: updateCache
940
933
  });
941
- node.addEventListener("scroll", throttledObserve, { passive: true });
934
+ eventTarget.addEventListener("scroll", throttledObserve, { passive: true });
935
+ function throttledObserve() {
936
+ rafId = requestAnimationFrame(observe);
937
+ }
942
938
  function updateCache() {
943
939
  cachedScrollHeight = scrollElement.scrollHeight;
944
940
  cachedClientHeight = scrollElement.clientHeight;
945
941
  }
946
- function throttledObserve() {
947
- const now = Date.now();
948
- if (now - lastThrottleTime < throttle) return;
949
- lastThrottleTime = now;
950
- rafId = requestAnimationFrame(observe);
951
- }
952
942
  function observe() {
953
943
  const scrollTop = scrollElement.scrollTop;
954
944
  if (Math.abs(scrollTop - prevScrollTop) < 1) return;
@@ -987,10 +977,11 @@ function scrollObserver(node, options = {}) {
987
977
  }
988
978
  prevScrollTop = scrollTop;
989
979
  prevScrollPercent = scrollPercent;
980
+ prevScrollDirection = scrollDirection;
990
981
  }
991
982
  return {
992
983
  destroy() {
993
- node.removeEventListener("scroll", throttledObserve);
984
+ eventTarget.removeEventListener("scroll", throttledObserve);
994
985
  if (rafId) cancelAnimationFrame(rafId);
995
986
  cacheObserver.destroy();
996
987
  }
@@ -1039,6 +1030,29 @@ var queryParams = {
1039
1030
 
1040
1031
  // src/dom/sanitize.js
1041
1032
  var import_dompurify = __toESM(require("dompurify"), 1);
1033
+
1034
+ // src/lib/form/sanitize.js
1035
+ function sanitize(value, options = {}) {
1036
+ const { sanitizer, ...rest } = options;
1037
+ if (!sanitizer) throw new Error("sanitizer function is required");
1038
+ if (typeof value === "string") return sanitizer(value, rest);
1039
+ if (Array.isArray(value)) return sanitizeArray(value, { sanitizer, ...rest });
1040
+ if (value && typeof value === "object") {
1041
+ return Object.fromEntries(
1042
+ Object.entries(value).map(([key, val]) => [
1043
+ key,
1044
+ sanitize(val, { sanitizer, ...rest })
1045
+ ])
1046
+ );
1047
+ }
1048
+ return value;
1049
+ }
1050
+ function sanitizeArray(arr, { sanitizer, ...rest }) {
1051
+ if (!sanitizer) throw new Error("sanitizer function is required");
1052
+ return arr.map((item) => sanitize(item, { sanitizer, ...rest }));
1053
+ }
1054
+
1055
+ // src/dom/sanitize.js
1042
1056
  function sanitize2(value, options = {}) {
1043
1057
  return sanitize(value, { sanitizer: import_dompurify.default.sanitize, ...options });
1044
1058
  }
@@ -1234,6 +1248,7 @@ function scrambleText(text) {
1234
1248
  rem,
1235
1249
  removeListeners,
1236
1250
  resizeObserver,
1251
+ rlh,
1237
1252
  sanitize,
1238
1253
  scrollObserver,
1239
1254
  scrollToElement,
@@ -130,12 +130,14 @@ function mutationObserver(target, options) {
130
130
  function resizeObserver(target, options) {
131
131
  const { callback, ...opts } = options;
132
132
  const observer = new ResizeObserver(observerFn);
133
- if (target === window) target = document.body;
133
+ if (target === window || target === document)
134
+ target = document.documentElement;
134
135
  useObserverMethodOnTarget(target, observer, "observe", opts);
135
136
  function observerFn(entries) {
136
137
  for (const entry of entries) {
137
138
  if (callback) callback({ entry, entries, observer });
138
- else dispatchEvent(target, "resize-obs", { entry, entries, observer });
139
+ else
140
+ dispatchEvent(entry.target, "resize-obs", { entry, entries, observer });
139
141
  }
140
142
  }
141
143
  return {
@@ -156,40 +158,44 @@ var defaultOptions2 = {
156
158
  // Float between 0 to 1.
157
159
  tolerance: 0.1,
158
160
  // Float between 0 to 1. Tolerance for event firing
159
- throttle: 16,
160
- // Throttle interval in ms (default: ~60fps)
161
161
  once: false
162
162
  // Only fire threshold callback once
163
163
  };
164
+ function getScrollElement(node) {
165
+ if (node === document || node === window || node === document.documentElement) {
166
+ return document.documentElement;
167
+ }
168
+ return (
169
+ /** @type {Element} */
170
+ node
171
+ );
172
+ }
164
173
  function scrollObserver(node, options = {}) {
165
174
  const { callback, onScrollDown, onScrollUp, onEnterThreshold, ...userOpts } = options;
166
175
  const opts = { ...defaultOptions2, ...userOpts };
167
- const { threshold, tolerance, throttle, once } = opts;
168
- const prevScrollDirection = null;
176
+ const { threshold, tolerance, once } = opts;
177
+ let prevScrollDirection = null;
169
178
  let prevScrollTop = 0;
170
179
  let prevScrollPercent = 0;
171
- let lastThrottleTime = 0;
172
180
  let thresholdFired = false;
173
181
  let rafId = null;
174
- const isDocumentScroll = node === document || node === window;
175
- const scrollElement = isDocumentScroll ? document.documentElement : node;
182
+ const isDocumentScroll = node === document || node === window || node === document.documentElement;
183
+ const scrollElement = getScrollElement(node);
184
+ const eventTarget = isDocumentScroll ? window : node;
176
185
  let cachedScrollHeight = 0;
177
186
  let cachedClientHeight = 0;
178
187
  updateCache();
179
188
  const cacheObserver = resizeObserver(scrollElement, {
180
189
  callback: updateCache
181
190
  });
182
- node.addEventListener("scroll", throttledObserve, { passive: true });
191
+ eventTarget.addEventListener("scroll", throttledObserve, { passive: true });
192
+ function throttledObserve() {
193
+ rafId = requestAnimationFrame(observe);
194
+ }
183
195
  function updateCache() {
184
196
  cachedScrollHeight = scrollElement.scrollHeight;
185
197
  cachedClientHeight = scrollElement.clientHeight;
186
198
  }
187
- function throttledObserve() {
188
- const now = Date.now();
189
- if (now - lastThrottleTime < throttle) return;
190
- lastThrottleTime = now;
191
- rafId = requestAnimationFrame(observe);
192
- }
193
199
  function observe() {
194
200
  const scrollTop = scrollElement.scrollTop;
195
201
  if (Math.abs(scrollTop - prevScrollTop) < 1) return;
@@ -228,10 +234,11 @@ function scrollObserver(node, options = {}) {
228
234
  }
229
235
  prevScrollTop = scrollTop;
230
236
  prevScrollPercent = scrollPercent;
237
+ prevScrollDirection = scrollDirection;
231
238
  }
232
239
  return {
233
240
  destroy() {
234
- node.removeEventListener("scroll", throttledObserve);
241
+ eventTarget.removeEventListener("scroll", throttledObserve);
235
242
  if (rafId) cancelAnimationFrame(rafId);
236
243
  cacheObserver.destroy();
237
244
  }