@sohanemon/utils 4.0.33 → 4.1.0

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.
@@ -80,21 +80,77 @@ export declare const svgToBase64: (str: string) => string;
80
80
  * @returns - A Promise that resolves after the specified time
81
81
  */
82
82
  export declare const sleep: (time?: number) => Promise<unknown>;
83
+ type DebouncedFunction<F extends (...args: any[]) => any> = {
84
+ (...args: Parameters<F>): ReturnType<F> | undefined;
85
+ readonly isPending: boolean;
86
+ };
83
87
  /**
84
88
  * Creates a debounced function that delays invoking the provided function until
85
- * after the specified wait time has elapsed since the last invocation.
89
+ * after the specified `wait` time has elapsed since the last invocation.
86
90
  *
87
- * @param func - The function to debounce
88
- * @param wait - The number of milliseconds to delay (default is 1000ms)
89
- * @returns - A debounced version of the function
91
+ * If the `immediate` option is set to `true`, the function will be invoked immediately
92
+ * on the leading edge of the wait interval. Subsequent calls during the wait interval
93
+ * will reset the timer but not invoke the function until the interval elapses again.
94
+ *
95
+ * The returned function includes the `isPending` property to check if the debounce
96
+ * timer is currently active.
97
+ *
98
+ * @typeParam F - The type of the function to debounce.
99
+ *
100
+ * @param function_ - The function to debounce.
101
+ * @param wait - The number of milliseconds to delay (default is 100ms).
102
+ * @param options - An optional object with the following properties:
103
+ * - `immediate` (boolean): If `true`, invokes the function on the leading edge
104
+ * of the wait interval instead of the trailing edge.
105
+ *
106
+ * @returns A debounced version of the provided function, enhanced with the `isPending` property.
107
+ *
108
+ * @throws {TypeError} If the first parameter is not a function.
109
+ * @throws {RangeError} If the `wait` parameter is negative.
110
+ *
111
+ * @example
112
+ * const log = debounce((message: string) => console.log(message), 200);
113
+ * log('Hello'); // Logs "Hello" after 200ms if no other call is made.
114
+ * console.log(log.isPending); // true if the timer is active.
90
115
  */
91
- export declare function debounce<T extends (...args: any[]) => void>(func: T, wait?: number): (...args: Parameters<T>) => void;
116
+ export declare function debounce<F extends (...args: any[]) => any>(function_: F, wait?: number, options?: {
117
+ immediate: boolean;
118
+ }): DebouncedFunction<F>;
119
+ type ThrottledFunction<F extends (...args: any[]) => any> = {
120
+ (...args: Parameters<F>): ReturnType<F> | undefined;
121
+ readonly isPending: boolean;
122
+ };
92
123
  /**
93
124
  * Creates a throttled function that invokes the provided function at most once
94
- * every specified wait time.
125
+ * every `wait` milliseconds.
126
+ *
127
+ * If the `leading` option is set to `true`, the function will be invoked immediately
128
+ * on the leading edge of the throttle interval. If the `trailing` option is set to `true`,
129
+ * the function will also be invoked at the end of the throttle interval if additional
130
+ * calls were made during the interval.
131
+ *
132
+ * The returned function includes the `isPending` property to check if the throttle
133
+ * timer is currently active.
134
+ *
135
+ * @typeParam F - The type of the function to throttle.
136
+ *
137
+ * @param function_ - The function to throttle.
138
+ * @param wait - The number of milliseconds to wait between invocations (default is 100ms).
139
+ * @param options - An optional object with the following properties:
140
+ * - `leading` (boolean): If `true`, invokes the function on the leading edge of the interval.
141
+ * - `trailing` (boolean): If `true`, invokes the function on the trailing edge of the interval.
142
+ *
143
+ * @returns A throttled version of the provided function, enhanced with the `isPending` property.
144
+ *
145
+ * @throws {TypeError} If the first parameter is not a function.
146
+ * @throws {RangeError} If the `wait` parameter is negative.
95
147
  *
96
- * @param func - The function to throttle
97
- * @param wait - The number of milliseconds to wait (default is 1000ms)
98
- * @returns - A throttled version of the function
148
+ * @example
149
+ * const log = throttle((message: string) => console.log(message), 200);
150
+ * log('Hello'); // Logs "Hello" immediately if leading is true.
151
+ * console.log(log.isPending); // true if the timer is active.
99
152
  */
