@boo-dreamer/hooks 0.0.1

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/dist/index.cjs ADDED
@@ -0,0 +1,578 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const vue = require("vue");
4
+ function useToggle(options = {}) {
5
+ const { defaultValue = false, reverseValue = !defaultValue } = options;
6
+ const state = vue.ref(defaultValue);
7
+ const toggle = () => {
8
+ state.value = !state.value;
9
+ };
10
+ const setLeft = () => {
11
+ state.value = defaultValue;
12
+ };
13
+ const setRight = () => {
14
+ state.value = reverseValue;
15
+ };
16
+ return {
17
+ state,
18
+ toggle,
19
+ setLeft,
20
+ setRight
21
+ };
22
+ }
23
+ function useBoolean(defaultValue = false) {
24
+ const state = vue.ref(defaultValue);
25
+ const setTrue = () => {
26
+ state.value = true;
27
+ };
28
+ const setFalse = () => {
29
+ state.value = false;
30
+ };
31
+ const toggle = () => {
32
+ state.value = !state.value;
33
+ };
34
+ const set = (value) => {
35
+ state.value = value;
36
+ };
37
+ return {
38
+ state,
39
+ setTrue,
40
+ setFalse,
41
+ toggle,
42
+ set
43
+ };
44
+ }
45
+ function useSetState(initialState) {
46
+ const state = vue.reactive({ ...initialState });
47
+ const setState = (newState) => {
48
+ if (typeof newState === "function") {
49
+ const patch = newState(state);
50
+ Object.assign(state, patch);
51
+ } else {
52
+ Object.assign(state, newState);
53
+ }
54
+ };
55
+ return [state, setState];
56
+ }
57
+ function useCounter(initialValue = 0, options = {}) {
58
+ const { min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER } = options;
59
+ const count = vue.ref(initialValue);
60
+ const inc = (delta = 1) => {
61
+ const next = count.value + delta;
62
+ if (next <= max) {
63
+ count.value = next;
64
+ } else {
65
+ count.value = max;
66
+ }
67
+ };
68
+ const dec = (delta = 1) => {
69
+ const next = count.value - delta;
70
+ if (next >= min) {
71
+ count.value = next;
72
+ } else {
73
+ count.value = min;
74
+ }
75
+ };
76
+ const set = (value) => {
77
+ if (value >= min && value <= max) {
78
+ count.value = value;
79
+ }
80
+ };
81
+ const reset = () => {
82
+ count.value = initialValue;
83
+ };
84
+ return {
85
+ count,
86
+ inc,
87
+ dec,
88
+ set,
89
+ reset
90
+ };
91
+ }
92
+ function useDebounce(value, options = {}) {
93
+ const { wait = 300, immediate = false } = options;
94
+ const debouncedValue = vue.ref(
95
+ typeof value === "function" ? value() : value.value
96
+ );
97
+ let timeout = null;
98
+ const debounce = (fn) => {
99
+ if (timeout) {
100
+ clearTimeout(timeout);
101
+ }
102
+ if (immediate && !timeout) {
103
+ fn();
104
+ }
105
+ timeout = setTimeout(() => {
106
+ if (!immediate) {
107
+ fn();
108
+ }
109
+ timeout = null;
110
+ }, wait);
111
+ };
112
+ vue.watch(
113
+ value,
114
+ (newVal) => {
115
+ debounce(() => {
116
+ debouncedValue.value = newVal;
117
+ });
118
+ },
119
+ { immediate: false }
120
+ );
121
+ return debouncedValue;
122
+ }
123
+ function useThrottle(value, options = {}) {
124
+ const { wait = 300, leading = true, trailing = true } = options;
125
+ const throttledValue = vue.ref(
126
+ typeof value === "function" ? value() : value.value
127
+ );
128
+ let lastExec = 0;
129
+ let timeout = null;
130
+ const throttle = (fn) => {
131
+ const now = Date.now();
132
+ const elapsed = now - lastExec;
133
+ const execute = () => {
134
+ lastExec = Date.now();
135
+ fn();
136
+ };
137
+ if (elapsed >= wait) {
138
+ if (leading) {
139
+ execute();
140
+ } else if (trailing) {
141
+ if (timeout) clearTimeout(timeout);
142
+ timeout = setTimeout(execute, wait);
143
+ }
144
+ } else if (trailing) {
145
+ if (timeout) clearTimeout(timeout);
146
+ timeout = setTimeout(() => {
147
+ lastExec = Date.now();
148
+ fn();
149
+ }, wait - elapsed);
150
+ }
151
+ };
152
+ vue.watch(
153
+ value,
154
+ (newVal) => {
155
+ throttle(() => {
156
+ throttledValue.value = newVal;
157
+ });
158
+ },
159
+ { immediate: false }
160
+ );
161
+ return throttledValue;
162
+ }
163
+ function useInterval(fn, delay, options = {}) {
164
+ const { immediate = false } = options;
165
+ const count = vue.ref(0);
166
+ let timer = null;
167
+ const start = () => {
168
+ if (timer) return;
169
+ if (immediate) {
170
+ fn();
171
+ count.value++;
172
+ }
173
+ timer = setInterval(() => {
174
+ fn();
175
+ count.value++;
176
+ }, delay);
177
+ };
178
+ const stop = () => {
179
+ if (timer) {
180
+ clearInterval(timer);
181
+ timer = null;
182
+ }
183
+ };
184
+ const reset = () => {
185
+ stop();
186
+ count.value = 0;
187
+ };
188
+ vue.onUnmounted(() => {
189
+ stop();
190
+ });
191
+ return {
192
+ count,
193
+ start,
194
+ stop,
195
+ reset
196
+ };
197
+ }
198
+ function useTimeout(fn, delay) {
199
+ const ready = vue.ref(false);
200
+ let timer = null;
201
+ const start = () => {
202
+ if (timer) return;
203
+ ready.value = false;
204
+ timer = setTimeout(() => {
205
+ ready.value = true;
206
+ fn();
207
+ }, delay);
208
+ };
209
+ const stop = () => {
210
+ if (timer) {
211
+ clearTimeout(timer);
212
+ timer = null;
213
+ }
214
+ };
215
+ vue.onUnmounted(() => {
216
+ stop();
217
+ });
218
+ return {
219
+ ready,
220
+ start,
221
+ stop
222
+ };
223
+ }
224
+ function useClickOutside(targetRef, handler) {
225
+ const listener = (event) => {
226
+ const el = targetRef.value;
227
+ if (!el) return;
228
+ if (!(el === event.target || el.contains(event.target))) {
229
+ handler(event);
230
+ }
231
+ };
232
+ vue.onMounted(() => {
233
+ document.addEventListener("click", listener, true);
234
+ });
235
+ vue.onUnmounted(() => {
236
+ document.removeEventListener("click", listener, true);
237
+ });
238
+ }
239
+ function useFullscreen(target) {
240
+ const isFullscreen = vue.ref(false);
241
+ const getElement = () => {
242
+ return (target == null ? void 0 : target.value) || document.documentElement;
243
+ };
244
+ const enter = async () => {
245
+ const el = getElement();
246
+ if (el.requestFullscreen) {
247
+ await el.requestFullscreen();
248
+ isFullscreen.value = true;
249
+ }
250
+ };
251
+ const exit = async () => {
252
+ if (document.exitFullscreen) {
253
+ await document.exitFullscreen();
254
+ isFullscreen.value = false;
255
+ }
256
+ };
257
+ const toggle = async () => {
258
+ if (isFullscreen.value) {
259
+ await exit();
260
+ } else {
261
+ await enter();
262
+ }
263
+ };
264
+ document.addEventListener("fullscreenchange", () => {
265
+ isFullscreen.value = !!document.fullscreenElement;
266
+ });
267
+ return {
268
+ isFullscreen,
269
+ enter,
270
+ exit,
271
+ toggle
272
+ };
273
+ }
274
+ function useResize() {
275
+ const width = vue.ref(window.innerWidth);
276
+ const height = vue.ref(window.innerHeight);
277
+ const handler = () => {
278
+ width.value = window.innerWidth;
279
+ height.value = window.innerHeight;
280
+ };
281
+ vue.onMounted(() => {
282
+ window.addEventListener("resize", handler);
283
+ });
284
+ vue.onUnmounted(() => {
285
+ window.removeEventListener("resize", handler);
286
+ });
287
+ return {
288
+ width,
289
+ height
290
+ };
291
+ }
292
+ function useScroll(options = {}) {
293
+ const { target } = options;
294
+ const scrollX = vue.ref(0);
295
+ const scrollY = vue.ref(0);
296
+ const getElement = () => {
297
+ return (target == null ? void 0 : target.value) || window;
298
+ };
299
+ const handler = () => {
300
+ const el = getElement();
301
+ if (el === window) {
302
+ scrollX.value = window.scrollX;
303
+ scrollY.value = window.scrollY;
304
+ } else {
305
+ scrollX.value = el.scrollLeft;
306
+ scrollY.value = el.scrollTop;
307
+ }
308
+ };
309
+ const scrollTo = (x, y) => {
310
+ const el = getElement();
311
+ if (el === window) {
312
+ window.scrollTo(x, y);
313
+ } else {
314
+ el.scrollTo(x, y);
315
+ }
316
+ };
317
+ const scrollToTop = () => {
318
+ scrollTo(0, 0);
319
+ };
320
+ vue.onMounted(() => {
321
+ const el = getElement();
322
+ el.addEventListener("scroll", handler, { passive: true });
323
+ handler();
324
+ });
325
+ vue.onUnmounted(() => {
326
+ const el = getElement();
327
+ el.removeEventListener("scroll", handler);
328
+ });
329
+ return {
330
+ scrollX,
331
+ scrollY,
332
+ scrollTo,
333
+ scrollToTop
334
+ };
335
+ }
336
+ function useLocalStorage(key, options = {}) {
337
+ const { defaultValue = null, serializer } = options;
338
+ const read = () => {
339
+ try {
340
+ const item = localStorage.getItem(key);
341
+ if (item === null) return defaultValue;
342
+ return serializer ? serializer.read(item) : JSON.parse(item);
343
+ } catch {
344
+ return defaultValue;
345
+ }
346
+ };
347
+ const write = (value) => {
348
+ try {
349
+ if (value === null) {
350
+ localStorage.removeItem(key);
351
+ } else {
352
+ const serialized = serializer ? serializer.write(value) : JSON.stringify(value);
353
+ localStorage.setItem(key, serialized);
354
+ }
355
+ } catch {
356
+ }
357
+ };
358
+ const storedValue = vue.ref(read());
359
+ vue.watch(
360
+ storedValue,
361
+ (newVal) => {
362
+ write(newVal);
363
+ },
364
+ { deep: true }
365
+ );
366
+ window.addEventListener("storage", (e) => {
367
+ if (e.key === key) {
368
+ storedValue.value = read();
369
+ }
370
+ });
371
+ return storedValue;
372
+ }
373
+ function useSessionStorage(key, options = {}) {
374
+ const { defaultValue = null, serializer } = options;
375
+ const read = () => {
376
+ try {
377
+ const item = sessionStorage.getItem(key);
378
+ if (item === null) return defaultValue;
379
+ return serializer ? serializer.read(item) : JSON.parse(item);
380
+ } catch {
381
+ return defaultValue;
382
+ }
383
+ };
384
+ const write = (value) => {
385
+ try {
386
+ if (value === null) {
387
+ sessionStorage.removeItem(key);
388
+ } else {
389
+ const serialized = serializer ? serializer.write(value) : JSON.stringify(value);
390
+ sessionStorage.setItem(key, serialized);
391
+ }
392
+ } catch {
393
+ }
394
+ };
395
+ const storedValue = vue.ref(read());
396
+ vue.watch(
397
+ storedValue,
398
+ (newVal) => {
399
+ write(newVal);
400
+ },
401
+ { deep: true }
402
+ );
403
+ return storedValue;
404
+ }
405
+ function useAsync(promiseFn) {
406
+ const data = vue.ref(null);
407
+ const error = vue.ref(null);
408
+ const loading = vue.ref(false);
409
+ const execute = async (...args) => {
410
+ loading.value = true;
411
+ error.value = null;
412
+ try {
413
+ const result = await promiseFn(...args);
414
+ data.value = result;
415
+ return result;
416
+ } catch (e) {
417
+ error.value = e;
418
+ throw e;
419
+ } finally {
420
+ loading.value = false;
421
+ }
422
+ };
423
+ return {
424
+ data,
425
+ error,
426
+ loading,
427
+ execute
428
+ };
429
+ }
430
+ function useFetch(url, options = {}) {
431
+ const { immediate = true, ...fetchOptions } = options;
432
+ const data = vue.ref(null);
433
+ const error = vue.ref(null);
434
+ const loading = vue.ref(false);
435
+ const execute = async () => {
436
+ const requestUrl = typeof url === "string" ? url : url.value;
437
+ loading.value = true;
438
+ error.value = null;
439
+ try {
440
+ const response = await fetch(requestUrl, fetchOptions);
441
+ if (!response.ok) {
442
+ throw new Error(`HTTP error! status: ${response.status}`);
443
+ }
444
+ const result = await response.json();
445
+ data.value = result;
446
+ } catch (e) {
447
+ error.value = e;
448
+ } finally {
449
+ loading.value = false;
450
+ }
451
+ };
452
+ const refresh = () => execute();
453
+ if (immediate) {
454
+ execute();
455
+ }
456
+ return {
457
+ data,
458
+ error,
459
+ loading,
460
+ execute,
461
+ refresh
462
+ };
463
+ }
464
+ function useLoading(defaultLoading = false) {
465
+ const loading = vue.ref(defaultLoading);
466
+ const startLoading = () => {
467
+ loading.value = true;
468
+ };
469
+ const stopLoading = () => {
470
+ loading.value = false;
471
+ };
472
+ const withLoading = async (fn) => {
473
+ startLoading();
474
+ try {
475
+ const result = await fn();
476
+ return result;
477
+ } finally {
478
+ stopLoading();
479
+ }
480
+ };
481
+ return {
482
+ loading,
483
+ withLoading,
484
+ startLoading,
485
+ stopLoading
486
+ };
487
+ }
488
+ function useClipboard() {
489
+ const text = vue.ref("");
490
+ const isSupported = typeof navigator !== "undefined" && "clipboard" in navigator;
491
+ const copy = async (value) => {
492
+ if (!isSupported) {
493
+ console.warn("Clipboard API not supported");
494
+ return false;
495
+ }
496
+ try {
497
+ await navigator.clipboard.writeText(value);
498
+ text.value = value;
499
+ return true;
500
+ } catch (err) {
501
+ console.error("Failed to copy:", err);
502
+ return false;
503
+ }
504
+ };
505
+ return {
506
+ text,
507
+ isSupported,
508
+ copy
509
+ };
510
+ }
511
+ function usePermission(permission) {
512
+ const state = vue.ref(void 0);
513
+ const isSupported = typeof navigator !== "undefined" && "permissions" in navigator;
514
+ if (isSupported) {
515
+ navigator.permissions.query({ name: permission }).then((result) => {
516
+ state.value = result.state;
517
+ result.addEventListener("change", () => {
518
+ state.value = result.state;
519
+ });
520
+ }).catch(() => {
521
+ state.value = "prompt";
522
+ });
523
+ }
524
+ return {
525
+ state,
526
+ isSupported
527
+ };
528
+ }
529
+ function useMediaQuery(query) {
530
+ const matches = vue.ref(false);
531
+ let mediaQuery = null;
532
+ const updateMatch = () => {
533
+ if (mediaQuery) {
534
+ matches.value = mediaQuery.matches;
535
+ }
536
+ };
537
+ vue.onMounted(() => {
538
+ mediaQuery = window.matchMedia(query);
539
+ updateMatch();
540
+ if (mediaQuery.addEventListener) {
541
+ mediaQuery.addEventListener("change", updateMatch);
542
+ } else {
543
+ mediaQuery.addListener(updateMatch);
544
+ }
545
+ });
546
+ vue.onUnmounted(() => {
547
+ if (mediaQuery) {
548
+ if (mediaQuery.removeEventListener) {
549
+ mediaQuery.removeEventListener("change", updateMatch);
550
+ } else {
551
+ mediaQuery.removeListener(updateMatch);
552
+ }
553
+ }
554
+ });
555
+ return {
556
+ matches
557
+ };
558
+ }
559
+ exports.useAsync = useAsync;
560
+ exports.useBoolean = useBoolean;
561
+ exports.useClickOutside = useClickOutside;
562
+ exports.useClipboard = useClipboard;
563
+ exports.useCounter = useCounter;
564
+ exports.useDebounce = useDebounce;
565
+ exports.useFetch = useFetch;
566
+ exports.useFullscreen = useFullscreen;
567
+ exports.useInterval = useInterval;
568
+ exports.useLoading = useLoading;
569
+ exports.useLocalStorage = useLocalStorage;
570
+ exports.useMediaQuery = useMediaQuery;
571
+ exports.usePermission = usePermission;
572
+ exports.useResize = useResize;
573
+ exports.useScroll = useScroll;
574
+ exports.useSessionStorage = useSessionStorage;
575
+ exports.useSetState = useSetState;
576
+ exports.useThrottle = useThrottle;
577
+ exports.useTimeout = useTimeout;
578
+ exports.useToggle = useToggle;