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.
@@ -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 { useLoaderProgress } from "./ui.loader-progress/useLoaderProgress";
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",
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",
@@ -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>
@@ -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
- __VuelessProgressLoaderInstance?: number;
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" | ["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 { getRequestWithoutQuery } from "./utilLoaderProgress";
6
-
7
- export const LoaderProgressSymbol = Symbol.for("vueless:loader-progress");
5
+ import { useRequestQueue } from "../composables/useRequestQueue";
8
6
 
9
7
  type LoaderProgress = {
10
- requestQueue: Readonly<Ref<readonly string[]>>;
11
- loaderProgressOn: (url: string | string[]) => void;
12
- loaderProgressOff: (url: string | string[]) => void;
8
+ isLoading: Readonly<Ref<boolean, boolean>>;
9
+ loaderProgressOn: (request: string | string[]) => void;
10
+ loaderProgressOff: (request: string | string[]) => void;
13
11
  };
14
12
 
15
- export function createLoaderProgress(): LoaderProgress {
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
- function loaderProgressOff(url: string | string[]): void {
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
- requestQueue: readonly(requestQueue),
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
+ }