@pequity/squirrel 1.2.12 → 2.0.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/cjs/p-loading.js +50 -17
- package/dist/cjs/usePLoading.js +27 -10
- package/dist/es/p-loading.js +51 -18
- package/dist/es/usePLoading.js +28 -11
- package/dist/squirrel/components/p-alert/p-alert.vue.d.ts +2 -2
- package/dist/squirrel/components/p-btn/p-btn.vue.d.ts +5 -4
- package/dist/squirrel/components/p-card/p-card.vue.d.ts +9 -7
- package/dist/squirrel/components/p-checkbox/p-checkbox.vue.d.ts +7 -5
- package/dist/squirrel/components/p-date-picker/p-date-picker.vue.d.ts +4 -4
- package/dist/squirrel/components/p-dropdown-select/p-dropdown-select.vue.d.ts +29 -27
- package/dist/squirrel/components/p-info-icon/p-info-icon.vue.d.ts +6 -4
- package/dist/squirrel/components/p-inline-date-picker/p-inline-date-picker.vue.d.ts +4 -4
- package/dist/squirrel/components/p-input/p-input.vue.d.ts +6 -6
- package/dist/squirrel/components/p-input-number/p-input-number.vue.d.ts +6 -6
- package/dist/squirrel/components/p-input-percent/p-input-percent.vue.d.ts +5 -4
- package/dist/squirrel/components/p-input-search/p-input-search.vue.d.ts +2 -2
- package/dist/squirrel/components/p-loading/usePLoading.d.ts +7 -3
- package/dist/squirrel/components/p-modal/p-modal.vue.d.ts +10 -8
- package/dist/squirrel/components/p-pagination-info/p-pagination-info.vue.d.ts +6 -4
- package/dist/squirrel/components/p-select/p-select.vue.d.ts +14 -11
- package/dist/squirrel/components/p-select-btn/p-select-btn.vue.d.ts +8 -6
- package/dist/squirrel/components/p-select-list/p-select-list.vue.d.ts +29 -27
- package/dist/squirrel/components/p-select-pill/p-select-pill.vue.d.ts +4 -4
- package/dist/squirrel/components/p-table/p-table.vue.d.ts +8 -6
- package/dist/squirrel/components/p-table-td/p-table-td.vue.d.ts +6 -4
- package/dist/squirrel/components/p-textarea/p-textarea.vue.d.ts +4 -4
- package/dist/squirrel/components/p-toggle/p-toggle.vue.d.ts +4 -4
- package/dist/squirrel/utils/inputClassesMixin.d.ts +2 -2
- package/dist/squirrel/utils/object.d.ts +1 -1
- package/dist/style.css +6 -6
- package/package.json +22 -22
- package/squirrel/components/p-loading/p-loading.spec.js +71 -13
- package/squirrel/components/p-loading/p-loading.stories.js +61 -4
- package/squirrel/components/p-loading/p-loading.vue +27 -3
- package/squirrel/components/p-loading/usePLoading.ts +46 -13
- package/squirrel/components/p-select-list/p-select-list.utils.ts +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import PLoading from '@squirrel/components/p-loading/p-loading.vue';
|
|
2
|
+
import PSkeletonLoader from '@squirrel/components/p-skeleton-loader/p-skeleton-loader.vue';
|
|
2
3
|
import { createWrapperFor, sleep, waitNT } from '@tests/jest.helpers';
|
|
3
4
|
import { usePLoading } from '@squirrel/components/p-loading/usePLoading';
|
|
4
5
|
|
|
@@ -9,25 +10,43 @@ const createAppWrapper = () =>
|
|
|
9
10
|
});
|
|
10
11
|
|
|
11
12
|
const createWrapper = (options) => {
|
|
12
|
-
return createWrapperFor(
|
|
13
|
-
|
|
13
|
+
return createWrapperFor(
|
|
14
|
+
{
|
|
15
|
+
template: `
|
|
14
16
|
<button class="show" @click="loadingShow"></button>
|
|
15
17
|
<button class="hide" @click="loadingHide"></button>
|
|
16
18
|
<button class="request-1-sec" @click="fireRequest(1000)"></button>
|
|
17
19
|
<button class="request-3-secs" @click="fireRequest(3000)"></button>
|
|
20
|
+
<button class="request-1-sec-text" @click="fireRequest(1000, '1 sec')"></button>
|
|
21
|
+
<button class="request-3-secs-text" @click="fireRequest(3000, '3 secs')"></button>
|
|
22
|
+
<button class="request-1-sec-component" @click="fireRequestComponent(1000)"></button>
|
|
18
23
|
`,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
setup() {
|
|
25
|
+
const { loadingShow, loadingHide } = usePLoading(options);
|
|
26
|
+
|
|
27
|
+
const fireRequest = async (time, text) => {
|
|
28
|
+
const hide = loadingShow(text);
|
|
29
|
+
await sleep(time);
|
|
30
|
+
hide();
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const fireRequestComponent = async (time) => {
|
|
34
|
+
const hide = loadingShow(PSkeletonLoader);
|
|
35
|
+
await new Promise((resolve) => setTimeout(resolve, time));
|
|
36
|
+
hide();
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return { loadingShow, loadingHide, fireRequest, fireRequestComponent };
|
|
40
|
+
},
|
|
29
41
|
},
|
|
30
|
-
|
|
42
|
+
{
|
|
43
|
+
global: {
|
|
44
|
+
stubs: {
|
|
45
|
+
PSkeletonLoader: true,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
);
|
|
31
50
|
};
|
|
32
51
|
|
|
33
52
|
describe('PLoading.vue', () => {
|
|
@@ -117,4 +136,43 @@ describe('PLoading.vue', () => {
|
|
|
117
136
|
await waitNT(appWrapper.vm);
|
|
118
137
|
expect(appWrapper.find('[aria-busy]').exists()).toBe(true);
|
|
119
138
|
});
|
|
139
|
+
|
|
140
|
+
it(`shows the loading indicator with variable text`, async () => {
|
|
141
|
+
const wrapper = createWrapper({ delay: 200 });
|
|
142
|
+
|
|
143
|
+
await wrapper.find('.request-3-secs-text').trigger('click');
|
|
144
|
+
|
|
145
|
+
jest.advanceTimersByTime(300);
|
|
146
|
+
await waitNT(appWrapper.vm);
|
|
147
|
+
expect(appWrapper.find('[aria-busy]').text()).toBe('3 secs');
|
|
148
|
+
|
|
149
|
+
await wrapper.find('.request-1-sec-text').trigger('click');
|
|
150
|
+
|
|
151
|
+
jest.advanceTimersByTime(300);
|
|
152
|
+
await waitNT(appWrapper.vm);
|
|
153
|
+
expect(appWrapper.find('[aria-busy]').text()).toBe('1 sec');
|
|
154
|
+
|
|
155
|
+
jest.advanceTimersByTime(1200);
|
|
156
|
+
await waitNT(appWrapper.vm);
|
|
157
|
+
expect(appWrapper.find('[aria-busy]').text()).toBe('3 secs');
|
|
158
|
+
|
|
159
|
+
jest.advanceTimersByTime(1200);
|
|
160
|
+
await waitNT(appWrapper.vm);
|
|
161
|
+
expect(appWrapper.find('[aria-busy]').exists()).toBe(false);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it(`accepts a component as the content`, async () => {
|
|
165
|
+
const wrapper = createWrapper({ delay: 200 });
|
|
166
|
+
|
|
167
|
+
await wrapper.find('.request-1-sec-component').trigger('click');
|
|
168
|
+
|
|
169
|
+
jest.advanceTimersByTime(300);
|
|
170
|
+
await waitNT(appWrapper.vm);
|
|
171
|
+
expect(appWrapper.find('[aria-busy]').exists()).toBe(true);
|
|
172
|
+
expect(appWrapper.findComponent(PSkeletonLoader).exists()).toBe(true);
|
|
173
|
+
|
|
174
|
+
jest.advanceTimersByTime(800);
|
|
175
|
+
await waitNT(appWrapper.vm);
|
|
176
|
+
expect(appWrapper.find('[aria-busy]').exists()).toBe(false);
|
|
177
|
+
});
|
|
120
178
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import ComputationStatus from '@/playground/components/ComputationStatus.vue';
|
|
1
2
|
import PBtn from '@squirrel/components/p-btn/p-btn.vue';
|
|
2
3
|
import PLoading from '@squirrel/components/p-loading/p-loading.vue';
|
|
3
4
|
import { usePLoading } from '@squirrel/components/p-loading/usePLoading';
|
|
@@ -23,15 +24,15 @@ export const Default = {
|
|
|
23
24
|
render: (args) => ({
|
|
24
25
|
components: { PLoading, PBtn },
|
|
25
26
|
setup() {
|
|
26
|
-
const { loadingShow
|
|
27
|
+
const { loadingShow } = usePLoading();
|
|
27
28
|
|
|
28
29
|
const fireRequest = async (time) => {
|
|
29
|
-
loadingShow();
|
|
30
|
+
const hide = loadingShow();
|
|
30
31
|
await new Promise((resolve) => setTimeout(resolve, time));
|
|
31
|
-
|
|
32
|
+
hide();
|
|
32
33
|
};
|
|
33
34
|
|
|
34
|
-
return { args, loadingShow,
|
|
35
|
+
return { args, loadingShow, fireRequest };
|
|
35
36
|
},
|
|
36
37
|
template: `
|
|
37
38
|
<PLoading />
|
|
@@ -47,3 +48,59 @@ export const Default = {
|
|
|
47
48
|
`,
|
|
48
49
|
}),
|
|
49
50
|
};
|
|
51
|
+
|
|
52
|
+
export const WithVariableText = {
|
|
53
|
+
render: (args) => ({
|
|
54
|
+
components: { PLoading, PBtn },
|
|
55
|
+
setup() {
|
|
56
|
+
const { loadingShow } = usePLoading();
|
|
57
|
+
|
|
58
|
+
const fireRequestText = async (time, text) => {
|
|
59
|
+
const hide = loadingShow(text);
|
|
60
|
+
await new Promise((resolve) => setTimeout(resolve, time));
|
|
61
|
+
hide();
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return { args, loadingShow, fireRequestText };
|
|
65
|
+
},
|
|
66
|
+
template: `
|
|
67
|
+
<PLoading />
|
|
68
|
+
<div class="mt-10">
|
|
69
|
+
<div>Demo with variable loading text</div>
|
|
70
|
+
<div class="flex gap-4 mt-2">
|
|
71
|
+
<PBtn @click="fireRequestText(1000, '1 sec')">Fire request 1 sec</PBtn>
|
|
72
|
+
<PBtn @click="fireRequestText(3000, '3 secs')">Fire request 3 secs</PBtn>
|
|
73
|
+
<PBtn @click="fireRequestText(5000, '5 secs')">Fire request 5 secs</PBtn>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
`,
|
|
77
|
+
}),
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const WithComponentAsContent = {
|
|
81
|
+
render: (args) => ({
|
|
82
|
+
components: { PLoading, PBtn },
|
|
83
|
+
setup() {
|
|
84
|
+
const { loadingShow } = usePLoading();
|
|
85
|
+
|
|
86
|
+
const fireRequestComponent = async (time) => {
|
|
87
|
+
const hide = loadingShow(ComputationStatus);
|
|
88
|
+
await new Promise((resolve) => setTimeout(resolve, time));
|
|
89
|
+
hide();
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return { args, loadingShow, fireRequestComponent };
|
|
93
|
+
},
|
|
94
|
+
template: `
|
|
95
|
+
<PLoading />
|
|
96
|
+
<div class="mt-10">
|
|
97
|
+
<div>Demo with a component as content</div>
|
|
98
|
+
<div class="flex gap-4 mt-2">
|
|
99
|
+
<PBtn @click="fireRequestComponent(1000)">Fire request 1 sec</PBtn>
|
|
100
|
+
<PBtn @click="fireRequestComponent(3000)">Fire request 3 secs</PBtn>
|
|
101
|
+
<PBtn @click="fireRequestComponent(5000)">Fire request 5 secs</PBtn>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
`,
|
|
105
|
+
}),
|
|
106
|
+
};
|
|
@@ -2,22 +2,46 @@
|
|
|
2
2
|
<Transition name="pm-backdrop-transition" enter-active-class="fadeInDown" leave-active-class="fadeOutUp">
|
|
3
3
|
<div v-if="show" class="fixed left-0 top-0 z-[120] flex w-full justify-center" aria-live="polite" aria-busy="true">
|
|
4
4
|
<div
|
|
5
|
-
|
|
5
|
+
:style="{ width: `${width}px` }"
|
|
6
|
+
class="h-8 overflow-hidden whitespace-nowrap rounded-b border-x border-b border-p-gray-30 bg-p-blue-10 px-4 pt-2 text-center text-sm font-semibold leading-none text-p-purple-60 shadow-sm transition-all duration-500"
|
|
6
7
|
>
|
|
7
|
-
|
|
8
|
+
<Component :is="content" v-if="isComponent(content)" />
|
|
9
|
+
<template v-else>{{ content }}</template>
|
|
8
10
|
</div>
|
|
9
11
|
</div>
|
|
10
12
|
</Transition>
|
|
13
|
+
<div v-if="content" class="invisible fixed">
|
|
14
|
+
<div ref="widthReference" class="inline-flex px-4">
|
|
15
|
+
<Component :is="content" v-if="isComponent(content)" />
|
|
16
|
+
<template v-else>{{ content }}</template>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
11
19
|
</template>
|
|
12
20
|
|
|
13
21
|
<script setup lang="ts">
|
|
22
|
+
import { type Component, ref, toValue, watch } from 'vue';
|
|
14
23
|
import { usePLoading } from '@squirrel/components/p-loading/usePLoading';
|
|
15
24
|
|
|
16
25
|
defineOptions({
|
|
17
26
|
name: 'PLoading',
|
|
18
27
|
});
|
|
19
28
|
|
|
20
|
-
const { show } = usePLoading();
|
|
29
|
+
const { show, content } = usePLoading();
|
|
30
|
+
const widthReference = ref<HTMLElement | null>(null);
|
|
31
|
+
const width = ref(0);
|
|
32
|
+
|
|
33
|
+
watch(
|
|
34
|
+
() => toValue(content),
|
|
35
|
+
() => {
|
|
36
|
+
if (widthReference.value) {
|
|
37
|
+
width.value = widthReference.value.offsetWidth;
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{ flush: 'post' }
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const isComponent = (content: unknown): content is Component =>
|
|
44
|
+
typeof content === 'object' && content !== null && 'render' in content && typeof content.render === 'function';
|
|
21
45
|
</script>
|
|
22
46
|
|
|
23
47
|
<style scoped lang="scss">
|
|
@@ -1,20 +1,40 @@
|
|
|
1
|
-
import { getCurrentScope, onScopeDispose, ref } from 'vue';
|
|
1
|
+
import { type Component, type Ref, computed, getCurrentScope, markRaw, onScopeDispose, ref } from 'vue';
|
|
2
2
|
import { uniqueId } from 'lodash-es';
|
|
3
3
|
|
|
4
4
|
type Options = {
|
|
5
5
|
delay?: number;
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
+
type Content = string | Component;
|
|
9
|
+
|
|
10
|
+
type LoadingItem = {
|
|
11
|
+
id: string;
|
|
12
|
+
content: Content;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type UsePLoading = {
|
|
16
|
+
show: Ref<boolean>;
|
|
17
|
+
content: Content;
|
|
18
|
+
loadingShow: (content?: Content) => () => void;
|
|
19
|
+
loadingHide: () => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const LOADING_TEXT = 'Loading...';
|
|
8
23
|
const show = ref(false);
|
|
9
|
-
const
|
|
24
|
+
const loadingItems = ref<LoadingItem[]>([]);
|
|
25
|
+
const content = computed(() => {
|
|
26
|
+
return loadingItems.value[loadingItems.value.length - 1]?.content;
|
|
27
|
+
});
|
|
10
28
|
let timer: ReturnType<typeof setTimeout>;
|
|
11
29
|
|
|
12
|
-
export const usePLoading = (options?: Options) => {
|
|
30
|
+
export const usePLoading = (options?: Options): UsePLoading => {
|
|
13
31
|
const { delay } = { delay: 200, ...options };
|
|
14
32
|
const scope = getCurrentScope();
|
|
15
33
|
|
|
16
|
-
const loadingShow = () => {
|
|
17
|
-
|
|
34
|
+
const loadingShow = (content?: Content) => {
|
|
35
|
+
const loadingId = uniqueId();
|
|
36
|
+
|
|
37
|
+
if (loadingItems.value.length === 0 && delay > 0) {
|
|
18
38
|
timer = setTimeout(() => {
|
|
19
39
|
show.value = true;
|
|
20
40
|
}, delay);
|
|
@@ -22,23 +42,36 @@ export const usePLoading = (options?: Options) => {
|
|
|
22
42
|
show.value = true;
|
|
23
43
|
}
|
|
24
44
|
|
|
25
|
-
|
|
45
|
+
loadingItems.value.push({
|
|
46
|
+
id: loadingId,
|
|
47
|
+
content: content && typeof content === 'object' ? markRaw(content) : content || LOADING_TEXT,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const hide = () => {
|
|
51
|
+
loadingItems.value = loadingItems.value.filter((item) => item.id !== loadingId);
|
|
52
|
+
clearTimeout(timer);
|
|
53
|
+
|
|
54
|
+
if (loadingItems.value.length === 0) {
|
|
55
|
+
show.value = false;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return hide;
|
|
26
60
|
};
|
|
27
61
|
|
|
28
62
|
const loadingHide = () => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
63
|
+
loadingItems.value = [];
|
|
64
|
+
show.value = false;
|
|
33
65
|
clearTimeout(timer);
|
|
34
|
-
loadingIds.pop();
|
|
35
66
|
};
|
|
36
67
|
|
|
37
68
|
if (scope) {
|
|
38
69
|
onScopeDispose(() => {
|
|
39
|
-
|
|
70
|
+
loadingItems.value = [];
|
|
71
|
+
show.value = false;
|
|
72
|
+
clearTimeout(timer);
|
|
40
73
|
});
|
|
41
74
|
}
|
|
42
75
|
|
|
43
|
-
return { show, loadingShow, loadingHide };
|
|
76
|
+
return { show, content, loadingShow, loadingHide };
|
|
44
77
|
};
|
|
@@ -27,7 +27,7 @@ export const createInternalValue = (
|
|
|
27
27
|
if (multiple) {
|
|
28
28
|
val = (modelValue as AnyObject[]).map((v) => v[itemValue as keyof typeof modelValue]) as AnyValue[];
|
|
29
29
|
} else {
|
|
30
|
-
val = modelValue ? modelValue[itemValue as keyof typeof modelValue] : modelValue;
|
|
30
|
+
val = modelValue ? (modelValue as AnyObject)[itemValue as keyof typeof modelValue] : modelValue;
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|