vueless 0.0.725 → 0.0.726

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vueless",
3
- "version": "0.0.725",
3
+ "version": "0.0.726",
4
4
  "license": "MIT",
5
5
  "description": "Vue Styleless UI Component Library, powered by Tailwind CSS.",
6
6
  "keywords": [
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { computed, onBeforeUnmount, watch, ref, onMounted, onUnmounted } from "vue";
2
+ import { computed, watch, ref } from "vue";
3
3
 
4
4
  import useUI from "../composables/useUI.ts";
5
5
  import { getDefaults } from "../utils/ui.ts";
@@ -7,7 +7,7 @@ import { getDefaults } from "../utils/ui.ts";
7
7
  import { clamp, queue, getRequestWithoutQuery } from "./utilLoaderProgress.ts";
8
8
  import { useLoaderProgress } from "./useLoaderProgress.ts";
9
9
 
10
- import { COMPONENT_NAME, MAXIMUM, SPEED, INFINITY_LOADING } from "./constants.ts";
10
+ import { COMPONENT_NAME, MAXIMUM, SPEED } from "./constants.ts";
11
11
  import defaultConfig from "./config.ts";
12
12
 
13
13
  import type { Props, Config } from "./types.ts";
@@ -25,16 +25,9 @@ const progress = ref(0);
25
25
  const opacity = ref(1);
26
26
  const status = ref<number | null>(null);
27
27
 
28
- const {
29
- requestQueue,
30
- removeRequestUrl,
31
- isLoading,
32
- loaderProgressOff,
33
- loaderProgressOn,
34
- addRequestUrl,
35
- } = useLoaderProgress();
28
+ const { requestQueue } = useLoaderProgress();
36
29
 
37
- const isStarted = computed(() => {
30
+ const isLoading = computed(() => {
38
31
  return typeof status.value === "number";
39
32
  });
40
33
 
@@ -45,68 +38,37 @@ const barStyle = computed(() => {
45
38
  };
46
39
  });
47
40
 
48
- const resourceNamesArray = computed(() => {
49
- return Array.isArray(props.resources)
50
- ? props.resources.map(getRequestWithoutQuery)
51
- : [getRequestWithoutQuery(props.resources)];
52
- });
53
-
54
- const isPropsLoading = computed(
55
- () => requestQueue.value.includes(INFINITY_LOADING) && props.loading,
56
- );
57
-
58
- watch(() => requestQueue.value.length, onChangeRequestsQueue);
59
-
60
- onMounted(() => {
61
- window.addEventListener("loaderProgressOn", setLoaderOnHandler as EventListener);
62
- window.addEventListener("loaderProgressOff", setLoaderOffHandler as EventListener);
63
-
64
- if (props.resources) {
65
- onChangeRequestsQueue();
41
+ const resourceSubscriptions = computed(() => {
42
+ if (Array.isArray(props.resources)) {
43
+ return props.resources.map(getRequestWithoutQuery);
66
44
  }
67
- });
68
45
 
69
- onBeforeUnmount(() => {
70
- removeRequestUrl(resourceNamesArray.value);
46
+ return [getRequestWithoutQuery(props.resources)];
71
47
  });
72
48
 
73
- onUnmounted(() => {
74
- window.removeEventListener("loaderProgressOn", setLoaderOnHandler as EventListener);
75
- window.removeEventListener("loaderProgressOff", setLoaderOffHandler as EventListener);
49
+ const isActiveRequests = computed(() => {
50
+ const isAnyRequestActive = props.resources === "any" && requestQueue.value.length;
51
+ const isSubscribedRequestsActive = resourceSubscriptions.value.some((resource) =>
52
+ requestQueue.value.includes(resource),
53
+ );
54
+
55
+ return isAnyRequestActive || isSubscribedRequestsActive;
76
56
  });
77
57
 
58
+ watch(() => requestQueue, onChangeRequestsQueue, { immediate: true, deep: true });
59
+
78
60
  watch(
79
61
  () => props.loading,
80
- () => {
81
- if (props.loading) {
82
- addRequestUrl(INFINITY_LOADING);
83
- isLoading.value = true;
84
- } else {
85
- removeRequestUrl(INFINITY_LOADING);
86
- }
87
- },
88
- { immediate: true },
62
+ () => (props.loading ? start() : stop()),
89
63
  );
90
64
 
91
- function setLoaderOnHandler(event: CustomEvent<{ resource: string }>) {
92
- loaderProgressOn(event.detail.resource);
93
- }
94
-
95
- function setLoaderOffHandler(event: CustomEvent<{ resource: string }>) {
96
- loaderProgressOff(event.detail.resource);
97
- }
98
-
99
65
  function onChangeRequestsQueue() {
100
- const isActiveRequests =
101
- isPropsLoading.value ||
102
- resourceNamesArray.value.some((resource: string) => {
103
- return requestQueue.value.includes(resource);
104
- });
66
+ if (props.loading !== undefined) return;
105
67
 
106
- if (isActiveRequests && !isStarted.value && isLoading.value) {
68
+ if (isActiveRequests.value && !isLoading.value) {
107
69
  start();
108
- } else if (!isActiveRequests && isStarted.value && show.value) {
109
- done();
70
+ } else if (!isActiveRequests.value && isLoading.value && show.value) {
71
+ stop();
110
72
  }
111
73
  }
112
74
 
@@ -125,8 +87,9 @@ function afterEnter() {
125
87
  }
126
88
 
127
89
  function work() {
90
+ // TODO: Use requestAnimationFrame for animations instead of setTimeout for better performance and smoothness.
128
91
  setTimeout(() => {
129
- if (!isStarted.value) {
92
+ if (!isLoading.value) {
130
93
  return;
131
94
  }
132
95
 
@@ -152,7 +115,7 @@ function start() {
152
115
  function set(amount: number) {
153
116
  let currentProgress;
154
117
 
155
- if (isStarted.value) {
118
+ if (isLoading.value) {
156
119
  currentProgress = amount < progress.value ? clamp(amount, 0, 100) : clamp(amount, 0.8, 100);
157
120
  } else {
158
121
  currentProgress = 0;
@@ -200,10 +163,30 @@ function increase(amount?: number) {
200
163
  set(clamp(currentProgress + (amount || 0), 0, MAXIMUM));
201
164
  }
202
165
 
203
- function done() {
166
+ function stop() {
204
167
  set(100);
205
168
  }
206
169
 
170
+ defineExpose({
171
+ /**
172
+ * Start loading animation.
173
+ * @property {Function}
174
+ */
175
+ start,
176
+
177
+ /**
178
+ * Stop loading animation.
179
+ * @property {Function}
180
+ */
181
+ stop,
182
+
183
+ /**
184
+ * Loading state.
185
+ * @property {Boolean}
186
+ */
187
+ isLoading,
188
+ });
189
+
207
190
  /**
208
191
  * Get element / nested component attributes for each config token ✨
209
192
  * Applies: `class`, `config`, redefined default `props` and dev `vl-...` attributes.
@@ -20,6 +20,6 @@ export default /*tw*/ {
20
20
  defaults: {
21
21
  color: "brand",
22
22
  size: "md",
23
- loading: false,
23
+ loading: undefined,
24
24
  },
25
25
  };
@@ -6,4 +6,3 @@ export const COMPONENT_NAME = "ULoaderProgress";
6
6
 
7
7
  export const MAXIMUM = 99;
8
8
  export const SPEED = 150;
9
- export const INFINITY_LOADING = "Infinity";
@@ -21,33 +21,21 @@ The loader uses queue of resources and will be shown until at least one item is
21
21
  import { useLoaderProgress } from "vueless";
22
22
 
23
23
  const {
24
- isLoading,
25
24
  loaderProgressOn,
26
25
  loaderProgressOff,
27
26
  requestQueue,
28
- addRequestUrl
29
- removeRequestUrl
30
27
  } = useLoaderProgress();
31
28
 
32
- // get loader state
33
- console.log(isLoading.value);
34
-
35
29
  // show loader (add resource into queue)
36
30
  loaderProgressOn("/transactions");
31
+ loaderProgressOff(["/transactions", "/products"]);
37
32
 
38
33
  // hide loader (remove resource from queue)
39
34
  loaderProgressOff("/transactions");
35
+ loaderProgressOff(["/transactions", "/products"]);
40
36
 
41
- // get current resource array
37
+ // get current global resource queue
42
38
  console.log(requestQueue.value);
43
-
44
- // add resource into loader queue
45
- addRequestUrl("/transactions");
46
- addRequestUrl(["/transactions", "/products"]);
47
-
48
- // remove resource from loader queue
49
- removeRequestUrl("/transactions");
50
- removeRequestUrl(["/transactions", "/products"]);
51
39
  `} language="jsx" dark />
52
40
 
53
41
  ## Using loader outside Vue components
@@ -97,7 +97,7 @@ const EnumVariantTemplate: StoryFn<ULoaderProgressArgs> = (
97
97
  });
98
98
 
99
99
  export const Default = DefaultTemplate.bind({});
100
- Default.args = { loading: false };
100
+ Default.args = {};
101
101
 
102
102
  export const Color = EnumVariantTemplate.bind({});
103
103
  Color.args = { enum: "color" };
@@ -33,7 +33,7 @@ export interface Props {
33
33
  /**
34
34
  * API resource names (endpoint URIs).
35
35
  */
36
- resources?: string | string[];
36
+ resources?: string | string[] | "any" | ["any"];
37
37
 
38
38
  /**
39
39
  * Progress size.
@@ -1,4 +1,4 @@
1
- import { inject, readonly, ref } from "vue";
1
+ import { inject, onBeforeUnmount, readonly, ref } from "vue";
2
2
 
3
3
  import type { Ref } from "vue";
4
4
 
@@ -7,38 +7,14 @@ import { getRequestWithoutQuery } from "./utilLoaderProgress.ts";
7
7
  export const LoaderProgressSymbol = Symbol.for("vueless:loader-progress");
8
8
 
9
9
  type LoaderProgress = {
10
- isLoading: Ref<boolean>;
11
10
  requestQueue: Readonly<Ref<readonly string[]>>;
12
11
  loaderProgressOn: (url: string | string[]) => void;
13
12
  loaderProgressOff: (url: string | string[]) => void;
14
- addRequestUrl: (url: string | string[]) => void;
15
- removeRequestUrl: (url: string | string[]) => void;
16
13
  };
17
14
 
18
- const isLoading = ref(false);
19
15
  const requestQueue = ref<string[]>([]);
20
- const requestTimeout = ref<number | undefined>(undefined);
21
16
 
22
17
  function loaderProgressOn(url: string | string[]): void {
23
- addRequestUrl(url);
24
- isLoading.value = true;
25
-
26
- if (requestTimeout.value !== undefined) {
27
- clearTimeout(requestTimeout.value);
28
- }
29
- }
30
-
31
- function loaderProgressOff(url: string | string[]): void {
32
- removeRequestUrl(url);
33
-
34
- requestTimeout.value = window.setTimeout(() => {
35
- if (!requestQueue.value.length) {
36
- isLoading.value = false;
37
- }
38
- }, 50);
39
- }
40
-
41
- function addRequestUrl(url: string | string[]): void {
42
18
  if (Array.isArray(url)) {
43
19
  requestQueue.value.push(...url.map(getRequestWithoutQuery));
44
20
  } else {
@@ -46,28 +22,41 @@ function addRequestUrl(url: string | string[]): void {
46
22
  }
47
23
  }
48
24
 
49
- function removeRequestUrl(url: string | string[]): void {
25
+ function loaderProgressOff(url: string | string[]): void {
50
26
  if (Array.isArray(url)) {
51
- url.map(getRequestWithoutQuery).forEach(removeRequestUrl);
27
+ url.map(getRequestWithoutQuery).forEach(loaderProgressOff);
52
28
  } else {
53
29
  requestQueue.value = requestQueue.value.filter((item) => item !== getRequestWithoutQuery(url));
54
30
  }
55
31
  }
56
32
 
33
+ function setLoaderOnHandler(event: CustomEvent<{ resource: string }>) {
34
+ loaderProgressOn(event.detail.resource);
35
+ }
36
+
37
+ function setLoaderOffHandler(event: CustomEvent<{ resource: string }>) {
38
+ loaderProgressOff(event.detail.resource);
39
+ }
40
+
57
41
  export function createLoaderProgress(): LoaderProgress {
58
42
  return {
59
- isLoading,
60
43
  requestQueue: readonly(requestQueue),
61
44
  loaderProgressOn,
62
45
  loaderProgressOff,
63
- addRequestUrl,
64
- removeRequestUrl,
65
46
  };
66
47
  }
67
48
 
68
49
  export function useLoaderProgress(): LoaderProgress {
69
50
  const loaderProgress = inject<LoaderProgress>(LoaderProgressSymbol);
70
51
 
52
+ window.addEventListener("loaderProgressOn", setLoaderOnHandler as EventListener);
53
+ window.addEventListener("loaderProgressOff", setLoaderOffHandler as EventListener);
54
+
55
+ onBeforeUnmount(() => {
56
+ window.removeEventListener("loaderProgressOn", setLoaderOnHandler as EventListener);
57
+ window.removeEventListener("loaderProgressOff", setLoaderOffHandler as EventListener);
58
+ });
59
+
71
60
  if (!loaderProgress) {
72
61
  throw new Error(
73
62
  "LoaderProgress not provided. Ensure you are using `provide` with `LoaderProgressSymbol`.",