vueless 1.2.10-beta.3 → 1.2.10-beta.5
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/composables/useRequestQueue.ts +47 -0
- package/index.d.ts +2 -2
- package/index.ts +2 -1
- package/package.json +1 -1
- package/ui.button/UButton.vue +2 -6
- package/ui.button/config.ts +5 -0
- package/ui.button/tests/UButton.test.ts +1 -1
- package/ui.form-calendar/tests/UCalendar.test.ts +4 -4
- package/ui.form-calendar/utilCalendar.ts +2 -2
- package/ui.loader-overlay/useLoaderOverlay.ts +4 -4
- package/ui.loader-progress/ULoaderProgress.vue +39 -42
- package/ui.loader-progress/storybook/stories.ts +0 -8
- package/ui.loader-progress/types.ts +2 -2
- package/ui.loader-progress/useLoaderProgress.ts +19 -27
- package/ui.loader-progress/utilLoaderProgress.ts +12 -18
- package/utils/requestQueue.ts +21 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { readonly, ref } from "vue";
|
|
2
|
+
|
|
3
|
+
import type { Ref } from "vue";
|
|
4
|
+
|
|
5
|
+
import { getRequestWithoutQuery } from "../utils/requestQueue";
|
|
6
|
+
|
|
7
|
+
const requestQueue = ref<string[]>([]);
|
|
8
|
+
|
|
9
|
+
function addToRequestQueue(url: string | string[]): void {
|
|
10
|
+
Array.isArray(url)
|
|
11
|
+
? requestQueue.value.push(...url.map(getRequestWithoutQuery))
|
|
12
|
+
: requestQueue.value.push(getRequestWithoutQuery(url));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function removeFromRequestQueue(url: string | string[]): void {
|
|
16
|
+
if (Array.isArray(url)) {
|
|
17
|
+
url.map(getRequestWithoutQuery).forEach(removeFromRequestQueue);
|
|
18
|
+
} else {
|
|
19
|
+
requestQueue.value = requestQueue.value.filter((item) => item !== getRequestWithoutQuery(url));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function isLoading(request: string | string[]): boolean {
|
|
24
|
+
return Array.isArray(request)
|
|
25
|
+
? request.some((url) => requestQueue.value.some((item: string) => item === url))
|
|
26
|
+
: requestQueue.value.some((item: string) => item === request);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function onAddToRequestQueue(event: CustomEvent<{ request: string }>) {
|
|
30
|
+
addToRequestQueue(event.detail.request);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function onRemoveFromRequestQueue(event: CustomEvent<{ request: string }>) {
|
|
34
|
+
removeFromRequestQueue(event.detail.request);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
window.addEventListener("addToRequestQueue", onAddToRequestQueue as EventListener);
|
|
38
|
+
window.addEventListener("removeFromRequestQueue", onRemoveFromRequestQueue as EventListener);
|
|
39
|
+
|
|
40
|
+
export function useRequestQueue() {
|
|
41
|
+
return {
|
|
42
|
+
isLoading,
|
|
43
|
+
addToRequestQueue,
|
|
44
|
+
removeFromRequestQueue,
|
|
45
|
+
requestQueue: readonly(requestQueue) as Readonly<Ref<readonly string[]>>,
|
|
46
|
+
};
|
|
47
|
+
}
|
package/index.d.ts
CHANGED
|
@@ -27,13 +27,13 @@ export { createVueI18nAdapter } from "./adapter.locale/vue-i18n";
|
|
|
27
27
|
export { useLocale } from "./composables/useLocale";
|
|
28
28
|
export { default as useUI } from "./composables/useUI";
|
|
29
29
|
export { useDarkMode } from "./composables/useDarkMode";
|
|
30
|
-
export {
|
|
30
|
+
export { useRequestQueue } from "./composables/useRequestQueue";
|
|
31
|
+
export { useLoaderOverlay } from "./ui.loader-overlay/useLoaderOverlay";
|
|
31
32
|
export { useMutationObserver } from "./composables/useMutationObserver";
|
|
32
33
|
export { Direction, useAutoPosition } from "./composables/useAutoPosition";
|
|
33
34
|
export { useComponentLocaleMessages } from "./composables/useComponentLocaleMassages";
|
|
34
35
|
/* loaders */
|
|
35
36
|
export { loaderProgressOn, loaderProgressOff } from "./ui.loader-progress/utilLoaderProgress";
|
|
36
|
-
export { useLoaderOverlay } from "./ui.loader-overlay/useLoaderOverlay";
|
|
37
37
|
export { loaderOverlayOn, loaderOverlayOff } from "./ui.loader-overlay/utilLoaderOverlay";
|
|
38
38
|
/* notifications */
|
|
39
39
|
export {
|
package/index.ts
CHANGED
|
@@ -33,13 +33,14 @@ export { createVueI18nAdapter } from "./adapter.locale/vue-i18n";
|
|
|
33
33
|
export { useLocale } from "./composables/useLocale";
|
|
34
34
|
export { default as useUI } from "./composables/useUI";
|
|
35
35
|
export { useDarkMode } from "./composables/useDarkMode";
|
|
36
|
+
export { useRequestQueue } from "./composables/useRequestQueue";
|
|
37
|
+
export { useLoaderOverlay } from "./ui.loader-overlay/useLoaderOverlay";
|
|
36
38
|
export { useLoaderProgress } from "./ui.loader-progress/useLoaderProgress";
|
|
37
39
|
export { useMutationObserver } from "./composables/useMutationObserver";
|
|
38
40
|
export { Direction, useAutoPosition } from "./composables/useAutoPosition";
|
|
39
41
|
export { useComponentLocaleMessages } from "./composables/useComponentLocaleMassages";
|
|
40
42
|
/* loaders */
|
|
41
43
|
export { loaderProgressOn, loaderProgressOff } from "./ui.loader-progress/utilLoaderProgress";
|
|
42
|
-
export { useLoaderOverlay } from "./ui.loader-overlay/useLoaderOverlay";
|
|
43
44
|
export { loaderOverlayOn, loaderOverlayOff } from "./ui.loader-overlay/utilLoaderOverlay";
|
|
44
45
|
/* notifications */
|
|
45
46
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vueless",
|
|
3
|
-
"version": "1.2.10-beta.
|
|
3
|
+
"version": "1.2.10-beta.5",
|
|
4
4
|
"description": "Vue Styleless UI Component Library, powered by Tailwind CSS.",
|
|
5
5
|
"author": "Johnny Grid <hello@vueless.com> (https://vueless.com)",
|
|
6
6
|
"homepage": "https://vueless.com",
|
package/ui.button/UButton.vue
CHANGED
|
@@ -62,6 +62,7 @@ defineExpose({
|
|
|
62
62
|
* Applies: `class`, `config`, redefined default `props` and dev `vl-...` attributes.
|
|
63
63
|
*/
|
|
64
64
|
const mutatedProps = computed(() => ({
|
|
65
|
+
icon: Boolean(props.icon) || hasSlotContent(slots["default"]),
|
|
65
66
|
leftIcon: Boolean(props.leftIcon) || hasSlotContent(slots["left"]),
|
|
66
67
|
rightIcon: Boolean(props.rightIcon) || hasSlotContent(slots["right"]),
|
|
67
68
|
label: Boolean(props.label),
|
|
@@ -129,11 +130,6 @@ const {
|
|
|
129
130
|
</template>
|
|
130
131
|
|
|
131
132
|
<!-- This is needed to prevent changing button height -->
|
|
132
|
-
<div
|
|
133
|
-
v-if="(!label && !hasSlotContent(slots['default']) && !icon) || loading"
|
|
134
|
-
tabindex="-1"
|
|
135
|
-
v-bind="invisibleAttrs"
|
|
136
|
-
v-text="'invisible'"
|
|
137
|
-
/>
|
|
133
|
+
<div v-if="icon || loading" tabindex="-1" v-bind="invisibleAttrs" v-text="'invisible'" />
|
|
138
134
|
</component>
|
|
139
135
|
</template>
|
package/ui.button/config.ts
CHANGED
|
@@ -54,6 +54,9 @@ export default /*tw*/ {
|
|
|
54
54
|
loading: {
|
|
55
55
|
true: "gap-0 pointer-events-none",
|
|
56
56
|
},
|
|
57
|
+
icon: {
|
|
58
|
+
true: "gap-0",
|
|
59
|
+
},
|
|
57
60
|
label: {
|
|
58
61
|
false: "gap-0",
|
|
59
62
|
},
|
|
@@ -62,6 +65,8 @@ export default /*tw*/ {
|
|
|
62
65
|
},
|
|
63
66
|
},
|
|
64
67
|
compoundVariants: [
|
|
68
|
+
{ label: false, leftIcon: true, class: "gap-0" },
|
|
69
|
+
{ label: false, rightIcon: true, class: "gap-0" },
|
|
65
70
|
{ square: true, size: "2xs", class: "p-1" },
|
|
66
71
|
{ square: true, size: "xs", class: "p-1.5" },
|
|
67
72
|
{ square: true, size: "sm", class: "p-2" },
|
|
@@ -115,7 +115,7 @@ describe("UButton.vue", () => {
|
|
|
115
115
|
|
|
116
116
|
const nestedUIconComponents = component.findAllComponents(UIcon);
|
|
117
117
|
|
|
118
|
-
expect(component.text()).toBe(
|
|
118
|
+
expect(component.text()).not.toBe(label);
|
|
119
119
|
expect(nestedUIconComponents.length).toBe(1);
|
|
120
120
|
expect(nestedUIconComponents[0].props("name")).toBe(icon);
|
|
121
121
|
});
|
|
@@ -375,7 +375,7 @@ describe("UCalendar.vue", () => {
|
|
|
375
375
|
},
|
|
376
376
|
});
|
|
377
377
|
|
|
378
|
-
const nextPrevButtons = component.findAll('[vl-key="nextPrevButton"]');
|
|
378
|
+
const nextPrevButtons = component.findAll('button[vl-key="nextPrevButton"]');
|
|
379
379
|
|
|
380
380
|
expect(nextPrevButtons.length).toBe(4);
|
|
381
381
|
});
|
|
@@ -391,7 +391,7 @@ describe("UCalendar.vue", () => {
|
|
|
391
391
|
},
|
|
392
392
|
});
|
|
393
393
|
|
|
394
|
-
const nextPrevButtons = component.findAll('[vl-key="nextPrevButton"]');
|
|
394
|
+
const nextPrevButtons = component.findAll('button[vl-key="nextPrevButton"]');
|
|
395
395
|
|
|
396
396
|
expect(nextPrevButtons.length).toBe(2);
|
|
397
397
|
});
|
|
@@ -422,7 +422,7 @@ describe("UCalendar.vue", () => {
|
|
|
422
422
|
|
|
423
423
|
const dayView = component.findComponent(DayView);
|
|
424
424
|
const initialDays = dayView.findAll('[vl-key="day"]').map((day) => day.text());
|
|
425
|
-
const navButtons = component.findAll('[vl-key="nextPrevButton"]');
|
|
425
|
+
const navButtons = component.findAll('button[vl-key="nextPrevButton"]');
|
|
426
426
|
|
|
427
427
|
expect(navButtons.length).toBe(4);
|
|
428
428
|
|
|
@@ -446,7 +446,7 @@ describe("UCalendar.vue", () => {
|
|
|
446
446
|
|
|
447
447
|
const dayView = component.findComponent(DayView);
|
|
448
448
|
const initialDays = dayView.findAll('[vl-key="day"]').map((day) => day.text());
|
|
449
|
-
const navButtons = component.findAll('[vl-key="nextPrevButton"]');
|
|
449
|
+
const navButtons = component.findAll('button[vl-key="nextPrevButton"]');
|
|
450
450
|
const nextButton = navButtons[2];
|
|
451
451
|
|
|
452
452
|
await nextButton.trigger("click");
|
|
@@ -86,7 +86,7 @@ export function parseDate<TLocale extends DateLocale>(
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
if (!(parsedDate instanceof Date && !isNaN(parsedDate.getTime()))) {
|
|
89
|
-
throw new Error(`Invalid date provided: ${originalDate}`);
|
|
89
|
+
throw new Error(`[vueless] Invalid date provided: ${originalDate}`);
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
if (timeless === true) {
|
|
@@ -158,7 +158,7 @@ export function dateIsOutOfRange<TLocale extends DateLocale>(
|
|
|
158
158
|
dateFormat: string | null = null,
|
|
159
159
|
) {
|
|
160
160
|
if ((!dateFormat && typeof min === "string") || (!dateFormat && typeof max === "string")) {
|
|
161
|
-
throw new Error("strings needs a date format");
|
|
161
|
+
throw new Error("[vueless] strings needs a date format.");
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
const minDate =
|
|
@@ -2,15 +2,15 @@ import { inject, readonly, ref } from "vue";
|
|
|
2
2
|
|
|
3
3
|
import type { Ref, InjectionKey } from "vue";
|
|
4
4
|
|
|
5
|
-
export const LoaderOverlaySymbol: InjectionKey<LoaderOverlay> =
|
|
6
|
-
Symbol.for("vueless:loader-overlay");
|
|
7
|
-
|
|
8
5
|
interface LoaderOverlay {
|
|
9
6
|
isLoading: Readonly<Ref<boolean, boolean>>;
|
|
10
7
|
loaderOverlayOn: () => void;
|
|
11
8
|
loaderOverlayOff: () => void;
|
|
12
9
|
}
|
|
13
10
|
|
|
11
|
+
export const LoaderOverlaySymbol: InjectionKey<LoaderOverlay> =
|
|
12
|
+
Symbol.for("vueless:loader-overlay");
|
|
13
|
+
|
|
14
14
|
const isLoading = ref(true);
|
|
15
15
|
|
|
16
16
|
function loaderOverlayOn(): void {
|
|
@@ -34,7 +34,7 @@ export function useLoaderOverlay(): LoaderOverlay {
|
|
|
34
34
|
|
|
35
35
|
if (!loaderOverlay) {
|
|
36
36
|
throw new Error(
|
|
37
|
-
"LoaderOverlay not provided. Ensure you are using `provide` with `LoaderOverlaySymbol`.",
|
|
37
|
+
"[vueless] LoaderOverlay not provided. Ensure you are using `provide` with `LoaderOverlaySymbol`.",
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -3,9 +3,11 @@ import { computed, watch, ref, useTemplateRef, onBeforeMount, onBeforeUnmount }
|
|
|
3
3
|
|
|
4
4
|
import useUI from "../composables/useUI";
|
|
5
5
|
import { getDefaults } from "../utils/ui";
|
|
6
|
+
import { useRequestQueue } from "../composables/useRequestQueue";
|
|
7
|
+
import { getRequestWithoutQuery } from "../utils/requestQueue";
|
|
6
8
|
|
|
7
|
-
import { clamp, queue, getRequestWithoutQuery } from "./utilLoaderProgress";
|
|
8
9
|
import { useLoaderProgress } from "./useLoaderProgress";
|
|
10
|
+
import { clamp, queue } from "./utilLoaderProgress";
|
|
9
11
|
|
|
10
12
|
import { COMPONENT_NAME, MAXIMUM, SPEED } from "./constants";
|
|
11
13
|
import defaultConfig from "./config";
|
|
@@ -25,46 +27,10 @@ const progress = ref(0);
|
|
|
25
27
|
const opacity = ref(1);
|
|
26
28
|
const status = ref<number | null>(null);
|
|
27
29
|
|
|
30
|
+
const { requestQueue } = useRequestQueue();
|
|
31
|
+
const { loaderProgressOff, loaderProgressOn } = useLoaderProgress();
|
|
28
32
|
const progressRef = useTemplateRef<HTMLDivElement>("progress-bar");
|
|
29
33
|
|
|
30
|
-
const { requestQueue, loaderProgressOff, loaderProgressOn } = useLoaderProgress();
|
|
31
|
-
|
|
32
|
-
onBeforeMount(() => {
|
|
33
|
-
if (window.__VuelessProgressLoaderInstance === undefined) {
|
|
34
|
-
window.__VuelessProgressLoaderInstance = 0;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (!window.__VuelessProgressLoaderInstance) {
|
|
38
|
-
window.addEventListener("loaderProgressOn", onLoaderProgressOn as EventListener);
|
|
39
|
-
window.addEventListener("loaderProgressOff", onLoaderProgressOff as EventListener);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
window.__VuelessProgressLoaderInstance += 1;
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
onBeforeUnmount(() => {
|
|
46
|
-
if (window.__VuelessProgressLoaderInstance === undefined) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
window.__VuelessProgressLoaderInstance -= 1;
|
|
51
|
-
|
|
52
|
-
if (!window.__VuelessProgressLoaderInstance) {
|
|
53
|
-
delete window.__VuelessProgressLoaderInstance;
|
|
54
|
-
|
|
55
|
-
window.removeEventListener("loaderProgressOn", onLoaderProgressOn as EventListener);
|
|
56
|
-
window.removeEventListener("loaderProgressOff", onLoaderProgressOff as EventListener);
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
function onLoaderProgressOn(event: CustomEvent<{ resource: string }>) {
|
|
61
|
-
loaderProgressOn(event.detail.resource);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function onLoaderProgressOff(event: CustomEvent<{ resource: string }>) {
|
|
65
|
-
loaderProgressOff(event.detail.resource);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
34
|
const isLoading = computed(() => {
|
|
69
35
|
return typeof status.value === "number";
|
|
70
36
|
});
|
|
@@ -151,12 +117,10 @@ function start() {
|
|
|
151
117
|
}
|
|
152
118
|
|
|
153
119
|
function set(amount: number) {
|
|
154
|
-
let currentProgress;
|
|
120
|
+
let currentProgress = 0;
|
|
155
121
|
|
|
156
122
|
if (isLoading.value) {
|
|
157
123
|
currentProgress = amount < progress.value ? clamp(amount, 0, 100) : clamp(amount, 0.8, 100);
|
|
158
|
-
} else {
|
|
159
|
-
currentProgress = 0;
|
|
160
124
|
}
|
|
161
125
|
|
|
162
126
|
status.value = currentProgress === 100 ? null : currentProgress;
|
|
@@ -205,6 +169,39 @@ function stop() {
|
|
|
205
169
|
set(100);
|
|
206
170
|
}
|
|
207
171
|
|
|
172
|
+
function onLoaderProgressOn(event: CustomEvent<{ request: string }>) {
|
|
173
|
+
loaderProgressOn(event.detail.request);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function onLoaderProgressOff(event: CustomEvent<{ request: string }>) {
|
|
177
|
+
loaderProgressOff(event.detail.request);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
onBeforeMount(() => {
|
|
181
|
+
if (!window.__VuelessLoaderProgressInstanceCount) {
|
|
182
|
+
window.addEventListener("loaderProgressOn", onLoaderProgressOn as EventListener);
|
|
183
|
+
window.addEventListener("loaderProgressOff", onLoaderProgressOff as EventListener);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
window.__VuelessLoaderProgressInstanceCount = window.__VuelessLoaderProgressInstanceCount ?? 0;
|
|
187
|
+
window.__VuelessLoaderProgressInstanceCount += 1;
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
onBeforeUnmount(() => {
|
|
191
|
+
if (window.__VuelessLoaderProgressInstanceCount === undefined) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
window.__VuelessLoaderProgressInstanceCount -= 1;
|
|
196
|
+
|
|
197
|
+
if (!window.__VuelessLoaderProgressInstanceCount) {
|
|
198
|
+
delete window.__VuelessLoaderProgressInstanceCount;
|
|
199
|
+
|
|
200
|
+
window.removeEventListener("loaderProgressOn", onLoaderProgressOn as EventListener);
|
|
201
|
+
window.removeEventListener("loaderProgressOff", onLoaderProgressOff as EventListener);
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
208
205
|
defineExpose({
|
|
209
206
|
/**
|
|
210
207
|
* Start loading animation.
|
|
@@ -6,7 +6,6 @@ import UButton from "../../ui.button/UButton.vue";
|
|
|
6
6
|
import URow from "../../ui.container-row/URow.vue";
|
|
7
7
|
import UCol from "../../ui.container-col/UCol.vue";
|
|
8
8
|
|
|
9
|
-
import { useLoaderProgress } from "../useLoaderProgress";
|
|
10
9
|
import { loaderProgressOff, loaderProgressOn } from "../utilLoaderProgress";
|
|
11
10
|
|
|
12
11
|
import type { Meta, StoryFn } from "@storybook/vue3-vite";
|
|
@@ -34,13 +33,6 @@ export default {
|
|
|
34
33
|
const DefaultTemplate: StoryFn<ULoaderProgressArgs> = (args: ULoaderProgressArgs) => ({
|
|
35
34
|
components: { ULoaderProgress, UButton, URow },
|
|
36
35
|
setup() {
|
|
37
|
-
const loaderProgress = useLoaderProgress();
|
|
38
|
-
|
|
39
|
-
if (!loaderProgress) {
|
|
40
|
-
throw new Error("LoaderProgress is not provided. Ensure it is properly injected.");
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const { loaderProgressOn, loaderProgressOff } = loaderProgress;
|
|
44
36
|
const slots = getSlotNames(ULoaderProgress.__name);
|
|
45
37
|
|
|
46
38
|
return { args, slots, loaderProgressOn, loaderProgressOff };
|
|
@@ -3,7 +3,7 @@ import type { ComponentConfig } from "../types";
|
|
|
3
3
|
|
|
4
4
|
declare global {
|
|
5
5
|
interface Window {
|
|
6
|
-
|
|
6
|
+
__VuelessLoaderProgressInstanceCount?: number;
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -27,7 +27,7 @@ export interface Props {
|
|
|
27
27
|
/**
|
|
28
28
|
* API resource names (endpoint URIs).
|
|
29
29
|
*/
|
|
30
|
-
resources?: string | string[] | "any"
|
|
30
|
+
resources?: string | string[] | "any";
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Loader progress size.
|
|
@@ -2,39 +2,31 @@ import { inject, readonly, ref } from "vue";
|
|
|
2
2
|
|
|
3
3
|
import type { Ref } from "vue";
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
export const LoaderProgressSymbol = Symbol.for("vueless:loader-progress");
|
|
5
|
+
import { useRequestQueue } from "../composables/useRequestQueue";
|
|
8
6
|
|
|
9
7
|
type LoaderProgress = {
|
|
10
|
-
|
|
11
|
-
loaderProgressOn: (
|
|
12
|
-
loaderProgressOff: (
|
|
8
|
+
isLoading: Readonly<Ref<boolean, boolean>>;
|
|
9
|
+
loaderProgressOn: (request: string | string[]) => void;
|
|
10
|
+
loaderProgressOff: (request: string | string[]) => void;
|
|
13
11
|
};
|
|
14
12
|
|
|
15
|
-
export
|
|
16
|
-
const requestQueue = ref<string[]>([]);
|
|
17
|
-
|
|
18
|
-
function loaderProgressOn(url: string | string[]): void {
|
|
19
|
-
if (Array.isArray(url)) {
|
|
20
|
-
requestQueue.value.push(...url.map(getRequestWithoutQuery));
|
|
21
|
-
} else {
|
|
22
|
-
requestQueue.value.push(getRequestWithoutQuery(url));
|
|
23
|
-
}
|
|
24
|
-
}
|
|
13
|
+
export const LoaderProgressSymbol = Symbol.for("vueless:loader-progress");
|
|
25
14
|
|
|
26
|
-
|
|
27
|
-
if (Array.isArray(url)) {
|
|
28
|
-
url.map(getRequestWithoutQuery).forEach(loaderProgressOff);
|
|
29
|
-
} else {
|
|
30
|
-
requestQueue.value = requestQueue.value.filter(
|
|
31
|
-
(item) => item !== getRequestWithoutQuery(url),
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
15
|
+
const { addToRequestQueue, removeFromRequestQueue } = useRequestQueue();
|
|
35
16
|
|
|
17
|
+
const isLoading = ref(true);
|
|
18
|
+
|
|
19
|
+
function loaderProgressOn(request?: string | string[]): void {
|
|
20
|
+
request ? addToRequestQueue(request) : (isLoading.value = true);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function loaderProgressOff(request?: string | string[]): void {
|
|
24
|
+
request ? removeFromRequestQueue(request) : (isLoading.value = false);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function createLoaderProgress(): LoaderProgress {
|
|
36
28
|
return {
|
|
37
|
-
|
|
29
|
+
isLoading: readonly(isLoading),
|
|
38
30
|
loaderProgressOn,
|
|
39
31
|
loaderProgressOff,
|
|
40
32
|
};
|
|
@@ -45,7 +37,7 @@ export function useLoaderProgress(): LoaderProgress {
|
|
|
45
37
|
|
|
46
38
|
if (!loaderProgress) {
|
|
47
39
|
throw new Error(
|
|
48
|
-
"LoaderProgress not provided. Ensure you are using `provide` with `LoaderProgressSymbol`.",
|
|
40
|
+
"[vueless] LoaderProgress not provided. Ensure you are using `provide` with `LoaderProgressSymbol`.",
|
|
49
41
|
);
|
|
50
42
|
}
|
|
51
43
|
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
export function loaderProgressOn(request: string | string[]): void {
|
|
2
|
+
const loaderProgressOnEvent = new CustomEvent("loaderProgressOn", { detail: { request } });
|
|
3
|
+
|
|
4
|
+
window.dispatchEvent(loaderProgressOnEvent);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function loaderProgressOff(request: string | string[]): void {
|
|
8
|
+
const loaderProgressOffEvent = new CustomEvent("loaderProgressOff", { detail: { request } });
|
|
9
|
+
|
|
10
|
+
window.dispatchEvent(loaderProgressOffEvent);
|
|
11
|
+
}
|
|
12
|
+
|
|
1
13
|
export function clamp(n: number, min: number, max: number): number {
|
|
2
14
|
if (n < min) {
|
|
3
15
|
return min;
|
|
@@ -29,21 +41,3 @@ export const queue = (() => {
|
|
|
29
41
|
}
|
|
30
42
|
};
|
|
31
43
|
})();
|
|
32
|
-
|
|
33
|
-
export function loaderProgressOn(resource: string): void {
|
|
34
|
-
const loaderProgressOnEvent = new CustomEvent("loaderProgressOn", { detail: { resource } });
|
|
35
|
-
|
|
36
|
-
window.dispatchEvent(loaderProgressOnEvent);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function loaderProgressOff(resource: string): void {
|
|
40
|
-
const loaderProgressOffEvent = new CustomEvent("loaderProgressOff", { detail: { resource } });
|
|
41
|
-
|
|
42
|
-
window.dispatchEvent(loaderProgressOffEvent);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function getRequestWithoutQuery(request: string | URL): string {
|
|
46
|
-
const [requestWithoutQuery] = String(request).split("?");
|
|
47
|
-
|
|
48
|
-
return requestWithoutQuery;
|
|
49
|
-
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function getRequestWithoutQuery(request: string | URL): string {
|
|
2
|
+
const [requestWithoutQuery] = String(request).split("?");
|
|
3
|
+
|
|
4
|
+
return requestWithoutQuery;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function addToRequestQueue(request: string | string[]): void {
|
|
8
|
+
const addToRequestQueueEvent = new CustomEvent("addToRequestQueue", {
|
|
9
|
+
detail: { request },
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
window.dispatchEvent(addToRequestQueueEvent);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function removeFromRequestQueue(request: string | string[]): void {
|
|
16
|
+
const removeFromRequestQueueEvent = new CustomEvent("removeFromRequestQueue", {
|
|
17
|
+
detail: { request },
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
window.dispatchEvent(removeFromRequestQueueEvent);
|
|
21
|
+
}
|