@sohanemon/utils 6.3.8 → 6.4.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.
- package/README.md +12 -2
- package/dist/components/index.cjs +1 -1
- package/dist/components/index.d.cts +101 -5
- package/dist/components/index.d.ts +97 -1
- package/dist/components/index.js +1 -1
- package/dist/{functions-DdbPkP6e.cjs → functions-BQWC9vZ0.cjs} +1 -1
- package/dist/hooks/index.cjs +1 -1
- package/dist/hooks/index.d.cts +337 -23
- package/dist/hooks/index.d.ts +337 -23
- package/dist/hooks/index.js +1 -1
- package/dist/hooks-C9b8HxlS.js +1 -0
- package/dist/hooks-CswCcD42.cjs +1 -0
- package/dist/{index-BZaFEd2-.d.ts → index-CKE8ocfo.d.ts} +479 -59
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +890 -57
- package/dist/index.d.ts +443 -1
- package/dist/schedule-BqFAJlSO.d.cts +43 -0
- package/package.json +4 -2
- package/dist/hooks-Brgpm2Un.cjs +0 -1
- package/dist/hooks-CKCxXGDE.js +0 -1
- package/dist/schedule-CRsY0oqG.d.cts +0 -15
|
@@ -2,9 +2,61 @@ import { ClassValue } from "clsx";
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
|
|
4
4
|
//#region src/functions/cookie.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Sets a client-side cookie with optional expiration and path.
|
|
8
|
+
*
|
|
9
|
+
* @param name - The name of the cookie
|
|
10
|
+
* @param value - The value to store in the cookie
|
|
11
|
+
* @param days - Optional number of days until the cookie expires
|
|
12
|
+
* @param path - Optional path for the cookie (defaults to '/')
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // Set a cookie that expires in 7 days
|
|
16
|
+
* setClientSideCookie('userId', '12345', 7);
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // Set a session cookie (no expiration)
|
|
20
|
+
* setClientSideCookie('sessionId', 'abc123');
|
|
21
|
+
*/
|
|
5
22
|
declare const setClientSideCookie: (name: string, value: string, days?: number, path?: string) => void;
|
|
23
|
+
/**
|
|
24
|
+
* Deletes a client-side cookie by setting its expiration to a past date.
|
|
25
|
+
*
|
|
26
|
+
* @param name - The name of the cookie to delete
|
|
27
|
+
* @param path - Optional path for the cookie (defaults to '/')
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* // Delete a cookie
|
|
31
|
+
* deleteClientSideCookie('userId');
|
|
32
|
+
*/
|
|
6
33
|
declare const deleteClientSideCookie: (name: string, path?: string) => void;
|
|
34
|
+
/**
|
|
35
|
+
* Checks if a client-side cookie exists.
|
|
36
|
+
*
|
|
37
|
+
* @param name - The name of the cookie to check
|
|
38
|
+
* @returns True if the cookie exists, false otherwise
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* // Check if a cookie exists
|
|
42
|
+
* if (hasClientSideCookie('userId')) {
|
|
43
|
+
* console.log('User is logged in');
|
|
44
|
+
* }
|
|
45
|
+
*/
|
|
7
46
|
declare const hasClientSideCookie: (name: string) => boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Retrieves the value of a client-side cookie.
|
|
49
|
+
*
|
|
50
|
+
* @param name - The name of the cookie to retrieve
|
|
51
|
+
* @returns An object containing the cookie value, or undefined if not found
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* // Get a cookie value
|
|
55
|
+
* const { value } = getClientSideCookie('userId');
|
|
56
|
+
* if (value) {
|
|
57
|
+
* console.log('User ID:', value);
|
|
58
|
+
* }
|
|
59
|
+
*/
|
|
8
60
|
declare const getClientSideCookie: (name: string) => {
|
|
9
61
|
value: string | undefined;
|
|
10
62
|
};
|
|
@@ -40,20 +92,52 @@ type TMerged<T> = [T] extends [Array<any>] ? { [K in keyof T]: TMerged<T[K]> } :
|
|
|
40
92
|
* @returns The merged object with proper typing
|
|
41
93
|
*
|
|
42
94
|
* @example
|
|
43
|
-
* // Basic merge
|
|
95
|
+
* // Basic shallow merge
|
|
44
96
|
* deepmerge({ a: 1 }, { b: 2 }) // { a: 1, b: 2 }
|
|
45
97
|
*
|
|
46
98
|
* @example
|
|
47
|
-
* //
|
|
48
|
-
* deepmerge({
|
|
99
|
+
* // Deep merge of nested objects
|
|
100
|
+
* deepmerge({ user: { name: 'John' } }, { user: { age: 30 } })
|
|
101
|
+
* // { user: { name: 'John', age: 30 } }
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* // Array concatenation
|
|
105
|
+
* deepmerge({ tags: ['react'] }, { tags: ['typescript'] }, { arrayMerge: 'concat' })
|
|
106
|
+
* // { tags: ['react', 'typescript'] }
|
|
49
107
|
*
|
|
50
108
|
* @example
|
|
51
|
-
* // Array
|
|
52
|
-
* deepmerge({
|
|
109
|
+
* // Array replacement (default)
|
|
110
|
+
* deepmerge({ items: [1, 2] }, { items: [3, 4] })
|
|
111
|
+
* // { items: [3, 4] }
|
|
53
112
|
*
|
|
54
113
|
* @example
|
|
55
|
-
* //
|
|
56
|
-
* deepmerge(
|
|
114
|
+
* // Custom array merging
|
|
115
|
+
* deepmerge(
|
|
116
|
+
* { scores: [85, 90] },
|
|
117
|
+
* { scores: [95] },
|
|
118
|
+
* { arrayMerge: (target, source) => [...target, ...source] }
|
|
119
|
+
* )
|
|
120
|
+
* // { scores: [85, 90, 95] }
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* // Configuration merging
|
|
124
|
+
* const defaultConfig = { theme: 'light', features: { darkMode: false } };
|
|
125
|
+
* const userConfig = { theme: 'dark', features: { darkMode: true, animations: true } };
|
|
126
|
+
* deepmerge(defaultConfig, userConfig);
|
|
127
|
+
* // { theme: 'dark', features: { darkMode: true, animations: true } }
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* // State updates in reducers
|
|
131
|
+
* const initialState = { user: { profile: { name: '' } }, settings: {} };
|
|
132
|
+
* const action = { user: { profile: { name: 'Alice' } }, settings: { theme: 'dark' } };
|
|
133
|
+
* const newState = deepmerge(initialState, action);
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* // Merging API responses
|
|
137
|
+
* const cachedData = { posts: [{ id: 1, title: 'Old' }] };
|
|
138
|
+
* const freshData = { posts: [{ id: 1, title: 'Updated', author: 'Bob' }] };
|
|
139
|
+
* deepmerge(cachedData, freshData);
|
|
140
|
+
* // { posts: [{ id: 1, title: 'Updated', author: 'Bob' }] }
|
|
57
141
|
*/
|
|
58
142
|
declare function deepmerge<T extends Record<string, any>, S extends Record<string, any>[]>(target: T, ...sources: S): TMerged<T | S[number]>;
|
|
59
143
|
declare function deepmerge<T extends Record<string, any>, S extends Record<string, any>[]>(target: T, sources: S, options?: {
|
|
@@ -72,8 +156,42 @@ type Hydrate<T> = T extends null ? undefined : T extends (infer U)[] ? Hydrate<U
|
|
|
72
156
|
* @returns Same type as input, but with all nulls replaced by undefined
|
|
73
157
|
*
|
|
74
158
|
* @example
|
|
75
|
-
*
|
|
76
|
-
*
|
|
159
|
+
* ```ts
|
|
160
|
+
* // Basic object hydration
|
|
161
|
+
* hydrate({ name: null, age: 25 }) // { name: undefined, age: 25 }
|
|
162
|
+
*
|
|
163
|
+
* // Nested object hydration
|
|
164
|
+
* hydrate({
|
|
165
|
+
* user: { email: null, profile: { avatar: null } },
|
|
166
|
+
* settings: { theme: 'dark' }
|
|
167
|
+
* })
|
|
168
|
+
* // { user: { email: undefined, profile: { avatar: undefined } }, settings: { theme: 'dark' } }
|
|
169
|
+
*
|
|
170
|
+
* // Array hydration
|
|
171
|
+
* hydrate([null, 'hello', null, 42]) // [undefined, 'hello', undefined, 42]
|
|
172
|
+
*
|
|
173
|
+
* // Mixed data structures
|
|
174
|
+
* hydrate({
|
|
175
|
+
* posts: [null, { title: 'Hello', content: null }],
|
|
176
|
+
* metadata: { published: null, tags: ['react', null] }
|
|
177
|
+
* })
|
|
178
|
+
* ```
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```ts
|
|
182
|
+
* // API response normalization
|
|
183
|
+
* const apiResponse = await fetch('/api/user');
|
|
184
|
+
* const rawData = await apiResponse.json(); // May contain null values
|
|
185
|
+
* const normalizedData = hydrate(rawData); // Convert nulls to undefined
|
|
186
|
+
*
|
|
187
|
+
* // Database result processing
|
|
188
|
+
* const dbResult = query('SELECT * FROM users'); // Some fields may be NULL
|
|
189
|
+
* const cleanData = hydrate(dbResult); // Normalize for consistent handling
|
|
190
|
+
*
|
|
191
|
+
* // Form data sanitization
|
|
192
|
+
* const formData = getFormValues(); // May have null values from empty fields
|
|
193
|
+
* const sanitizedData = hydrate(formData); // Prepare for validation/state
|
|
194
|
+
* ```
|
|
77
195
|
*/
|
|
78
196
|
declare function hydrate<T>(data: T): Hydrate<T>;
|
|
79
197
|
//#endregion
|
|
@@ -157,14 +275,32 @@ declare function getObjectValue<T, S extends string>(obj: T, path: S): GetValue<
|
|
|
157
275
|
* @returns The same object/function, augmented with the given properties
|
|
158
276
|
*
|
|
159
277
|
* @example
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* const
|
|
167
|
-
*
|
|
278
|
+
* ```ts
|
|
279
|
+
* // Extend a plain object
|
|
280
|
+
* const config = extendProps({ apiUrl: '/api' }, { timeout: 5000 });
|
|
281
|
+
* // config has both apiUrl and timeout properties
|
|
282
|
+
*
|
|
283
|
+
* // Extend a function with metadata
|
|
284
|
+
* const fetchData = (url: string) => fetch(url).then(r => r.json());
|
|
285
|
+
* const enhancedFetch = extendProps(fetchData, {
|
|
286
|
+
* description: 'Data fetching utility',
|
|
287
|
+
* version: '1.0'
|
|
288
|
+
* });
|
|
289
|
+
* // enhancedFetch is callable and has description/version properties
|
|
290
|
+
*
|
|
291
|
+
* // Create plugin system
|
|
292
|
+
* const basePlugin = { name: 'base', enabled: true };
|
|
293
|
+
* const authPlugin = extendProps(basePlugin, {
|
|
294
|
+
* authenticate: (token: string) => validateToken(token)
|
|
295
|
+
* });
|
|
296
|
+
*
|
|
297
|
+
* // Build configuration objects
|
|
298
|
+
* const defaultSettings = { theme: 'light', lang: 'en' };
|
|
299
|
+
* const userSettings = extendProps(defaultSettings, {
|
|
300
|
+
* theme: 'dark',
|
|
301
|
+
* notifications: true
|
|
302
|
+
* });
|
|
303
|
+
* ```
|
|
168
304
|
*/
|
|
169
305
|
declare function extendProps<T extends object, P$1 extends object>(base: T, props: P$1): T & P$1;
|
|
170
306
|
//#endregion
|
|
@@ -195,11 +331,52 @@ declare function extendProps<T extends object, P$1 extends object>(base: T, prop
|
|
|
195
331
|
*
|
|
196
332
|
* @example
|
|
197
333
|
* ```ts
|
|
334
|
+
* // Poll for job completion
|
|
198
335
|
* const job = await poll(async () => {
|
|
199
336
|
* const status = await getJobStatus();
|
|
200
337
|
* return status === 'done' ? status : null;
|
|
201
338
|
* }, { interval: 3000, timeout: 60000 });
|
|
202
339
|
* ```
|
|
340
|
+
*
|
|
341
|
+
* @example
|
|
342
|
+
* ```ts
|
|
343
|
+
* // Wait for API endpoint to be ready
|
|
344
|
+
* const apiReady = await poll(async () => {
|
|
345
|
+
* try {
|
|
346
|
+
* await fetch('/api/health');
|
|
347
|
+
* return true;
|
|
348
|
+
* } catch {
|
|
349
|
+
* return null;
|
|
350
|
+
* }
|
|
351
|
+
* }, { interval: 1000, timeout: 30000 });
|
|
352
|
+
* ```
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* ```ts
|
|
356
|
+
* // Poll with abort signal for cancellation
|
|
357
|
+
* const controller = new AbortController();
|
|
358
|
+
* setTimeout(() => controller.abort(), 10000); // Cancel after 10s
|
|
359
|
+
*
|
|
360
|
+
* try {
|
|
361
|
+
* const result = await poll(
|
|
362
|
+
* () => checkExternalService(),
|
|
363
|
+
* { interval: 2000, signal: controller.signal }
|
|
364
|
+
* );
|
|
365
|
+
* } catch (err) {
|
|
366
|
+
* if (err.name === 'AbortError') {
|
|
367
|
+
* console.log('Polling was cancelled');
|
|
368
|
+
* }
|
|
369
|
+
* }
|
|
370
|
+
* ```
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* ```ts
|
|
374
|
+
* // Poll for user action completion
|
|
375
|
+
* const userConfirmed = await poll(async () => {
|
|
376
|
+
* const confirmations = await getPendingConfirmations();
|
|
377
|
+
* return confirmations.length > 0 ? confirmations[0] : null;
|
|
378
|
+
* }, { interval: 5000, timeout: 300000 }); // 5 min timeout
|
|
379
|
+
* ```
|
|
203
380
|
*/
|
|
204
381
|
declare function poll<T>(cond: () => Promise<T | null | false | undefined>, {
|
|
205
382
|
interval,
|
|
@@ -214,16 +391,44 @@ declare function poll<T>(cond: () => Promise<T | null | false | undefined>, {
|
|
|
214
391
|
}>): Promise<T>;
|
|
215
392
|
//#endregion
|
|
216
393
|
//#region src/functions/schedule.d.ts
|
|
394
|
+
/**
|
|
395
|
+
* A task function that can be synchronous or asynchronous.
|
|
396
|
+
*/
|
|
217
397
|
type Task = () => Promise<void> | void;
|
|
398
|
+
/**
|
|
399
|
+
* Options for configuring the schedule function.
|
|
400
|
+
*/
|
|
218
401
|
interface ScheduleOpts {
|
|
402
|
+
/** Number of retry attempts on failure. Defaults to 0. */
|
|
219
403
|
retry?: number;
|
|
404
|
+
/** Delay in milliseconds between retries. Defaults to 0. */
|
|
220
405
|
delay?: number;
|
|
406
|
+
/** Maximum time in milliseconds to wait for the task to complete. */
|
|
221
407
|
timeout?: number;
|
|
222
408
|
}
|
|
223
409
|
/**
|
|
224
|
-
* Runs a function asynchronously in the background.
|
|
225
|
-
*
|
|
226
|
-
*
|
|
410
|
+
* Runs a function asynchronously in the background without blocking the main thread.
|
|
411
|
+
*
|
|
412
|
+
* Executes the task immediately using setTimeout, with optional retry logic on failure.
|
|
413
|
+
* Useful for non-critical operations like analytics, logging, or background processing.
|
|
414
|
+
* Logs execution time and retry attempts to the console.
|
|
415
|
+
*
|
|
416
|
+
* @param task - The function to execute asynchronously
|
|
417
|
+
* @param options - Configuration options for retries and timing
|
|
418
|
+
*
|
|
419
|
+
* @example
|
|
420
|
+
* ```ts
|
|
421
|
+
* // Simple background task
|
|
422
|
+
* schedule(() => {
|
|
423
|
+
* console.log('Background work done');
|
|
424
|
+
* });
|
|
425
|
+
*
|
|
426
|
+
* // Task with retry on failure
|
|
427
|
+
* schedule(
|
|
428
|
+
* () => sendAnalytics(),
|
|
429
|
+
* { retry: 3, delay: 1000 }
|
|
430
|
+
* );
|
|
431
|
+
* ```
|
|
227
432
|
*/
|
|
228
433
|
declare function schedule(task: Task, options?: ScheduleOpts): void;
|
|
229
434
|
//#endregion
|
|
@@ -237,11 +442,62 @@ declare function schedule(task: Task, options?: ScheduleOpts): void;
|
|
|
237
442
|
*
|
|
238
443
|
* @example
|
|
239
444
|
* ```ts
|
|
240
|
-
*
|
|
241
|
-
*
|
|
445
|
+
* // Synchronous error handling
|
|
446
|
+
* const [err, value] = shield(() => {
|
|
447
|
+
* if (Math.random() > 0.5) throw new Error('Random failure');
|
|
448
|
+
* return 'success';
|
|
449
|
+
* });
|
|
450
|
+
* if (err) {
|
|
451
|
+
* console.error('Operation failed:', err);
|
|
452
|
+
* } else {
|
|
453
|
+
* console.log('Result:', value);
|
|
454
|
+
* }
|
|
455
|
+
*
|
|
456
|
+
* // Asynchronous error handling
|
|
457
|
+
* const [asyncErr, result] = await shield(async () => {
|
|
458
|
+
* const response = await fetch('/api/data');
|
|
459
|
+
* if (!response.ok) throw new Error('API error');
|
|
460
|
+
* return response.json();
|
|
461
|
+
* });
|
|
462
|
+
* if (asyncErr) {
|
|
463
|
+
* console.error('API call failed:', asyncErr);
|
|
464
|
+
* } else {
|
|
465
|
+
* processData(result);
|
|
466
|
+
* }
|
|
467
|
+
*
|
|
468
|
+
* // API calls with fallbacks
|
|
469
|
+
* const [fetchErr, data] = await shield(fetchUserData(userId));
|
|
470
|
+
* const userData = fetchErr ? getCachedUserData(userId) : data;
|
|
471
|
+
*
|
|
472
|
+
* // File operations
|
|
473
|
+
* const [fileErr, content] = shield(() => readFileSync('config.json'));
|
|
474
|
+
* if (fileErr) {
|
|
475
|
+
* console.warn('Could not read config, using defaults');
|
|
476
|
+
* return defaultConfig;
|
|
477
|
+
* }
|
|
478
|
+
* ```
|
|
242
479
|
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
480
|
+
* @example
|
|
481
|
+
* ```ts
|
|
482
|
+
* // In async functions
|
|
483
|
+
* async function safeApiCall() {
|
|
484
|
+
* const [err, result] = await shield(callExternalAPI());
|
|
485
|
+
* if (err) {
|
|
486
|
+
* await logError(err);
|
|
487
|
+
* return null;
|
|
488
|
+
* }
|
|
489
|
+
* return result;
|
|
490
|
+
* }
|
|
491
|
+
*
|
|
492
|
+
* // In event handlers
|
|
493
|
+
* function handleSubmit(formData) {
|
|
494
|
+
* const [validationErr, validatedData] = shield(() => validateForm(formData));
|
|
495
|
+
* if (validationErr) {
|
|
496
|
+
* showValidationError(validationErr);
|
|
497
|
+
* return;
|
|
498
|
+
* }
|
|
499
|
+
* submitData(validatedData);
|
|
500
|
+
* }
|
|
245
501
|
* ```
|
|
246
502
|
*/
|
|
247
503
|
declare function shield<T, E = Error>(operation: Promise<T>): Promise<[E | null, T | null]>;
|
|
@@ -253,6 +509,12 @@ declare function shield<T, E = Error>(operation: () => T): [E | null, T | null];
|
|
|
253
509
|
*
|
|
254
510
|
* @param {...ClassValue[]} inputs - Class names to merge.
|
|
255
511
|
* @returns {string} - A string of merged class names.
|
|
512
|
+
*
|
|
513
|
+
* @example
|
|
514
|
+
* ```ts
|
|
515
|
+
* cn('px-2 py-1', 'bg-red-500') // 'px-2 py-1 bg-red-500'
|
|
516
|
+
* cn('px-2', 'px-4') // 'px-4' (Tailwind resolves conflicts)
|
|
517
|
+
* ```
|
|
256
518
|
*/
|
|
257
519
|
declare function cn(...inputs: ClassValue[]): string;
|
|
258
520
|
/**
|
|
@@ -263,16 +525,40 @@ declare function cn(...inputs: ClassValue[]): string;
|
|
|
263
525
|
* @param href - The target URL.
|
|
264
526
|
* @param path - The current browser path.
|
|
265
527
|
* @returns - True if the navigation is active, false otherwise.
|
|
528
|
+
*
|
|
529
|
+
* @example
|
|
530
|
+
* ```ts
|
|
531
|
+
* isNavActive('/about', '/about/team') // true
|
|
532
|
+
* isNavActive('/contact', '/about') // false
|
|
533
|
+
* ```
|
|
266
534
|
*/
|
|
267
535
|
declare function isNavActive(href: string, path: string): boolean;
|
|
268
536
|
/**
|
|
269
537
|
* Checks if a link is active, considering optional localization prefixes.
|
|
270
538
|
*
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
* @param
|
|
275
|
-
* @
|
|
539
|
+
* Compares paths while ignoring locale prefixes (e.g., /en/, /fr/) for consistent
|
|
540
|
+
* navigation highlighting across different language versions of the same page.
|
|
541
|
+
*
|
|
542
|
+
* @param params - Parameters object.
|
|
543
|
+
* @param params.path - The target path of the link.
|
|
544
|
+
* @param params.currentPath - The current browser path.
|
|
545
|
+
* @param params.locales - Supported locale prefixes to ignore during comparison.
|
|
546
|
+
* @param params.exact - Whether to require exact path match (default: true). If false, checks if current path starts with target path.
|
|
547
|
+
* @returns True if the link is active, false otherwise.
|
|
548
|
+
*
|
|
549
|
+
* @example
|
|
550
|
+
* ```ts
|
|
551
|
+
* // Exact match
|
|
552
|
+
* isLinkActive({ path: '/about', currentPath: '/about' }) // true
|
|
553
|
+
* isLinkActive({ path: '/about', currentPath: '/about/team' }) // false
|
|
554
|
+
*
|
|
555
|
+
* // With locales
|
|
556
|
+
* isLinkActive({ path: '/about', currentPath: '/en/about' }) // true
|
|
557
|
+
* isLinkActive({ path: '/about', currentPath: '/fr/about' }) // true
|
|
558
|
+
*
|
|
559
|
+
* // Partial match
|
|
560
|
+
* isLinkActive({ path: '/blog', currentPath: '/blog/post-1', exact: false }) // true
|
|
561
|
+
* ```
|
|
276
562
|
*/
|
|
277
563
|
declare function isLinkActive({
|
|
278
564
|
path,
|
|
@@ -288,29 +574,74 @@ declare function isLinkActive({
|
|
|
288
574
|
/**
|
|
289
575
|
* Cleans a file path by removing the `/public/` prefix if present.
|
|
290
576
|
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
577
|
+
* Useful when working with static assets that may have been processed
|
|
578
|
+
* or when normalizing paths between development and production environments.
|
|
579
|
+
*
|
|
580
|
+
* @param src - The source path to clean.
|
|
581
|
+
* @returns The cleaned path with `/public/` prefix removed and whitespace trimmed.
|
|
582
|
+
*
|
|
583
|
+
* @example
|
|
584
|
+
* ```ts
|
|
585
|
+
* cleanSrc('/public/images/logo.png') // '/images/logo.png'
|
|
586
|
+
* cleanSrc('images/logo.png') // 'images/logo.png'
|
|
587
|
+
* cleanSrc(' /public/docs/readme.md ') // '/docs/readme.md'
|
|
588
|
+
* ```
|
|
293
589
|
*/
|
|
294
590
|
declare function cleanSrc(src: string): string;
|
|
295
591
|
/**
|
|
296
592
|
* Smoothly scrolls to the top or bottom of a specified container.
|
|
297
593
|
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
594
|
+
* Provides smooth scrolling animation to either end of a scrollable element.
|
|
595
|
+
* Accepts either a CSS selector string or a React ref to the container element.
|
|
596
|
+
*
|
|
597
|
+
* @param containerSelector - The CSS selector string or React ref for the scrollable container.
|
|
598
|
+
* @param to - Direction to scroll: 'top' for top of container, 'bottom' for bottom.
|
|
599
|
+
*
|
|
600
|
+
* @example
|
|
601
|
+
* ```ts
|
|
602
|
+
* // Scroll to top using selector
|
|
603
|
+
* scrollTo('.main-content', 'top');
|
|
604
|
+
*
|
|
605
|
+
* // Scroll to bottom using ref
|
|
606
|
+
* scrollTo(containerRef, 'bottom');
|
|
607
|
+
* ```
|
|
300
608
|
*/
|
|
301
609
|
declare const scrollTo: (containerSelector: string | React.RefObject<HTMLDivElement>, to: "top" | "bottom") => void;
|
|
302
610
|
/**
|
|
303
|
-
* Copies a given string to the clipboard.
|
|
611
|
+
* Copies a given string to the clipboard using the modern Clipboard API.
|
|
612
|
+
*
|
|
613
|
+
* Safely attempts to copy text to the user's clipboard. Falls back gracefully
|
|
614
|
+
* if the Clipboard API is not available or if the operation fails.
|
|
304
615
|
*
|
|
305
|
-
* @param
|
|
306
|
-
* @param
|
|
616
|
+
* @param value - The text value to copy to the clipboard.
|
|
617
|
+
* @param onSuccess - Optional callback executed after successful copy operation.
|
|
618
|
+
*
|
|
619
|
+
* @example
|
|
620
|
+
* ```ts
|
|
621
|
+
* copyToClipboard('Hello World!', () => {
|
|
622
|
+
* console.log('Text copied successfully');
|
|
623
|
+
* });
|
|
624
|
+
* ```
|
|
307
625
|
*/
|
|
308
626
|
declare const copyToClipboard: (value: string, onSuccess?: () => void) => void;
|
|
309
627
|
/**
|
|
310
|
-
* Converts camelCase, PascalCase, kebab-case, snake_case into normal case.
|
|
628
|
+
* Converts various case styles (camelCase, PascalCase, kebab-case, snake_case) into readable normal case.
|
|
629
|
+
*
|
|
630
|
+
* Transforms technical naming conventions into human-readable titles by:
|
|
631
|
+
* - Adding spaces between words
|
|
632
|
+
* - Capitalizing the first letter of each word
|
|
633
|
+
* - Handling common separators (-, _, camelCase boundaries)
|
|
634
|
+
*
|
|
635
|
+
* @param inputString - The string to convert (supports camelCase, PascalCase, kebab-case, snake_case).
|
|
636
|
+
* @returns The converted string in normal case (title case).
|
|
311
637
|
*
|
|
312
|
-
* @
|
|
313
|
-
*
|
|
638
|
+
* @example
|
|
639
|
+
* ```ts
|
|
640
|
+
* convertToNormalCase('camelCase') // 'Camel Case'
|
|
641
|
+
* convertToNormalCase('kebab-case') // 'Kebab Case'
|
|
642
|
+
* convertToNormalCase('snake_case') // 'Snake Case'
|
|
643
|
+
* convertToNormalCase('PascalCase') // 'Pascal Case'
|
|
644
|
+
* ```
|
|
314
645
|
*/
|
|
315
646
|
declare function convertToNormalCase(inputString: string): string;
|
|
316
647
|
/**
|
|
@@ -327,6 +658,17 @@ declare const convertToSlug: (str: string) => string;
|
|
|
327
658
|
* Checks if the code is running in a server-side environment.
|
|
328
659
|
*
|
|
329
660
|
* @returns - True if the code is executed in SSR (Server-Side Rendering) context, false otherwise
|
|
661
|
+
*
|
|
662
|
+
* @example
|
|
663
|
+
* ```ts
|
|
664
|
+
* if (isSSR) {
|
|
665
|
+
* // Server-side only code
|
|
666
|
+
* console.log('Running on server');
|
|
667
|
+
* } else {
|
|
668
|
+
* // Client-side only code
|
|
669
|
+
* window.addEventListener('load', () => {});
|
|
670
|
+
* }
|
|
671
|
+
* ```
|
|
330
672
|
*/
|
|
331
673
|
declare const isSSR: boolean;
|
|
332
674
|
/**
|
|
@@ -334,6 +676,13 @@ declare const isSSR: boolean;
|
|
|
334
676
|
*
|
|
335
677
|
* @param str - The SVG string to encode
|
|
336
678
|
* @returns - Base64-encoded string representation of the SVG
|
|
679
|
+
*
|
|
680
|
+
* @example
|
|
681
|
+
* ```ts
|
|
682
|
+
* const svg = '<svg><circle cx="50" cy="50" r="40"/></svg>';
|
|
683
|
+
* const base64 = svgToBase64(svg);
|
|
684
|
+
* // Use in data URL: `data:image/svg+xml;base64,${base64}`
|
|
685
|
+
* ```
|
|
337
686
|
*/
|
|
338
687
|
declare const svgToBase64: (str: string) => string;
|
|
339
688
|
/**
|
|
@@ -375,9 +724,23 @@ type DebouncedFunction<F extends (...args: any[]) => any> = {
|
|
|
375
724
|
* @throws {RangeError} If the `wait` parameter is negative.
|
|
376
725
|
*
|
|
377
726
|
* @example
|
|
727
|
+
* ```ts
|
|
728
|
+
* // Basic debouncing
|
|
378
729
|
* const log = debounce((message: string) => console.log(message), 200);
|
|
379
730
|
* log('Hello'); // Logs "Hello" after 200ms if no other call is made.
|
|
380
731
|
* console.log(log.isPending); // true if the timer is active.
|
|
732
|
+
*
|
|
733
|
+
* // Immediate execution
|
|
734
|
+
* const save = debounce(() => saveToServer(), 500, { immediate: true });
|
|
735
|
+
* save(); // Executes immediately, then waits 500ms for subsequent calls
|
|
736
|
+
*
|
|
737
|
+
* // Check pending state
|
|
738
|
+
* const debouncedSearch = debounce(searchAPI, 300);
|
|
739
|
+
* debouncedSearch('query');
|
|
740
|
+
* if (debouncedSearch.isPending) {
|
|
741
|
+
* showLoadingIndicator();
|
|
742
|
+
* }
|
|
743
|
+
* ```
|
|
381
744
|
*/
|
|
382
745
|
declare function debounce<F extends (...args: any[]) => any>(function_: F, wait?: number, options?: {
|
|
383
746
|
immediate: boolean;
|
|
@@ -412,9 +775,29 @@ type ThrottledFunction<F extends (...args: any[]) => any> = {
|
|
|
412
775
|
* @throws {RangeError} If the `wait` parameter is negative.
|
|
413
776
|
*
|
|
414
777
|
* @example
|
|
778
|
+
* ```ts
|
|
779
|
+
* // Basic throttling (leading edge by default)
|
|
415
780
|
* const log = throttle((message: string) => console.log(message), 200);
|
|
416
|
-
* log('Hello'); // Logs "Hello" immediately
|
|
417
|
-
*
|
|
781
|
+
* log('Hello'); // Logs "Hello" immediately
|
|
782
|
+
* log('World'); // Ignored for 200ms
|
|
783
|
+
* console.log(log.isPending); // true if within throttle window
|
|
784
|
+
*
|
|
785
|
+
* // Trailing edge only
|
|
786
|
+
* const trailingLog = throttle(() => console.log('trailing'), 200, {
|
|
787
|
+
* leading: false,
|
|
788
|
+
* trailing: true
|
|
789
|
+
* });
|
|
790
|
+
* trailingLog(); // No immediate execution
|
|
791
|
+
* // After 200ms: logs "trailing"
|
|
792
|
+
*
|
|
793
|
+
* // Both edges
|
|
794
|
+
* const bothLog = throttle(() => console.log('both'), 200, {
|
|
795
|
+
* leading: true,
|
|
796
|
+
* trailing: true
|
|
797
|
+
* });
|
|
798
|
+
* bothLog(); // Immediate execution
|
|
799
|
+
* // After 200ms: executes again if called during window
|
|
800
|
+
* ```
|
|
418
801
|
*/
|
|
419
802
|
declare function throttle<F extends (...args: any[]) => any>(function_: F, wait?: number, options?: {
|
|
420
803
|
leading?: boolean;
|
|
@@ -422,26 +805,31 @@ declare function throttle<F extends (...args: any[]) => any>(function_: F, wait?
|
|
|
422
805
|
}): ThrottledFunction<F>;
|
|
423
806
|
/**
|
|
424
807
|
* Formats a string by replacing each '%s' placeholder with the corresponding argument.
|
|
425
|
-
* This function mimics the basic behavior of C's printf for %s substitution.
|
|
426
808
|
*
|
|
427
|
-
*
|
|
809
|
+
* Mimics the basic behavior of C's printf for %s substitution. Supports both
|
|
810
|
+
* variadic arguments and array-based argument passing. Extra placeholders
|
|
811
|
+
* are left as-is, missing arguments result in empty strings.
|
|
428
812
|
*
|
|
429
813
|
* @param format - The format string containing '%s' placeholders.
|
|
430
|
-
* @param args - The values to substitute
|
|
431
|
-
* @returns The formatted string with
|
|
814
|
+
* @param args - The values to substitute, either as separate arguments or a single array.
|
|
815
|
+
* @returns The formatted string with placeholders replaced by arguments.
|
|
432
816
|
*
|
|
433
817
|
* @example
|
|
434
818
|
* ```ts
|
|
435
|
-
*
|
|
436
|
-
*
|
|
819
|
+
* // Basic usage with separate arguments
|
|
820
|
+
* printf("%s love %s", "I", "Bangladesh") // "I love Bangladesh"
|
|
821
|
+
*
|
|
822
|
+
* // Using array of arguments
|
|
823
|
+
* printf("%s love %s", ["I", "Bangladesh"]) // "I love Bangladesh"
|
|
437
824
|
*
|
|
438
|
-
*
|
|
439
|
-
*
|
|
440
|
-
* // message2 === "I love Bangladesh"
|
|
825
|
+
* // Extra placeholders remain unchanged
|
|
826
|
+
* printf("%s %s %s", "Hello", "World") // "Hello World %s"
|
|
441
827
|
*
|
|
442
|
-
* //
|
|
443
|
-
*
|
|
444
|
-
*
|
|
828
|
+
* // Missing arguments become empty strings
|
|
829
|
+
* printf("%s and %s", "this") // "this and "
|
|
830
|
+
*
|
|
831
|
+
* // Multiple occurrences
|
|
832
|
+
* printf("%s %s %s", "repeat", "repeat", "repeat") // "repeat repeat repeat"
|
|
445
833
|
* ```
|
|
446
834
|
*/
|
|
447
835
|
declare function printf(format: string, ...args: unknown[]): string;
|
|
@@ -449,29 +837,54 @@ declare function printf(format: string, ...args: unknown[]): string;
|
|
|
449
837
|
* Merges multiple refs into a single ref callback.
|
|
450
838
|
*
|
|
451
839
|
* @param refs - An array of refs to merge.
|
|
452
|
-
*
|
|
453
840
|
* @returns - A function that updates the merged ref with the provided value.
|
|
841
|
+
*
|
|
842
|
+
* @example
|
|
843
|
+
* ```tsx
|
|
844
|
+
* const MyComponent = () => {
|
|
845
|
+
* const ref1 = useRef<HTMLDivElement>(null);
|
|
846
|
+
* const ref2 = useRef<HTMLDivElement>(null);
|
|
847
|
+
*
|
|
848
|
+
* const mergedRef = mergeRefs(ref1, ref2);
|
|
849
|
+
*
|
|
850
|
+
* return <div ref={mergedRef}>Content</div>;
|
|
851
|
+
* };
|
|
852
|
+
* ```
|
|
454
853
|
*/
|
|
455
854
|
type MergeRefs = <T>(...refs: Array<React.Ref<T> | undefined>) => React.RefCallback<T>;
|
|
456
855
|
declare const mergeRefs: MergeRefs;
|
|
457
856
|
/**
|
|
458
|
-
* Navigates to the specified client-side hash without
|
|
459
|
-
* use `scroll-margin-top` with css to add margins
|
|
857
|
+
* Navigates to the specified client-side hash without triggering SSR.
|
|
460
858
|
*
|
|
461
|
-
*
|
|
859
|
+
* Smoothly scrolls to an element by ID and updates the URL hash.
|
|
860
|
+
* Use `scroll-margin-top` CSS property to add margins for fixed headers.
|
|
861
|
+
*
|
|
862
|
+
* @param id - The ID of the element (without #) to navigate to.
|
|
863
|
+
* @param opts - Additional options for scrollIntoView.
|
|
864
|
+
*
|
|
865
|
+
* @example
|
|
866
|
+
* ```ts
|
|
867
|
+
* // Navigate to an element
|
|
868
|
+
* goToClientSideHash('section-about');
|
|
462
869
|
*
|
|
463
|
-
*
|
|
870
|
+
* // With custom scroll behavior
|
|
871
|
+
* goToClientSideHash('contact', { behavior: 'auto', block: 'center' });
|
|
872
|
+
* ```
|
|
464
873
|
*/
|
|
465
874
|
declare function goToClientSideHash(id: string, opts?: ScrollIntoViewOptions): void;
|
|
466
875
|
/**
|
|
467
876
|
* Escapes a string for use in a regular expression.
|
|
468
877
|
*
|
|
469
878
|
* @param str - The string to escape
|
|
470
|
-
* @returns - The escaped string
|
|
879
|
+
* @returns - The escaped string safe for use in RegExp constructor
|
|
471
880
|
*
|
|
472
881
|
* @example
|
|
882
|
+
* ```ts
|
|
473
883
|
* const escapedString = escapeRegExp('Hello, world!');
|
|
474
884
|
* // escapedString === 'Hello\\, world!'
|
|
885
|
+
*
|
|
886
|
+
* const regex = new RegExp(escapeRegExp(userInput));
|
|
887
|
+
* ```
|
|
475
888
|
*/
|
|
476
889
|
declare function escapeRegExp(str: string): string;
|
|
477
890
|
/**
|
|
@@ -487,6 +900,13 @@ declare function escapeRegExp(str: string): string;
|
|
|
487
900
|
* @param options.removeAccents - Whether to remove diacritic marks like accents (default: true)
|
|
488
901
|
* @param options.removeNonAlphanumeric - Whether to trim non-alphanumeric characters from the edges (default: true)
|
|
489
902
|
* @returns The normalized string
|
|
903
|
+
*
|
|
904
|
+
* @example
|
|
905
|
+
* ```ts
|
|
906
|
+
* normalizeText('Café') // 'cafe'
|
|
907
|
+
* normalizeText(' Hello! ') // 'hello'
|
|
908
|
+
* normalizeText('José', { removeAccents: false }) // 'josé'
|
|
909
|
+
* ```
|
|
490
910
|
*/
|
|
491
911
|
declare function normalizeText(str?: string | null, options?: {
|
|
492
912
|
lowercase?: boolean;
|