@mozaic-ds/vue 1.0.0-rc.2 → 2.1.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/LICENSE +51 -0
- package/README.md +76 -77
- package/dist/mozaic-vue.css +1 -1
- package/dist/mozaic-vue.d.ts +1664 -0
- package/dist/mozaic-vue.js +1943 -0
- package/dist/mozaic-vue.js.map +1 -0
- package/dist/mozaic-vue.umd.cjs +2 -0
- package/dist/mozaic-vue.umd.cjs.map +1 -0
- package/env.d.ts +1 -0
- package/package.json +78 -51
- package/src/components/Contributing.mdx +118 -0
- package/src/components/GettingStarted.mdx +45 -0
- package/src/components/Introduction.mdx +100 -0
- package/src/components/Support.mdx +18 -0
- package/src/components/breadcrumb/MBreadcrumb.spec.ts +105 -0
- package/src/components/breadcrumb/MBreadcrumb.stories.ts +82 -0
- package/src/components/breadcrumb/MBreadcrumb.vue +52 -55
- package/src/components/button/MButton.spec.ts +191 -0
- package/src/components/button/MButton.stories.ts +59 -0
- package/src/components/button/MButton.vue +98 -154
- package/src/components/checkbox/MCheckbox.spec.ts +104 -0
- package/src/components/checkbox/MCheckbox.stories.ts +83 -0
- package/src/components/checkbox/MCheckbox.vue +60 -101
- package/src/components/checkboxgroup/MCheckboxGroup.spec.ts +78 -0
- package/src/components/checkboxgroup/MCheckboxGroup.stories.ts +61 -0
- package/src/components/checkboxgroup/MCheckboxGroup.vue +97 -0
- package/src/components/datepicker/MDatepicker.spec.ts +95 -0
- package/src/components/datepicker/MDatepicker.stories.ts +75 -0
- package/src/components/datepicker/MDatepicker.vue +114 -0
- package/src/components/divider/MDivider.spec.ts +57 -0
- package/src/components/divider/MDivider.stories.ts +64 -0
- package/src/components/divider/MDivider.vue +56 -0
- package/src/components/drawer/MDrawer.spec.ts +100 -0
- package/src/components/drawer/MDrawer.stories.ts +128 -0
- package/src/components/drawer/MDrawer.vue +140 -0
- package/src/components/field/MField.spec.ts +166 -0
- package/src/components/field/MField.stories.ts +369 -0
- package/src/components/field/MField.vue +78 -61
- package/src/components/fieldgroup/MFieldGroup.spec.ts +165 -0
- package/src/components/fieldgroup/MFieldGroup.stories.ts +416 -0
- package/src/components/fieldgroup/MFieldGroup.vue +79 -0
- package/src/components/flag/MFlag.spec.ts +46 -0
- package/src/components/flag/MFlag.stories.ts +46 -0
- package/src/components/flag/MFlag.vue +28 -39
- package/src/components/iconbutton/MIconButton.spec.ts +108 -0
- package/src/components/iconbutton/MIconButton.stories.ts +74 -0
- package/src/components/iconbutton/MIconButton.vue +73 -0
- package/src/components/link/MLink.spec.ts +154 -0
- package/src/components/link/MLink.stories.ts +89 -0
- package/src/components/link/MLink.vue +86 -120
- package/src/components/loader/MLoader.spec.ts +104 -0
- package/src/components/loader/MLoader.stories.ts +43 -0
- package/src/components/loader/MLoader.vue +66 -55
- package/src/components/loadingoverlay/MLoadingOverlay.spec.ts +37 -0
- package/src/components/loadingoverlay/MLoadingOverlay.stories.ts +40 -0
- package/src/components/loadingoverlay/MLoadingOverlay.vue +28 -0
- package/src/components/modal/MModal.spec.ts +103 -0
- package/src/components/modal/MModal.stories.ts +127 -0
- package/src/components/modal/MModal.vue +106 -154
- package/src/components/numberbadge/MNumberBadge.spec.ts +56 -0
- package/src/components/numberbadge/MNumberBadge.stories.ts +48 -0
- package/src/components/numberbadge/MNumberBadge.vue +45 -0
- package/src/components/overlay/MOverlay.spec.ts +51 -0
- package/src/components/overlay/MOverlay.stories.ts +35 -0
- package/src/components/overlay/MOverlay.vue +27 -19
- package/src/components/pagination/MPagination.spec.ts +123 -0
- package/src/components/pagination/MPagination.stories.ts +83 -0
- package/src/components/pagination/MPagination.vue +120 -140
- package/src/components/passwordinput/MPasswordInput.spec.ts +104 -0
- package/src/components/passwordinput/MPasswordInput.stories.ts +75 -0
- package/src/components/passwordinput/MPasswordInput.vue +126 -77
- package/src/components/pincode/MPincode.spec.ts +126 -0
- package/src/components/pincode/MPincode.stories.ts +68 -0
- package/src/components/pincode/MPincode.vue +148 -0
- package/src/components/quantityselector/MQuantitySelector.spec.ts +262 -0
- package/src/components/quantityselector/MQuantitySelector.stories.ts +89 -0
- package/src/components/quantityselector/MQuantitySelector.vue +159 -148
- package/src/components/radio/MRadio.spec.ts +104 -0
- package/src/components/radio/MRadio.stories.ts +68 -0
- package/src/components/radio/MRadio.vue +56 -39
- package/src/components/radiogroup/MRadioGroup.spec.ts +54 -0
- package/src/components/radiogroup/MRadioGroup.stories.ts +61 -0
- package/src/components/radiogroup/MRadioGroup.vue +79 -0
- package/src/components/select/MSelect.spec.ts +114 -0
- package/src/components/select/MSelect.stories.ts +101 -0
- package/src/components/select/MSelect.vue +77 -119
- package/src/components/statusbadge/MStatusBadge.stories.ts +45 -0
- package/src/components/statusbadge/MStatusBadge.vue +40 -0
- package/src/components/statusbadge/MstatusBadge.spec.ts +16 -0
- package/src/components/statusdot/MStatusDot.spec.ts +51 -0
- package/src/components/statusdot/MStatusDot.stories.ts +48 -0
- package/src/components/statusdot/MStatusDot.vue +36 -0
- package/src/components/statusnotification/MStatusNotification.spec.ts +103 -0
- package/src/components/statusnotification/MStatusNotification.stories.ts +89 -0
- package/src/components/statusnotification/MStatusNotification.vue +106 -0
- package/src/components/tabs/MTabs.stories.ts +104 -0
- package/src/components/tabs/MTabs.vue +113 -0
- package/src/components/tabs/Mtabs.spec.ts +149 -0
- package/src/components/tag/MTag.spec.ts +107 -0
- package/src/components/tag/MTag.stories.ts +75 -0
- package/src/components/tag/MTag.vue +151 -0
- package/src/components/textarea/MTextArea.spec.ts +112 -0
- package/src/components/textarea/MTextArea.stories.ts +67 -0
- package/src/components/textarea/MTextArea.vue +81 -43
- package/src/components/textinput/MTextInput.spec.ts +121 -0
- package/src/components/textinput/MTextInput.stories.ts +107 -0
- package/src/components/textinput/MTextInput.vue +127 -47
- package/src/components/toggle/MToggle.spec.ts +99 -0
- package/src/components/toggle/MToggle.stories.ts +68 -0
- package/src/components/toggle/MToggle.vue +63 -103
- package/src/components/togglegroup/MToggleGroup.spec.ts +78 -0
- package/src/components/togglegroup/MToggleGroup.stories.ts +61 -0
- package/src/components/togglegroup/MToggleGroup.vue +97 -0
- package/src/components/usingIcons.mdx +35 -0
- package/src/components/usingPresets.mdx +128 -0
- package/src/main.ts +32 -0
- package/dist/demo.html +0 -1
- package/dist/mozaic-vue.adeo.css +0 -47
- package/dist/mozaic-vue.adeo.umd.js +0 -31109
- package/dist/mozaic-vue.common.js +0 -31099
- package/dist/mozaic-vue.common.js.map +0 -1
- package/dist/mozaic-vue.umd.js +0 -31110
- package/dist/mozaic-vue.umd.js.map +0 -1
- package/dist/mozaic-vue.umd.min.js +0 -4
- package/dist/mozaic-vue.umd.min.js.map +0 -1
- package/postinstall.js +0 -3
- package/src/components/accordion/MAccordion.vue +0 -128
- package/src/components/accordion/index.js +0 -7
- package/src/components/autocomplete/MAutocomplete.vue +0 -381
- package/src/components/autocomplete/index.js +0 -7
- package/src/components/badge/MBadge.vue +0 -43
- package/src/components/badge/index.js +0 -7
- package/src/components/breadcrumb/index.js +0 -7
- package/src/components/button/index.js +0 -7
- package/src/components/card/MCard.vue +0 -78
- package/src/components/card/index.js +0 -7
- package/src/components/checkbox/MCheckboxGroup.vue +0 -163
- package/src/components/checkbox/index.js +0 -12
- package/src/components/container/MContainer.vue +0 -33
- package/src/components/container/index.js +0 -7
- package/src/components/datatable/MDataTable.vue +0 -651
- package/src/components/datatable/MDataTableHeader.vue +0 -55
- package/src/components/datatable/MDataTableTop.vue +0 -35
- package/src/components/datatable/helpers.js +0 -132
- package/src/components/datatable/index.js +0 -12
- package/src/components/dropdown/MDropdown.vue +0 -317
- package/src/components/dropdown/index.js +0 -7
- package/src/components/field/index.js +0 -7
- package/src/components/fileuploader/MFileResult.vue +0 -149
- package/src/components/fileuploader/MFileUploader.vue +0 -142
- package/src/components/fileuploader/index.js +0 -7
- package/src/components/flag/index.js +0 -7
- package/src/components/heading/MHeading.vue +0 -75
- package/src/components/heading/index.js +0 -7
- package/src/components/hero/MHero.vue +0 -93
- package/src/components/hero/index.js +0 -7
- package/src/components/icon/MIcon.vue +0 -136
- package/src/components/icon/index.js +0 -7
- package/src/components/index.js +0 -44
- package/src/components/layer/MLayer.vue +0 -208
- package/src/components/layer/index.js +0 -7
- package/src/components/link/index.js +0 -7
- package/src/components/listbox/MListBox.vue +0 -146
- package/src/components/listbox/MListBoxActions.vue +0 -251
- package/src/components/listbox/index.js +0 -12
- package/src/components/loader/index.js +0 -7
- package/src/components/modal/index.js +0 -7
- package/src/components/notification/MNotification.vue +0 -110
- package/src/components/notification/index.js +0 -7
- package/src/components/optionbutton/MOptionButton.vue +0 -67
- package/src/components/optionbutton/index.js +0 -7
- package/src/components/optioncard/MOptionCard.vue +0 -132
- package/src/components/optioncard/index.js +0 -7
- package/src/components/optiongroup/MOptionGroup.vue +0 -18
- package/src/components/optiongroup/index.js +0 -7
- package/src/components/overlay/MOverlayLoader.vue +0 -43
- package/src/components/overlay/index.js +0 -12
- package/src/components/pagination/index.js +0 -7
- package/src/components/passwordinput/index.js +0 -7
- package/src/components/phonenumber/MPhoneNumber.vue +0 -398
- package/src/components/phonenumber/index.js +0 -7
- package/src/components/progressbar/MProgress.vue +0 -102
- package/src/components/progressbar/index.js +0 -7
- package/src/components/quantityselector/index.js +0 -7
- package/src/components/radio/MRadioGroup.vue +0 -111
- package/src/components/radio/index.js +0 -12
- package/src/components/ratingstars/MStarsInput.vue +0 -119
- package/src/components/ratingstars/MStarsResult.vue +0 -89
- package/src/components/ratingstars/index.js +0 -12
- package/src/components/select/index.js +0 -7
- package/src/components/stepper/MStepper.vue +0 -111
- package/src/components/stepper/index.js +0 -7
- package/src/components/tabs/MTab.vue +0 -198
- package/src/components/tabs/index.js +0 -7
- package/src/components/tags/MTag.vue +0 -173
- package/src/components/tags/index.js +0 -7
- package/src/components/textarea/index.js +0 -7
- package/src/components/textinput/MTextInputField.vue +0 -105
- package/src/components/textinput/MTextInputIcon.vue +0 -42
- package/src/components/textinput/index.js +0 -7
- package/src/components/toggle/index.js +0 -7
- package/src/components/tooltip/MTooltip.vue +0 -42
- package/src/components/tooltip/index.js +0 -7
- package/src/index.js +0 -63
- package/src/shims-tsx.d.ts +0 -13
- package/src/shims.vue.d.ts +0 -4
- package/src/tokens/adeo/android/colors.xml +0 -448
- package/src/tokens/adeo/android/font_dimens.xml +0 -18
- package/src/tokens/adeo/css/_variables.scss +0 -442
- package/src/tokens/adeo/css/root.scss +0 -444
- package/src/tokens/adeo/ios/StyleDictionaryColor.h +0 -456
- package/src/tokens/adeo/ios/StyleDictionaryColor.m +0 -468
- package/src/tokens/adeo/ios/StyleDictionaryColor.swift +0 -451
- package/src/tokens/adeo/ios/StyleDictionarySize.h +0 -69
- package/src/tokens/adeo/ios/StyleDictionarySize.m +0 -70
- package/src/tokens/adeo/ios/StyleDictionarySize.swift +0 -71
- package/src/tokens/adeo/js/tokens.js +0 -540
- package/src/tokens/adeo/js/tokensObject.js +0 -11641
- package/src/tokens/adeo/scss/_tokens.scss +0 -1514
- package/src/utils/mozaicClasses.js +0 -16
- package/src/utils/theme.validator.js +0 -19
- package/types/index.d.ts +0 -104
|
@@ -1,133 +1,99 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<component
|
|
3
|
-
:is="
|
|
4
|
-
v-bind="linkComponentProps"
|
|
5
|
-
:href="router ? null : href && !disabled ? href : null"
|
|
3
|
+
:is="router ? 'router-link' : 'a'"
|
|
6
4
|
class="mc-link"
|
|
7
|
-
:class="
|
|
8
|
-
|
|
5
|
+
:class="classObject"
|
|
6
|
+
:href="href"
|
|
7
|
+
:target="target"
|
|
8
|
+
:to="router ? href : undefined"
|
|
9
9
|
>
|
|
10
|
-
<
|
|
11
|
-
v-if="icon && iconPosition
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
10
|
+
<span
|
|
11
|
+
v-if="$slots.icon && iconPosition == 'left'"
|
|
12
|
+
class="mc-link__icon"
|
|
13
|
+
aria-hidden="true"
|
|
14
|
+
>
|
|
15
|
+
<slot name="icon" />
|
|
16
|
+
</span>
|
|
17
|
+
<span class="mc-link__label">
|
|
18
|
+
<slot />
|
|
19
|
+
</span>
|
|
20
|
+
<span
|
|
21
|
+
v-if="$slots.icon && iconPosition == 'right'"
|
|
22
|
+
class="mc-link__icon"
|
|
23
|
+
aria-hidden="true"
|
|
24
|
+
>
|
|
25
|
+
<slot name="icon" />
|
|
26
|
+
</span>
|
|
21
27
|
</component>
|
|
22
28
|
</template>
|
|
23
29
|
|
|
24
|
-
<script>
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
<script setup lang="ts">
|
|
31
|
+
import { computed, type VNode } from 'vue';
|
|
32
|
+
/**
|
|
33
|
+
* A link is a component used exclusively to navigate to internal or external webpages or to anchors in the current page.
|
|
34
|
+
*/
|
|
35
|
+
const props = withDefaults(
|
|
36
|
+
defineProps<{
|
|
37
|
+
/**
|
|
38
|
+
* Position of the icon relative to the text.
|
|
39
|
+
*/
|
|
40
|
+
iconPosition?: 'left' | 'right';
|
|
41
|
+
/**
|
|
42
|
+
* Allows to define the link style
|
|
43
|
+
*/
|
|
44
|
+
appearance?: 'secondary' | 'accent' | 'inverse' | 'standard';
|
|
45
|
+
/**
|
|
46
|
+
* Allows to define the link size
|
|
47
|
+
*/
|
|
48
|
+
size?: 's' | 'm';
|
|
49
|
+
/**
|
|
50
|
+
* URL for the link (for external links or the `to` prop for `router-link`).
|
|
51
|
+
*/
|
|
52
|
+
href?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Where to open the link
|
|
55
|
+
*/
|
|
56
|
+
target?: '_self' | '_blank' | '_parent' | '_top';
|
|
57
|
+
/**
|
|
58
|
+
* Specify wether the link is inline
|
|
59
|
+
*/
|
|
60
|
+
inline?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* If `true`, the link will be rendered as a `router-link` for internal navigation (Vue Router).
|
|
63
|
+
*/
|
|
64
|
+
router?: boolean;
|
|
65
|
+
}>(),
|
|
66
|
+
{
|
|
67
|
+
href: undefined,
|
|
68
|
+
target: undefined,
|
|
69
|
+
appearance: 'standard',
|
|
70
|
+
size: 's',
|
|
71
|
+
iconPosition: 'left',
|
|
37
72
|
},
|
|
73
|
+
);
|
|
38
74
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
type: String,
|
|
50
|
-
default: null,
|
|
51
|
-
validator: (value) => checkThemeValue(value),
|
|
52
|
-
},
|
|
53
|
-
size: {
|
|
54
|
-
type: String,
|
|
55
|
-
default: 'm',
|
|
56
|
-
validator: (value) => responsiveModifierValidators(value, ['s', 'm']),
|
|
57
|
-
},
|
|
58
|
-
// Experimental solution waiting on this issue https://github.com/adeo/mozaic-vue/issues/52
|
|
59
|
-
responsiveSizeModifiers: {
|
|
60
|
-
type: Array,
|
|
61
|
-
default: null,
|
|
62
|
-
validator: (array) =>
|
|
63
|
-
array.every((e) =>
|
|
64
|
-
responsiveModifierValidators(e, [
|
|
65
|
-
's@from-m',
|
|
66
|
-
's@from-l',
|
|
67
|
-
's@from-xl',
|
|
68
|
-
's@from-xxl',
|
|
69
|
-
'm@from-m',
|
|
70
|
-
'm@from-l',
|
|
71
|
-
'm@from-xl',
|
|
72
|
-
'm@from-xxl',
|
|
73
|
-
])
|
|
74
|
-
),
|
|
75
|
-
},
|
|
76
|
-
icon: {
|
|
77
|
-
type: String,
|
|
78
|
-
default: null,
|
|
79
|
-
},
|
|
80
|
-
iconPosition: {
|
|
81
|
-
type: String,
|
|
82
|
-
default: 'left',
|
|
83
|
-
validator: (value) => ['left', 'right'].includes(value),
|
|
84
|
-
},
|
|
85
|
-
disabled: {
|
|
86
|
-
type: Boolean,
|
|
87
|
-
default: false,
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
computed: {
|
|
92
|
-
setClasses() {
|
|
93
|
-
const classes = [];
|
|
94
|
-
|
|
95
|
-
if (this.theme) {
|
|
96
|
-
classes.push(`mc-link--${this.theme}`);
|
|
97
|
-
}
|
|
75
|
+
defineSlots<{
|
|
76
|
+
/**
|
|
77
|
+
* Use this slot to insert the textual content of the Link
|
|
78
|
+
*/
|
|
79
|
+
default: string;
|
|
80
|
+
/**
|
|
81
|
+
* Use this slot to insert an icon for the Link
|
|
82
|
+
*/
|
|
83
|
+
icon?: VNode;
|
|
84
|
+
}>();
|
|
98
85
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
},
|
|
109
|
-
linkComponentName() {
|
|
110
|
-
const isLinkValid = this.href && !this.disabled;
|
|
111
|
-
const routerComponent = this.router?.name ?? null;
|
|
112
|
-
const defaultComponent = isLinkValid ? 'a' : 'span';
|
|
113
|
-
|
|
114
|
-
return routerComponent ?? defaultComponent;
|
|
115
|
-
},
|
|
116
|
-
linkComponentProps() {
|
|
117
|
-
return this.router?.props ?? {};
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
methods: {
|
|
121
|
-
onClick(event) {
|
|
122
|
-
if (!this.disabled) {
|
|
123
|
-
this.$emit('click', event);
|
|
124
|
-
}
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
};
|
|
86
|
+
const classObject = computed(() => {
|
|
87
|
+
return {
|
|
88
|
+
[`mc-link--${props.appearance}`]:
|
|
89
|
+
props.appearance && props.appearance != 'standard',
|
|
90
|
+
[`mc-link--${props.size}`]: props.size && props.size != 's',
|
|
91
|
+
'mc-link--inline': props.inline,
|
|
92
|
+
'mc-link--stand-alone': !props.inline,
|
|
93
|
+
};
|
|
94
|
+
});
|
|
128
95
|
</script>
|
|
129
96
|
|
|
130
|
-
<style lang="scss">
|
|
131
|
-
@
|
|
132
|
-
@import 'components/c.links';
|
|
97
|
+
<style lang="scss" scoped>
|
|
98
|
+
@use '@mozaic-ds/styles/components/link';
|
|
133
99
|
</style>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import MLoader from './MLoader.vue';
|
|
4
|
+
|
|
5
|
+
describe('MLoader component', () => {
|
|
6
|
+
it('should render correctly with the given props', () => {
|
|
7
|
+
const wrapper = mount(MLoader, {
|
|
8
|
+
props: {
|
|
9
|
+
size: 's',
|
|
10
|
+
appearance: 'accent',
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
expect(wrapper.exists()).toBe(true);
|
|
15
|
+
|
|
16
|
+
const loaderElement = wrapper.find('.mc-loader');
|
|
17
|
+
expect(loaderElement.exists()).toBe(true);
|
|
18
|
+
expect(loaderElement.classes()).toContain('mc-loader--s');
|
|
19
|
+
expect(loaderElement.classes()).toContain('mc-loader--accent');
|
|
20
|
+
|
|
21
|
+
const svg = wrapper.find('svg.mc-loader__icon');
|
|
22
|
+
expect(svg.exists()).toBe(true);
|
|
23
|
+
|
|
24
|
+
const circle = wrapper.find('circle.mc-loader__path');
|
|
25
|
+
expect(circle.exists()).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('changes class based on size prop', async () => {
|
|
29
|
+
const wrapper = mount(MLoader, {
|
|
30
|
+
props: {
|
|
31
|
+
size: 's',
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
let loader = wrapper.find('.mc-loader');
|
|
36
|
+
expect(loader.classes()).toContain('mc-loader--s');
|
|
37
|
+
|
|
38
|
+
await wrapper.setProps({ size: 'l' });
|
|
39
|
+
loader = wrapper.find('.mc-loader');
|
|
40
|
+
expect(loader.classes()).toContain('mc-loader--l');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('changes class based on appearance prop', async () => {
|
|
44
|
+
const wrapper = mount(MLoader, {
|
|
45
|
+
props: {
|
|
46
|
+
appearance: 'accent',
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
let loader = wrapper.find('.mc-loader');
|
|
51
|
+
expect(loader.classes()).toContain('mc-loader--accent');
|
|
52
|
+
|
|
53
|
+
await wrapper.setProps({ appearance: 'inverse' });
|
|
54
|
+
loader = wrapper.find('.mc-loader');
|
|
55
|
+
expect(loader.classes()).toContain('mc-loader--inverse');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('renders the loader text when text prop is provided', () => {
|
|
59
|
+
const wrapper = mount(MLoader, {
|
|
60
|
+
props: {
|
|
61
|
+
text: 'Loading...',
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const textElement = wrapper.find('.mc-loader__text');
|
|
66
|
+
expect(textElement.exists()).toBe(true);
|
|
67
|
+
expect(textElement.text()).toBe('Loading...');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('does not render the loader text when text prop is not provided', () => {
|
|
71
|
+
const wrapper = mount(MLoader);
|
|
72
|
+
|
|
73
|
+
const textElement = wrapper.find('.mc-loader__text');
|
|
74
|
+
expect(textElement.exists()).toBe(false);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('sets the correct viewBox based on size prop', async () => {
|
|
78
|
+
const wrapper = mount(MLoader, {
|
|
79
|
+
props: {
|
|
80
|
+
size: 's',
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const svg = wrapper.find('svg.mc-loader__icon');
|
|
85
|
+
expect(svg.attributes('viewBox')).toBe('0 0 24 24');
|
|
86
|
+
|
|
87
|
+
await wrapper.setProps({ size: 'l' });
|
|
88
|
+
expect(svg.attributes('viewBox')).toBe('0 0 64 64');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('sets the correct circle radius based on size prop', async () => {
|
|
92
|
+
const wrapper = mount(MLoader, {
|
|
93
|
+
props: {
|
|
94
|
+
size: 's',
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const circle = wrapper.find('circle.mc-loader__path');
|
|
99
|
+
expect(circle.attributes('r')).toBe('6');
|
|
100
|
+
|
|
101
|
+
await wrapper.setProps({ size: 'l' });
|
|
102
|
+
expect(circle.attributes('r')).toBe('19');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
import MLoader from './MLoader.vue';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof MLoader> = {
|
|
5
|
+
title: 'Indicators/Loader',
|
|
6
|
+
component: MLoader,
|
|
7
|
+
parameters: {
|
|
8
|
+
docs: {
|
|
9
|
+
description: {
|
|
10
|
+
component:
|
|
11
|
+
'A loader is a visual indicator used to inform users that a process is in progress, typically during data fetching, page loading, or background operations. It provides feedback that the system is working, helping to manage user expectations and reduce perceived wait time.',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
render: (args) => ({
|
|
16
|
+
components: { MLoader },
|
|
17
|
+
setup() {
|
|
18
|
+
return { args };
|
|
19
|
+
},
|
|
20
|
+
template: `
|
|
21
|
+
<MLoader v-bind="args"></MLoader>
|
|
22
|
+
`,
|
|
23
|
+
}),
|
|
24
|
+
};
|
|
25
|
+
export default meta;
|
|
26
|
+
type Story = StoryObj<typeof MLoader>;
|
|
27
|
+
|
|
28
|
+
export const Standard: Story = {};
|
|
29
|
+
|
|
30
|
+
export const Accent: Story = {
|
|
31
|
+
args: { appearance: 'accent' },
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const Inverse: Story = {
|
|
35
|
+
globals: {
|
|
36
|
+
backgrounds: { value: 'inverse' },
|
|
37
|
+
},
|
|
38
|
+
args: { appearance: 'inverse' },
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const Size: Story = {
|
|
42
|
+
args: { size: 's' },
|
|
43
|
+
};
|
|
@@ -1,84 +1,95 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="mc-loader" :class="
|
|
2
|
+
<div class="mc-loader" :class="classObject">
|
|
3
3
|
<span class="mc-loader__spinner">
|
|
4
4
|
<svg
|
|
5
5
|
class="mc-loader__icon"
|
|
6
6
|
xmlns="http://www.w3.org/2000/svg"
|
|
7
|
-
:viewBox="
|
|
7
|
+
:viewBox="setViewBox"
|
|
8
|
+
aria-hidden="true"
|
|
8
9
|
>
|
|
9
|
-
<circle
|
|
10
|
+
<circle
|
|
11
|
+
class="mc-loader__path"
|
|
12
|
+
cx="50%"
|
|
13
|
+
cy="50%"
|
|
14
|
+
:r="setCircleRadius"
|
|
15
|
+
></circle>
|
|
10
16
|
</svg>
|
|
11
17
|
</span>
|
|
12
|
-
|
|
13
|
-
<span v-if="text" class="mc-loader__text">{{ text }}</span>
|
|
18
|
+
<p v-if="text" class="mc-loader__text" role="status">{{ text }}</p>
|
|
14
19
|
</div>
|
|
15
20
|
</template>
|
|
16
21
|
|
|
17
|
-
<script>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
<script setup lang="ts">
|
|
23
|
+
import { computed } from 'vue';
|
|
24
|
+
/**
|
|
25
|
+
* A loader indicates that content or data is being loaded or processed, providing visual feedback to users during wait times.
|
|
26
|
+
*/
|
|
27
|
+
const props = withDefaults(
|
|
28
|
+
defineProps<{
|
|
22
29
|
/**
|
|
23
|
-
*
|
|
24
|
-
* @values s, m , l
|
|
30
|
+
* Specifies the visual appearance of the loader.
|
|
25
31
|
*/
|
|
26
|
-
|
|
27
|
-
type: String,
|
|
28
|
-
default: 'm',
|
|
29
|
-
validator: (value) => ['s', 'm', 'l'].includes(value),
|
|
30
|
-
},
|
|
32
|
+
appearance?: 'standard' | 'accent' | 'inverse';
|
|
31
33
|
|
|
32
34
|
/**
|
|
33
|
-
*
|
|
34
|
-
* @values dark, light, primary
|
|
35
|
+
* Defines the size of the loader.
|
|
35
36
|
*/
|
|
36
|
-
|
|
37
|
-
type: String,
|
|
38
|
-
default: 'primary',
|
|
39
|
-
validator: (value) => ['dark', 'light', 'primary'].includes(value),
|
|
40
|
-
},
|
|
37
|
+
size?: 's' | 'm' | 'l';
|
|
41
38
|
|
|
42
39
|
/**
|
|
43
|
-
*
|
|
40
|
+
* Text to display alongside the loader when using the loader inside an `Overlay`.
|
|
44
41
|
*/
|
|
45
|
-
text
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
text?: string;
|
|
43
|
+
}>(),
|
|
44
|
+
{
|
|
45
|
+
appearance: 'standard',
|
|
46
|
+
size: 'm',
|
|
49
47
|
},
|
|
48
|
+
);
|
|
50
49
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
const classObject = computed(() => {
|
|
51
|
+
return {
|
|
52
|
+
[`mc-loader--${props.size}`]: props.size && props.size !== 'm',
|
|
53
|
+
[`mc-loader--${props.appearance}`]:
|
|
54
|
+
props.appearance && props.appearance !== 'standard',
|
|
55
|
+
'mc-loader--text-visible': props.text,
|
|
56
|
+
};
|
|
57
|
+
});
|
|
54
58
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
59
|
+
const setViewBox = computed(() => {
|
|
60
|
+
let viewBox: string;
|
|
58
61
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
switch (props.size) {
|
|
63
|
+
case 's':
|
|
64
|
+
viewBox = '0 0 24 24';
|
|
65
|
+
break;
|
|
66
|
+
case 'l':
|
|
67
|
+
viewBox = '0 0 64 64';
|
|
68
|
+
break;
|
|
69
|
+
default:
|
|
70
|
+
viewBox = '0 0 32 32';
|
|
71
|
+
}
|
|
72
|
+
return viewBox;
|
|
73
|
+
});
|
|
62
74
|
|
|
63
|
-
|
|
64
|
-
|
|
75
|
+
const setCircleRadius = computed(() => {
|
|
76
|
+
let circleRadius: number;
|
|
65
77
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
78
|
+
switch (props.size) {
|
|
79
|
+
case 's':
|
|
80
|
+
circleRadius = 6;
|
|
81
|
+
break;
|
|
82
|
+
case 'l':
|
|
83
|
+
circleRadius = 19;
|
|
84
|
+
break;
|
|
85
|
+
default:
|
|
86
|
+
circleRadius = 9;
|
|
87
|
+
}
|
|
73
88
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
|
-
};
|
|
89
|
+
return circleRadius;
|
|
90
|
+
});
|
|
79
91
|
</script>
|
|
80
92
|
|
|
81
|
-
<style lang="scss">
|
|
82
|
-
@
|
|
83
|
-
@import 'components/c.loader';
|
|
93
|
+
<style lang="scss" scoped>
|
|
94
|
+
@use '@mozaic-ds/styles/components/loader';
|
|
84
95
|
</style>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { mount } from '@vue/test-utils';
|
|
3
|
+
import MLoadingOverlay from './MLoadingOverlay.vue';
|
|
4
|
+
|
|
5
|
+
describe('MLoadingOverlay component', () => {
|
|
6
|
+
it('renders and applies isVisible class based on prop', () => {
|
|
7
|
+
const wrapper = mount(MLoadingOverlay, {
|
|
8
|
+
props: { isVisible: true, text: 'Loading data...' },
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
expect(wrapper.classes()).toContain('is-visible');
|
|
12
|
+
|
|
13
|
+
const dialog = wrapper.find('[role="dialog"]');
|
|
14
|
+
expect(dialog.attributes('aria-label')).toBe('Loading data...');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('does not have is-visible class when isVisible is false or undefined', () => {
|
|
18
|
+
const wrapper = mount(MLoadingOverlay, {
|
|
19
|
+
props: { isVisible: false },
|
|
20
|
+
});
|
|
21
|
+
expect(wrapper.classes()).not.toContain('is-visible');
|
|
22
|
+
|
|
23
|
+
const wrapperNoProp = mount(MLoadingOverlay);
|
|
24
|
+
expect(wrapperNoProp.classes()).not.toContain('is-visible');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('passes down attributes via $attrs', () => {
|
|
28
|
+
const wrapper = mount(MLoadingOverlay, {
|
|
29
|
+
props: { isVisible: true, text: 'Loading...' },
|
|
30
|
+
attrs: { id: 'custom-id', 'data-test': 'loading-overlay' },
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const dialog = wrapper.find('[role="dialog"]');
|
|
34
|
+
expect(dialog.attributes('id')).toBe('custom-id');
|
|
35
|
+
expect(dialog.attributes('data-test')).toBe('loading-overlay');
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
import MLoadingOverlay from './MLoadingOverlay.vue';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof MLoadingOverlay> = {
|
|
5
|
+
title: 'Overlay/Loading Overlay',
|
|
6
|
+
component: MLoadingOverlay,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'fullscreen',
|
|
9
|
+
docs: {
|
|
10
|
+
story: { height: '400px' },
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
'An overlay component is a UI element that appears above the main content to display additional information or interactions, often blocking or dimming the background.',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
args: {
|
|
18
|
+
isVisible: true,
|
|
19
|
+
ariaLabel: 'Page loading',
|
|
20
|
+
},
|
|
21
|
+
render: (args) => ({
|
|
22
|
+
components: { MLoadingOverlay },
|
|
23
|
+
setup() {
|
|
24
|
+
return { args };
|
|
25
|
+
},
|
|
26
|
+
template: `
|
|
27
|
+
<MLoadingOverlay v-bind="args"/>
|
|
28
|
+
`,
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
export default meta;
|
|
32
|
+
type Story = StoryObj<typeof MLoadingOverlay>;
|
|
33
|
+
|
|
34
|
+
export const Default: Story = {};
|
|
35
|
+
|
|
36
|
+
export const text: Story = {
|
|
37
|
+
args: {
|
|
38
|
+
text: 'Insert your text here',
|
|
39
|
+
},
|
|
40
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="mc-loading-loader" :class="{ 'is-visible': isVisible }">
|
|
3
|
+
<div role="dialog" tabindex="-1" :aria-label="text" v-bind="$attrs">
|
|
4
|
+
<MLoader size="l" appearance="inverse" :text="text" />
|
|
5
|
+
</div>
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script setup lang="ts">
|
|
10
|
+
import MLoader from '../loader/MLoader.vue';
|
|
11
|
+
/**
|
|
12
|
+
* A loading overlay is a full-screen or container-level layer that indicates a process is in progress, preventing user interaction until the task is completed. It includes a progress indicator, and a message to inform users about the loading state. Loading Overlays are commonly used in data-heavy applications, form submissions, and page transitions to enhance user experience by managing wait times effectively.
|
|
13
|
+
*/
|
|
14
|
+
defineProps<{
|
|
15
|
+
/**
|
|
16
|
+
* Controls the visibility of the loading overlay.
|
|
17
|
+
*/
|
|
18
|
+
isVisible?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Text of the loading overlay.
|
|
21
|
+
*/
|
|
22
|
+
text?: string;
|
|
23
|
+
}>();
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<style lang="scss" scoped>
|
|
27
|
+
@use '@mozaic-ds/styles/components/loading-overlay';
|
|
28
|
+
</style>
|