100
- export declare function throttle<T extends (...args: any[]) => void>(func: T, wait?: number): (...args: Parameters<T>) => void;
153
+ export declare function throttle<F extends (...args: any[]) => any>(function_: F, wait?: number, options?: {
154
+ leading?: boolean;
155
+ trailing?: boolean;
156
+ }): ThrottledFunction<F>;
@@ -131,36 +131,150 @@ export const svgToBase64 = (str) => isSSR ? Buffer.from(str).toString('base64')
131
131
  export const sleep = (time = 1000) => new Promise((resolve) => setTimeout(resolve, time));
132
132
  /**
133
133
  * Creates a debounced function that delays invoking the provided function until
134
- * after the specified wait time has elapsed since the last invocation.
134
+ * after the specified `wait` time has elapsed since the last invocation.
135
135
  *
136
- * @param func - The function to debounce
137
- * @param wait - The number of milliseconds to delay (default is 1000ms)
138
- * @returns - A debounced version of the function
136
+ * If the `immediate` option is set to `true`, the function will be invoked immediately
137
+ * on the leading edge of the wait interval. Subsequent calls during the wait interval
138
+ * will reset the timer but not invoke the function until the interval elapses again.
139
+ *
140
+ * The returned function includes the `isPending` property to check if the debounce
141
+ * timer is currently active.
142
+ *
143
+ * @typeParam F - The type of the function to debounce.
144
+ *
145
+ * @param function_ - The function to debounce.
146
+ * @param wait - The number of milliseconds to delay (default is 100ms).
147
+ * @param options - An optional object with the following properties:
148
+ * - `immediate` (boolean): If `true`, invokes the function on the leading edge
149
+ * of the wait interval instead of the trailing edge.
150
+ *
151
+ * @returns A debounced version of the provided function, enhanced with the `isPending` property.
152
+ *
153
+ * @throws {TypeError} If the first parameter is not a function.
154
+ * @throws {RangeError} If the `wait` parameter is negative.
155
+ *
156
+ * @example
157
+ * const log = debounce((message: string) => console.log(message), 200);
158
+ * log('Hello'); // Logs "Hello" after 200ms if no other call is made.
159
+ * console.log(log.isPending); // true if the timer is active.
139
160
  */
