@mwakidenis/logx-react 0.0.0-stage → 0.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/LICENSE +23 -0
  3. package/README.md +151 -3
  4. package/dist/components/index.d.mts +71 -0
  5. package/dist/components/index.d.ts +71 -0
  6. package/dist/components/index.js +268 -0
  7. package/dist/components/index.js.map +1 -0
  8. package/dist/components/index.mjs +262 -0
  9. package/dist/components/index.mjs.map +1 -0
  10. package/dist/hooks/index.d.mts +316 -0
  11. package/dist/hooks/index.d.ts +316 -0
  12. package/dist/hooks/index.js +638 -0
  13. package/dist/hooks/index.js.map +1 -0
  14. package/dist/hooks/index.mjs +615 -0
  15. package/dist/hooks/index.mjs.map +1 -0
  16. package/dist/hooks/storage/index.d.mts +40 -0
  17. package/dist/hooks/storage/index.d.ts +40 -0
  18. package/dist/hooks/storage/index.js +119 -0
  19. package/dist/hooks/storage/index.js.map +1 -0
  20. package/dist/hooks/storage/index.mjs +116 -0
  21. package/dist/hooks/storage/index.mjs.map +1 -0
  22. package/dist/index.d.mts +16 -0
  23. package/dist/index.d.ts +16 -0
  24. package/dist/index.js +1066 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/index.mjs +974 -0
  27. package/dist/index.mjs.map +1 -0
  28. package/dist/providers/LogxProvider.d.mts +134 -0
  29. package/dist/providers/LogxProvider.d.ts +134 -0
  30. package/dist/providers/LogxProvider.js +117 -0
  31. package/dist/providers/LogxProvider.js.map +1 -0
  32. package/dist/providers/LogxProvider.mjs +114 -0
  33. package/dist/providers/LogxProvider.mjs.map +1 -0
  34. package/dist/types/index.d.mts +87 -0
  35. package/dist/types/index.d.ts +87 -0
  36. package/dist/types/index.js +4 -0
  37. package/dist/types/index.js.map +1 -0
  38. package/dist/types/index.mjs +3 -0
  39. package/dist/types/index.mjs.map +1 -0
  40. package/dist/utilities/index.d.mts +140 -0
  41. package/dist/utilities/index.d.ts +140 -0
  42. package/dist/utilities/index.js +167 -0
  43. package/dist/utilities/index.js.map +1 -0
  44. package/dist/utilities/index.mjs +104 -0
  45. package/dist/utilities/index.mjs.map +1 -0
  46. package/package.json +127 -6
