@mozaic-ds/vue 1.0.0-beta.3 → 1.0.0-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.
- package/LICENSE +51 -0
- package/README.md +224 -82
- package/dist/mozaic-vue.css +1 -1
- package/dist/mozaic-vue.d.ts +1202 -0
- package/dist/mozaic-vue.js +1220 -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 +81 -50
- package/src/components/Contributing.mdx +118 -0
- package/src/components/GettingStarted.mdx +50 -0
- package/src/components/Introduction.mdx +54 -0
- package/src/components/Support.mdx +18 -0
- package/src/components/badge/MBadge.spec.ts +16 -0
- package/src/components/badge/MBadge.stories.ts +50 -0
- package/src/components/badge/MBadge.vue +36 -34
- package/src/components/breadcrumb/MBreadcrumb.spec.ts +105 -0
- package/src/components/breadcrumb/MBreadcrumb.stories.ts +57 -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 +66 -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/field/MField.spec.ts +166 -0
- package/src/components/field/MField.stories.ts +376 -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 +423 -0
- package/src/components/fieldgroup/MFieldGroup.vue +79 -0
- package/src/components/iconbutton/MIconButton.spec.ts +108 -0
- package/src/components/iconbutton/MIconButton.stories.ts +66 -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 +98 -0
- package/src/components/link/MLink.vue +86 -109
- package/src/components/loader/MLoader.spec.ts +104 -0
- package/src/components/loader/MLoader.stories.ts +45 -0
- package/src/components/loader/MLoader.vue +65 -55
- package/src/components/overlay/MOverlay.spec.ts +51 -0
- package/src/components/overlay/MOverlay.stories.ts +40 -0
- package/src/components/overlay/MOverlay.vue +27 -19
- package/src/components/passwordinput/MPasswordInput.spec.ts +104 -0
- package/src/components/passwordinput/MPasswordInput.stories.ts +75 -0
- package/src/components/passwordinput/MPasswordInput.vue +129 -76
- package/src/components/quantityselector/MQuantitySelector.spec.ts +262 -0
- package/src/components/quantityselector/MQuantitySelector.stories.ts +89 -0
- package/src/components/quantityselector/MQuantitySelector.vue +160 -136
- 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 +99 -0
- package/src/components/statusnotification/MStatusNotification.stories.ts +96 -0
- package/src/components/statusnotification/MStatusNotification.vue +106 -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 -42
- package/src/components/textinput/MTextInput.spec.ts +121 -0
- package/src/components/textinput/MTextInput.stories.ts +114 -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 +43 -0
- package/src/components/usingPresets.mdx +125 -0
- package/src/main.ts +47 -0
- package/dist/demo.html +0 -1
- package/dist/mozaic-vue.adeo.css +0 -45
- package/dist/mozaic-vue.adeo.umd.js +0 -41775
- package/dist/mozaic-vue.common.js +0 -41765
- package/dist/mozaic-vue.common.js.map +0 -1
- package/dist/mozaic-vue.umd.js +0 -41776
- 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 -198
- package/src/components/autocomplete/index.js +0 -7
- 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 -155
- 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/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/MFlag.vue +0 -46
- 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 -120
- package/src/components/icon/index.js +0 -7
- package/src/components/index.js +0 -43
- 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 -106
- package/src/components/listbox/index.js +0 -7
- package/src/components/loader/index.js +0 -7
- package/src/components/modal/MModal.vue +0 -179
- 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/MPagination.vue +0 -162
- package/src/components/pagination/index.js +0 -7
- package/src/components/passwordinput/index.js +0 -7
- package/src/components/phonenumber/MPhoneNumber.vue +0 -390
- 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 -118
- 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 -70
- package/src/components/stepper/index.js +0 -7
- package/src/components/tabs/MTab.vue +0 -184
- 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 -62
- package/src/shims-tsx.d.ts +0 -13
- package/src/shims.vue.d.ts +0 -4
- package/src/tokens/adeo/android/colors.xml +0 -391
- package/src/tokens/adeo/android/font_dimens.xml +0 -18
- package/src/tokens/adeo/css/_variables.scss +0 -385
- package/src/tokens/adeo/css/root.scss +0 -387
- package/src/tokens/adeo/ios/StyleDictionaryColor.h +0 -399
- package/src/tokens/adeo/ios/StyleDictionaryColor.m +0 -411
- package/src/tokens/adeo/ios/StyleDictionaryColor.swift +0 -394
- 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 -483
- package/src/tokens/adeo/js/tokensObject.js +0 -10354
- package/src/tokens/adeo/scss/_tokens.scss +0 -1300
- package/src/utils/mozaicClasses.js +0 -16
- package/src/utils/theme.validator.js +0 -19
- package/types/index.d.ts +0 -100
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import MStatusDot from './MStatusDot.vue';
|
|
4
|
+
|
|
5
|
+
describe('MStatusDot.vue', () => {
|
|
6
|
+
it('renders with default status and size', () => {
|
|
7
|
+
const wrapper = mount(MStatusDot);
|
|
8
|
+
|
|
9
|
+
expect(wrapper.classes()).toContain('mc-status-dot');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('renders with custom status', () => {
|
|
13
|
+
const wrapper = mount(MStatusDot, {
|
|
14
|
+
props: {
|
|
15
|
+
status: 'success',
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
expect(wrapper.classes()).toContain('mc-status-dot--success');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('renders with custom size', () => {
|
|
23
|
+
const wrapper = mount(MStatusDot, {
|
|
24
|
+
props: {
|
|
25
|
+
size: 's',
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
expect(wrapper.classes()).toContain('mc-status-dot--s');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('does not render the "info" status when a custom one is passed', () => {
|
|
33
|
+
const wrapper = mount(MStatusDot, {
|
|
34
|
+
props: {
|
|
35
|
+
status: 'warning',
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
expect(wrapper.classes()).not.toContain('mc-status-dot--info');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('does not render the "m" size when a custom one is passed', () => {
|
|
43
|
+
const wrapper = mount(MStatusDot, {
|
|
44
|
+
props: {
|
|
45
|
+
size: 'l',
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
expect(wrapper.classes()).not.toContain('mc-status-dot--m');
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3';
|
|
2
|
+
import MStatusDot from './MStatusDot.vue';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof MStatusDot> = {
|
|
5
|
+
title: 'Status/Status Dot',
|
|
6
|
+
component: MStatusDot,
|
|
7
|
+
parameters: {
|
|
8
|
+
docs: {
|
|
9
|
+
description: {
|
|
10
|
+
component:
|
|
11
|
+
'A Status dot is a small visual indicator used to represent the state or condition of an element. It is often color-coded to convey different statuses at a glance, such as availability, activity, or urgency. Status Dots are commonly found in user presence indicators, system statuses, or process tracking to provide quick, unobtrusive feedback.',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
render: (args) => ({
|
|
16
|
+
components: { MStatusDot },
|
|
17
|
+
setup() {
|
|
18
|
+
return { args };
|
|
19
|
+
},
|
|
20
|
+
template: `
|
|
21
|
+
<MStatusDot v-bind="args"></MStatusDot>
|
|
22
|
+
`,
|
|
23
|
+
}),
|
|
24
|
+
};
|
|
25
|
+
export default meta;
|
|
26
|
+
type Story = StoryObj<typeof MStatusDot>;
|
|
27
|
+
|
|
28
|
+
export const Info: Story = {};
|
|
29
|
+
|
|
30
|
+
export const Success: Story = {
|
|
31
|
+
args: { status: 'success' },
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const Warning: Story = {
|
|
35
|
+
args: { status: 'warning' },
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const Error: Story = {
|
|
39
|
+
args: { status: 'error' },
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const Neutral: Story = {
|
|
43
|
+
args: { status: 'neutral' },
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const Size: Story = {
|
|
47
|
+
args: { size: 'l' },
|
|
48
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<span class="mc-status-dot" :class="classObject"></span>
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script setup lang="ts">
|
|
6
|
+
import { computed } from 'vue';
|
|
7
|
+
/**
|
|
8
|
+
* A badge indicates the status of an entity and can evolve at any time.
|
|
9
|
+
*/
|
|
10
|
+
const props = withDefaults(
|
|
11
|
+
defineProps<{
|
|
12
|
+
/**
|
|
13
|
+
* Allows to define the Status Dot style
|
|
14
|
+
*/
|
|
15
|
+
status?: 'info' | 'success' | 'warning' | 'error' | 'neutral';
|
|
16
|
+
/**
|
|
17
|
+
* Determines the size of the Status Dot.
|
|
18
|
+
*/
|
|
19
|
+
size?: 's' | 'm' | 'l';
|
|
20
|
+
}>(),
|
|
21
|
+
{
|
|
22
|
+
status: 'info',
|
|
23
|
+
},
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const classObject = computed(() => {
|
|
27
|
+
return {
|
|
28
|
+
[`mc-status-dot--${props.status}`]: props.status && props.status != 'info',
|
|
29
|
+
[`mc-status-dot--${props.size}`]: props.size && props.size != 'm',
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<style lang="scss" scoped>
|
|
35
|
+
@use '@mozaic-ds/styles/components/status-dot';
|
|
36
|
+
</style>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import MStatusNotification from './MStatusNotification.vue';
|
|
4
|
+
import InfoCircle32 from '@mozaic-ds/icons-vue/src/components/InfoCircle32/InfoCircle32.vue';
|
|
5
|
+
import CheckCircle32 from '@mozaic-ds/icons-vue/src/components/CheckCircle32/CheckCircle32.vue';
|
|
6
|
+
import WarningCircle32 from '@mozaic-ds/icons-vue/src/components/WarningCircle32/WarningCircle32.vue';
|
|
7
|
+
import CrossCircle32 from '@mozaic-ds/icons-vue/src/components/CrossCircle32/CrossCircle32.vue';
|
|
8
|
+
|
|
9
|
+
describe('MStatusNotification.vue', () => {
|
|
10
|
+
it('should render correctly with the default props', () => {
|
|
11
|
+
const wrapper = mount(MStatusNotification, {
|
|
12
|
+
props: {
|
|
13
|
+
title: 'Test Title',
|
|
14
|
+
description: 'Test Description',
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
expect(wrapper.text()).toContain('Test Title');
|
|
19
|
+
expect(wrapper.text()).toContain('Test Description');
|
|
20
|
+
expect(wrapper.findComponent(InfoCircle32).exists()).toBe(true); // Default icon is InfoCircle32
|
|
21
|
+
expect(wrapper.classes()).toContain('mc-status-notification');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should display the correct icon based on the status prop', () => {
|
|
25
|
+
const wrapperSuccess = mount(MStatusNotification, {
|
|
26
|
+
props: {
|
|
27
|
+
title: 'Success',
|
|
28
|
+
description: 'Success Description',
|
|
29
|
+
status: 'success',
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
expect(wrapperSuccess.findComponent(CheckCircle32).exists()).toBe(true);
|
|
33
|
+
|
|
34
|
+
const wrapperWarning = mount(MStatusNotification, {
|
|
35
|
+
props: {
|
|
36
|
+
title: 'Warning',
|
|
37
|
+
description: 'Warning Description',
|
|
38
|
+
status: 'warning',
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
expect(wrapperWarning.findComponent(WarningCircle32).exists()).toBe(true);
|
|
42
|
+
|
|
43
|
+
const wrapperError = mount(MStatusNotification, {
|
|
44
|
+
props: {
|
|
45
|
+
title: 'Error',
|
|
46
|
+
description: 'Error Description',
|
|
47
|
+
status: 'error',
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
expect(wrapperError.findComponent(CrossCircle32).exists()).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should show the close button if closable prop is true', () => {
|
|
54
|
+
const wrapper = mount(MStatusNotification, {
|
|
55
|
+
props: {
|
|
56
|
+
title: 'Closable Test',
|
|
57
|
+
description: 'Test Description',
|
|
58
|
+
closable: true,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
expect(
|
|
63
|
+
wrapper.find('button.mc-status-notification-closable__close').exists(),
|
|
64
|
+
).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should emit a close event when the close button is clicked', async () => {
|
|
68
|
+
const wrapper = mount(MStatusNotification, {
|
|
69
|
+
props: {
|
|
70
|
+
title: 'Closable Test',
|
|
71
|
+
description: 'Test Description',
|
|
72
|
+
closable: true,
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const closeButton = wrapper.find(
|
|
77
|
+
'button.mc-status-notification-closable__close',
|
|
78
|
+
);
|
|
79
|
+
await closeButton.trigger('click');
|
|
80
|
+
|
|
81
|
+
// Check if the "close" event was emitted
|
|
82
|
+
expect(wrapper.emitted()).toHaveProperty('close');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should render footer slot if provided', () => {
|
|
86
|
+
const footerSlotContent = '<button>Footer Button</button>';
|
|
87
|
+
const wrapper = mount(MStatusNotification, {
|
|
88
|
+
props: {
|
|
89
|
+
title: 'With Footer',
|
|
90
|
+
description: 'Description with footer',
|
|
91
|
+
},
|
|
92
|
+
slots: {
|
|
93
|
+
footer: footerSlotContent,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
expect(wrapper.html()).toContain(footerSlotContent);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3';
|
|
2
|
+
import MStatusNotification from './MStatusNotification.vue';
|
|
3
|
+
import { action } from '@storybook/addon-actions';
|
|
4
|
+
import MButton from '../button/MButton.vue';
|
|
5
|
+
import MLink from '../link/MLink.vue';
|
|
6
|
+
import ArrowNext20 from '@mozaic-ds/icons-vue/src/components/ArrowNext20/ArrowNext20.vue';
|
|
7
|
+
|
|
8
|
+
const meta: Meta<typeof MStatusNotification> = {
|
|
9
|
+
title: 'Status/Status Notification',
|
|
10
|
+
component: MStatusNotification,
|
|
11
|
+
parameters: {
|
|
12
|
+
docs: {
|
|
13
|
+
description: {
|
|
14
|
+
component:
|
|
15
|
+
'A Status Notification is used to draw the user’s attention to important information that needs to be acknowledged. It often provides feedback on a process, highlights a status update, or alerts users about an issue. Notifications are typically triggered by user actions or system events and are designed to be easily noticeable while maintaining a non-intrusive experience.',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
args: {
|
|
20
|
+
title:
|
|
21
|
+
'This is a title, be concise and use the description message to give details.',
|
|
22
|
+
description: 'Description message.',
|
|
23
|
+
},
|
|
24
|
+
argTypes: {
|
|
25
|
+
$slots: {
|
|
26
|
+
table: {
|
|
27
|
+
disable: true,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
render: (args) => ({
|
|
32
|
+
components: { MStatusNotification, MButton, MLink, ArrowNext20 },
|
|
33
|
+
setup() {
|
|
34
|
+
const handleClick = action('close');
|
|
35
|
+
|
|
36
|
+
return { args, handleClick };
|
|
37
|
+
},
|
|
38
|
+
template: `
|
|
39
|
+
<MStatusNotification
|
|
40
|
+
v-bind="args"
|
|
41
|
+
@click="handleClick"
|
|
42
|
+
>
|
|
43
|
+
<template v-if="${'footer' in args}" v-slot:footer>${args.footer}</template>
|
|
44
|
+
</MStatusNotification>
|
|
45
|
+
`,
|
|
46
|
+
}),
|
|
47
|
+
};
|
|
48
|
+
export default meta;
|
|
49
|
+
type Story = StoryObj<typeof MStatusNotification>;
|
|
50
|
+
|
|
51
|
+
export const Info: Story = {};
|
|
52
|
+
|
|
53
|
+
export const Success: Story = {
|
|
54
|
+
args: { status: 'success' },
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const Warning: Story = {
|
|
58
|
+
args: { status: 'warning' },
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const Error: Story = {
|
|
62
|
+
args: { status: 'error' },
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const Closable: Story = {
|
|
66
|
+
args: { closable: true },
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const WithButton = {
|
|
70
|
+
args: {
|
|
71
|
+
footer: `
|
|
72
|
+
<MButton outlined>Button Label</MButton>
|
|
73
|
+
`,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const WithLink = {
|
|
78
|
+
args: {
|
|
79
|
+
footer: `
|
|
80
|
+
<MLink href="#" iconPosition="right">
|
|
81
|
+
Stand-alone link
|
|
82
|
+
|
|
83
|
+
<template #icon><ArrowNext20 /></template>
|
|
84
|
+
</MLink>
|
|
85
|
+
`,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const WithButtons = {
|
|
90
|
+
args: {
|
|
91
|
+
footer: `
|
|
92
|
+
<MButton>Button Label</MButton>
|
|
93
|
+
<MButton outlined>Button Label</MButton>
|
|
94
|
+
`,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<section class="mc-status-notification" role="status" :class="classObject">
|
|
3
|
+
<component
|
|
4
|
+
:is="iconComponent"
|
|
5
|
+
class="mc-status-notification__icon"
|
|
6
|
+
aria-hidden="true"
|
|
7
|
+
/>
|
|
8
|
+
<div class="mc-status-notification__content">
|
|
9
|
+
<h2 class="mc-status-notification__title">{{ title }}</h2>
|
|
10
|
+
|
|
11
|
+
<p class="mc-status-notification__message">
|
|
12
|
+
{{ description }}
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<div v-if="$slots.footer" class="mc-status-notification__footer">
|
|
16
|
+
<slot name="footer" />
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<button
|
|
21
|
+
v-if="closable"
|
|
22
|
+
class="mc-status-notification-closable__close"
|
|
23
|
+
@click="emit('close')"
|
|
24
|
+
>
|
|
25
|
+
<Cross20
|
|
26
|
+
class="mc-status-notification-closable__icon"
|
|
27
|
+
aria-hidden="true"
|
|
28
|
+
/>
|
|
29
|
+
<span class="mc-status-notification-closable__text">Close</span>
|
|
30
|
+
</button>
|
|
31
|
+
</section>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<script setup lang="ts">
|
|
35
|
+
import { computed, type VNode } from 'vue';
|
|
36
|
+
import Cross20 from '@mozaic-ds/icons-vue/src/components/Cross20/Cross20.vue';
|
|
37
|
+
import InfoCircle32 from '@mozaic-ds/icons-vue/src/components/InfoCircle32/InfoCircle32.vue';
|
|
38
|
+
import WarningCircle32 from '@mozaic-ds/icons-vue/src/components/WarningCircle32/WarningCircle32.vue';
|
|
39
|
+
import CrossCircle32 from '@mozaic-ds/icons-vue/src/components/CrossCircle32/CrossCircle32.vue';
|
|
40
|
+
import CheckCircle32 from '@mozaic-ds/icons-vue/src/components/CheckCircle32/CheckCircle32.vue';
|
|
41
|
+
/**
|
|
42
|
+
* A Status Notification is used to draw the user’s attention to important information that needs to be acknowledged. It often provides feedback on a process, highlights a status update, or alerts users about an issue. Notifications are typically triggered by user actions or system events and are designed to be easily noticeable while maintaining a non-intrusive experience.
|
|
43
|
+
*/
|
|
44
|
+
const props = withDefaults(
|
|
45
|
+
defineProps<{
|
|
46
|
+
/**
|
|
47
|
+
* Title of the Status Notification
|
|
48
|
+
*/
|
|
49
|
+
title: string;
|
|
50
|
+
/**
|
|
51
|
+
* Description of the Status Notification
|
|
52
|
+
*/
|
|
53
|
+
description: string;
|
|
54
|
+
/**
|
|
55
|
+
* Allows to define the Status Notification style
|
|
56
|
+
*/
|
|
57
|
+
status?: 'info' | 'success' | 'warning' | 'error';
|
|
58
|
+
/**
|
|
59
|
+
* if `true`, display the close button.
|
|
60
|
+
*/
|
|
61
|
+
closable?: boolean;
|
|
62
|
+
}>(),
|
|
63
|
+
{
|
|
64
|
+
status: 'info',
|
|
65
|
+
},
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
defineSlots<{
|
|
69
|
+
/**
|
|
70
|
+
* Use this slot to insert a button or a link in the footer
|
|
71
|
+
*/
|
|
72
|
+
footer?: VNode;
|
|
73
|
+
}>();
|
|
74
|
+
|
|
75
|
+
const classObject = computed(() => {
|
|
76
|
+
return {
|
|
77
|
+
[`mc-status-notification--${props.status}`]:
|
|
78
|
+
props.status && props.status != 'info',
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const iconComponent = computed(() => {
|
|
83
|
+
switch (props.status) {
|
|
84
|
+
case 'success':
|
|
85
|
+
return CheckCircle32;
|
|
86
|
+
case 'warning':
|
|
87
|
+
return WarningCircle32;
|
|
88
|
+
case 'error':
|
|
89
|
+
return CrossCircle32;
|
|
90
|
+
case 'info':
|
|
91
|
+
default:
|
|
92
|
+
return InfoCircle32;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const emit = defineEmits<{
|
|
97
|
+
/**
|
|
98
|
+
* Emits when closing the notification.
|
|
99
|
+
*/
|
|
100
|
+
(on: 'close'): void;
|
|
101
|
+
}>();
|
|
102
|
+
</script>
|
|
103
|
+
|
|
104
|
+
<style lang="scss" scoped>
|
|
105
|
+
@use '@mozaic-ds/styles/components/status-notification';
|
|
106
|
+
</style>
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import MTextArea from './MTextArea.vue';
|
|
4
|
+
|
|
5
|
+
describe('MTextArea component', () => {
|
|
6
|
+
it('should render correctly with the given props', () => {
|
|
7
|
+
const wrapper = mount(MTextArea, {
|
|
8
|
+
props: {
|
|
9
|
+
id: 'textarea-id',
|
|
10
|
+
modelValue: 'Test value',
|
|
11
|
+
placeholder: 'Enter text here...',
|
|
12
|
+
rows: 5,
|
|
13
|
+
maxLength: 200,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const textarea = wrapper.find('textarea');
|
|
18
|
+
|
|
19
|
+
expect(textarea.attributes('id')).toBe('textarea-id');
|
|
20
|
+
expect(textarea.attributes('placeholder')).toBe('Enter text here...');
|
|
21
|
+
expect(textarea.attributes('rows')).toBe('5');
|
|
22
|
+
expect(textarea.attributes('maxlength')).toBe('200');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should apply is-invalid class when isInvalid prop is true', () => {
|
|
26
|
+
const wrapper = mount(MTextArea, {
|
|
27
|
+
props: {
|
|
28
|
+
id: 'textarea-id',
|
|
29
|
+
modelValue: 'Test value',
|
|
30
|
+
isInvalid: true,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const textarea = wrapper.find('textarea');
|
|
35
|
+
expect(textarea.classes()).toContain('is-invalid');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should update modelValue when the textarea value changes', async () => {
|
|
39
|
+
const wrapper = mount(MTextArea, {
|
|
40
|
+
props: {
|
|
41
|
+
id: 'textarea-id',
|
|
42
|
+
modelValue: 'Initial value',
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const textarea = wrapper.find('textarea');
|
|
47
|
+
await textarea.setValue('Updated value');
|
|
48
|
+
|
|
49
|
+
expect(wrapper.emitted()['update:modelValue']).toBeTruthy();
|
|
50
|
+
expect(wrapper.emitted()['update:modelValue'][0]).toEqual([
|
|
51
|
+
'Updated value',
|
|
52
|
+
]);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should not allow changes if the textarea is disabled', async () => {
|
|
56
|
+
const wrapper = mount(MTextArea, {
|
|
57
|
+
props: {
|
|
58
|
+
id: 'textarea-id',
|
|
59
|
+
modelValue: 'Initial value',
|
|
60
|
+
disabled: true,
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const textarea = wrapper.find('textarea');
|
|
65
|
+
expect(textarea.attributes('disabled')).toBeDefined();
|
|
66
|
+
|
|
67
|
+
await textarea.setValue('Updated value');
|
|
68
|
+
|
|
69
|
+
expect(wrapper.emitted()['update:modelValue']).toBeFalsy();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should be read-only if the readonly prop is true', async () => {
|
|
73
|
+
const wrapper = mount(MTextArea, {
|
|
74
|
+
props: {
|
|
75
|
+
id: 'textarea-id',
|
|
76
|
+
modelValue: 'Initial value',
|
|
77
|
+
readonly: true,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const textarea = wrapper.find('textarea');
|
|
82
|
+
expect(textarea.attributes('readonly')).toBeDefined();
|
|
83
|
+
|
|
84
|
+
await textarea.setValue('Updated value');
|
|
85
|
+
|
|
86
|
+
expect(textarea.attributes('value')).toBe('Initial value');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should apply a default classObject computed class', () => {
|
|
90
|
+
const wrapper = mount(MTextArea, {
|
|
91
|
+
props: {
|
|
92
|
+
id: 'textarea-id',
|
|
93
|
+
modelValue: 'Test value',
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
expect(wrapper.classes()).toContain('mc-textarea');
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('should correctly bind rows attribute', () => {
|
|
101
|
+
const wrapper = mount(MTextArea, {
|
|
102
|
+
props: {
|
|
103
|
+
id: 'textarea-id',
|
|
104
|
+
modelValue: 'Test value',
|
|
105
|
+
rows: 4,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const textarea = wrapper.find('textarea');
|
|
110
|
+
expect(textarea.attributes('rows')).toBe('4');
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3';
|
|
2
|
+
import { action } from '@storybook/addon-actions';
|
|
3
|
+
|
|
4
|
+
import MTextArea from './MTextArea.vue';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof MTextArea> = {
|
|
7
|
+
title: 'Form Elements/Textarea',
|
|
8
|
+
component: MTextArea,
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
'A text area is an input designed for multi-line text entry, allowing users to input longer content compared to a standard text input. It is commonly used for comments, feedback, descriptions, and messaging. Text areas can be resizable or fixed in height, depending on the context, and often include placeholder text, character limits, and validation messages to guide users.<br><br> To put a label, requierement text, help text or to apply a valid or invalid message, the examples are available in the [Field section](/docs/form-elements-field--docs#textarea).',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
args: {
|
|
18
|
+
id: 'textareaId',
|
|
19
|
+
placeholder: 'Placeholder',
|
|
20
|
+
},
|
|
21
|
+
render: (args) => ({
|
|
22
|
+
components: { MTextArea },
|
|
23
|
+
setup() {
|
|
24
|
+
const handleUpdate = action('update:modelValue');
|
|
25
|
+
|
|
26
|
+
return { args, handleUpdate };
|
|
27
|
+
},
|
|
28
|
+
template: `
|
|
29
|
+
<MTextArea
|
|
30
|
+
v-bind="args"
|
|
31
|
+
@update:modelValue="handleUpdate"
|
|
32
|
+
/>
|
|
33
|
+
`,
|
|
34
|
+
}),
|
|
35
|
+
};
|
|
36
|
+
export default meta;
|
|
37
|
+
type Story = StoryObj<typeof MTextArea>;
|
|
38
|
+
|
|
39
|
+
export const WithValue: Story = {
|
|
40
|
+
args: {
|
|
41
|
+
id: 'withValueId',
|
|
42
|
+
modelValue: 'Value of the textarea component',
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const Default: Story = {};
|
|
47
|
+
|
|
48
|
+
export const Disabled: Story = {
|
|
49
|
+
args: {
|
|
50
|
+
id: 'disabledId',
|
|
51
|
+
disabled: true,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const ReadOnly: Story = {
|
|
56
|
+
args: {
|
|
57
|
+
id: 'readonlyId',
|
|
58
|
+
readonly: true,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const Invalid: Story = {
|
|
63
|
+
args: {
|
|
64
|
+
id: 'invalidId',
|
|
65
|
+
isInvalid: true,
|
|
66
|
+
},
|
|
67
|
+
};
|