@splendidlabz/utils 1.7.0 → 1.8.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 +18 -0
- package/dist/cjs/dom/font-size.cjs +1 -1
- package/dist/cjs/dom/index.cjs +91 -1
- package/dist/cjs/dom/observers/index.cjs +92 -2
- package/dist/cjs/dom/observers/scroll-observer.cjs +170 -0
- package/dist/cjs/lib/date/index.cjs +3 -1
- package/dist/cjs/lib/date/time.cjs +3 -1
- package/dist/cjs/lib/functions/functional.cjs +20 -0
- package/dist/cjs/lib/functions/index.cjs +20 -0
- package/dist/cjs/lib/index.cjs +27 -2
- package/dist/cjs/lib/numbers/index.cjs +1 -1
- package/dist/cjs/lib/objects/extend.cjs +2 -1
- package/dist/cjs/lib/objects/index.cjs +4 -1
- package/dist/cjs/lib/objects/mix/mix.cjs +4 -1
- package/dist/cjs/node/file-cache.cjs +3 -3
- package/dist/cjs/node/index.cjs +3 -3
- package/dist/esm/dom/font-size.js +1 -1
- package/dist/esm/dom/index.js +90 -1
- package/dist/esm/dom/observers/index.js +90 -1
- package/dist/esm/dom/observers/scroll-observer.js +144 -0
- package/dist/esm/lib/date/index.js +3 -1
- package/dist/esm/lib/date/time.js +3 -1
- package/dist/esm/lib/functions/functional.js +18 -0
- package/dist/esm/lib/functions/index.js +18 -0
- package/dist/esm/lib/index.js +24 -2
- package/dist/esm/lib/numbers/index.js +1 -1
- package/dist/esm/lib/objects/extend.js +2 -1
- package/dist/esm/lib/objects/index.js +3 -1
- package/dist/esm/lib/objects/mix/mix.js +3 -1
- package/dist/esm/node/file-cache.js +1 -1
- package/dist/esm/node/index.js +1 -1
- package/dist/types/dom/index.d.cts +1 -0
- package/dist/types/dom/observers/index.d.cts +1 -0
- package/dist/types/dom/observers/scroll-observer.d.cts +27 -0
- package/dist/types/lib/functions/functional.d.cts +71 -5
- package/dist/types/lib/functions/index.d.cts +1 -1
- package/dist/types/lib/index.d.cts +2 -2
- package/dist/types/lib/objects/extend.d.cts +1 -1
- package/dist/types/lib/objects/index.d.cts +1 -1
- package/dist/types/lib/objects/mix/mix.d.cts +43 -3
- package/package.json +2 -3
- package/src/dom/observers/index.js +1 -0
- package/src/dom/observers/resize-observer.js +5 -5
- package/src/dom/observers/scroll-observer.js +132 -0
- package/src/lib/date/time.js +2 -0
- package/src/lib/functions/functional.js +82 -0
- package/src/lib/functions/functional.test.js +196 -0
- package/src/lib/numbers/index.js +1 -1
- package/src/lib/numbers/split-unit.test.js +45 -0
- package/src/lib/objects/mix/mix.js +74 -4
- package/src/lib/objects/mix/mix.test.js +51 -2
- package/src/node/file-cache.js +1 -1
|
@@ -49,8 +49,9 @@ function curry(fn) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
// src/lib/objects/mix/mix.js
|
|
52
|
-
var DEFAULT_OPTIONS = { array: "
|
|
52
|
+
var DEFAULT_OPTIONS = { array: "replace" };
|
|
53
53
|
var mix = createMix();
|
|
54
|
+
var concatMix = createMix({ array: "concat" });
|
|
54
55
|
function createMix(userOptions = {}) {
|
|
55
56
|
const options = { ...DEFAULT_OPTIONS, ...userOptions };
|
|
56
57
|
function _mix(...sources) {
|
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
var objects_exports = {};
|
|
31
31
|
__export(objects_exports, {
|
|
32
32
|
camelCaseKeys: () => camelCaseKeys,
|
|
33
|
+
concatMix: () => concatMix,
|
|
33
34
|
createMix: () => createMix,
|
|
34
35
|
extendObject: () => extendObject,
|
|
35
36
|
flattenObject: () => flattenObject,
|
|
@@ -147,8 +148,9 @@ function pipe(...fns) {
|
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
// src/lib/objects/mix/mix.js
|
|
150
|
-
var DEFAULT_OPTIONS = { array: "
|
|
151
|
+
var DEFAULT_OPTIONS = { array: "replace" };
|
|
151
152
|
var mix = createMix();
|
|
153
|
+
var concatMix = createMix({ array: "concat" });
|
|
152
154
|
function createMix(userOptions = {}) {
|
|
153
155
|
const options = { ...DEFAULT_OPTIONS, ...userOptions };
|
|
154
156
|
function _mix(...sources) {
|
|
@@ -354,6 +356,7 @@ function splitObject(obj, keys) {
|
|
|
354
356
|
// Annotate the CommonJS export names for ESM import in node:
|
|
355
357
|
0 && (module.exports = {
|
|
356
358
|
camelCaseKeys,
|
|
359
|
+
concatMix,
|
|
357
360
|
createMix,
|
|
358
361
|
extendObject,
|
|
359
362
|
flattenObject,
|
|
@@ -19,12 +19,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
// src/lib/objects/mix/mix.js
|
|
20
20
|
var mix_exports = {};
|
|
21
21
|
__export(mix_exports, {
|
|
22
|
+
concatMix: () => concatMix,
|
|
22
23
|
createMix: () => createMix,
|
|
23
24
|
mix: () => mix
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(mix_exports);
|
|
26
|
-
var DEFAULT_OPTIONS = { array: "
|
|
27
|
+
var DEFAULT_OPTIONS = { array: "replace" };
|
|
27
28
|
var mix = createMix();
|
|
29
|
+
var concatMix = createMix({ array: "concat" });
|
|
28
30
|
function createMix(userOptions = {}) {
|
|
29
31
|
const options = { ...DEFAULT_OPTIONS, ...userOptions };
|
|
30
32
|
function _mix(...sources) {
|
|
@@ -107,6 +109,7 @@ function objectType(value) {
|
|
|
107
109
|
}
|
|
108
110
|
// Annotate the CommonJS export names for ESM import in node:
|
|
109
111
|
0 && (module.exports = {
|
|
112
|
+
concatMix,
|
|
110
113
|
createMix,
|
|
111
114
|
mix
|
|
112
115
|
});
|
|
@@ -37,7 +37,7 @@ __export(file_cache_exports, {
|
|
|
37
37
|
});
|
|
38
38
|
module.exports = __toCommonJS(file_cache_exports);
|
|
39
39
|
var import_promises = __toESM(require("fs/promises"), 1);
|
|
40
|
-
var
|
|
40
|
+
var import_glob = require("glob");
|
|
41
41
|
var import_node_path = __toESM(require("path"), 1);
|
|
42
42
|
|
|
43
43
|
// src/lib/objects/nested-property.js
|
|
@@ -164,11 +164,11 @@ async function fileCache({ dir, file }) {
|
|
|
164
164
|
async function getLastModifiedTime(globPath) {
|
|
165
165
|
let files;
|
|
166
166
|
if (typeof globPath === "string") {
|
|
167
|
-
files = await (0,
|
|
167
|
+
files = await (0, import_glob.glob)(removeFirstSlash(globPath));
|
|
168
168
|
}
|
|
169
169
|
if (Array.isArray(globPath)) {
|
|
170
170
|
const a = await Promise.all(
|
|
171
|
-
globPath.map((path2) => (0,
|
|
171
|
+
globPath.map((path2) => (0, import_glob.glob)(removeFirstSlash(path2)))
|
|
172
172
|
);
|
|
173
173
|
files = a.flat();
|
|
174
174
|
}
|
package/dist/cjs/node/index.cjs
CHANGED
|
@@ -63,7 +63,7 @@ function dirname(url) {
|
|
|
63
63
|
|
|
64
64
|
// src/node/file-cache.js
|
|
65
65
|
var import_promises = __toESM(require("fs/promises"), 1);
|
|
66
|
-
var
|
|
66
|
+
var import_glob = require("glob");
|
|
67
67
|
var import_node_path2 = __toESM(require("path"), 1);
|
|
68
68
|
|
|
69
69
|
// src/lib/objects/nested-property.js
|
|
@@ -190,11 +190,11 @@ async function fileCache({ dir, file }) {
|
|
|
190
190
|
async function getLastModifiedTime(globPath) {
|
|
191
191
|
let files;
|
|
192
192
|
if (typeof globPath === "string") {
|
|
193
|
-
files = await (0,
|
|
193
|
+
files = await (0, import_glob.glob)(removeFirstSlash(globPath));
|
|
194
194
|
}
|
|
195
195
|
if (Array.isArray(globPath)) {
|
|
196
196
|
const a = await Promise.all(
|
|
197
|
-
globPath.map((path3) => (0,
|
|
197
|
+
globPath.map((path3) => (0, import_glob.glob)(removeFirstSlash(path3)))
|
|
198
198
|
);
|
|
199
199
|
files = a.flat();
|
|
200
200
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/lib/numbers/index.js
|
|
2
2
|
function splitUnit(string) {
|
|
3
3
|
if (typeof string === "number") return [string, null];
|
|
4
|
-
const regex = /(-?\d*\.?\d+)([a-z]+)/i;
|
|
4
|
+
const regex = /(-?\d*\.?\d+)\s*([a-z]+)/i;
|
|
5
5
|
const match = string.match(regex);
|
|
6
6
|
if (match) return [parseFloat(match[1]), match[2]];
|
|
7
7
|
return [parseFloat(string), null];
|
package/dist/esm/dom/index.js
CHANGED
|
@@ -242,7 +242,7 @@ function nativeMasonrySupport(node) {
|
|
|
242
242
|
// src/lib/numbers/index.js
|
|
243
243
|
function splitUnit(string) {
|
|
244
244
|
if (typeof string === "number") return [string, null];
|
|
245
|
-
const regex = /(-?\d*\.?\d+)([a-z]+)/i;
|
|
245
|
+
const regex = /(-?\d*\.?\d+)\s*([a-z]+)/i;
|
|
246
246
|
const match = string.match(regex);
|
|
247
247
|
if (match) return [parseFloat(match[1]), match[2]];
|
|
248
248
|
return [parseFloat(string), null];
|
|
@@ -847,6 +847,94 @@ function mutationObserver(target, options) {
|
|
|
847
847
|
};
|
|
848
848
|
}
|
|
849
849
|
|
|
850
|
+
// src/dom/observers/scroll-observer.js
|
|
851
|
+
var defaultOptions2 = {
|
|
852
|
+
threshold: 0,
|
|
853
|
+
// Float between 0 to 1.
|
|
854
|
+
tolerance: 0.1,
|
|
855
|
+
// Float between 0 to 1. Tolerance for event firing
|
|
856
|
+
throttle: 16,
|
|
857
|
+
// Throttle interval in ms (default: ~60fps)
|
|
858
|
+
once: false
|
|
859
|
+
// Only fire threshold callback once
|
|
860
|
+
};
|
|
861
|
+
function scrollObserver(node, options = {}) {
|
|
862
|
+
const { callback, onScrollDown, onScrollUp, onEnterThreshold, ...userOpts } = options;
|
|
863
|
+
const opts = { ...defaultOptions2, ...userOpts };
|
|
864
|
+
const { threshold, tolerance, throttle, once } = opts;
|
|
865
|
+
const prevScrollDirection = null;
|
|
866
|
+
let prevScrollTop = 0;
|
|
867
|
+
let prevScrollPercent = 0;
|
|
868
|
+
let lastThrottleTime = 0;
|
|
869
|
+
let thresholdFired = false;
|
|
870
|
+
let rafId = null;
|
|
871
|
+
const isDocumentScroll = node === document || node === window;
|
|
872
|
+
const scrollElement = isDocumentScroll ? document.documentElement : node;
|
|
873
|
+
let cachedScrollHeight = 0;
|
|
874
|
+
let cachedClientHeight = 0;
|
|
875
|
+
updateCache();
|
|
876
|
+
const cacheObserver = resizeObserver(scrollElement, {
|
|
877
|
+
callback: updateCache
|
|
878
|
+
});
|
|
879
|
+
node.addEventListener("scroll", throttledObserve, { passive: true });
|
|
880
|
+
function updateCache() {
|
|
881
|
+
cachedScrollHeight = scrollElement.scrollHeight;
|
|
882
|
+
cachedClientHeight = scrollElement.clientHeight;
|
|
883
|
+
}
|
|
884
|
+
function throttledObserve() {
|
|
885
|
+
const now = Date.now();
|
|
886
|
+
if (now - lastThrottleTime < throttle) return;
|
|
887
|
+
lastThrottleTime = now;
|
|
888
|
+
rafId = requestAnimationFrame(observe);
|
|
889
|
+
}
|
|
890
|
+
function observe() {
|
|
891
|
+
const scrollTop = scrollElement.scrollTop;
|
|
892
|
+
if (Math.abs(scrollTop - prevScrollTop) < 1) return;
|
|
893
|
+
const scrollDirection = scrollTop > prevScrollTop ? "down" : "up";
|
|
894
|
+
const maxScroll = Math.max(1, cachedScrollHeight - cachedClientHeight);
|
|
895
|
+
const scrollPercent = Math.min(1, Math.max(0, scrollTop / maxScroll));
|
|
896
|
+
const thresholdMin = threshold - tolerance / 2;
|
|
897
|
+
const thresholdMax = threshold + tolerance / 2;
|
|
898
|
+
const wasInThreshold = prevScrollPercent >= thresholdMin && prevScrollPercent <= thresholdMax;
|
|
899
|
+
const isInThreshold = scrollPercent >= thresholdMin && scrollPercent <= thresholdMax;
|
|
900
|
+
const hasEnteredThreshold = !wasInThreshold && isInThreshold && (!once || !thresholdFired);
|
|
901
|
+
if (hasEnteredThreshold && once) {
|
|
902
|
+
thresholdFired = true;
|
|
903
|
+
}
|
|
904
|
+
const callbackData = {
|
|
905
|
+
scrollTop,
|
|
906
|
+
scrollDirection,
|
|
907
|
+
scrollPercent,
|
|
908
|
+
directionChanged: scrollDirection !== prevScrollDirection,
|
|
909
|
+
hasEnteredThreshold,
|
|
910
|
+
isInThreshold
|
|
911
|
+
};
|
|
912
|
+
if (typeof callback === "function") {
|
|
913
|
+
callback(callbackData);
|
|
914
|
+
}
|
|
915
|
+
if (scrollDirection !== prevScrollDirection) {
|
|
916
|
+
if (scrollDirection === "down" && typeof onScrollDown === "function") {
|
|
917
|
+
onScrollDown(callbackData);
|
|
918
|
+
}
|
|
919
|
+
if (scrollDirection === "up" && typeof onScrollUp === "function") {
|
|
920
|
+
onScrollUp(callbackData);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
if (hasEnteredThreshold && typeof onEnterThreshold === "function") {
|
|
924
|
+
onEnterThreshold(callbackData);
|
|
925
|
+
}
|
|
926
|
+
prevScrollTop = scrollTop;
|
|
927
|
+
prevScrollPercent = scrollPercent;
|
|
928
|
+
}
|
|
929
|
+
return {
|
|
930
|
+
destroy() {
|
|
931
|
+
node.removeEventListener("scroll", throttledObserve);
|
|
932
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
933
|
+
cacheObserver.destroy();
|
|
934
|
+
}
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
|
|
850
938
|
// src/dom/random-string.js
|
|
851
939
|
function randomString(length = 10) {
|
|
852
940
|
const firstLetter = String.fromCharCode(65 + Math.floor(Math.random() * 26));
|
|
@@ -1085,6 +1173,7 @@ export {
|
|
|
1085
1173
|
removeListeners,
|
|
1086
1174
|
resizeObserver,
|
|
1087
1175
|
sanitize2 as sanitize,
|
|
1176
|
+
scrollObserver,
|
|
1088
1177
|
scrollToElement,
|
|
1089
1178
|
sessionStore,
|
|
1090
1179
|
setCSSValue,
|
|
@@ -121,8 +121,97 @@ function resizeObserver(target, options) {
|
|
|
121
121
|
destroy: (_) => observer.disconnect()
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
|
+
|
|
125
|
+
// src/dom/observers/scroll-observer.js
|
|
126
|
+
var defaultOptions2 = {
|
|
127
|
+
threshold: 0,
|
|
128
|
+
// Float between 0 to 1.
|
|
129
|
+
tolerance: 0.1,
|
|
130
|
+
// Float between 0 to 1. Tolerance for event firing
|
|
131
|
+
throttle: 16,
|
|
132
|
+
// Throttle interval in ms (default: ~60fps)
|
|
133
|
+
once: false
|
|
134
|
+
// Only fire threshold callback once
|
|
135
|
+
};
|
|
136
|
+
function scrollObserver(node, options = {}) {
|
|
137
|
+
const { callback, onScrollDown, onScrollUp, onEnterThreshold, ...userOpts } = options;
|
|
138
|
+
const opts = { ...defaultOptions2, ...userOpts };
|
|
139
|
+
const { threshold, tolerance, throttle, once } = opts;
|
|
140
|
+
const prevScrollDirection = null;
|
|
141
|
+
let prevScrollTop = 0;
|
|
142
|
+
let prevScrollPercent = 0;
|
|
143
|
+
let lastThrottleTime = 0;
|
|
144
|
+
let thresholdFired = false;
|
|
145
|
+
let rafId = null;
|
|
146
|
+
const isDocumentScroll = node === document || node === window;
|
|
147
|
+
const scrollElement = isDocumentScroll ? document.documentElement : node;
|
|
148
|
+
let cachedScrollHeight = 0;
|
|
149
|
+
let cachedClientHeight = 0;
|
|
150
|
+
updateCache();
|
|
151
|
+
const cacheObserver = resizeObserver(scrollElement, {
|
|
152
|
+
callback: updateCache
|
|
153
|
+
});
|
|
154
|
+
node.addEventListener("scroll", throttledObserve, { passive: true });
|
|
155
|
+
function updateCache() {
|
|
156
|
+
cachedScrollHeight = scrollElement.scrollHeight;
|
|
157
|
+
cachedClientHeight = scrollElement.clientHeight;
|
|
158
|
+
}
|
|
159
|
+
function throttledObserve() {
|
|
160
|
+
const now = Date.now();
|
|
161
|
+
if (now - lastThrottleTime < throttle) return;
|
|
162
|
+
lastThrottleTime = now;
|
|
163
|
+
rafId = requestAnimationFrame(observe);
|
|
164
|
+
}
|
|
165
|
+
function observe() {
|
|
166
|
+
const scrollTop = scrollElement.scrollTop;
|
|
167
|
+
if (Math.abs(scrollTop - prevScrollTop) < 1) return;
|
|
168
|
+
const scrollDirection = scrollTop > prevScrollTop ? "down" : "up";
|
|
169
|
+
const maxScroll = Math.max(1, cachedScrollHeight - cachedClientHeight);
|
|
170
|
+
const scrollPercent = Math.min(1, Math.max(0, scrollTop / maxScroll));
|
|
171
|
+
const thresholdMin = threshold - tolerance / 2;
|
|
172
|
+
const thresholdMax = threshold + tolerance / 2;
|
|
173
|
+
const wasInThreshold = prevScrollPercent >= thresholdMin && prevScrollPercent <= thresholdMax;
|
|
174
|
+
const isInThreshold = scrollPercent >= thresholdMin && scrollPercent <= thresholdMax;
|
|
175
|
+
const hasEnteredThreshold = !wasInThreshold && isInThreshold && (!once || !thresholdFired);
|
|
176
|
+
if (hasEnteredThreshold && once) {
|
|
177
|
+
thresholdFired = true;
|
|
178
|
+
}
|
|
179
|
+
const callbackData = {
|
|
180
|
+
scrollTop,
|
|
181
|
+
scrollDirection,
|
|
182
|
+
scrollPercent,
|
|
183
|
+
directionChanged: scrollDirection !== prevScrollDirection,
|
|
184
|
+
hasEnteredThreshold,
|
|
185
|
+
isInThreshold
|
|
186
|
+
};
|
|
187
|
+
if (typeof callback === "function") {
|
|
188
|
+
callback(callbackData);
|
|
189
|
+
}
|
|
190
|
+
if (scrollDirection !== prevScrollDirection) {
|
|
191
|
+
if (scrollDirection === "down" && typeof onScrollDown === "function") {
|
|
192
|
+
onScrollDown(callbackData);
|
|
193
|
+
}
|
|
194
|
+
if (scrollDirection === "up" && typeof onScrollUp === "function") {
|
|
195
|
+
onScrollUp(callbackData);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (hasEnteredThreshold && typeof onEnterThreshold === "function") {
|
|
199
|
+
onEnterThreshold(callbackData);
|
|
200
|
+
}
|
|
201
|
+
prevScrollTop = scrollTop;
|
|
202
|
+
prevScrollPercent = scrollPercent;
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
destroy() {
|
|
206
|
+
node.removeEventListener("scroll", throttledObserve);
|
|
207
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
208
|
+
cacheObserver.destroy();
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
124
212
|
export {
|
|
125
213
|
intersectionObserver,
|
|
126
214
|
mutationObserver,
|
|
127
|
-
resizeObserver
|
|
215
|
+
resizeObserver,
|
|
216
|
+
scrollObserver
|
|
128
217
|
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// src/dom/events.js
|
|
2
|
+
function dispatchEvent(node, eventName, detail, options = {}) {
|
|
3
|
+
node.dispatchEvent(
|
|
4
|
+
new CustomEvent(eventName, {
|
|
5
|
+
...options,
|
|
6
|
+
detail
|
|
7
|
+
})
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// src/dom/get-element.js
|
|
12
|
+
function getNodeType(node) {
|
|
13
|
+
if (node instanceof Element) return "element";
|
|
14
|
+
if (node instanceof NodeList) return "nodelist";
|
|
15
|
+
if (Array.isArray(node)) return "array";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/dom/observers/observer.js
|
|
19
|
+
function useObserverMethodOnTarget(target, observer, method = "observe", options = void 0) {
|
|
20
|
+
const targetType = getNodeType(target);
|
|
21
|
+
if (targetType === "element") observer[method](target, options);
|
|
22
|
+
if (targetType === "nodelist") {
|
|
23
|
+
const elements = Array.from(target);
|
|
24
|
+
elements.forEach((element) => observer[method](element, options));
|
|
25
|
+
}
|
|
26
|
+
if (targetType === "array") {
|
|
27
|
+
target.forEach((element) => observer[method](element, options));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/dom/observers/resize-observer.js
|
|
32
|
+
function resizeObserver(target, options) {
|
|
33
|
+
const { callback, ...opts } = options;
|
|
34
|
+
const observer = new ResizeObserver(observerFn);
|
|
35
|
+
if (target === window) target = document.body;
|
|
36
|
+
useObserverMethodOnTarget(target, observer, "observe", opts);
|
|
37
|
+
function observerFn(entries) {
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
if (callback) callback({ entry, entries, observer });
|
|
40
|
+
else dispatchEvent(target, "resize-obs", { entry, entries, observer });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
observe(target2) {
|
|
45
|
+
useObserverMethodOnTarget(target2, observer, "observe", options);
|
|
46
|
+
},
|
|
47
|
+
unobserve(target2) {
|
|
48
|
+
useObserverMethodOnTarget(target2, observer, "unobserve");
|
|
49
|
+
},
|
|
50
|
+
disconnect: (_) => observer.disconnect(),
|
|
51
|
+
destroy: (_) => observer.disconnect()
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/dom/observers/scroll-observer.js
|
|
56
|
+
var defaultOptions = {
|
|
57
|
+
threshold: 0,
|
|
58
|
+
// Float between 0 to 1.
|
|
59
|
+
tolerance: 0.1,
|
|
60
|
+
// Float between 0 to 1. Tolerance for event firing
|
|
61
|
+
throttle: 16,
|
|
62
|
+
// Throttle interval in ms (default: ~60fps)
|
|
63
|
+
once: false
|
|
64
|
+
// Only fire threshold callback once
|
|
65
|
+
};
|
|
66
|
+
function scrollObserver(node, options = {}) {
|
|
67
|
+
const { callback, onScrollDown, onScrollUp, onEnterThreshold, ...userOpts } = options;
|
|
68
|
+
const opts = { ...defaultOptions, ...userOpts };
|
|
69
|
+
const { threshold, tolerance, throttle, once } = opts;
|
|
70
|
+
const prevScrollDirection = null;
|
|
71
|
+
let prevScrollTop = 0;
|
|
72
|
+
let prevScrollPercent = 0;
|
|
73
|
+
let lastThrottleTime = 0;
|
|
74
|
+
let thresholdFired = false;
|
|
75
|
+
let rafId = null;
|
|
76
|
+
const isDocumentScroll = node === document || node === window;
|
|
77
|
+
const scrollElement = isDocumentScroll ? document.documentElement : node;
|
|
78
|
+
let cachedScrollHeight = 0;
|
|
79
|
+
let cachedClientHeight = 0;
|
|
80
|
+
updateCache();
|
|
81
|
+
const cacheObserver = resizeObserver(scrollElement, {
|
|
82
|
+
callback: updateCache
|
|
83
|
+
});
|
|
84
|
+
node.addEventListener("scroll", throttledObserve, { passive: true });
|
|
85
|
+
function updateCache() {
|
|
86
|
+
cachedScrollHeight = scrollElement.scrollHeight;
|
|
87
|
+
cachedClientHeight = scrollElement.clientHeight;
|
|
88
|
+
}
|
|
89
|
+
function throttledObserve() {
|
|
90
|
+
const now = Date.now();
|
|
91
|
+
if (now - lastThrottleTime < throttle) return;
|
|
92
|
+
lastThrottleTime = now;
|
|
93
|
+
rafId = requestAnimationFrame(observe);
|
|
94
|
+
}
|
|
95
|
+
function observe() {
|
|
96
|
+
const scrollTop = scrollElement.scrollTop;
|
|
97
|
+
if (Math.abs(scrollTop - prevScrollTop) < 1) return;
|
|
98
|
+
const scrollDirection = scrollTop > prevScrollTop ? "down" : "up";
|
|
99
|
+
const maxScroll = Math.max(1, cachedScrollHeight - cachedClientHeight);
|
|
100
|
+
const scrollPercent = Math.min(1, Math.max(0, scrollTop / maxScroll));
|
|
101
|
+
const thresholdMin = threshold - tolerance / 2;
|
|
102
|
+
const thresholdMax = threshold + tolerance / 2;
|
|
103
|
+
const wasInThreshold = prevScrollPercent >= thresholdMin && prevScrollPercent <= thresholdMax;
|
|
104
|
+
const isInThreshold = scrollPercent >= thresholdMin && scrollPercent <= thresholdMax;
|
|
105
|
+
const hasEnteredThreshold = !wasInThreshold && isInThreshold && (!once || !thresholdFired);
|
|
106
|
+
if (hasEnteredThreshold && once) {
|
|
107
|
+
thresholdFired = true;
|
|
108
|
+
}
|
|
109
|
+
const callbackData = {
|
|
110
|
+
scrollTop,
|
|
111
|
+
scrollDirection,
|
|
112
|
+
scrollPercent,
|
|
113
|
+
directionChanged: scrollDirection !== prevScrollDirection,
|
|
114
|
+
hasEnteredThreshold,
|
|
115
|
+
isInThreshold
|
|
116
|
+
};
|
|
117
|
+
if (typeof callback === "function") {
|
|
118
|
+
callback(callbackData);
|
|
119
|
+
}
|
|
120
|
+
if (scrollDirection !== prevScrollDirection) {
|
|
121
|
+
if (scrollDirection === "down" && typeof onScrollDown === "function") {
|
|
122
|
+
onScrollDown(callbackData);
|
|
123
|
+
}
|
|
124
|
+
if (scrollDirection === "up" && typeof onScrollUp === "function") {
|
|
125
|
+
onScrollUp(callbackData);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (hasEnteredThreshold && typeof onEnterThreshold === "function") {
|
|
129
|
+
onEnterThreshold(callbackData);
|
|
130
|
+
}
|
|
131
|
+
prevScrollTop = scrollTop;
|
|
132
|
+
prevScrollPercent = scrollPercent;
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
destroy() {
|
|
136
|
+
node.removeEventListener("scroll", throttledObserve);
|
|
137
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
138
|
+
cacheObserver.destroy();
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
export {
|
|
143
|
+
scrollObserver
|
|
144
|
+
};
|
|
@@ -88,7 +88,7 @@ var MONTHS = [
|
|
|
88
88
|
// src/lib/numbers/index.js
|
|
89
89
|
function splitUnit(string) {
|
|
90
90
|
if (typeof string === "number") return [string, null];
|
|
91
|
-
const regex = /(-?\d*\.?\d+)([a-z]+)/i;
|
|
91
|
+
const regex = /(-?\d*\.?\d+)\s*([a-z]+)/i;
|
|
92
92
|
const match = string.match(regex);
|
|
93
93
|
if (match) return [parseFloat(match[1]), match[2]];
|
|
94
94
|
return [parseFloat(string), null];
|
|
@@ -106,10 +106,12 @@ function ms(arg) {
|
|
|
106
106
|
if (unit === "hours") return getTimeInMs(value, "hours");
|
|
107
107
|
if (unit === "m") return getTimeInMs(value, "minutes");
|
|
108
108
|
if (unit === "min") return getTimeInMs(value, "minutes");
|
|
109
|
+
if (unit === "mins") return getTimeInMs(value, "minutes");
|
|
109
110
|
if (unit === "minute") return getTimeInMs(value, "minutes");
|
|
110
111
|
if (unit === "minutes") return getTimeInMs(value, "minutes");
|
|
111
112
|
if (unit === "s") return getTimeInMs(value, "seconds");
|
|
112
113
|
if (unit === "sec") return getTimeInMs(value, "seconds");
|
|
114
|
+
if (unit === "secs") return getTimeInMs(value, "seconds");
|
|
113
115
|
if (unit === "second") return getTimeInMs(value, "seconds");
|
|
114
116
|
if (unit === "seconds") return getTimeInMs(value, "seconds");
|
|
115
117
|
return value;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/lib/numbers/index.js
|
|
2
2
|
function splitUnit(string) {
|
|
3
3
|
if (typeof string === "number") return [string, null];
|
|
4
|
-
const regex = /(-?\d*\.?\d+)([a-z]+)/i;
|
|
4
|
+
const regex = /(-?\d*\.?\d+)\s*([a-z]+)/i;
|
|
5
5
|
const match = string.match(regex);
|
|
6
6
|
if (match) return [parseFloat(match[1]), match[2]];
|
|
7
7
|
return [parseFloat(string), null];
|
|
@@ -19,10 +19,12 @@ function ms(arg) {
|
|
|
19
19
|
if (unit === "hours") return getTimeInMs(value, "hours");
|
|
20
20
|
if (unit === "m") return getTimeInMs(value, "minutes");
|
|
21
21
|
if (unit === "min") return getTimeInMs(value, "minutes");
|
|
22
|
+
if (unit === "mins") return getTimeInMs(value, "minutes");
|
|
22
23
|
if (unit === "minute") return getTimeInMs(value, "minutes");
|
|
23
24
|
if (unit === "minutes") return getTimeInMs(value, "minutes");
|
|
24
25
|
if (unit === "s") return getTimeInMs(value, "seconds");
|
|
25
26
|
if (unit === "sec") return getTimeInMs(value, "seconds");
|
|
27
|
+
if (unit === "secs") return getTimeInMs(value, "seconds");
|
|
26
28
|
if (unit === "second") return getTimeInMs(value, "seconds");
|
|
27
29
|
if (unit === "seconds") return getTimeInMs(value, "seconds");
|
|
28
30
|
return value;
|
|
@@ -15,11 +15,27 @@ function compose(...fns) {
|
|
|
15
15
|
return fns.reduceRight((acc, fn) => fn(acc), value);
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
|
+
function composeAsync(...fns) {
|
|
19
|
+
return async function(value) {
|
|
20
|
+
return fns.reduceRight(async (acc, fn) => {
|
|
21
|
+
const result = await acc;
|
|
22
|
+
return await fn(result);
|
|
23
|
+
}, value);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
18
26
|
function pipe(...fns) {
|
|
19
27
|
return function(value) {
|
|
20
28
|
return fns.reduce((acc, fn) => fn(acc), value);
|
|
21
29
|
};
|
|
22
30
|
}
|
|
31
|
+
function pipeAsync(...fns) {
|
|
32
|
+
return async function(value) {
|
|
33
|
+
return fns.reduce(async (acc, fn) => {
|
|
34
|
+
const result = await acc;
|
|
35
|
+
return await fn(result);
|
|
36
|
+
}, value);
|
|
37
|
+
};
|
|
38
|
+
}
|
|
23
39
|
function times(fn, n) {
|
|
24
40
|
const result = [];
|
|
25
41
|
for (let i = 0; i < n; i++) {
|
|
@@ -29,7 +45,9 @@ function times(fn, n) {
|
|
|
29
45
|
}
|
|
30
46
|
export {
|
|
31
47
|
compose,
|
|
48
|
+
composeAsync,
|
|
32
49
|
curry,
|
|
33
50
|
pipe,
|
|
51
|
+
pipeAsync,
|
|
34
52
|
times
|
|
35
53
|
};
|
|
@@ -38,11 +38,27 @@ function compose(...fns) {
|
|
|
38
38
|
return fns.reduceRight((acc, fn) => fn(acc), value);
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
+
function composeAsync(...fns) {
|
|
42
|
+
return async function(value) {
|
|
43
|
+
return fns.reduceRight(async (acc, fn) => {
|
|
44
|
+
const result = await acc;
|
|
45
|
+
return await fn(result);
|
|
46
|
+
}, value);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
41
49
|
function pipe(...fns) {
|
|
42
50
|
return function(value) {
|
|
43
51
|
return fns.reduce((acc, fn) => fn(acc), value);
|
|
44
52
|
};
|
|
45
53
|
}
|
|
54
|
+
function pipeAsync(...fns) {
|
|
55
|
+
return async function(value) {
|
|
56
|
+
return fns.reduce(async (acc, fn) => {
|
|
57
|
+
const result = await acc;
|
|
58
|
+
return await fn(result);
|
|
59
|
+
}, value);
|
|
60
|
+
};
|
|
61
|
+
}
|
|
46
62
|
function times(fn, n) {
|
|
47
63
|
const result = [];
|
|
48
64
|
for (let i = 0; i < n; i++) {
|
|
@@ -75,11 +91,13 @@ function wait(ms) {
|
|
|
75
91
|
}
|
|
76
92
|
export {
|
|
77
93
|
compose,
|
|
94
|
+
composeAsync,
|
|
78
95
|
curry,
|
|
79
96
|
debounce,
|
|
80
97
|
delay,
|
|
81
98
|
getEnv,
|
|
82
99
|
pipe,
|
|
100
|
+
pipeAsync,
|
|
83
101
|
throttle,
|
|
84
102
|
timeout,
|
|
85
103
|
times,
|
package/dist/esm/lib/index.js
CHANGED
|
@@ -252,7 +252,7 @@ function toRadians(angle) {
|
|
|
252
252
|
// src/lib/numbers/index.js
|
|
253
253
|
function splitUnit(string) {
|
|
254
254
|
if (typeof string === "number") return [string, null];
|
|
255
|
-
const regex = /(-?\d*\.?\d+)([a-z]+)/i;
|
|
255
|
+
const regex = /(-?\d*\.?\d+)\s*([a-z]+)/i;
|
|
256
256
|
const match = string.match(regex);
|
|
257
257
|
if (match) return [parseFloat(match[1]), match[2]];
|
|
258
258
|
return [parseFloat(string), null];
|
|
@@ -270,10 +270,12 @@ function ms(arg) {
|
|
|
270
270
|
if (unit === "hours") return getTimeInMs(value, "hours");
|
|
271
271
|
if (unit === "m") return getTimeInMs(value, "minutes");
|
|
272
272
|
if (unit === "min") return getTimeInMs(value, "minutes");
|
|
273
|
+
if (unit === "mins") return getTimeInMs(value, "minutes");
|
|
273
274
|
if (unit === "minute") return getTimeInMs(value, "minutes");
|
|
274
275
|
if (unit === "minutes") return getTimeInMs(value, "minutes");
|
|
275
276
|
if (unit === "s") return getTimeInMs(value, "seconds");
|
|
276
277
|
if (unit === "sec") return getTimeInMs(value, "seconds");
|
|
278
|
+
if (unit === "secs") return getTimeInMs(value, "seconds");
|
|
277
279
|
if (unit === "second") return getTimeInMs(value, "seconds");
|
|
278
280
|
if (unit === "seconds") return getTimeInMs(value, "seconds");
|
|
279
281
|
return value;
|
|
@@ -448,11 +450,27 @@ function compose(...fns) {
|
|
|
448
450
|
return fns.reduceRight((acc, fn) => fn(acc), value);
|
|
449
451
|
};
|
|
450
452
|
}
|
|
453
|
+
function composeAsync(...fns) {
|
|
454
|
+
return async function(value) {
|
|
455
|
+
return fns.reduceRight(async (acc, fn) => {
|
|
456
|
+
const result = await acc;
|
|
457
|
+
return await fn(result);
|
|
458
|
+
}, value);
|
|
459
|
+
};
|
|
460
|
+
}
|
|
451
461
|
function pipe(...fns) {
|
|
452
462
|
return function(value) {
|
|
453
463
|
return fns.reduce((acc, fn) => fn(acc), value);
|
|
454
464
|
};
|
|
455
465
|
}
|
|
466
|
+
function pipeAsync(...fns) {
|
|
467
|
+
return async function(value) {
|
|
468
|
+
return fns.reduce(async (acc, fn) => {
|
|
469
|
+
const result = await acc;
|
|
470
|
+
return await fn(result);
|
|
471
|
+
}, value);
|
|
472
|
+
};
|
|
473
|
+
}
|
|
456
474
|
function times(fn, n) {
|
|
457
475
|
const result = [];
|
|
458
476
|
for (let i = 0; i < n; i++) {
|
|
@@ -603,8 +621,9 @@ function notEqual(a, b) {
|
|
|
603
621
|
}
|
|
604
622
|
|
|
605
623
|
// src/lib/objects/mix/mix.js
|
|
606
|
-
var DEFAULT_OPTIONS = { array: "
|
|
624
|
+
var DEFAULT_OPTIONS = { array: "replace" };
|
|
607
625
|
var mix = createMix();
|
|
626
|
+
var concatMix = createMix({ array: "concat" });
|
|
608
627
|
function createMix(userOptions = {}) {
|
|
609
628
|
const options = { ...DEFAULT_OPTIONS, ...userOptions };
|
|
610
629
|
function _mix(...sources) {
|
|
@@ -943,6 +962,8 @@ export {
|
|
|
943
962
|
RouteManager,
|
|
944
963
|
camelCaseKeys,
|
|
945
964
|
compose,
|
|
965
|
+
composeAsync,
|
|
966
|
+
concatMix,
|
|
946
967
|
createMix,
|
|
947
968
|
createSSE,
|
|
948
969
|
curry,
|
|
@@ -983,6 +1004,7 @@ export {
|
|
|
983
1004
|
parseJSON,
|
|
984
1005
|
parseSSE,
|
|
985
1006
|
pipe,
|
|
1007
|
+
pipeAsync,
|
|
986
1008
|
plural,
|
|
987
1009
|
pluralize,
|
|
988
1010
|
reject,
|
|
@@ -9,7 +9,7 @@ function toRadians(angle) {
|
|
|
9
9
|
// src/lib/numbers/index.js
|
|
10
10
|
function splitUnit(string) {
|
|
11
11
|
if (typeof string === "number") return [string, null];
|
|
12
|
-
const regex = /(-?\d*\.?\d+)([a-z]+)/i;
|
|
12
|
+
const regex = /(-?\d*\.?\d+)\s*([a-z]+)/i;
|
|
13
13
|
const match = string.match(regex);
|
|
14
14
|
if (match) return [parseFloat(match[1]), match[2]];
|
|
15
15
|
return [parseFloat(string), null];
|