@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/CHANGELOG.md +12 -0
- package/dist/cjs/dom/actions/index.cjs +75 -73
- package/dist/cjs/dom/actions/masonry.cjs +4 -2
- package/dist/cjs/dom/actions/prefer-horizontal-scroll.cjs +24 -24
- package/dist/cjs/dom/actions/sticky.cjs +4 -2
- package/dist/cjs/dom/index.cjs +62 -49
- package/dist/cjs/dom/observers/index.cjs +14 -3
- package/dist/cjs/dom/observers/resize-observer.cjs +4 -2
- package/dist/cjs/dom/observers/scroll-observer.cjs +14 -3
- package/dist/esm/dom/actions/index.js +75 -73
- package/dist/esm/dom/actions/masonry.js +4 -2
- package/dist/esm/dom/actions/prefer-horizontal-scroll.js +24 -24
- package/dist/esm/dom/actions/sticky.js +4 -2
- package/dist/esm/dom/index.js +62 -49
- package/dist/esm/dom/observers/index.js +14 -3
- package/dist/esm/dom/observers/resize-observer.js +4 -2
- package/dist/esm/dom/observers/scroll-observer.js +14 -3
- package/dist/types/dom/events.d.cts +2 -2
- package/dist/types/dom/observers/resize-observer.d.cts +3 -3
- package/dist/types/dom/observers/scroll-observer.d.cts +2 -12
- package/dist/types/dom/spam-prevention.d.cts +7 -7
- package/dist/types/lib/checks.d.cts +1 -1
- package/package.json +1 -1
- package/src/dom/actions/prefer-horizontal-scroll.js +3 -8
- package/src/dom/events.js +1 -1
- package/src/dom/font-size.js +1 -1
- package/src/dom/observers/resize-observer.js +6 -4
- package/src/dom/observers/scroll-observer.js +17 -2
- package/src/dom/spam-prevention.js +5 -4
- package/src/dom/events.test.js +0 -99
|
@@ -81,12 +81,14 @@ function useObserverMethodOnTarget(target, observer, method = "observe", options
|
|
|
81
81
|
function resizeObserver(target, options) {
|
|
82
82
|
const { callback, ...opts } = options;
|
|
83
83
|
const observer = new ResizeObserver(observerFn);
|
|
84
|
-
if (target === window
|
|
84
|
+
if (target === window || target === document)
|
|
85
|
+
target = document.documentElement;
|
|
85
86
|
useObserverMethodOnTarget(target, observer, "observe", opts);
|
|
86
87
|
function observerFn(entries) {
|
|
87
88
|
for (const entry of entries) {
|
|
88
89
|
if (callback) callback({ entry, entries, observer });
|
|
89
|
-
else
|
|
90
|
+
else
|
|
91
|
+
dispatchEvent(entry.target, "resize-obs", { entry, entries, observer });
|
|
90
92
|
}
|
|
91
93
|
}
|
|
92
94
|
return {
|
|
@@ -134,58 +136,6 @@ function nativeMasonrySupport(node) {
|
|
|
134
136
|
return getComputedStyle(node).gridTemplateRows === "masonry";
|
|
135
137
|
}
|
|
136
138
|
|
|
137
|
-
// src/dom/bounding-box.js
|
|
138
|
-
function boundingBox(element, { containsPadding = true } = {}) {
|
|
139
|
-
const box = element.getBoundingClientRect();
|
|
140
|
-
const ret = {};
|
|
141
|
-
for (const prop in box) ret[prop] = box[prop];
|
|
142
|
-
if (!containsPadding) {
|
|
143
|
-
const style = getComputedStyle(element);
|
|
144
|
-
const paddingTop = parseFloat(style.paddingTop);
|
|
145
|
-
const paddingRight = parseFloat(style.paddingRight);
|
|
146
|
-
const paddingBottom = parseFloat(style.paddingBottom);
|
|
147
|
-
const paddingLeft = parseFloat(style.paddingLeft);
|
|
148
|
-
ret.x = ret.x + paddingLeft;
|
|
149
|
-
ret.y = ret.y + paddingTop;
|
|
150
|
-
ret.width = ret.width - paddingLeft - paddingRight;
|
|
151
|
-
ret.height = ret.height - paddingTop - paddingBottom;
|
|
152
|
-
ret.top = ret.top + paddingTop;
|
|
153
|
-
ret.bottom = ret.bottom - paddingBottom;
|
|
154
|
-
ret.right = ret.right - paddingRight;
|
|
155
|
-
ret.left = ret.left + paddingLeft;
|
|
156
|
-
}
|
|
157
|
-
ret.xCenter = (ret.left + ret.right) / 2;
|
|
158
|
-
ret.yCenter = (ret.top + ret.bottom) / 2;
|
|
159
|
-
return ret;
|
|
160
|
-
}
|
|
161
|
-
function boundingBoxRelativeToAncestor({ element, ancestorElement }) {
|
|
162
|
-
ancestorElement = ancestorElement || element.parentElement;
|
|
163
|
-
const box = boundingBox(element);
|
|
164
|
-
const ancestorBox = boundingBox(ancestorElement, {
|
|
165
|
-
containsPadding: false
|
|
166
|
-
});
|
|
167
|
-
return {
|
|
168
|
-
top: box.top - ancestorBox.top,
|
|
169
|
-
right: box.right - ancestorBox.right,
|
|
170
|
-
bottom: box.bottom - ancestorBox.bottom,
|
|
171
|
-
left: box.left - ancestorBox.left,
|
|
172
|
-
width: box.width,
|
|
173
|
-
height: box.height,
|
|
174
|
-
xCenter: (box.left + box.right) / 2 - ancestorBox.left,
|
|
175
|
-
yCenter: (box.top + box.bottom) / 2 - ancestorBox.top
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// src/dom/css-vars.js
|
|
180
|
-
function getCSSVar(element, prop) {
|
|
181
|
-
element = getElement(element);
|
|
182
|
-
return getComputedStyle(element).getPropertyValue(prop);
|
|
183
|
-
}
|
|
184
|
-
function setCSSVar(element, prop, value) {
|
|
185
|
-
element = getElement(element);
|
|
186
|
-
element.style.setProperty(prop, value);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
139
|
// src/lib/objects/omit-empty.js
|
|
190
140
|
function omitEmpty(obj, shallow = false) {
|
|
191
141
|
if (typeof obj !== "object" || obj === null) return obj;
|
|
@@ -200,25 +150,14 @@ function omitEmpty(obj, shallow = false) {
|
|
|
200
150
|
return result;
|
|
201
151
|
}
|
|
202
152
|
|
|
203
|
-
// src/dom/
|
|
204
|
-
function
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
return parent;
|
|
212
|
-
}
|
|
213
|
-
if (direction === "horizontal") {
|
|
214
|
-
if (overflowX === "auto" || overflowX === "scroll") return parent;
|
|
215
|
-
}
|
|
216
|
-
if (direction === "vertical") {
|
|
217
|
-
if (overflowY === "auto" || overflowY === "scroll") return parent;
|
|
218
|
-
}
|
|
219
|
-
parent = parent.parentElement;
|
|
220
|
-
}
|
|
221
|
-
return document.documentElement;
|
|
153
|
+
// src/dom/css-vars.js
|
|
154
|
+
function getCSSVar(element, prop) {
|
|
155
|
+
element = getElement(element);
|
|
156
|
+
return getComputedStyle(element).getPropertyValue(prop);
|
|
157
|
+
}
|
|
158
|
+
function setCSSVar(element, prop, value) {
|
|
159
|
+
element = getElement(element);
|
|
160
|
+
element.style.setProperty(prop, value);
|
|
222
161
|
}
|
|
223
162
|
|
|
224
163
|
// src/dom/actions/prefer-horizontal-scroll.js
|
|
@@ -307,6 +246,69 @@ function isTrackpad(event) {
|
|
|
307
246
|
if (event.wheelDeltaY === event.deltaY * -3) return true;
|
|
308
247
|
}
|
|
309
248
|
|
|
249
|
+
// src/dom/bounding-box.js
|
|
250
|
+
function boundingBox(element, { containsPadding = true } = {}) {
|
|
251
|
+
const box = element.getBoundingClientRect();
|
|
252
|
+
const ret = {};
|
|
253
|
+
for (const prop in box) ret[prop] = box[prop];
|
|
254
|
+
if (!containsPadding) {
|
|
255
|
+
const style = getComputedStyle(element);
|
|
256
|
+
const paddingTop = parseFloat(style.paddingTop);
|
|
257
|
+
const paddingRight = parseFloat(style.paddingRight);
|
|
258
|
+
const paddingBottom = parseFloat(style.paddingBottom);
|
|
259
|
+
const paddingLeft = parseFloat(style.paddingLeft);
|
|
260
|
+
ret.x = ret.x + paddingLeft;
|
|
261
|
+
ret.y = ret.y + paddingTop;
|
|
262
|
+
ret.width = ret.width - paddingLeft - paddingRight;
|
|
263
|
+
ret.height = ret.height - paddingTop - paddingBottom;
|
|
264
|
+
ret.top = ret.top + paddingTop;
|
|
265
|
+
ret.bottom = ret.bottom - paddingBottom;
|
|
266
|
+
ret.right = ret.right - paddingRight;
|
|
267
|
+
ret.left = ret.left + paddingLeft;
|
|
268
|
+
}
|
|
269
|
+
ret.xCenter = (ret.left + ret.right) / 2;
|
|
270
|
+
ret.yCenter = (ret.top + ret.bottom) / 2;
|
|
271
|
+
return ret;
|
|
272
|
+
}
|
|
273
|
+
function boundingBoxRelativeToAncestor({ element, ancestorElement }) {
|
|
274
|
+
ancestorElement = ancestorElement || element.parentElement;
|
|
275
|
+
const box = boundingBox(element);
|
|
276
|
+
const ancestorBox = boundingBox(ancestorElement, {
|
|
277
|
+
containsPadding: false
|
|
278
|
+
});
|
|
279
|
+
return {
|
|
280
|
+
top: box.top - ancestorBox.top,
|
|
281
|
+
right: box.right - ancestorBox.right,
|
|
282
|
+
bottom: box.bottom - ancestorBox.bottom,
|
|
283
|
+
left: box.left - ancestorBox.left,
|
|
284
|
+
width: box.width,
|
|
285
|
+
height: box.height,
|
|
286
|
+
xCenter: (box.left + box.right) / 2 - ancestorBox.left,
|
|
287
|
+
yCenter: (box.top + box.bottom) / 2 - ancestorBox.top
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/dom/ui/scroll-container.js
|
|
292
|
+
function findScrollContainer(element, direction = "both") {
|
|
293
|
+
if (!element) return;
|
|
294
|
+
let parent = element.parentElement;
|
|
295
|
+
while (parent) {
|
|
296
|
+
const { overflow, overflowX, overflowY } = getComputedStyle(parent);
|
|
297
|
+
if (direction === "both") {
|
|
298
|
+
if (overflow.includes("auto") || overflow.includes("scroll"))
|
|
299
|
+
return parent;
|
|
300
|
+
}
|
|
301
|
+
if (direction === "horizontal") {
|
|
302
|
+
if (overflowX === "auto" || overflowX === "scroll") return parent;
|
|
303
|
+
}
|
|
304
|
+
if (direction === "vertical") {
|
|
305
|
+
if (overflowY === "auto" || overflowY === "scroll") return parent;
|
|
306
|
+
}
|
|
307
|
+
parent = parent.parentElement;
|
|
308
|
+
}
|
|
309
|
+
return document.documentElement;
|
|
310
|
+
}
|
|
311
|
+
|
|
310
312
|
// src/dom/actions/sticky.js
|
|
311
313
|
function sticky(node, props = {}) {
|
|
312
314
|
const scrollContainer = findScrollContainer(node);
|
|
@@ -66,12 +66,14 @@ function useObserverMethodOnTarget(target, observer, method = "observe", options
|
|
|
66
66
|
function resizeObserver(target, options) {
|
|
67
67
|
const { callback, ...opts } = options;
|
|
68
68
|
const observer = new ResizeObserver(observerFn);
|
|
69
|
-
if (target === window
|
|
69
|
+
if (target === window || target === document)
|
|
70
|
+
target = document.documentElement;
|
|
70
71
|
useObserverMethodOnTarget(target, observer, "observe", opts);
|
|
71
72
|
function observerFn(entries) {
|
|
72
73
|
for (const entry of entries) {
|
|
73
74
|
if (callback) callback({ entry, entries, observer });
|
|
74
|
-
else
|
|
75
|
+
else
|
|
76
|
+
dispatchEvent(entry.target, "resize-obs", { entry, entries, observer });
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
79
|
return {
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
// src/lib/objects/omit-empty.js
|
|
2
|
+
function omitEmpty(obj, shallow = false) {
|
|
3
|
+
if (typeof obj !== "object" || obj === null) return obj;
|
|
4
|
+
if (obj instanceof Date) return obj;
|
|
5
|
+
const result = Array.isArray(obj) ? [] : {};
|
|
6
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
7
|
+
if (value === null || value === void 0 || value === "" || typeof value === "object" && !(value instanceof Date) && Object.keys(value).length === 0) {
|
|
8
|
+
continue;
|
|
9
|
+
}
|
|
10
|
+
result[key] = shallow ? value : omitEmpty(value);
|
|
11
|
+
}
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
14
|
+
|
|
1
15
|
// src/dom/get-element.js
|
|
2
16
|
function getElement(selector) {
|
|
3
17
|
if (!selector) return;
|
|
@@ -5,18 +19,6 @@ function getElement(selector) {
|
|
|
5
19
|
return document.querySelector(selector);
|
|
6
20
|
}
|
|
7
21
|
|
|
8
|
-
// src/dom/events.js
|
|
9
|
-
function addListeners(listeners) {
|
|
10
|
-
listeners.forEach(({ node, event, handler }) => {
|
|
11
|
-
node.addEventListener(event, handler);
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
function removeListeners(listeners) {
|
|
15
|
-
listeners.forEach(({ node, event, handler }) => {
|
|
16
|
-
node.removeEventListener(event, handler);
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
|
|
20
22
|
// src/dom/css-vars.js
|
|
21
23
|
function getCSSVar(element, prop) {
|
|
22
24
|
element = getElement(element);
|
|
@@ -27,18 +29,16 @@ function setCSSVar(element, prop, value) {
|
|
|
27
29
|
element.style.setProperty(prop, value);
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
// src/
|
|
31
|
-
function
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
return result;
|
|
32
|
+
// src/dom/events.js
|
|
33
|
+
function addListeners(listeners) {
|
|
34
|
+
listeners.forEach(({ node, event, handler }) => {
|
|
35
|
+
node.addEventListener(event, handler);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function removeListeners(listeners) {
|
|
39
|
+
listeners.forEach(({ node, event, handler }) => {
|
|
40
|
+
node.removeEventListener(event, handler);
|
|
41
|
+
});
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
// src/dom/actions/prefer-horizontal-scroll.js
|
|
@@ -74,12 +74,14 @@ function useObserverMethodOnTarget(target, observer, method = "observe", options
|
|
|
74
74
|
function resizeObserver(target, options) {
|
|
75
75
|
const { callback, ...opts } = options;
|
|
76
76
|
const observer = new ResizeObserver(observerFn);
|
|
77
|
-
if (target === window
|
|
77
|
+
if (target === window || target === document)
|
|
78
|
+
target = document.documentElement;
|
|
78
79
|
useObserverMethodOnTarget(target, observer, "observe", opts);
|
|
79
80
|
function observerFn(entries) {
|
|
80
81
|
for (const entry of entries) {
|
|
81
82
|
if (callback) callback({ entry, entries, observer });
|
|
82
|
-
else
|
|
83
|
+
else
|
|
84
|
+
dispatchEvent(entry.target, "resize-obs", { entry, entries, observer });
|
|
83
85
|
}
|
|
84
86
|
}
|
|
85
87
|
return {
|
package/dist/esm/dom/index.js
CHANGED
|
@@ -152,12 +152,14 @@ function useObserverMethodOnTarget(target, observer, method = "observe", options
|
|
|
152
152
|
function resizeObserver(target, options) {
|
|
153
153
|
const { callback, ...opts } = options;
|
|
154
154
|
const observer = new ResizeObserver(observerFn);
|
|
155
|
-
if (target === window
|
|
155
|
+
if (target === window || target === document)
|
|
156
|
+
target = document.documentElement;
|
|
156
157
|
useObserverMethodOnTarget(target, observer, "observe", opts);
|
|
157
158
|
function observerFn(entries) {
|
|
158
159
|
for (const entry of entries) {
|
|
159
160
|
if (callback) callback({ entry, entries, observer });
|
|
160
|
-
else
|
|
161
|
+
else
|
|
162
|
+
dispatchEvent(entry.target, "resize-obs", { entry, entries, observer });
|
|
161
163
|
}
|
|
162
164
|
}
|
|
163
165
|
return {
|
|
@@ -205,36 +207,6 @@ function nativeMasonrySupport(node) {
|
|
|
205
207
|
return getComputedStyle(node).gridTemplateRows === "masonry";
|
|
206
208
|
}
|
|
207
209
|
|
|
208
|
-
// src/lib/numbers/index.js
|
|
209
|
-
function splitUnit(string) {
|
|
210
|
-
if (typeof string === "number") return [string, null];
|
|
211
|
-
const regex = /(-?\d*\.?\d+)\s*([a-z]+)/i;
|
|
212
|
-
const match = string.match(regex);
|
|
213
|
-
if (match) return [parseFloat(match[1]), match[2]];
|
|
214
|
-
return [parseFloat(string), null];
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// src/lib/form/sanitize.js
|
|
218
|
-
function sanitize(value, options = {}) {
|
|
219
|
-
const { sanitizer, ...rest } = options;
|
|
220
|
-
if (!sanitizer) throw new Error("sanitizer function is required");
|
|
221
|
-
if (typeof value === "string") return sanitizer(value, rest);
|
|
222
|
-
if (Array.isArray(value)) return sanitizeArray(value, { sanitizer, ...rest });
|
|
223
|
-
if (value && typeof value === "object") {
|
|
224
|
-
return Object.fromEntries(
|
|
225
|
-
Object.entries(value).map(([key, val]) => [
|
|
226
|
-
key,
|
|
227
|
-
sanitize(val, { sanitizer, ...rest })
|
|
228
|
-
])
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
return value;
|
|
232
|
-
}
|
|
233
|
-
function sanitizeArray(arr, { sanitizer, ...rest }) {
|
|
234
|
-
if (!sanitizer) throw new Error("sanitizer function is required");
|
|
235
|
-
return arr.map((item) => sanitize(item, { sanitizer, ...rest }));
|
|
236
|
-
}
|
|
237
|
-
|
|
238
210
|
// src/lib/objects/omit-empty.js
|
|
239
211
|
function omitEmpty(obj, shallow = false) {
|
|
240
212
|
if (typeof obj !== "object" || obj === null) return obj;
|
|
@@ -249,6 +221,22 @@ function omitEmpty(obj, shallow = false) {
|
|
|
249
221
|
return result;
|
|
250
222
|
}
|
|
251
223
|
|
|
224
|
+
// src/dom/css-vars.js
|
|
225
|
+
function getCSSValue(element, prop) {
|
|
226
|
+
return getCSSVar(element, prop);
|
|
227
|
+
}
|
|
228
|
+
function setCSSValue(element, prop, value) {
|
|
229
|
+
setCSSVar(element, prop, value);
|
|
230
|
+
}
|
|
231
|
+
function getCSSVar(element, prop) {
|
|
232
|
+
element = getElement(element);
|
|
233
|
+
return getComputedStyle(element).getPropertyValue(prop);
|
|
234
|
+
}
|
|
235
|
+
function setCSSVar(element, prop, value) {
|
|
236
|
+
element = getElement(element);
|
|
237
|
+
element.style.setProperty(prop, value);
|
|
238
|
+
}
|
|
239
|
+
|
|
252
240
|
// src/dom/actions/prefer-horizontal-scroll.js
|
|
253
241
|
var DEFAULT_OPTIONS = {
|
|
254
242
|
scrollSnapDelay: 1e3
|
|
@@ -504,22 +492,6 @@ function setCookie(name, value, days) {
|
|
|
504
492
|
document.cookie = name + "=" + (value || "") + expires + "; path=/";
|
|
505
493
|
}
|
|
506
494
|
|
|
507
|
-
// src/dom/css-vars.js
|
|
508
|
-
function getCSSValue(element, prop) {
|
|
509
|
-
return getCSSVar(element, prop);
|
|
510
|
-
}
|
|
511
|
-
function setCSSValue(element, prop, value) {
|
|
512
|
-
setCSSVar(element, prop, value);
|
|
513
|
-
}
|
|
514
|
-
function getCSSVar(element, prop) {
|
|
515
|
-
element = getElement(element);
|
|
516
|
-
return getComputedStyle(element).getPropertyValue(prop);
|
|
517
|
-
}
|
|
518
|
-
function setCSSVar(element, prop, value) {
|
|
519
|
-
element = getElement(element);
|
|
520
|
-
element.style.setProperty(prop, value);
|
|
521
|
-
}
|
|
522
|
-
|
|
523
495
|
// src/dom/focusable.js
|
|
524
496
|
function getFocusableElements(container = document.body) {
|
|
525
497
|
return {
|
|
@@ -635,6 +607,15 @@ function Focusable(container = document.body) {
|
|
|
635
607
|
return getFocusableElements(container);
|
|
636
608
|
}
|
|
637
609
|
|
|
610
|
+
// src/lib/numbers/index.js
|
|
611
|
+
function splitUnit(string) {
|
|
612
|
+
if (typeof string === "number") return [string, null];
|
|
613
|
+
const regex = /(-?\d*\.?\d+)\s*([a-z]+)/i;
|
|
614
|
+
const match = string.match(regex);
|
|
615
|
+
if (match) return [parseFloat(match[1]), match[2]];
|
|
616
|
+
return [parseFloat(string), null];
|
|
617
|
+
}
|
|
618
|
+
|
|
638
619
|
// src/dom/font-size.js
|
|
639
620
|
function getUnit(value) {
|
|
640
621
|
const [, unit] = splitUnit(value);
|
|
@@ -826,6 +807,15 @@ var defaultOptions2 = {
|
|
|
826
807
|
once: false
|
|
827
808
|
// Only fire threshold callback once
|
|
828
809
|
};
|
|
810
|
+
function getScrollElement(node) {
|
|
811
|
+
if (node === document || node === window || node === document.documentElement) {
|
|
812
|
+
return document.documentElement;
|
|
813
|
+
}
|
|
814
|
+
return (
|
|
815
|
+
/** @type {Element} */
|
|
816
|
+
node
|
|
817
|
+
);
|
|
818
|
+
}
|
|
829
819
|
function scrollObserver(node, options = {}) {
|
|
830
820
|
const { callback, onScrollDown, onScrollUp, onEnterThreshold, ...userOpts } = options;
|
|
831
821
|
const opts = { ...defaultOptions2, ...userOpts };
|
|
@@ -836,7 +826,7 @@ function scrollObserver(node, options = {}) {
|
|
|
836
826
|
let thresholdFired = false;
|
|
837
827
|
let rafId = null;
|
|
838
828
|
const isDocumentScroll = node === document || node === window || node === document.documentElement;
|
|
839
|
-
const scrollElement =
|
|
829
|
+
const scrollElement = getScrollElement(node);
|
|
840
830
|
const eventTarget = isDocumentScroll ? window : node;
|
|
841
831
|
let cachedScrollHeight = 0;
|
|
842
832
|
let cachedClientHeight = 0;
|
|
@@ -943,6 +933,29 @@ var queryParams = {
|
|
|
943
933
|
|
|
944
934
|
// src/dom/sanitize.js
|
|
945
935
|
import DOMPurify from "dompurify";
|
|
936
|
+
|
|
937
|
+
// src/lib/form/sanitize.js
|
|
938
|
+
function sanitize(value, options = {}) {
|
|
939
|
+
const { sanitizer, ...rest } = options;
|
|
940
|
+
if (!sanitizer) throw new Error("sanitizer function is required");
|
|
941
|
+
if (typeof value === "string") return sanitizer(value, rest);
|
|
942
|
+
if (Array.isArray(value)) return sanitizeArray(value, { sanitizer, ...rest });
|
|
943
|
+
if (value && typeof value === "object") {
|
|
944
|
+
return Object.fromEntries(
|
|
945
|
+
Object.entries(value).map(([key, val]) => [
|
|
946
|
+
key,
|
|
947
|
+
sanitize(val, { sanitizer, ...rest })
|
|
948
|
+
])
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
return value;
|
|
952
|
+
}
|
|
953
|
+
function sanitizeArray(arr, { sanitizer, ...rest }) {
|
|
954
|
+
if (!sanitizer) throw new Error("sanitizer function is required");
|
|
955
|
+
return arr.map((item) => sanitize(item, { sanitizer, ...rest }));
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
// src/dom/sanitize.js
|
|
946
959
|
function sanitize2(value, options = {}) {
|
|
947
960
|
return sanitize(value, { sanitizer: DOMPurify.sanitize, ...options });
|
|
948
961
|
}
|
|
@@ -102,12 +102,14 @@ function mutationObserver(target, options) {
|
|
|
102
102
|
function resizeObserver(target, options) {
|
|
103
103
|
const { callback, ...opts } = options;
|
|
104
104
|
const observer = new ResizeObserver(observerFn);
|
|
105
|
-
if (target === window
|
|
105
|
+
if (target === window || target === document)
|
|
106
|
+
target = document.documentElement;
|
|
106
107
|
useObserverMethodOnTarget(target, observer, "observe", opts);
|
|
107
108
|
function observerFn(entries) {
|
|
108
109
|
for (const entry of entries) {
|
|
109
110
|
if (callback) callback({ entry, entries, observer });
|
|
110
|
-
else
|
|
111
|
+
else
|
|
112
|
+
dispatchEvent(entry.target, "resize-obs", { entry, entries, observer });
|
|
111
113
|
}
|
|
112
114
|
}
|
|
113
115
|
return {
|
|
@@ -131,6 +133,15 @@ var defaultOptions2 = {
|
|
|
131
133
|
once: false
|
|
132
134
|
// Only fire threshold callback once
|
|
133
135
|
};
|
|
136
|
+
function getScrollElement(node) {
|
|
137
|
+
if (node === document || node === window || node === document.documentElement) {
|
|
138
|
+
return document.documentElement;
|
|
139
|
+
}
|
|
140
|
+
return (
|
|
141
|
+
/** @type {Element} */
|
|
142
|
+
node
|
|
143
|
+
);
|
|
144
|
+
}
|
|
134
145
|
function scrollObserver(node, options = {}) {
|
|
135
146
|
const { callback, onScrollDown, onScrollUp, onEnterThreshold, ...userOpts } = options;
|
|
136
147
|
const opts = { ...defaultOptions2, ...userOpts };
|
|
@@ -141,7 +152,7 @@ function scrollObserver(node, options = {}) {
|
|
|
141
152
|
let thresholdFired = false;
|
|
142
153
|
let rafId = null;
|
|
143
154
|
const isDocumentScroll = node === document || node === window || node === document.documentElement;
|
|
144
|
-
const scrollElement =
|
|
155
|
+
const scrollElement = getScrollElement(node);
|
|
145
156
|
const eventTarget = isDocumentScroll ? window : node;
|
|
146
157
|
let cachedScrollHeight = 0;
|
|
147
158
|
let cachedClientHeight = 0;
|
|
@@ -32,12 +32,14 @@ function useObserverMethodOnTarget(target, observer, method = "observe", options
|
|
|
32
32
|
function resizeObserver(target, options) {
|
|
33
33
|
const { callback, ...opts } = options;
|
|
34
34
|
const observer = new ResizeObserver(observerFn);
|
|
35
|
-
if (target === window
|
|
35
|
+
if (target === window || target === document)
|
|
36
|
+
target = document.documentElement;
|
|
36
37
|
useObserverMethodOnTarget(target, observer, "observe", opts);
|
|
37
38
|
function observerFn(entries) {
|
|
38
39
|
for (const entry of entries) {
|
|
39
40
|
if (callback) callback({ entry, entries, observer });
|
|
40
|
-
else
|
|
41
|
+
else
|
|
42
|
+
dispatchEvent(entry.target, "resize-obs", { entry, entries, observer });
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
return {
|
|
@@ -32,12 +32,14 @@ function useObserverMethodOnTarget(target, observer, method = "observe", options
|
|
|
32
32
|
function resizeObserver(target, options) {
|
|
33
33
|
const { callback, ...opts } = options;
|
|
34
34
|
const observer = new ResizeObserver(observerFn);
|
|
35
|
-
if (target === window
|
|
35
|
+
if (target === window || target === document)
|
|
36
|
+
target = document.documentElement;
|
|
36
37
|
useObserverMethodOnTarget(target, observer, "observe", opts);
|
|
37
38
|
function observerFn(entries) {
|
|
38
39
|
for (const entry of entries) {
|
|
39
40
|
if (callback) callback({ entry, entries, observer });
|
|
40
|
-
else
|
|
41
|
+
else
|
|
42
|
+
dispatchEvent(entry.target, "resize-obs", { entry, entries, observer });
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
return {
|
|
@@ -61,6 +63,15 @@ var defaultOptions = {
|
|
|
61
63
|
once: false
|
|
62
64
|
// Only fire threshold callback once
|
|
63
65
|
};
|
|
66
|
+
function getScrollElement(node) {
|
|
67
|
+
if (node === document || node === window || node === document.documentElement) {
|
|
68
|
+
return document.documentElement;
|
|
69
|
+
}
|
|
70
|
+
return (
|
|
71
|
+
/** @type {Element} */
|
|
72
|
+
node
|
|
73
|
+
);
|
|
74
|
+
}
|
|
64
75
|
function scrollObserver(node, options = {}) {
|
|
65
76
|
const { callback, onScrollDown, onScrollUp, onEnterThreshold, ...userOpts } = options;
|
|
66
77
|
const opts = { ...defaultOptions, ...userOpts };
|
|
@@ -71,7 +82,7 @@ function scrollObserver(node, options = {}) {
|
|
|
71
82
|
let thresholdFired = false;
|
|
72
83
|
let rafId = null;
|
|
73
84
|
const isDocumentScroll = node === document || node === window || node === document.documentElement;
|
|
74
|
-
const scrollElement =
|
|
85
|
+
const scrollElement = getScrollElement(node);
|
|
75
86
|
const eventTarget = isDocumentScroll ? window : node;
|
|
76
87
|
let cachedScrollHeight = 0;
|
|
77
88
|
let cachedClientHeight = 0;
|
|
@@ -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 {
|
|
5
|
+
* @property {EventListenerOrEventListenerObject} handler - The event handler function
|
|
6
6
|
*/
|
|
7
7
|
/**
|
|
8
8
|
* @typedef {Object} ListenerManager
|
|
@@ -54,7 +54,7 @@ type EventListener = {
|
|
|
54
54
|
/**
|
|
55
55
|
* - The event handler function
|
|
56
56
|
*/
|
|
57
|
-
handler:
|
|
57
|
+
handler: EventListenerOrEventListenerObject;
|
|
58
58
|
};
|
|
59
59
|
type ListenerManager = {
|
|
60
60
|
/**
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Creates and manages a ResizeObserver instance to monitor size changes of a target element.
|
|
3
3
|
*
|
|
4
|
-
* @param {Element|Window|NodeList|Element[]} target - The element(s) to observe.
|
|
5
|
-
* - If window is provided, document.
|
|
4
|
+
* @param {Element|Window|Document|NodeList|Element[]} target - The element(s) to observe.
|
|
5
|
+
* - If window or document is provided, document.documentElement will be observed instead.
|
|
6
6
|
* - If NodeList or Array of elements is provided, all elements will be observed.
|
|
7
7
|
* @param {Object} options - Configuration options for the resize observer
|
|
8
8
|
* @param {boolean} [options.observe=true] - Whether to start observing immediately. If false, the observer won't be created.
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* console.log('Element resized:', detail.entry.contentRect);
|
|
32
32
|
* });
|
|
33
33
|
*/
|
|
34
|
-
declare function resizeObserver(target: Element | Window | NodeList | Element[], options: {
|
|
34
|
+
declare function resizeObserver(target: Element | Window | Document | NodeList | Element[], options: {
|
|
35
35
|
observe?: boolean;
|
|
36
36
|
callback?: Function;
|
|
37
37
|
observerOptions?: any;
|
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @typedef {Object} ScrollObserverOptions
|
|
3
|
-
* @property {number} [threshold] - Float between 0 to 1. When to trigger callback (0.75 = 75% down page)
|
|
4
|
-
* @property {number} [tolerance] - Float between 0 to 1. Tolerance zone around threshold
|
|
5
|
-
* @property {boolean} [once] - Only fire threshold callback once (default: false)
|
|
6
|
-
* @property {Function} [callback] - Called on every scroll with scrollPercent
|
|
7
|
-
* @property {Function} [onScrollDown] - Called when scrolling down
|
|
8
|
-
* @property {Function} [onScrollUp] - Called when scrolling up
|
|
9
|
-
* @property {Function} [onEnterThreshold] - Called when entering threshold zone
|
|
10
|
-
*/
|
|
11
1
|
/**
|
|
12
2
|
* Scroll Observer - Optimized for performance
|
|
13
|
-
* @param {Element} node - The element to observe scroll events on
|
|
3
|
+
* @param {Element | Document | Window} node - The element to observe scroll events on
|
|
14
4
|
* @param {ScrollObserverOptions} [options] - Configuration options
|
|
15
5
|
*/
|
|
16
|
-
declare function scrollObserver(node: Element, options?: ScrollObserverOptions): {
|
|
6
|
+
declare function scrollObserver(node: Element | Document | Window, options?: ScrollObserverOptions): {
|
|
17
7
|
destroy(): void;
|
|
18
8
|
};
|
|
19
9
|
type ScrollObserverOptions = {
|
|
@@ -1,14 +1,14 @@
|
|
|
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 {
|
|
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
|
declare function preventSpam(form: HTMLFormElement, { honeypotField, honeypotDuration }?: {
|
|
10
|
-
honeypotField
|
|
11
|
-
honeypotDuration
|
|
12
|
-
}):
|
|
10
|
+
honeypotField?: string;
|
|
11
|
+
honeypotDuration?: number;
|
|
12
|
+
}): void;
|
|
13
13
|
|
|
14
14
|
export { preventSpam };
|
|
@@ -27,6 +27,6 @@ declare function isArray(x: unknown): boolean;
|
|
|
27
27
|
* notObject({}) // false
|
|
28
28
|
*/
|
|
29
29
|
declare function notObject(x: unknown): boolean;
|
|
30
|
-
declare function getType(x: any): "
|
|
30
|
+
declare function getType(x: any): "string" | "integer" | "float" | "boolean" | "function" | "undefined" | "symbol" | "bigint" | "array" | "object" | "unknown";
|
|
31
31
|
|
|
32
32
|
export { getType, isArray, isObject, notObject };
|
package/package.json
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
removeListeners,
|
|
5
|
-
setCSSVar,
|
|
6
|
-
} from '../index.js'
|
|
7
|
-
|
|
8
|
-
import { omitEmpty } from '../../lib/index.js'
|
|
1
|
+
import { omitEmpty } from '../../lib/objects/omit-empty.js'
|
|
2
|
+
import { getCSSVar, setCSSVar } from '../css-vars.js'
|
|
3
|
+
import { addListeners, removeListeners } from '../events.js'
|
|
9
4
|
|
|
10
5
|
const DEFAULT_OPTIONS = {
|
|
11
6
|
scrollSnapDelay: 1000,
|