@ametie/vue-muza-use 0.2.0 → 0.3.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/dist/index.cjs +60 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.mjs +60 -0
- package/package.json +5 -1
package/dist/index.cjs
CHANGED
|
@@ -198,13 +198,27 @@ function useApi(url, options = {}) {
|
|
|
198
198
|
authMode = "default",
|
|
199
199
|
useGlobalAbort = globalOptions?.useGlobalAbort ?? true,
|
|
200
200
|
initialLoading = false,
|
|
201
|
+
poll = 0,
|
|
201
202
|
...axiosConfig
|
|
202
203
|
} = options;
|
|
203
204
|
const startLoading = initialLoading ?? immediate;
|
|
204
205
|
const state = useApiState(initialData, { initialLoading: startLoading });
|
|
205
206
|
const abortController2 = (0, import_vue4.ref)(null);
|
|
206
207
|
const globalAbort = useGlobalAbort ? useAbortController() : null;
|
|
208
|
+
let pollTimer = null;
|
|
209
|
+
const getPollConfig = () => {
|
|
210
|
+
const val = (0, import_vue4.toValue)(poll);
|
|
211
|
+
if (typeof val === "number") return { interval: val, whenHidden: false };
|
|
212
|
+
if (val && typeof val === "object") {
|
|
213
|
+
return {
|
|
214
|
+
interval: (0, import_vue4.toValue)(val.interval),
|
|
215
|
+
whenHidden: (0, import_vue4.toValue)(val.whenHidden) ?? false
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
return { interval: 0, whenHidden: false };
|
|
219
|
+
};
|
|
207
220
|
const executeRequest = async (config) => {
|
|
221
|
+
if (pollTimer) clearTimeout(pollTimer);
|
|
208
222
|
const requestUrl = typeof url === "string" ? url : url.value;
|
|
209
223
|
if (abortController2.value) abortController2.value.abort("Cancelled by new request");
|
|
210
224
|
const controller = new AbortController();
|
|
@@ -260,11 +274,25 @@ function useApi(url, options = {}) {
|
|
|
260
274
|
if (!wasCancelled) {
|
|
261
275
|
state.setLoading(false);
|
|
262
276
|
onFinish?.();
|
|
277
|
+
const { interval, whenHidden } = getPollConfig();
|
|
278
|
+
if (interval > 0) {
|
|
279
|
+
const shouldPoll = whenHidden || typeof document !== "undefined" && !document.hidden;
|
|
280
|
+
if (shouldPoll) {
|
|
281
|
+
pollTimer = setTimeout(() => {
|
|
282
|
+
pollTimer = null;
|
|
283
|
+
const { whenHidden: currentWhenHidden } = getPollConfig();
|
|
284
|
+
if (currentWhenHidden || (typeof document === "undefined" || !document.hidden)) {
|
|
285
|
+
execute();
|
|
286
|
+
}
|
|
287
|
+
}, interval);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
263
290
|
}
|
|
264
291
|
}
|
|
265
292
|
};
|
|
266
293
|
const execute = debounce > 0 ? debounceFn(executeRequest, debounce) : executeRequest;
|
|
267
294
|
const abort = (msg) => {
|
|
295
|
+
if (pollTimer) clearTimeout(pollTimer);
|
|
268
296
|
abortController2.value?.abort(msg);
|
|
269
297
|
abortController2.value = null;
|
|
270
298
|
};
|
|
@@ -282,6 +310,38 @@ function useApi(url, options = {}) {
|
|
|
282
310
|
(0, import_vue4.onScopeDispose)(() => abort("Scope disposed"));
|
|
283
311
|
}
|
|
284
312
|
if (immediate) execute();
|
|
313
|
+
if (typeof document !== "undefined") {
|
|
314
|
+
const handleVisibility = () => {
|
|
315
|
+
if (document.hidden) return;
|
|
316
|
+
const { interval } = getPollConfig();
|
|
317
|
+
if (interval > 0 && !pollTimer && !state.loading.value) {
|
|
318
|
+
execute();
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
document.addEventListener("visibilitychange", handleVisibility);
|
|
322
|
+
if ((0, import_vue4.getCurrentScope)()) {
|
|
323
|
+
(0, import_vue4.onScopeDispose)(() => document.removeEventListener("visibilitychange", handleVisibility));
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (poll) {
|
|
327
|
+
(0, import_vue4.watch)(() => (0, import_vue4.toValue)(poll), () => {
|
|
328
|
+
const { interval } = getPollConfig();
|
|
329
|
+
if (interval > 0) {
|
|
330
|
+
if (pollTimer) {
|
|
331
|
+
clearTimeout(pollTimer);
|
|
332
|
+
pollTimer = null;
|
|
333
|
+
}
|
|
334
|
+
if (!state.loading.value) {
|
|
335
|
+
execute();
|
|
336
|
+
}
|
|
337
|
+
} else {
|
|
338
|
+
if (pollTimer) {
|
|
339
|
+
clearTimeout(pollTimer);
|
|
340
|
+
pollTimer = null;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}, { deep: true });
|
|
344
|
+
}
|
|
285
345
|
return { ...state, execute, abort, reset };
|
|
286
346
|
}
|
|
287
347
|
function useApiGet(url, options) {
|
package/dist/index.d.cts
CHANGED
|
@@ -34,6 +34,16 @@ interface UseApiOptions<T = unknown, D = unknown> extends ApiRequestConfig<D> {
|
|
|
34
34
|
useGlobalAbort?: boolean;
|
|
35
35
|
initialLoading?: boolean;
|
|
36
36
|
watch?: WatchSource | WatchSource[];
|
|
37
|
+
/**
|
|
38
|
+
* Polling configuration.
|
|
39
|
+
* - Pass a **number** (ms) for simple polling.
|
|
40
|
+
* - Pass an **object** `{ interval: number, whenHidden?: boolean }` for advanced control.
|
|
41
|
+
* Properties inside the object can also be Refs.
|
|
42
|
+
*/
|
|
43
|
+
poll?: MaybeRefOrGetter<number | {
|
|
44
|
+
interval: MaybeRefOrGetter<number>;
|
|
45
|
+
whenHidden?: MaybeRefOrGetter<boolean>;
|
|
46
|
+
}>;
|
|
37
47
|
}
|
|
38
48
|
interface UseApiReturn<T = unknown, D = unknown> {
|
|
39
49
|
data: Ref<T | null>;
|
package/dist/index.d.ts
CHANGED
|
@@ -34,6 +34,16 @@ interface UseApiOptions<T = unknown, D = unknown> extends ApiRequestConfig<D> {
|
|
|
34
34
|
useGlobalAbort?: boolean;
|
|
35
35
|
initialLoading?: boolean;
|
|
36
36
|
watch?: WatchSource | WatchSource[];
|
|
37
|
+
/**
|
|
38
|
+
* Polling configuration.
|
|
39
|
+
* - Pass a **number** (ms) for simple polling.
|
|
40
|
+
* - Pass an **object** `{ interval: number, whenHidden?: boolean }` for advanced control.
|
|
41
|
+
* Properties inside the object can also be Refs.
|
|
42
|
+
*/
|
|
43
|
+
poll?: MaybeRefOrGetter<number | {
|
|
44
|
+
interval: MaybeRefOrGetter<number>;
|
|
45
|
+
whenHidden?: MaybeRefOrGetter<boolean>;
|
|
46
|
+
}>;
|
|
37
47
|
}
|
|
38
48
|
interface UseApiReturn<T = unknown, D = unknown> {
|
|
39
49
|
data: Ref<T | null>;
|
package/dist/index.mjs
CHANGED
|
@@ -148,13 +148,27 @@ function useApi(url, options = {}) {
|
|
|
148
148
|
authMode = "default",
|
|
149
149
|
useGlobalAbort = globalOptions?.useGlobalAbort ?? true,
|
|
150
150
|
initialLoading = false,
|
|
151
|
+
poll = 0,
|
|
151
152
|
...axiosConfig
|
|
152
153
|
} = options;
|
|
153
154
|
const startLoading = initialLoading ?? immediate;
|
|
154
155
|
const state = useApiState(initialData, { initialLoading: startLoading });
|
|
155
156
|
const abortController2 = ref3(null);
|
|
156
157
|
const globalAbort = useGlobalAbort ? useAbortController() : null;
|
|
158
|
+
let pollTimer = null;
|
|
159
|
+
const getPollConfig = () => {
|
|
160
|
+
const val = toValue(poll);
|
|
161
|
+
if (typeof val === "number") return { interval: val, whenHidden: false };
|
|
162
|
+
if (val && typeof val === "object") {
|
|
163
|
+
return {
|
|
164
|
+
interval: toValue(val.interval),
|
|
165
|
+
whenHidden: toValue(val.whenHidden) ?? false
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
return { interval: 0, whenHidden: false };
|
|
169
|
+
};
|
|
157
170
|
const executeRequest = async (config) => {
|
|
171
|
+
if (pollTimer) clearTimeout(pollTimer);
|
|
158
172
|
const requestUrl = typeof url === "string" ? url : url.value;
|
|
159
173
|
if (abortController2.value) abortController2.value.abort("Cancelled by new request");
|
|
160
174
|
const controller = new AbortController();
|
|
@@ -210,11 +224,25 @@ function useApi(url, options = {}) {
|
|
|
210
224
|
if (!wasCancelled) {
|
|
211
225
|
state.setLoading(false);
|
|
212
226
|
onFinish?.();
|
|
227
|
+
const { interval, whenHidden } = getPollConfig();
|
|
228
|
+
if (interval > 0) {
|
|
229
|
+
const shouldPoll = whenHidden || typeof document !== "undefined" && !document.hidden;
|
|
230
|
+
if (shouldPoll) {
|
|
231
|
+
pollTimer = setTimeout(() => {
|
|
232
|
+
pollTimer = null;
|
|
233
|
+
const { whenHidden: currentWhenHidden } = getPollConfig();
|
|
234
|
+
if (currentWhenHidden || (typeof document === "undefined" || !document.hidden)) {
|
|
235
|
+
execute();
|
|
236
|
+
}
|
|
237
|
+
}, interval);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
213
240
|
}
|
|
214
241
|
}
|
|
215
242
|
};
|
|
216
243
|
const execute = debounce > 0 ? debounceFn(executeRequest, debounce) : executeRequest;
|
|
217
244
|
const abort = (msg) => {
|
|
245
|
+
if (pollTimer) clearTimeout(pollTimer);
|
|
218
246
|
abortController2.value?.abort(msg);
|
|
219
247
|
abortController2.value = null;
|
|
220
248
|
};
|
|
@@ -232,6 +260,38 @@ function useApi(url, options = {}) {
|
|
|
232
260
|
onScopeDispose(() => abort("Scope disposed"));
|
|
233
261
|
}
|
|
234
262
|
if (immediate) execute();
|
|
263
|
+
if (typeof document !== "undefined") {
|
|
264
|
+
const handleVisibility = () => {
|
|
265
|
+
if (document.hidden) return;
|
|
266
|
+
const { interval } = getPollConfig();
|
|
267
|
+
if (interval > 0 && !pollTimer && !state.loading.value) {
|
|
268
|
+
execute();
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
document.addEventListener("visibilitychange", handleVisibility);
|
|
272
|
+
if (getCurrentScope()) {
|
|
273
|
+
onScopeDispose(() => document.removeEventListener("visibilitychange", handleVisibility));
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (poll) {
|
|
277
|
+
watch(() => toValue(poll), () => {
|
|
278
|
+
const { interval } = getPollConfig();
|
|
279
|
+
if (interval > 0) {
|
|
280
|
+
if (pollTimer) {
|
|
281
|
+
clearTimeout(pollTimer);
|
|
282
|
+
pollTimer = null;
|
|
283
|
+
}
|
|
284
|
+
if (!state.loading.value) {
|
|
285
|
+
execute();
|
|
286
|
+
}
|
|
287
|
+
} else {
|
|
288
|
+
if (pollTimer) {
|
|
289
|
+
clearTimeout(pollTimer);
|
|
290
|
+
pollTimer = null;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}, { deep: true });
|
|
294
|
+
}
|
|
235
295
|
return { ...state, execute, abort, reset };
|
|
236
296
|
}
|
|
237
297
|
function useApiGet(url, options) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ametie/vue-muza-use",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Powerful Vue 3 API composable (Muza Kit) with Axios, Auto-Refresh & TypeScript",
|
|
5
5
|
"author": "MortyQ",
|
|
6
6
|
"license": "MIT",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"build": "tsup",
|
|
47
|
+
"test": "vitest",
|
|
47
48
|
"dev": "tsup --watch"
|
|
48
49
|
},
|
|
49
50
|
"peerDependencies": {
|
|
@@ -55,10 +56,13 @@
|
|
|
55
56
|
"@semantic-release/github": "^12.0.3",
|
|
56
57
|
"@semantic-release/npm": "^13.1.3",
|
|
57
58
|
"@types/node": "^24.10.10",
|
|
59
|
+
"@vue/test-utils": "^2.4.6",
|
|
58
60
|
"axios": "^1.13.4",
|
|
61
|
+
"happy-dom": "^20.5.0",
|
|
59
62
|
"semantic-release": "^25.0.3",
|
|
60
63
|
"tsup": "^8.5.1",
|
|
61
64
|
"typescript": "^5.9.3",
|
|
65
|
+
"vitest": "^4.0.18",
|
|
62
66
|
"vue": "^3.5.27"
|
|
63
67
|
}
|
|
64
68
|
}
|