package/dist/index.js ADDED
@@ -0,0 +1,1066 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var _function = require('@mwakidenis/logx/function');
5
+ var browser = require('@mwakidenis/logx/browser');
6
+ var validation = require('@mwakidenis/logx/validation');
7
+ var object = require('@mwakidenis/logx/object');
8
+ var number = require('@mwakidenis/logx/number');
9
+ var array = require('@mwakidenis/logx/array');
10
+ var async = require('@mwakidenis/logx/async');
11
+ var date = require('@mwakidenis/logx/date');
12
+ var string = require('@mwakidenis/logx/string');
13
+ var jsxRuntime = require('react/jsx-runtime');
14
+
15
+ var __defProp = Object.defineProperty;
16
+ var __export = (target, all) => {
17
+ for (var name in all)
18
+ __defProp(target, name, { get: all[name], enumerable: true });
19
+ };
20
+ function useToggle(initialValue = false) {
21
+ const [value, setValue] = react.useState(!!initialValue);
22
+ const toggle = react.useCallback(() => setValue((current) => !current), []);
23
+ const setTrue = react.useCallback(() => setValue(true), []);
24
+ const setFalse = react.useCallback(() => setValue(false), []);
25
+ const set3 = react.useCallback(
26
+ (next) => setValue((current) => typeof next === "boolean" ? next : !current),
27
+ []
28
+ );
29
+ return [value, { toggle, set: set3, setTrue, setFalse }];
30
+ }
31
+ function useBoolean(initialValue = false) {
32
+ const [value, setValue] = react.useState(!!initialValue);
33
+ const setTrue = react.useCallback(() => setValue(true), []);
34
+ const setFalse = react.useCallback(() => setValue(false), []);
35
+ const toggle = react.useCallback(() => setValue((current) => !current), []);
36
+ const set3 = react.useCallback(
37
+ (next) => setValue((current) => typeof next === "boolean" ? next : !current),
38
+ []
39
+ );
40
+ return [value, { setTrue, setFalse, toggle, set: set3 }];
41
+ }
42
+ function useCounter(initialValue = 0) {
43
+ const [count, setCount] = react.useState(initialValue);
44
+ const increment = react.useCallback(
45
+ (step = 1) => setCount((current) => current + step),
46
+ []
47
+ );
48
+ const decrement = react.useCallback(
49
+ (step = 1) => setCount((current) => current - step),
50
+ []
51
+ );
52
+ const reset = react.useCallback(() => setCount(initialValue), [initialValue]);
53
+ const set3 = react.useCallback((value) => setCount(value), []);
54
+ return { count, increment, decrement, reset, set: set3 };
55
+ }
56
+ function usePrevious(value) {
57
+ const ref = react.useRef(void 0);
58
+ react.useEffect(() => {
59
+ ref.current = value;
60
+ });
61
+ return ref.current;
62
+ }
63
+ function useLatest(value) {
64
+ const ref = react.useRef(value);
65
+ ref.current = value;
66
+ return ref;
67
+ }
68
+ function useMounted() {
69
+ const [mounted, setMounted] = react.useState(false);
70
+ react.useEffect(() => {
71
+ setMounted(true);
72
+ return () => setMounted(false);
73
+ }, []);
74
+ return mounted;
75
+ }
76
+
77
+ // src/internal/logx.ts
78
+ var logx_exports = {};
79
+ __export(logx_exports, {
80
+ addDays: () => date.addDays,
81
+ camelCase: () => string.camelCase,
82
+ capitalize: () => string.capitalize,
83
+ chunk: () => array.chunk,
84
+ clamp: () => number.clamp,
85
+ clone: () => object.clone,
86
+ compact: () => array.compact,
87
+ createLogxDebounce: () => createLogxDebounce,
88
+ debounce: () => _function.debounce,
89
+ deepClone: () => object.deepClone,
90
+ difference: () => array.difference,
91
+ drop: () => array.drop,
92
+ entries: () => object.entries,
93
+ escapeHtml: () => string.escapeHtml,
94
+ first: () => array.first,
95
+ flatten: () => array.flatten,
96
+ flattenDeep: () => array.flattenDeep,
97
+ get: () => object.get,
98
+ has: () => object.has,
99
+ hasLocalStorage: () => browser.hasLocalStorage,
100
+ hasSessionStorage: () => browser.hasSessionStorage,
101
+ inRange: () => number.inRange,
102
+ intersection: () => array.intersection,
103
+ invert: () => object.invert,
104
+ isArray: () => validation.isArray,
105
+ isBoolean: () => validation.isBoolean,
106
+ isBrowser: () => browser.isBrowser,
107
+ isEmail: () => validation.isEmail,
108
+ isEmpty: () => validation.isEmpty,
109
+ isFunction: () => validation.isFunction,
110
+ isNil: () => validation.isNil,
111
+ isNode: () => browser.isNode,
112
+ isNull: () => validation.isNull,
113
+ isNumber: () => validation.isNumber,
114
+ isObject: () => validation.isObject,
115
+ isString: () => validation.isString,
116
+ isURL: () => validation.isURL,
117
+ isValidDate: () => date.isValidDate,
118
+ kebabCase: () => string.kebabCase,
119
+ keys: () => object.keys,
120
+ last: () => array.last,
121
+ localStorageHelpers: () => browser.localStorageHelpers,
122
+ mapKeys: () => object.mapKeys,
123
+ mapValues: () => object.mapValues,
124
+ merge: () => object.merge,
125
+ omit: () => object.omit,
126
+ partition: () => array.partition,
127
+ pascalCase: () => string.pascalCase,
128
+ percentage: () => number.percentage,
129
+ pick: () => object.pick,
130
+ randomInt: () => number.randomInt,
131
+ retry: () => async.retry,
132
+ round: () => number.round,
133
+ safeStorage: () => browser.safeStorage,
134
+ sample: () => array.sample,
135
+ sessionStorageHelpers: () => browser.sessionStorageHelpers,
136
+ set: () => object.set,
137
+ shuffle: () => array.shuffle,
138
+ sleep: () => async.sleep,
139
+ snakeCase: () => string.snakeCase,
140
+ take: () => array.take,
141
+ throttle: () => _function.throttle,
142
+ timeout: () => async.timeout,
143
+ trim: () => string.trim,
144
+ truncate: () => string.truncate,
145
+ union: () => array.union,
146
+ unique: () => array.unique,
147
+ values: () => object.values,
148
+ withTimeout: () => async.withTimeout
149
+ });
150
+ function createLogxDebounce(func, wait) {
151
+ if (!Number.isFinite(wait) || wait < 0) {
152
+ throw new RangeError("debounce: wait must be a non-negative number");
153
+ }
154
+ const debounced = _function.debounce(func, wait);
155
+ return {
156
+ fn: debounced,
157
+ cancel: () => debounced.cancel(),
158
+ flush: () => debounced.flush(),
159
+ pending: () => debounced.pending()
160
+ };
161
+ }
162
+
163
+ // src/hooks/useArray.ts
164
+ function useArray(initialValue = []) {
165
+ const [array$1, setArray] = react.useState(initialValue);
166
+ const set3 = react.useCallback(
167
+ (value) => setArray(
168
+ (prev) => typeof value === "function" ? value(prev) : value
169
+ ),
170
+ []
171
+ );
172
+ const push = react.useCallback((...items) => setArray((prev) => [...prev, ...items]), []);
173
+ const unshift = react.useCallback((...items) => setArray((prev) => [...items, ...prev]), []);
174
+ const remove = react.useCallback(
175
+ (index) => setArray((prev) => prev.filter((_, i) => i !== index)),
176
+ []
177
+ );
178
+ const removeBy = react.useCallback(
179
+ (predicate) => setArray((prev) => prev.filter((v, i) => !predicate(v, i))),
180
+ []
181
+ );
182
+ const update = react.useCallback(
183
+ (index, value) => setArray((prev) => prev.map((v, i) => i === index ? value : v)),
184
+ []
185
+ );
186
+ const clear = react.useCallback(() => setArray([]), []);
187
+ const reset = react.useCallback(() => setArray(initialValue), [initialValue]);
188
+ const unique3 = react.useCallback(() => setArray((prev) => array.unique(prev)), []);
189
+ const compact3 = react.useCallback(() => setArray((prev) => array.compact(prev)), []);
190
+ const shuffle3 = react.useCallback(() => setArray((prev) => array.shuffle(prev)), []);
191
+ const firstValue = react.useCallback(() => array.first(array$1), [array$1]);
192
+ const lastValue = react.useCallback(() => array.last(array$1), [array$1]);
193
+ const takeValue = react.useCallback(
194
+ (count) => array.take(array$1, count),
195
+ [array$1]
196
+ );
197
+ const dropValue = react.useCallback(
198
+ (count) => array.drop(array$1, count),
199
+ [array$1]
200
+ );
201
+ return {
202
+ array: array$1,
203
+ set: set3,
204
+ push,
205
+ unshift,
206
+ remove,
207
+ removeBy,
208
+ update,
209
+ clear,
210
+ reset,
211
+ unique: unique3,
212
+ compact: compact3,
213
+ shuffle: shuffle3,
214
+ first: firstValue,
215
+ last: lastValue,
216
+ take: takeValue,
217
+ drop: dropValue,
218
+ // Expose LOGX-derived pure helpers for consumers who need them.
219
+ difference: react.useCallback(
220
+ (...others) => array.difference(array$1, ...others),
221
+ [array$1]
222
+ ),
223
+ intersection: react.useCallback(
224
+ (...others) => array.intersection(array$1, ...others),
225
+ [array$1]
226
+ ),
227
+ union: react.useCallback(
228
+ (...others) => array.union(array$1, ...others),
229
+ [array$1]
230
+ ),
231
+ partition: react.useCallback(
232
+ (predicate) => array.partition(array$1, predicate),
233
+ [array$1]
234
+ ),
235
+ flatten: react.useCallback(() => array.flatten(array$1), [array$1])
236
+ };
237
+ }
238
+ function useObject(initialValue = {}) {
239
+ const [object$1, setObject] = react.useState(initialValue);
240
+ const set3 = react.useCallback(
241
+ (value) => setObject(
242
+ (prev) => typeof value === "function" ? value(prev) : value
243
+ ),
244
+ []
245
+ );
246
+ const setKey = react.useCallback(
247
+ (key, value) => setObject((prev) => ({ ...prev, [key]: value })),
248
+ []
249
+ );
250
+ const removeKey = react.useCallback(
251
+ (key) => setObject((prev) => {
252
+ const next = { ...prev };
253
+ delete next[key];
254
+ return next;
255
+ }),
256
+ []
257
+ );
258
+ const clear = react.useCallback(() => setObject({}), []);
259
+ const reset = react.useCallback(() => setObject(initialValue), [initialValue]);
260
+ const pickValue = react.useCallback(
261
+ (pickedKeys) => object.pick(object$1, pickedKeys),
262
+ [object$1]
263
+ );
264
+ const omitValue = react.useCallback(
265
+ (omittedKeys) => object.omit(object$1, omittedKeys),
266
+ [object$1]
267
+ );
268
+ const mergeValue = react.useCallback(
269
+ (sources) => object.merge(object$1, ...sources),
270
+ [object$1]
271
+ );
272
+ const getValue = react.useCallback(
273
+ (path) => object.get(object$1, path),
274
+ [object$1]
275
+ );
276
+ const keysValue = react.useCallback(() => object.keys(object$1), [object$1]);
277
+ const valuesValue = react.useCallback(() => object.values(object$1), [object$1]);
278
+ const entriesValue = react.useCallback(() => object.entries(object$1), [object$1]);
279
+ const cloneValue = react.useCallback(() => object.clone(object$1), [object$1]);
280
+ const deepCloneValue = react.useCallback(() => object.deepClone(object$1), [object$1]);
281
+ const mapValuesValue = react.useCallback(
282
+ (iteratee) => object.mapValues(object$1, iteratee),
283
+ [object$1]
284
+ );
285
+ return {
286
+ object: object$1,
287
+ set: set3,
288
+ setKey,
289
+ removeKey,
290
+ clear,
291
+ reset,
292
+ pick: pickValue,
293
+ omit: omitValue,
294
+ merge: mergeValue,
295
+ get: getValue,
296
+ keys: keysValue,
297
+ values: valuesValue,
298
+ entries: entriesValue,
299
+ clone: cloneValue,
300
+ deepClone: deepCloneValue,
301
+ mapValues: mapValuesValue
302
+ };
303
+ }
304
+ function useDebouncedValue(value, options = {}) {
305
+ const { delay = 300, leading = false } = options;
306
+ const [debounced, setDebounced] = react.useState(value);
307
+ const latest = useLatest(value);
308
+ const timerRef = react.useRef(null);
309
+ const lastLeadingRef = react.useRef(void 0);
310
+ react.useEffect(() => {
311
+ if (timerRef.current !== null) {
312
+ clearTimeout(timerRef.current);
313
+ timerRef.current = null;
314
+ }
315
+ timerRef.current = setTimeout(() => {
316
+ setDebounced(latest.current);
317
+ timerRef.current = null;
318
+ }, delay);
319
+ return () => {
320
+ if (timerRef.current !== null) {
321
+ clearTimeout(timerRef.current);
322
+ timerRef.current = null;
323
+ }
324
+ };
325
+ }, [value, delay]);
326
+ react.useEffect(() => {
327
+ if (!leading) return;
328
+ const current = latest.current;
329
+ if (lastLeadingRef.current !== current) {
330
+ lastLeadingRef.current = current;
331
+ setDebounced(current);
332
+ }
333
+ }, [value, leading]);
334
+ return debounced;
335
+ }
336
+ function useDebouncedCallback(callback, delay) {
337
+ const latest = useLatest(callback);
338
+ const debouncedRef = react.useRef(null);
339
+ react.useEffect(() => {
340
+ const debounced = _function.debounce(
341
+ (...args) => {
342
+ latest.current(...args);
343
+ },
344
+ delay
345
+ );
346
+ debouncedRef.current = debounced;
347
+ return () => {
348
+ debounced.cancel();
349
+ };
350
+ }, [delay]);
351
+ const invoke = react.useCallback((...args) => {
352
+ debouncedRef.current?.(...args);
353
+ }, []);
354
+ const cancel = react.useCallback(() => {
355
+ debouncedRef.current?.cancel();
356
+ }, []);
357
+ const flush = react.useCallback(() => {
358
+ debouncedRef.current?.flush();
359
+ }, []);
360
+ const pending = react.useCallback(() => debouncedRef.current?.pending() ?? false, []);
361
+ return Object.assign(invoke, { cancel, flush, pending });
362
+ }
363
+ function useThrottle(callback, wait) {
364
+ const latest = useLatest(callback);
365
+ const throttledRef = react.useRef(null);
366
+ react.useEffect(() => {
367
+ const throttled = _function.throttle(
368
+ (...args) => {
369
+ latest.current(...args);
370
+ },
371
+ wait
372
+ );
373
+ throttledRef.current = throttled;
374
+ return () => {
375
+ throttled.cancel();
376
+ };
377
+ }, [wait]);
378
+ const invoke = react.useCallback((...args) => {
379
+ throttledRef.current?.(...args);
380
+ }, []);
381
+ const cancel = react.useCallback(() => {
382
+ throttledRef.current?.cancel();
383
+ }, []);
384
+ const flush = react.useCallback(() => {
385
+ throttledRef.current?.flush();
386
+ }, []);
387
+ const pending = react.useCallback(() => throttledRef.current?.pending() ?? false, []);
388
+ return Object.assign(invoke, { cancel, flush, pending });
389
+ }
390
+
391
+ // src/internal/storage.ts
392
+ var jsonSerializer = {
393
+ serialize: (value) => JSON.stringify(value),
394
+ deserialize: (raw) => {
395
+ if (raw === null) return null;
396
+ try {
397
+ return JSON.parse(raw);
398
+ } catch {
399
+ return null;
400
+ }
401
+ }
402
+ };
403
+
404
+ // src/hooks/storage/useLocalStorage.ts
405
+ function useLocalStorage(key, initialValue, options) {
406
+ const serializer = options?.serializer ?? jsonSerializer;
407
+ const [value, setValue] = react.useState(initialValue);
408
+ react.useEffect(() => {
409
+ const helpers = browser.localStorageHelpers();
410
+ if (!helpers) return;
411
+ const raw = helpers.get(key);
412
+ if (raw === null) return;
413
+ const parsed = serializer.deserialize(raw);
414
+ if (parsed !== null) setValue(parsed);
415
+ }, [key, serializer]);
416
+ const set3 = react.useCallback(
417
+ (next) => setValue((prev) => {
418
+ const resolved = typeof next === "function" ? next(prev) : next;
419
+ const helpers = browser.localStorageHelpers();
420
+ if (helpers) {
421
+ try {
422
+ helpers.set(key, serializer.serialize(resolved));
423
+ } catch {
424
+ }
425
+ }
426
+ return resolved;
427
+ }),
428
+ [key, serializer]
429
+ );
430
+ const remove = react.useCallback(() => {
431
+ setValue(initialValue);
432
+ const helpers = browser.localStorageHelpers();
433
+ if (helpers) {
434
+ try {
435
+ helpers.remove(key);
436
+ } catch {
437
+ }
438
+ }
439
+ }, [key, initialValue]);
440
+ react.useEffect(() => {
441
+ if (typeof window === "undefined") return;
442
+ const handle = (event) => {
443
+ if (event.key === key && event.storageArea === localStorage) {
444
+ const parsed = event.newValue === null ? null : serializer.deserialize(event.newValue);
445
+ if (parsed !== null) setValue(parsed);
446
+ }
447
+ };
448
+ window.addEventListener("storage", handle);
449
+ return () => window.removeEventListener("storage", handle);
450
+ }, [key, serializer]);
451
+ return [value, set3, remove];
452
+ }
453
+ function useSessionStorage(key, initialValue, options) {
454
+ const serializer = options?.serializer ?? jsonSerializer;
455
+ const [value, setValue] = react.useState(initialValue);
456
+ react.useEffect(() => {
457
+ const helpers = browser.sessionStorageHelpers();
458
+ if (!helpers) return;
459
+ const raw = helpers.get(key);
460
+ if (raw === null) return;
461
+ const parsed = serializer.deserialize(raw);
462
+ if (parsed !== null) setValue(parsed);
463
+ }, [key, serializer]);
464
+ const set3 = react.useCallback(
465
+ (next) => setValue((prev) => {
466
+ const resolved = typeof next === "function" ? next(prev) : next;
467
+ const helpers = browser.sessionStorageHelpers();
468
+ if (helpers) {
469
+ try {
470
+ helpers.set(key, serializer.serialize(resolved));
471
+ } catch {
472
+ }
473
+ }
474
+ return resolved;
475
+ }),
476
+ [key, serializer]
477
+ );
478
+ const remove = react.useCallback(() => {
479
+ setValue(initialValue);
480
+ const helpers = browser.sessionStorageHelpers();
481
+ if (helpers) {
482
+ try {
483
+ helpers.remove(key);
484
+ } catch {
485
+ }
486
+ }
487
+ }, [key, initialValue]);
488
+ return [value, set3, remove];
489
+ }
490
+ function useMediaQuery(query) {
491
+ const [matches, setMatches] = react.useState(false);
492
+ react.useEffect(() => {
493
+ if (typeof window === "undefined") return;
494
+ const media = window.matchMedia(query);
495
+ setMatches(media.matches);
496
+ const handler = (event) => setMatches(event.matches);
497
+ media.addEventListener("change", handler);
498
+ return () => {
499
+ media.removeEventListener("change", handler);
500
+ };
501
+ }, [query]);
502
+ return matches;
503
+ }
504
+ function useWindowSize() {
505
+ const [size, setSize] = react.useState(
506
+ () => typeof window !== "undefined" ? { width: window.innerWidth, height: window.innerHeight } : { width: 0, height: 0 }
507
+ );
508
+ react.useEffect(() => {
509
+ if (typeof window === "undefined") return;
510
+ const handler = () => setSize({ width: window.innerWidth, height: window.innerHeight });
511
+ window.addEventListener("resize", handler);
512
+ return () => window.removeEventListener("resize", handler);
513
+ }, []);
514
+ return size;
515
+ }
516
+ function useClickOutside(ref, handler) {
517
+ const latest = react.useRef(handler);
518
+ latest.current = handler;
519
+ react.useEffect(() => {
520
+ const handle = (event) => {
521
+ if (ref.current && !ref.current.contains(event.target)) {
522
+ latest.current(event);
523
+ }
524
+ };
525
+ if (typeof document !== "undefined") {
526
+ document.addEventListener("mousedown", handle);
527
+ document.addEventListener("touchstart", handle);
528
+ return () => {
529
+ document.removeEventListener("mousedown", handle);
530
+ document.removeEventListener("touchstart", handle);
531
+ };
532
+ }
533
+ return void 0;
534
+ }, [ref]);
535
+ }
536
+ function useEventListener(target, type, listener, options) {
537
+ const latest = react.useRef(listener);
538
+ latest.current = listener;
539
+ react.useEffect(() => {
540
+ if (!target) return void 0;
541
+ const handle = (event) => latest.current(event);
542
+ target.addEventListener(type, handle, options);
543
+ return () => {
544
+ target.removeEventListener(type, handle, options);
545
+ };
546
+ }, [target, type, options]);
547
+ }
548
+ function useClipboard() {
549
+ const isSupported = typeof navigator !== "undefined" && !!navigator.clipboard && !!navigator.clipboard.writeText;
550
+ const copy = react.useCallback(async (text) => {
551
+ try {
552
+ if (isSupported && typeof navigator !== "undefined") {
553
+ await navigator.clipboard.writeText(text);
554
+ return true;
555
+ }
556
+ if (typeof document !== "undefined") {
557
+ const textarea = document.createElement("textarea");
558
+ textarea.value = text;
559
+ textarea.setAttribute("readonly", "");
560
+ textarea.style.position = "absolute";
561
+ textarea.style.position = "fixed";
562
+ textarea.style.opacity = "0";
563
+ document.body.appendChild(textarea);
564
+ textarea.select();
565
+ try {
566
+ document.execCommand("copy");
567
+ } finally {
568
+ document.body.removeChild(textarea);
569
+ }
570
+ return true;
571
+ }
572
+ return false;
573
+ } catch {
574
+ return false;
575
+ }
576
+ }, [isSupported]);
577
+ return { copy, isSupported };
578
+ }
579
+ function useOnlineStatus() {
580
+ const [online, setOnline] = react.useState(
581
+ () => typeof navigator !== "undefined" ? navigator.onLine : true
582
+ );
583
+ react.useEffect(() => {
584
+ if (typeof window === "undefined") return;
585
+ setOnline(navigator.onLine);
586
+ const onOnline = () => setOnline(true);
587
+ const onOffline = () => setOnline(false);
588
+ window.addEventListener("online", onOnline);
589
+ window.addEventListener("offline", onOffline);
590
+ return () => {
591
+ window.removeEventListener("online", onOnline);
592
+ window.removeEventListener("offline", onOffline);
593
+ };
594
+ }, []);
595
+ return online;
596
+ }
597
+ function useTimeout(callback, delay) {
598
+ const latest = useLatest(callback);
599
+ const timerRef = react.useRef(null);
600
+ const [active, setActive] = react.useState(false);
601
+ const stop = react.useCallback(() => {
602
+ if (timerRef.current !== null) {
603
+ clearTimeout(timerRef.current);
604
+ timerRef.current = null;
605
+ }
606
+ setActive(false);
607
+ }, []);
608
+ const start = react.useCallback(() => {
609
+ stop();
610
+ if (delay !== null && delay >= 0) {
611
+ timerRef.current = setTimeout(() => {
612
+ timerRef.current = null;
613
+ setActive(false);
614
+ latest.current();
615
+ }, delay);
616
+ setActive(true);
617
+ }
618
+ }, [delay]);
619
+ const reset = react.useCallback(() => {
620
+ start();
621
+ }, [start]);
622
+ react.useEffect(() => {
623
+ start();
624
+ return () => stop();
625
+ }, [delay, start, stop]);
626
+ return { start, stop, reset, active };
627
+ }
628
+ function useInterval(callback, delay) {
629
+ const latest = useLatest(callback);
630
+ const timerRef = react.useRef(null);
631
+ const [active, setActive] = react.useState(false);
632
+ const stop = react.useCallback(() => {
633
+ if (timerRef.current !== null) {
634
+ clearInterval(timerRef.current);
635
+ timerRef.current = null;
636
+ }
637
+ setActive(false);
638
+ }, []);
639
+ const start = react.useCallback(() => {
640
+ stop();
641
+ if (delay !== null && delay >= 0) {
642
+ timerRef.current = setInterval(() => latest.current(), delay);
643
+ setActive(true);
644
+ }
645
+ }, [delay]);
646
+ react.useEffect(() => {
647
+ start();
648
+ return () => stop();
649
+ }, [delay, start, stop]);
650
+ return { start, stop, active };
651
+ }
652
+ function useAsync(asyncFn, immediate = true) {
653
+ const [state, setState] = react.useState({
654
+ data: null,
655
+ error: null,
656
+ isLoading: false,
657
+ isSuccess: false,
658
+ isError: false
659
+ });
660
+ const latest = useLatest(asyncFn);
661
+ const abortRef = react.useRef(null);
662
+ const seqRef = react.useRef(0);
663
+ const cancel = react.useCallback(() => {
664
+ if (abortRef.current) {
665
+ abortRef.current.abort();
666
+ abortRef.current = null;
667
+ setState({ data: null, error: null, isLoading: false, isSuccess: false, isError: false });
668
+ }
669
+ }, []);
670
+ const setData = react.useCallback((data) => {
671
+ setState({ data, error: null, isLoading: false, isSuccess: true, isError: false });
672
+ }, []);
673
+ const setError = react.useCallback((error) => {
674
+ setState({ data: null, error, isLoading: false, isSuccess: false, isError: true });
675
+ }, []);
676
+ const reset = react.useCallback(() => {
677
+ cancel();
678
+ setState({ data: null, error: null, isLoading: false, isSuccess: false, isError: false });
679
+ }, [cancel]);
680
+ const execute = react.useCallback(async () => {
681
+ cancel();
682
+ const controller = new AbortController();
683
+ abortRef.current = controller;
684
+ const seq = ++seqRef.current;
685
+ setState({ data: null, error: null, isLoading: true, isSuccess: false, isError: false });
686
+ try {
687
+ const data = await latest.current();
688
+ if (controller.signal.aborted || seq !== seqRef.current) return;
689
+ setState({ data, error: null, isLoading: false, isSuccess: true, isError: false });
690
+ } catch (err) {
691
+ if (controller.signal.aborted || seq !== seqRef.current) return;
692
+ const error = err instanceof Error ? err : new Error(String(err));
693
+ setState({ data: null, error, isLoading: false, isSuccess: false, isError: true });
694
+ } finally {
695
+ if (abortRef.current === controller) abortRef.current = null;
696
+ }
697
+ }, []);
698
+ react.useEffect(() => {
699
+ if (!immediate) return;
700
+ void execute();
701
+ return () => cancel();
702
+ }, [immediate, execute, cancel]);
703
+ return { ...state, execute, setData, setError, reset, cancel };
704
+ }
705
+ function CopyButton({
706
+ text,
707
+ label = "Copy",
708
+ copyingLabel = "Copying...",
709
+ successLabel = "Copied!",
710
+ errorLabel = "Error",
711
+ className,
712
+ onCopy,
713
+ onError,
714
+ timeout: timeout2 = 2e3
715
+ }) {
716
+ const [status, setStatus] = react.useState("idle");
717
+ const { copy } = useClipboard();
718
+ const handleCopy = react.useCallback(async () => {
719
+ setStatus("copying");
720
+ try {
721
+ const ok = await copy(text);
722
+ if (ok) {
723
+ setStatus("success");
724
+ onCopy?.(text);
725
+ } else {
726
+ setStatus("error");
727
+ onError?.(new Error("Failed to copy to clipboard"));
728
+ }
729
+ } catch (err) {
730
+ setStatus("error");
731
+ onError?.(err);
732
+ }
733
+ setTimeout(() => setStatus("idle"), timeout2);
734
+ }, [text, copy, onCopy, onError, timeout2]);
735
+ const displayLabel = status === "copying" ? copyingLabel : status === "success" ? successLabel : status === "error" ? errorLabel : label;
736
+ return /* @__PURE__ */ jsxRuntime.jsx(
737
+ "button",
738
+ {
739
+ type: "button",
740
+ className,
741
+ disabled: status === "copying",
742
+ onClick: handleCopy,
743
+ "aria-label": status === "success" ? "Copied to clipboard" : label,
744
+ "aria-pressed": status === "success",
745
+ children: displayLabel
746
+ }
747
+ );
748
+ }
749
+ function DebouncedInput({
750
+ value,
751
+ defaultValue,
752
+ onChange,
753
+ onDebouncedChange,
754
+ delay = 300,
755
+ ...rest
756
+ }) {
757
+ const [internalValue, setInternalValue] = react.useState(defaultValue ?? "");
758
+ const isControlled = value !== void 0;
759
+ const currentValue = isControlled ? value ?? "" : internalValue;
760
+ const handleChange = react.useCallback(
761
+ (event) => {
762
+ const next = event.target.value;
763
+ if (!isControlled) setInternalValue(next);
764
+ onChange?.(next);
765
+ },
766
+ [isControlled, onChange]
767
+ );
768
+ const debounced = useDebouncedValue(currentValue, { delay });
769
+ const initialized = react.useRef(false);
770
+ react.useEffect(() => {
771
+ if (!initialized.current) {
772
+ initialized.current = true;
773
+ return;
774
+ }
775
+ onDebouncedChange?.(debounced);
776
+ }, [debounced, onDebouncedChange]);
777
+ return /* @__PURE__ */ jsxRuntime.jsx("input", { ...rest, value: currentValue, onChange: handleChange });
778
+ }
779
+ function PasswordInput({
780
+ value,
781
+ defaultValue,
782
+ onChange,
783
+ label = "Password",
784
+ placeholder,
785
+ disabled = false,
786
+ required: required2 = false,
787
+ name,
788
+ id,
789
+ showToggle = true,
790
+ className
791
+ }) {
792
+ const [show, setShow] = react.useState(false);
793
+ const [internalValue, setInternalValue] = react.useState(defaultValue ?? "");
794
+ const isControlled = value !== void 0;
795
+ const currentValue = isControlled ? value ?? "" : internalValue;
796
+ const handleChange = react.useCallback(
797
+ (event) => {
798
+ const next = event.target.value;
799
+ if (!isControlled) setInternalValue(next);
800
+ onChange?.(next);
801
+ },
802
+ [isControlled, onChange]
803
+ );
804
+ const toggle = react.useCallback(() => setShow((current) => !current), []);
805
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
806
+ label && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, children: label }),
807
+ /* @__PURE__ */ jsxRuntime.jsx(
808
+ "input",
809
+ {
810
+ id,
811
+ name,
812
+ type: show ? "text" : "password",
813
+ value: currentValue,
814
+ onChange: handleChange,
815
+ placeholder,
816
+ disabled,
817
+ required: required2,
818
+ "aria-label": label
819
+ }
820
+ ),
821
+ showToggle && /* @__PURE__ */ jsxRuntime.jsx(
822
+ "button",
823
+ {
824
+ type: "button",
825
+ onClick: toggle,
826
+ "aria-label": show ? "Hide password" : "Show password",
827
+ "aria-pressed": show,
828
+ children: show ? "Hide password" : "Show password"
829
+ }
830
+ )
831
+ ] });
832
+ }
833
+ function Responsive({ children, query, fallback }) {
834
+ const matches = useMediaQuery(query);
835
+ const renderChildren = react.useCallback(
836
+ (m) => m ? children(m) : fallback ?? null,
837
+ [children, fallback]
838
+ );
839
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: renderChildren(matches) });
840
+ }
841
+ var ErrorBoundary = class extends react.Component {
842
+ constructor() {
843
+ super(...arguments);
844
+ this.state = { hasError: false, error: null, info: null };
845
+ }
846
+ static getDerivedStateFromError(error) {
847
+ return { hasError: true, error, info: null };
848
+ }
849
+ componentDidCatch(error, info) {
850
+ this.setState({ info });
851
+ this.props.onError?.(error, info);
852
+ }
853
+ componentDidUpdate(prevProps) {
854
+ if (this.props.resetKeys !== prevProps.resetKeys) {
855
+ const prev = JSON.stringify(prevProps.resetKeys);
856
+ const next = JSON.stringify(this.props.resetKeys);
857
+ if (prev !== next) {
858
+ this.setState({ hasError: false, error: null, info: null });
859
+ }
860
+ }
861
+ }
862
+ render() {
863
+ if (this.state.hasError) {
864
+ const { fallback } = this.props;
865
+ if (fallback === void 0) return null;
866
+ if (typeof fallback === "function") {
867
+ return fallback(
868
+ this.state.error,
869
+ this.state.info
870
+ );
871
+ }
872
+ return fallback;
873
+ }
874
+ return this.props.children;
875
+ }
876
+ };
877
+
878
+ // src/utilities/array.ts
879
+ var chunk2 = array.chunk;
880
+ var compact2 = array.compact;
881
+ var difference2 = array.difference;
882
+ var drop2 = array.drop;
883
+ var flatten2 = array.flatten;
884
+ var flattenDeep2 = array.flattenDeep;
885
+ var intersection2 = array.intersection;
886
+ var last2 = array.last;
887
+ var partition2 = array.partition;
888
+ var sample2 = array.sample;
889
+ var shuffle2 = array.shuffle;
890
+ var take2 = array.take;
891
+ var union2 = array.union;
892
+ var unique2 = array.unique;
893
+ function first2(array) {
894
+ return array[0];
895
+ }
896
+ function distinct(array) {
897
+ return unique2(array);
898
+ }
899
+
900
+ // src/utilities/object.ts
901
+ var clone2 = object.clone;
902
+ var deepClone2 = object.deepClone;
903
+ var entries2 = object.entries;
904
+ var get2 = object.get;
905
+ var has2 = object.has;
906
+ var keys2 = object.keys;
907
+ var mapKeys2 = object.mapKeys;
908
+ var mapValues2 = object.mapValues;
909
+ var merge2 = object.merge;
910
+ var omit2 = object.omit;
911
+ var pick2 = object.pick;
912
+ var set2 = object.set;
913
+ var values2 = object.values;
914
+ function safeGet(object$1, path) {
915
+ const result = object.get(object$1, path);
916
+ return result === void 0 ? void 0 : result;
917
+ }
918
+
919
+ // src/utilities/string.ts
920
+ var camelCase2 = string.camelCase;
921
+ var capitalize2 = string.capitalize;
922
+ var escapeHtml2 = string.escapeHtml;
923
+ var kebabCase2 = string.kebabCase;
924
+ var pascalCase2 = string.pascalCase;
925
+ var snakeCase2 = string.snakeCase;
926
+ var trim2 = string.trim;
927
+ var truncate2 = string.truncate;
928
+ function htmlEscape(input) {
929
+ return escapeHtml2(input);
930
+ }
931
+
932
+ // src/utilities/number.ts
933
+ var clamp2 = number.clamp;
934
+ var inRange2 = number.inRange;
935
+ var round2 = number.round;
936
+ var percentage2 = number.percentage;
937
+ var randomInt2 = number.randomInt;
938
+
939
+ // src/utilities/validation.ts
940
+ var isArray2 = validation.isArray;
941
+ var isBoolean2 = validation.isBoolean;
942
+ var isEmail2 = validation.isEmail;
943
+ var isEmpty2 = validation.isEmpty;
944
+ var isFunction2 = validation.isFunction;
945
+ var isNil2 = validation.isNil;
946
+ var isNull2 = validation.isNull;
947
+ var isNumber2 = validation.isNumber;
948
+ var isObject2 = validation.isObject;
949
+ var isString2 = validation.isString;
950
+ var isURL2 = validation.isURL;
951
+ function required(value, fieldName = "This field") {
952
+ if (isNil2(value)) return `${fieldName} is required`;
953
+ if (isString2(value) && value.trim() === "") return `${fieldName} is required`;
954
+ return null;
955
+ }
956
+
957
+ // src/utilities/date.ts
958
+ var addDays2 = date.addDays;
959
+ var isValidDate2 = date.isValidDate;
960
+
961
+ // src/utilities/browser.ts
962
+ var hasLocalStorage = browser.hasLocalStorage;
963
+ var hasSessionStorage = browser.hasSessionStorage;
964
+ var isBrowser = browser.isBrowser;
965
+ var isNode = browser.isNode;
966
+ var LogxContext = react.createContext(null);
967
+ function LogxProvider({ children }) {
968
+ return /* @__PURE__ */ jsxRuntime.jsx(LogxContext.Provider, { value: { logx: logx_exports }, children });
969
+ }
970
+ function useLogx() {
971
+ return react.useContext(LogxContext);
972
+ }
973
+
974
+ exports.CopyButton = CopyButton;
975
+ exports.DebouncedInput = DebouncedInput;
976
+ exports.ErrorBoundary = ErrorBoundary;
977
+ exports.LogxProvider = LogxProvider;
978
+ exports.PasswordInput = PasswordInput;
979
+ exports.Responsive = Responsive;
980
+ exports.addDays = addDays2;
981
+ exports.camelCase = camelCase2;
982
+ exports.capitalize = capitalize2;
983
+ exports.chunk = chunk2;
984
+ exports.clamp = clamp2;
985
+ exports.clone = clone2;
986
+ exports.compact = compact2;
987
+ exports.deepClone = deepClone2;
988
+ exports.difference = difference2;
989
+ exports.distinct = distinct;
990
+ exports.drop = drop2;
991
+ exports.entries = entries2;
992
+ exports.escapeHtml = escapeHtml2;
993
+ exports.first = first2;
994
+ exports.flatten = flatten2;
995
+ exports.flattenDeep = flattenDeep2;
996
+ exports.get = get2;
997
+ exports.has = has2;
998
+ exports.hasLocalStorage = hasLocalStorage;
999
+ exports.hasSessionStorage = hasSessionStorage;
1000
+ exports.htmlEscape = htmlEscape;
1001
+ exports.inRange = inRange2;
1002
+ exports.intersection = intersection2;
1003
+ exports.isArray = isArray2;
1004
+ exports.isBoolean = isBoolean2;
1005
+ exports.isBrowser = isBrowser;
1006
+ exports.isEmail = isEmail2;
1007
+ exports.isEmpty = isEmpty2;
1008
+ exports.isFunction = isFunction2;
1009
+ exports.isNil = isNil2;
1010
+ exports.isNode = isNode;
1011
+ exports.isNull = isNull2;
1012
+ exports.isNumber = isNumber2;
1013
+ exports.isObject = isObject2;
1014
+ exports.isString = isString2;
1015
+ exports.isURL = isURL2;
1016
+ exports.isValidDate = isValidDate2;
1017
+ exports.kebabCase = kebabCase2;
1018
+ exports.keys = keys2;
1019
+ exports.last = last2;
1020
+ exports.mapKeys = mapKeys2;
1021
+ exports.mapValues = mapValues2;
1022
+ exports.merge = merge2;
1023
+ exports.omit = omit2;
1024
+ exports.partition = partition2;
1025
+ exports.pascalCase = pascalCase2;
1026
+ exports.percentage = percentage2;
1027
+ exports.pick = pick2;
1028
+ exports.randomInt = randomInt2;
1029
+ exports.required = required;
1030
+ exports.round = round2;
1031
+ exports.safeGet = safeGet;
1032
+ exports.sample = sample2;
1033
+ exports.set = set2;
1034
+ exports.shuffle = shuffle2;
1035
+ exports.snakeCase = snakeCase2;
1036
+ exports.take = take2;
1037
+ exports.trim = trim2;
1038
+ exports.truncate = truncate2;
1039
+ exports.union = union2;
1040
+ exports.unique = unique2;
1041
+ exports.useArray = useArray;
1042
+ exports.useAsync = useAsync;
1043
+ exports.useBoolean = useBoolean;
1044
+ exports.useClickOutside = useClickOutside;
1045
+ exports.useClipboard = useClipboard;
1046
+ exports.useCounter = useCounter;
1047
+ exports.useDebouncedCallback = useDebouncedCallback;
1048
+ exports.useDebouncedValue = useDebouncedValue;
1049
+ exports.useEventListener = useEventListener;
1050
+ exports.useInterval = useInterval;
1051
+ exports.useLatest = useLatest;
1052
+ exports.useLocalStorage = useLocalStorage;
1053
+ exports.useLogx = useLogx;
1054
+ exports.useMediaQuery = useMediaQuery;
1055
+ exports.useMounted = useMounted;
1056
+ exports.useObject = useObject;
1057
+ exports.useOnlineStatus = useOnlineStatus;
1058
+ exports.usePrevious = usePrevious;
1059
+ exports.useSessionStorage = useSessionStorage;
1060
+ exports.useThrottle = useThrottle;
1061
+ exports.useTimeout = useTimeout;
1062
+ exports.useToggle = useToggle;
1063
+ exports.useWindowSize = useWindowSize;
1064
+ exports.values = values2;
1065
+ //# sourceMappingURL=index.js.map
1066
+ //# sourceMappingURL=index.js.map