@weni/unnnic-system 2.13.0 → 2.13.1
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/CHANGELOG.md +6 -0
- package/README.md +56 -19
- package/dist/style.css +1 -1
- package/dist/unnnic.mjs +4546 -4471
- package/dist/unnnic.umd.js +19 -19
- package/package.json +1 -1
- package/src/components/Alert/Alert.vue +2 -0
- package/src/components/Alert/AlertBanner.vue +2 -0
- package/src/components/Alert/Version1dot1.vue +1 -0
- package/src/components/Alert/__tests__/Alert.spec.js +84 -0
- package/src/components/Alert/__tests__/AlertBanner.spec.js +89 -0
- package/src/components/Alert/__tests__/AlertCaller.spec.js +98 -0
- package/src/components/Alert/__tests__/Version1dot1.spec.js +124 -0
- package/src/components/AudioRecorder/AudioRecorder.vue +30 -1
- package/src/components/AvatarIcon/__tests__/AvatarIcon.spec.js +84 -0
- package/src/components/AvatarIcon/__tests__/__snapshots__/AvatarIcon.spec.js.snap +7 -0
- package/src/components/Breadcrumb/Breadcrumb.vue +4 -0
- package/src/components/Breadcrumb/__tests__/Breadcrumb.spec.js +68 -0
- package/src/components/FormElement/FormElement.vue +101 -28
- package/src/components/Input/BaseInput.vue +30 -38
- package/src/components/Input/Input.scss +43 -0
- package/src/components/Input/TextInput.vue +24 -25
- package/src/components/Input/__test__/TextInput.spec.js +2 -2
- package/src/components/Input/__test__/__snapshots__/Input.spec.js.snap +1 -1
- package/src/components/Input/__test__/__snapshots__/TextInput.spec.js.snap +1 -1
- package/src/components/Pagination/Pagination.vue +23 -4
- package/src/components/Pagination/__tests__/Pagination.spec.js +208 -0
- package/src/components/SelectSmart/SelectSmart.vue +16 -44
- package/src/components/SelectSmart/SelectSmartMultipleHeader.vue +5 -13
- package/src/components/SelectSmart/SelectSmartOption.vue +13 -9
- package/src/components/SkeletonLoading/SkeletonLoading.vue +17 -11
- package/src/components/SkeletonLoading/__tests__/SkeletonLoading.spec.js +125 -0
- package/src/components/TextArea/TextArea.vue +45 -128
- package/src/components/TextArea/__test__/TextArea.spec.js +26 -24
- package/src/components/TextArea/__test__/__snapshots__/TextArea.spec.js.snap +4 -4
- package/src/stories/Input.mdx +76 -0
- package/src/stories/Input.stories.js +82 -8
- package/src/stories/SelectSmart.mdx +15 -17
- package/src/stories/SelectSmart.stories.js +72 -6
- package/src/stories/TextArea.mdx +68 -0
- package/src/stories/TextArea.stories.js +68 -6
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { beforeEach, describe, expect, it } from 'vitest';
|
|
3
|
+
import Pagination from '../Pagination.vue';
|
|
4
|
+
|
|
5
|
+
function setup(props) {
|
|
6
|
+
return mount(Pagination, { props });
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
describe('Pagination', () => {
|
|
10
|
+
describe('when pagination is not disabled', () => {
|
|
11
|
+
let wrapper;
|
|
12
|
+
|
|
13
|
+
describe('when the user is on the first page', () => {
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
wrapper = setup({
|
|
16
|
+
modelValue: 1,
|
|
17
|
+
max: 10,
|
|
18
|
+
disabled: false,
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should show 1, 2, 3, ..., 10 page buttons', () => {
|
|
23
|
+
const texts = wrapper
|
|
24
|
+
.findAll('[data-test="page-button"]')
|
|
25
|
+
.map((element) => element.text());
|
|
26
|
+
|
|
27
|
+
['1', '2', '3', '...', '10'].forEach((value, index) => {
|
|
28
|
+
expect(texts[index]).contains(value);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('the previous button should be disabled', () => {
|
|
33
|
+
expect(
|
|
34
|
+
wrapper.find('[data-test="previous-button"]').isDisabled(),
|
|
35
|
+
).toBeTruthy();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('when the user clicks on the next button', () => {
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
wrapper.find('[data-test="next-button"]').trigger('click');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('emits @update:model-value with page number 2', () => {
|
|
44
|
+
expect(wrapper.emitted('update:model-value')).toHaveLength(1);
|
|
45
|
+
expect(wrapper.emitted('update:model-value')).toContainEqual([2]);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('when the user clicks on the right ellipsis button', () => {
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
wrapper.findAll('[data-test="page-button"]').at(-2).trigger('click');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('emits @update:model-value with page number 4', () => {
|
|
55
|
+
expect(wrapper.emitted('update:model-value')).toHaveLength(1);
|
|
56
|
+
expect(wrapper.emitted('update:model-value')).toContainEqual([4]);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('when the user is on the second page', () => {
|
|
62
|
+
beforeEach(() => {
|
|
63
|
+
wrapper = setup({
|
|
64
|
+
modelValue: 2,
|
|
65
|
+
max: 10,
|
|
66
|
+
disabled: false,
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should show 1, 2, 3, ..., 10 page buttons', () => {
|
|
71
|
+
const texts = wrapper
|
|
72
|
+
.findAll('[data-test="page-button"]')
|
|
73
|
+
.map((element) => element.text());
|
|
74
|
+
|
|
75
|
+
['1', '2', '3', '...', '10'].forEach((value, index) => {
|
|
76
|
+
expect(texts[index]).contains(value);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('when the user clicks on the previous button', () => {
|
|
81
|
+
beforeEach(() => {
|
|
82
|
+
wrapper.find('[data-test="previous-button"]').trigger('click');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('emits @update:model-value with page number 1', () => {
|
|
86
|
+
expect(wrapper.emitted('update:model-value')).toHaveLength(1);
|
|
87
|
+
expect(wrapper.emitted('update:model-value')).toContainEqual([1]);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe('when the user is on the last page', () => {
|
|
93
|
+
beforeEach(() => {
|
|
94
|
+
wrapper = setup({
|
|
95
|
+
modelValue: 11,
|
|
96
|
+
max: 10,
|
|
97
|
+
disabled: false,
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('the next button should be disabled', () => {
|
|
102
|
+
expect(
|
|
103
|
+
wrapper.find('[data-test="next-button"]').isDisabled(),
|
|
104
|
+
).toBeTruthy();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe('when the user is on the 9th page', () => {
|
|
109
|
+
beforeEach(() => {
|
|
110
|
+
wrapper = setup({
|
|
111
|
+
modelValue: 9,
|
|
112
|
+
max: 10,
|
|
113
|
+
disabled: false,
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should show 1, ..., 8, 9, 10 page buttons', () => {
|
|
118
|
+
const texts = wrapper
|
|
119
|
+
.findAll('[data-test="page-button"]')
|
|
120
|
+
.map((element) => element.text());
|
|
121
|
+
|
|
122
|
+
['1', '...', '8', '9', '10'].forEach((value, index) => {
|
|
123
|
+
expect(texts[index]).contains(value);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe('when the user clicks on the left ellipsis button', () => {
|
|
128
|
+
beforeEach(() => {
|
|
129
|
+
wrapper.findAll('[data-test="page-button"]').at(1).trigger('click');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('emits @update:model-value with page number 7', () => {
|
|
133
|
+
expect(wrapper.emitted('update:model-value')).toHaveLength(1);
|
|
134
|
+
expect(wrapper.emitted('update:model-value')).toContainEqual([7]);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe('when the user is on the 4rd page', () => {
|
|
140
|
+
beforeEach(() => {
|
|
141
|
+
wrapper = setup({
|
|
142
|
+
modelValue: 4,
|
|
143
|
+
max: 10,
|
|
144
|
+
disabled: false,
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should show 1, ..., 4 ..., 10 page buttons', () => {
|
|
149
|
+
const texts = wrapper
|
|
150
|
+
.findAll('[data-test="page-button"]')
|
|
151
|
+
.map((element) => element.text());
|
|
152
|
+
|
|
153
|
+
['1', '...', '4', '...', '10'].forEach((value, index) => {
|
|
154
|
+
expect(texts[index]).contains(value);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe('when the user clicks on the right ellipsis button', () => {
|
|
159
|
+
beforeEach(() => {
|
|
160
|
+
wrapper.findAll('[data-test="page-button"]').at(-2).trigger('click');
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('emits @update:model-value with page number 5', () => {
|
|
164
|
+
expect(wrapper.emitted('update:model-value')).toHaveLength(1);
|
|
165
|
+
expect(wrapper.emitted('update:model-value')).toContainEqual([5]);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe('when the user is on the 3rd page', () => {
|
|
171
|
+
beforeEach(() => {
|
|
172
|
+
wrapper = setup({
|
|
173
|
+
modelValue: 3,
|
|
174
|
+
max: 10,
|
|
175
|
+
disabled: false,
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
describe('when the user wants clicks on the next page button', () => {
|
|
180
|
+
it('emits @update:model-value with page number 4', () => {
|
|
181
|
+
wrapper.find('[data-test="next-button"]').trigger('click');
|
|
182
|
+
|
|
183
|
+
expect(wrapper.emitted('update:model-value')).toHaveLength(1);
|
|
184
|
+
expect(wrapper.emitted('update:model-value')).toContainEqual([4]);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe('when the user is on the 7th page', () => {
|
|
190
|
+
beforeEach(() => {
|
|
191
|
+
wrapper = setup({
|
|
192
|
+
modelValue: 9,
|
|
193
|
+
max: 10,
|
|
194
|
+
disabled: false,
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe('when the user wants clicks on the previous page button', () => {
|
|
199
|
+
it('emits @update:model-value with page number 8', () => {
|
|
200
|
+
wrapper.find('[data-test="previous-button"]').trigger('click');
|
|
201
|
+
|
|
202
|
+
expect(wrapper.emitted('update:model-value')).toHaveLength(1);
|
|
203
|
+
expect(wrapper.emitted('update:model-value')).toContainEqual([8]);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
});
|
|
@@ -22,9 +22,8 @@
|
|
|
22
22
|
:iconLeft="
|
|
23
23
|
isAutocompleteAllowed && autocompleteIconLeft ? 'search-1' : ''
|
|
24
24
|
"
|
|
25
|
-
:iconRight="active ? '
|
|
26
|
-
|
|
27
|
-
@icon-right-click="handleClickInput"
|
|
25
|
+
:iconRight="active ? 'keyboard_arrow_up' : 'keyboard_arrow_down'"
|
|
26
|
+
iconRightSize="ant"
|
|
28
27
|
@click.stop="handleClickInput"
|
|
29
28
|
@update:model-value="searchValue = $event"
|
|
30
29
|
/>
|
|
@@ -46,7 +45,6 @@
|
|
|
46
45
|
:withoutSelectsMessage="multipleWithoutSelectsMessage"
|
|
47
46
|
:locale="locale"
|
|
48
47
|
:translations="translations"
|
|
49
|
-
@clear-selected-options="clearSelectedOptions"
|
|
50
48
|
@unselect-option="unselectOption"
|
|
51
49
|
/>
|
|
52
50
|
<div
|
|
@@ -56,6 +54,7 @@
|
|
|
56
54
|
`size-${size}`,
|
|
57
55
|
{
|
|
58
56
|
'with-descriptions': hasDescriptionOptions,
|
|
57
|
+
'with-checkboxes': !!multiple,
|
|
59
58
|
},
|
|
60
59
|
]"
|
|
61
60
|
>
|
|
@@ -329,10 +328,6 @@ export default {
|
|
|
329
328
|
);
|
|
330
329
|
},
|
|
331
330
|
|
|
332
|
-
clearSelectedOptions() {
|
|
333
|
-
this.$emit('update:modelValue', []);
|
|
334
|
-
},
|
|
335
|
-
|
|
336
331
|
handleSelect(option) {
|
|
337
332
|
if (option) {
|
|
338
333
|
if (this.multiple && this.optionIsSelected(option)) {
|
|
@@ -559,7 +554,7 @@ export default {
|
|
|
559
554
|
left: 0;
|
|
560
555
|
right: 0;
|
|
561
556
|
|
|
562
|
-
margin-top:
|
|
557
|
+
margin-top: $unnnic-spacing-nano;
|
|
563
558
|
|
|
564
559
|
border-radius: $unnnic-border-radius-sm;
|
|
565
560
|
|
|
@@ -578,7 +573,7 @@ export default {
|
|
|
578
573
|
margin-right: $unnnic-inline-xs;
|
|
579
574
|
padding-right: $unnnic-inline-xs;
|
|
580
575
|
|
|
581
|
-
max-height: calc-max-height(
|
|
576
|
+
max-height: calc-max-height(9.25);
|
|
582
577
|
|
|
583
578
|
overflow-y: auto;
|
|
584
579
|
|
|
@@ -597,14 +592,22 @@ export default {
|
|
|
597
592
|
}
|
|
598
593
|
|
|
599
594
|
&.with-descriptions {
|
|
600
|
-
max-height: calc-max-height(
|
|
595
|
+
max-height: calc-max-height(14.25);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
&.with-checkboxes {
|
|
599
|
+
max-height: calc-max-height(11.75);
|
|
601
600
|
}
|
|
602
601
|
|
|
603
602
|
&.size-sm {
|
|
604
|
-
max-height: calc-max-height(8);
|
|
603
|
+
max-height: calc-max-height(8.75);
|
|
605
604
|
|
|
606
605
|
&.with-descriptions {
|
|
607
|
-
max-height: calc-max-height(
|
|
606
|
+
max-height: calc-max-height(13.75);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
&.with-checkboxes {
|
|
610
|
+
max-height: calc-max-height(10.75);
|
|
608
611
|
}
|
|
609
612
|
}
|
|
610
613
|
}
|
|
@@ -632,43 +635,12 @@ export default {
|
|
|
632
635
|
.unnnic-select-smart__input input {
|
|
633
636
|
// entire class name to have higher priority in styles
|
|
634
637
|
|
|
635
|
-
color: $unnnic-color-neutral-dark;
|
|
636
|
-
|
|
637
638
|
&:read-only {
|
|
638
639
|
cursor: pointer;
|
|
639
|
-
|
|
640
|
-
&::placeholder {
|
|
641
|
-
color: $unnnic-color-neutral-cloudy;
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
&:not(:read-only :focus) {
|
|
646
|
-
&::placeholder {
|
|
647
|
-
color: $unnnic-color-neutral-cloudy;
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
&:not(:read-only) {
|
|
652
|
-
&:focus {
|
|
653
|
-
&::placeholder {
|
|
654
|
-
color: $unnnic-color-neutral-cleanest;
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
640
|
}
|
|
658
641
|
|
|
659
642
|
&:disabled {
|
|
660
|
-
box-shadow: inset 0 0 0 $unnnic-border-width-thinner
|
|
661
|
-
$unnnic-color-neutral-cleanest;
|
|
662
|
-
|
|
663
643
|
cursor: not-allowed;
|
|
664
|
-
|
|
665
|
-
&::placeholder {
|
|
666
|
-
color: $unnnic-color-neutral-cleanest;
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
+ .icon-right {
|
|
670
|
-
cursor: not-allowed;
|
|
671
|
-
}
|
|
672
644
|
}
|
|
673
645
|
}
|
|
674
646
|
}
|
|
@@ -20,13 +20,6 @@
|
|
|
20
20
|
+{{ selectedOptions.length - multipleSelectedsTags }}
|
|
21
21
|
</p>
|
|
22
22
|
</div>
|
|
23
|
-
<UnnnicIcon
|
|
24
|
-
class="unnnic-select-smart__options__multiple__selecteds__clear"
|
|
25
|
-
icon="close-1"
|
|
26
|
-
size="xs"
|
|
27
|
-
clickable
|
|
28
|
-
@click="clearSelectedOptions"
|
|
29
|
-
/>
|
|
30
23
|
</div>
|
|
31
24
|
<p
|
|
32
25
|
v-if="!selectedOptions[0]"
|
|
@@ -39,14 +32,12 @@
|
|
|
39
32
|
|
|
40
33
|
<script>
|
|
41
34
|
import Tag from '../Tag/Tag.vue';
|
|
42
|
-
import UnnnicIcon from '../Icon.vue';
|
|
43
35
|
import UnnnicI18n from '../../mixins/i18n';
|
|
44
36
|
|
|
45
37
|
export default {
|
|
46
38
|
name: 'UnnnicSelectSmartMultipleHeader',
|
|
47
39
|
components: {
|
|
48
40
|
Tag,
|
|
49
|
-
UnnnicIcon,
|
|
50
41
|
},
|
|
51
42
|
mixins: [UnnnicI18n],
|
|
52
43
|
props: {
|
|
@@ -85,9 +76,6 @@ export default {
|
|
|
85
76
|
},
|
|
86
77
|
},
|
|
87
78
|
methods: {
|
|
88
|
-
clearSelectedOptions() {
|
|
89
|
-
this.$emit('clear-selected-options');
|
|
90
|
-
},
|
|
91
79
|
unselectOption(option) {
|
|
92
80
|
this.$emit('unselect-option', option);
|
|
93
81
|
},
|
|
@@ -117,6 +105,10 @@ export default {
|
|
|
117
105
|
margin: $unnnic-spacing-xs;
|
|
118
106
|
margin-right: 0;
|
|
119
107
|
|
|
108
|
+
&:first-child {
|
|
109
|
+
margin-left: $unnnic-spacing-sm;
|
|
110
|
+
}
|
|
111
|
+
|
|
120
112
|
&.unnnic-tag {
|
|
121
113
|
outline-color: $unnnic-color-neutral-light;
|
|
122
114
|
background-color: $unnnic-color-neutral-light;
|
|
@@ -144,7 +136,7 @@ export default {
|
|
|
144
136
|
line-height: $unnnic-font-size-body-md + $unnnic-line-height-medium;
|
|
145
137
|
font-size: $unnnic-font-size-body-md;
|
|
146
138
|
|
|
147
|
-
padding: $unnnic-spacing-ant;
|
|
139
|
+
padding: $unnnic-spacing-ant $unnnic-spacing-sm;
|
|
148
140
|
}
|
|
149
141
|
}
|
|
150
142
|
</style>
|
|
@@ -74,6 +74,7 @@ export default {
|
|
|
74
74
|
type: Boolean,
|
|
75
75
|
default: false,
|
|
76
76
|
},
|
|
77
|
+
isMultiple: Boolean,
|
|
77
78
|
},
|
|
78
79
|
};
|
|
79
80
|
</script>
|
|
@@ -87,7 +88,7 @@ export default {
|
|
|
87
88
|
max-width: 100%;
|
|
88
89
|
|
|
89
90
|
font-family: $unnnic-font-family-secondary;
|
|
90
|
-
color: $unnnic-color-neutral-
|
|
91
|
+
color: $unnnic-color-neutral-darkest;
|
|
91
92
|
font-weight: $unnnic-font-weight-regular;
|
|
92
93
|
|
|
93
94
|
white-space: nowrap;
|
|
@@ -95,9 +96,12 @@ export default {
|
|
|
95
96
|
overflow: hidden;
|
|
96
97
|
-webkit-line-clamp: 1;
|
|
97
98
|
|
|
99
|
+
& + & {
|
|
100
|
+
margin-top: $unnnic-spacing-nano;
|
|
101
|
+
}
|
|
102
|
+
|
|
98
103
|
&--selectable:hover,
|
|
99
|
-
&--focused
|
|
100
|
-
&--active {
|
|
104
|
+
&--focused {
|
|
101
105
|
border-radius: $unnnic-border-radius-sm;
|
|
102
106
|
|
|
103
107
|
background-color: $unnnic-color-neutral-light;
|
|
@@ -109,6 +113,7 @@ export default {
|
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
&--with-checkbox {
|
|
116
|
+
padding: $unnnic-spacing-xs $unnnic-spacing-ant;
|
|
112
117
|
display: flex;
|
|
113
118
|
align-items: center;
|
|
114
119
|
gap: $unnnic-spacing-xs;
|
|
@@ -119,13 +124,15 @@ export default {
|
|
|
119
124
|
}
|
|
120
125
|
|
|
121
126
|
&__label {
|
|
127
|
+
display: block;
|
|
128
|
+
|
|
122
129
|
&--md {
|
|
123
130
|
font-size: $unnnic-font-size-body-gt;
|
|
124
131
|
line-height: $unnnic-font-size-body-gt + $unnnic-line-height-medium;
|
|
125
132
|
}
|
|
126
133
|
&--sm {
|
|
127
134
|
font-size: $unnnic-font-size-body-md;
|
|
128
|
-
line-height: $unnnic-font-size-body-md + $unnnic-line-height-
|
|
135
|
+
line-height: $unnnic-font-size-body-md + $unnnic-line-height-md;
|
|
129
136
|
}
|
|
130
137
|
}
|
|
131
138
|
|
|
@@ -135,14 +142,11 @@ export default {
|
|
|
135
142
|
color: $unnnic-color-neutral-cloudy;
|
|
136
143
|
font-weight: $unnnic-font-weight-regular;
|
|
137
144
|
|
|
138
|
-
&--md
|
|
145
|
+
&--md,
|
|
146
|
+
&--sm {
|
|
139
147
|
font-size: $unnnic-font-size-body-md;
|
|
140
148
|
line-height: $unnnic-font-size-body-md + $unnnic-line-height-medium;
|
|
141
149
|
}
|
|
142
|
-
&--sm {
|
|
143
|
-
font-size: $unnnic-font-size-body-sm;
|
|
144
|
-
line-height: $unnnic-font-size-body-md + $unnnic-line-height-small;
|
|
145
|
-
}
|
|
146
150
|
}
|
|
147
151
|
}
|
|
148
152
|
</style>
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<component
|
|
3
3
|
:is="tag"
|
|
4
|
-
v-if="
|
|
4
|
+
v-if="direct"
|
|
5
|
+
:class="classes"
|
|
6
|
+
:style="styles"
|
|
7
|
+
></component>
|
|
8
|
+
|
|
9
|
+
<component
|
|
10
|
+
:is="tag"
|
|
11
|
+
v-else-if="showLoading"
|
|
5
12
|
>
|
|
6
13
|
<span
|
|
7
14
|
v-for="(element, index) in elements"
|
|
@@ -47,6 +54,9 @@ export default {
|
|
|
47
54
|
type: Boolean,
|
|
48
55
|
default: undefined,
|
|
49
56
|
},
|
|
57
|
+
direct: {
|
|
58
|
+
type: Boolean,
|
|
59
|
+
},
|
|
50
60
|
},
|
|
51
61
|
setup() {
|
|
52
62
|
const themeStyle = inject('_themeStyle', ref(SkeletonStyle));
|
|
@@ -58,11 +68,6 @@ export default {
|
|
|
58
68
|
};
|
|
59
69
|
},
|
|
60
70
|
computed: {
|
|
61
|
-
isLoading() {
|
|
62
|
-
return typeof this.theme.loading !== 'undefined'
|
|
63
|
-
? this.theme.loading
|
|
64
|
-
: this.loading;
|
|
65
|
-
},
|
|
66
71
|
classes() {
|
|
67
72
|
return [`${this.prefix}-skeleton`];
|
|
68
73
|
},
|
|
@@ -86,21 +91,22 @@ export default {
|
|
|
86
91
|
return elements;
|
|
87
92
|
},
|
|
88
93
|
showLoading() {
|
|
89
|
-
return typeof this.
|
|
90
|
-
? this.
|
|
94
|
+
return typeof this.loading !== 'undefined'
|
|
95
|
+
? this.loading
|
|
91
96
|
: this.isEmptyVNode(this.$slots.default);
|
|
92
97
|
},
|
|
93
98
|
},
|
|
94
99
|
methods: {
|
|
95
100
|
isEmptyVNode(children) {
|
|
96
101
|
if (!children) return true;
|
|
97
|
-
const [firstNode] = children;
|
|
98
|
-
let str = firstNode.
|
|
102
|
+
const [firstNode] = children();
|
|
103
|
+
let str = firstNode.children;
|
|
104
|
+
|
|
99
105
|
if (str) {
|
|
100
106
|
// remove all line-break and space character
|
|
101
107
|
str = str.replace(/(\n|\r\n|\s)/g, '');
|
|
102
108
|
}
|
|
103
|
-
return
|
|
109
|
+
return !str;
|
|
104
110
|
},
|
|
105
111
|
},
|
|
106
112
|
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { beforeEach, describe, expect, it } from 'vitest';
|
|
3
|
+
import SkeletonLoading from '../SkeletonLoading.vue';
|
|
4
|
+
|
|
5
|
+
function setup(options) {
|
|
6
|
+
return mount(SkeletonLoading, options);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
describe('SkeletonLoading', () => {
|
|
10
|
+
let wrapper;
|
|
11
|
+
|
|
12
|
+
describe('when the skeleton loading is a circle', () => {
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
wrapper = setup({
|
|
15
|
+
props: {
|
|
16
|
+
count: 1,
|
|
17
|
+
duration: 1.5,
|
|
18
|
+
tag: 'span',
|
|
19
|
+
width: '100px',
|
|
20
|
+
height: '100px',
|
|
21
|
+
circle: true,
|
|
22
|
+
loading: undefined,
|
|
23
|
+
direct: false,
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should have borderRadius', () => {
|
|
29
|
+
expect(wrapper.vm.styles.borderRadius).toBe('50%');
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('when the skeleton loading has not a duration', () => {
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
wrapper = setup({
|
|
36
|
+
props: {
|
|
37
|
+
count: 1,
|
|
38
|
+
duration: 0,
|
|
39
|
+
tag: 'span',
|
|
40
|
+
width: '100px',
|
|
41
|
+
height: '100px',
|
|
42
|
+
circle: false,
|
|
43
|
+
loading: undefined,
|
|
44
|
+
direct: false,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should not have the gradient background', () => {
|
|
50
|
+
expect(wrapper.vm.styles.backgroundImage).toBe('');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('when the default slot is provided and loading is undefined', () => {
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
wrapper = setup({
|
|
57
|
+
props: {
|
|
58
|
+
count: 1,
|
|
59
|
+
duration: 0,
|
|
60
|
+
tag: 'span',
|
|
61
|
+
width: '100px',
|
|
62
|
+
height: '100px',
|
|
63
|
+
circle: false,
|
|
64
|
+
loading: undefined,
|
|
65
|
+
direct: false,
|
|
66
|
+
},
|
|
67
|
+
slots: { default: 'Default slot' },
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should not show the skeleton loading', () => {
|
|
72
|
+
expect(wrapper.html()).toBe('<!--v-if-->');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('when the loading prop is provided', () => {
|
|
77
|
+
beforeEach(() => {
|
|
78
|
+
wrapper = setup({
|
|
79
|
+
props: {
|
|
80
|
+
count: 1,
|
|
81
|
+
duration: 0,
|
|
82
|
+
tag: 'span',
|
|
83
|
+
width: '100px',
|
|
84
|
+
height: '100px',
|
|
85
|
+
circle: false,
|
|
86
|
+
loading: true,
|
|
87
|
+
direct: false,
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('showLoading should be as same as the loading prop', async () => {
|
|
93
|
+
expect(wrapper.vm.showLoading).toBeTruthy();
|
|
94
|
+
|
|
95
|
+
await wrapper.setProps({
|
|
96
|
+
loading: false,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
expect(wrapper.vm.showLoading).toBeFalsy();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('when the direct', () => {
|
|
104
|
+
beforeEach(() => {
|
|
105
|
+
wrapper = setup({
|
|
106
|
+
props: {
|
|
107
|
+
count: 1,
|
|
108
|
+
duration: 0,
|
|
109
|
+
tag: 'span',
|
|
110
|
+
width: '100px',
|
|
111
|
+
height: '100px',
|
|
112
|
+
circle: false,
|
|
113
|
+
loading: true,
|
|
114
|
+
direct: true,
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('renders the skeleton loading directly on the component', async () => {
|
|
120
|
+
expect(wrapper.html()).toBe(
|
|
121
|
+
'<span class="unnnic-skeleton" style="background-color: rgb(232, 244, 244); width: 100px; height: 100px;"></span>',
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|