140
- export function debounce(func, wait = 1000) {
141
- let timeout;
142
- return function (...args) {
143
- clearTimeout(timeout);
144
- timeout = setTimeout(() => func.apply(this, args), wait);
161
+ export function debounce(function_, wait = 100, options) {
162
+ if (typeof function_ !== 'function') {
163
+ throw new TypeError(`Expected the first parameter to be a function, got \`${typeof function_}\`.`);
164
+ }
165
+ if (wait < 0) {
166
+ throw new RangeError('`wait` must not be negative.');
167
+ }
168
+ const immediate = options?.immediate ?? false;
169
+ let timeoutId;
170
+ let lastArgs;
171
+ let lastContext;
172
+ let result;
173
+ function run() {
174
+ result = function_.apply(lastContext, lastArgs);
175
+ lastArgs = undefined;
176
+ lastContext = undefined;
177
+ return result;
178
+ }
179
+ const debounced = function (...args) {
180
+ lastArgs = args;
181
+ lastContext = this;
182
+ if (timeoutId === undefined && immediate) {
183
+ result = run.call(this);
184
+ }
185
+ if (timeoutId !== undefined) {
186
+ clearTimeout(timeoutId);
187
+ }
188
+ timeoutId = setTimeout(run.bind(this), wait);
189
+ return result;
145
190
  };
191
+ Object.defineProperty(debounced, 'isPending', {
192
+ get() {
193
+ return timeoutId !== undefined;
194
+ },
195
+ });
196
+ return debounced;
146
197
  }
147
198
  /**
148
199
  * Creates a throttled function that invokes the provided function at most once
149
- * every specified wait time.
200
+ * every `wait` milliseconds.
201
+ *
202
+ * If the `leading` option is set to `true`, the function will be invoked immediately
203
+ * on the leading edge of the throttle interval. If the `trailing` option is set to `true`,
204
+ * the function will also be invoked at the end of the throttle interval if additional
205
+ * calls were made during the interval.
150
206
  *
151
- * @param func - The function to throttle
152
- * @param wait - The number of milliseconds to wait (default is 1000ms)
153
- * @returns - A throttled version of the function
207
+ * The returned function includes the `isPending` property to check if the throttle
208
+ * timer is currently active.
209
+ *
210
+ * @typeParam F - The type of the function to throttle.
211
+ *
212
+ * @param function_ - The function to throttle.
213
+ * @param wait - The number of milliseconds to wait between invocations (default is 100ms).
214
+ * @param options - An optional object with the following properties:
215
+ * - `leading` (boolean): If `true`, invokes the function on the leading edge of the interval.
216
+ * - `trailing` (boolean): If `true`, invokes the function on the trailing edge of the interval.
217
+ *
218
+ * @returns A throttled version of the provided function, enhanced with the `isPending` property.
219
+ *
220
+ * @throws {TypeError} If the first parameter is not a function.
221
+ * @throws {RangeError} If the `wait` parameter is negative.
222
+ *
223
+ * @example
224
+ * const log = throttle((message: string) => console.log(message), 200);
225
+ * log('Hello'); // Logs "Hello" immediately if leading is true.
226
+ * console.log(log.isPending); // true if the timer is active.
154
227
  */
155
- export function throttle(func, wait = 1000) {
156
- let inThrottle = false;
157
- return function (...args) {
158
- if (!inThrottle) {
159
- func.apply(this, args);
160
- inThrottle = true;
161
- setTimeout(() => {
162
- inThrottle = false;
163
- }, wait);
228
+ export function throttle(function_, wait = 100, options) {
229
+ if (typeof function_ !== 'function') {
230
+ throw new TypeError(`Expected the first parameter to be a function, got \`${typeof function_}\`.`);
231
+ }
232
+ if (wait < 0) {
233
+ throw new RangeError('`wait` must not be negative.');
234
+ }
235
+ const leading = options?.leading ?? true;
236
+ const trailing = options?.trailing ?? true;
237
+ let timeoutId;
238
+ let lastArgs;
239
+ let lastContext;
240
+ let lastCallTime;
241
+ let result;
242
+ function invoke() {
243
+ lastCallTime = Date.now();
244
+ result = function_.apply(lastContext, lastArgs);
245
+ lastArgs = undefined;
246
+ lastContext = undefined;
247
+ }
248
+ function later() {
249
+ timeoutId = undefined;
250
+ if (trailing && lastArgs) {
251
+ invoke();
252
+ }
253
+ }
254
+ const throttled = function (...args) {
255
+ const now = Date.now();
256
+ const timeSinceLastCall = lastCallTime
257
+ ? now - lastCallTime
258
+ : Number.POSITIVE_INFINITY;
259
+ lastArgs = args;
260
+ lastContext = this;
261
+ if (timeSinceLastCall >= wait) {
262
+ if (leading) {
263
+ invoke();
264
+ }
265
+ else {
266
+ timeoutId = setTimeout(later, wait);
267
+ }
268
+ }
269
+ else if (!timeoutId && trailing) {
270
+ timeoutId = setTimeout(later, wait - timeSinceLastCall);
164
271
  }
272
+ return result;
165
273
  };
274
+ Object.defineProperty(throttled, 'isPending', {
275
+ get() {
276
+ return timeoutId !== undefined;
277
+ },
278
+ });
279
+ return throttled;
166
280
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sohanemon/utils",
3
- "version": "4.0.33",
3
+ "version": "4.1.0",
4
4
  "author": "Sohan Emon <sohanemon@outlook.com>",
5
5
  "description": "",
6
6
  "type": "module",
@@ -15,19 +15,33 @@
15
15
  },
16
16
  "typesVersions": {
17
17
  "*": {
18
- "core": ["dist/index.d.ts"],
19
- "types": ["dist/types/index.d.ts"],
20
- "hooks": ["dist/hooks/index.d.ts"],
21
- "components": ["dist/components/index.d.ts"]
18
+ "core": [
19
+ "dist/index.d.ts"
20
+ ],
21
+ "types": [
22
+ "dist/types/index.d.ts"
23
+ ],
24
+ "hooks": [
25
+ "dist/hooks/index.d.ts"
26
+ ],
27
+ "components": [
28
+ "dist/components/index.d.ts"
29
+ ]
22
30
  }
23
31
  },
24
- "files": ["dist", "README.md"],
32
+ "files": [
33
+ "dist",
34
+ "README.md"
35
+ ],
25
36
  "scripts": {
26
37
  "build": "tsc",
27
38
  "build:watch": "tsc --watch",
28
39
  "export": "tsc && npm publish"
29
40
  },
30
- "keywords": ["utils", "cn"],
41
+ "keywords": [
42
+ "utils",
43
+ "cn"
44
+ ],
31
45
  "license": "ISC",
32
46
  "devDependencies": {
33
47
  "@types/node": "^22.4.0",