@mozaic-ds/vue 2.11.0 → 2.13.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/mozaic-vue.css +1 -1
- package/dist/mozaic-vue.d.ts +791 -353
- package/dist/mozaic-vue.js +2945 -2404
- package/dist/mozaic-vue.js.map +1 -1
- package/dist/mozaic-vue.umd.cjs +5 -5
- package/dist/mozaic-vue.umd.cjs.map +1 -1
- package/package.json +7 -6
- package/src/components/{usingPresets.mdx → BrandPresets.mdx} +2 -2
- package/src/components/Changelog.mdx +19 -0
- package/src/components/Color.mdx +226 -0
- package/src/components/Contributing.mdx +12 -6
- package/src/components/GettingStarted.mdx +1 -1
- package/src/components/Icon.stories.ts +134 -0
- package/src/components/Welcome.mdx +49 -0
- package/src/components/accordionlist/MAccordionList.spec.ts +136 -0
- package/src/components/accordionlist/MAccordionList.stories.ts +123 -0
- package/src/components/accordionlist/MAccordionList.vue +91 -0
- package/src/components/accordionlist/README.md +24 -0
- package/src/components/accordionlist/m-accordion-list.const.ts +9 -0
- package/src/components/accordionlistitem/MAccordionListItem.spec.ts +123 -0
- package/src/components/accordionlistitem/MAccordionListItem.vue +95 -0
- package/src/components/accordionlistitem/README.md +23 -0
- package/src/components/actionbottombar/MActionBottomBar.spec.ts +52 -0
- package/src/components/actionbottombar/MActionBottomBar.stories.ts +162 -0
- package/src/components/actionbottombar/MActionBottomBar.vue +45 -0
- package/src/components/actionbottombar/README.md +31 -0
- package/src/components/actionlistbox/MActionListbox.spec.ts +134 -0
- package/src/components/actionlistbox/MActionListbox.stories.ts +74 -0
- package/src/components/actionlistbox/MActionListbox.vue +89 -0
- package/src/components/actionlistbox/README.md +25 -0
- package/src/components/avatar/MAvatar.stories.ts +1 -1
- package/src/components/breadcrumb/README.md +14 -0
- package/src/components/builtinmenu/MBuiltInMenu.spec.ts +111 -0
- package/src/components/builtinmenu/MBuiltInMenu.stories.ts +59 -0
- package/src/components/builtinmenu/MBuiltInMenu.vue +110 -0
- package/src/components/builtinmenu/README.md +32 -0
- package/src/components/button/MButton.spec.ts +1 -1
- package/src/components/button/MButton.stories.ts +165 -5
- package/src/components/button/README.md +33 -1
- package/src/components/callout/MCallout.spec.ts +7 -6
- package/src/components/callout/MCallout.stories.ts +1 -2
- package/src/components/carousel/MCarousel.spec.ts +1 -2
- package/src/components/carousel/MCarousel.stories.ts +2 -1
- package/src/components/carousel/MCarousel.vue +1 -2
- package/src/components/carousel/README.md +14 -0
- package/src/components/checkbox/README.md +14 -0
- package/src/components/checkboxgroup/README.md +14 -0
- package/src/components/checklistmenu/MCheckListMenu.spec.ts +77 -0
- package/src/components/checklistmenu/MCheckListMenu.stories.ts +47 -0
- package/src/components/checklistmenu/MCheckListMenu.vue +61 -0
- package/src/components/checklistmenu/README.md +32 -0
- package/src/components/circularprogressbar/README.md +15 -1
- package/src/components/datepicker/MDatepicker.vue +1 -1
- package/src/components/divider/README.md +22 -0
- package/src/components/drawer/MDrawer.vue +1 -2
- package/src/components/drawer/README.md +16 -0
- package/src/components/field/README.md +14 -0
- package/src/components/fileuploader/MFileUploader.spec.ts +304 -0
- package/src/components/fileuploader/MFileUploader.stories.ts +123 -0
- package/src/components/fileuploader/MFileUploader.vue +314 -0
- package/src/components/fileuploader/README.md +58 -0
- package/src/components/fileuploaderitem/MFileUploaderItem.spec.ts +91 -0
- package/src/components/fileuploaderitem/MFileUploaderItem.vue +180 -0
- package/src/components/fileuploaderitem/README.md +58 -0
- package/src/components/flag/README.md +1 -1
- package/src/components/iconbutton/MIconButton.spec.ts +1 -1
- package/src/components/iconbutton/MIconButton.stories.ts +116 -7
- package/src/components/iconbutton/README.md +25 -1
- package/src/components/kpiitem/MKpiItem.vue +5 -3
- package/src/components/linearprogressbarbuffer/README.md +14 -0
- package/src/components/link/MLink.stories.ts +1 -2
- package/src/components/link/README.md +14 -0
- package/src/components/loader/README.md +20 -0
- package/src/components/loadingoverlay/README.md +14 -0
- package/src/components/modal/MModal.stories.ts +1 -2
- package/src/components/modal/MModal.vue +1 -1
- package/src/components/modal/README.md +16 -0
- package/src/components/numberbadge/README.md +17 -1
- package/src/components/overlay/README.md +16 -0
- package/src/components/pagination/MPagination.vue +1 -2
- package/src/components/pagination/README.md +18 -0
- package/src/components/passwordinput/MPasswordInput.vue +1 -1
- package/src/components/passwordinput/README.md +14 -0
- package/src/components/phonenumber/MPhoneNumber.spec.ts +7 -6
- package/src/components/phonenumber/MPhoneNumber.vue +1 -1
- package/src/components/quantityselector/MQuantitySelector.vue +1 -2
- package/src/components/radio/README.md +14 -0
- package/src/components/radiogroup/README.md +14 -0
- package/src/components/select/README.md +14 -0
- package/src/components/starrating/MStarRating.spec.ts +1 -2
- package/src/components/starrating/MStarRating.vue +1 -3
- package/src/components/statusbadge/README.md +14 -0
- package/src/components/statusdot/README.md +14 -0
- package/src/components/statusmessage/MStatusMessage.spec.ts +6 -4
- package/src/components/statusmessage/MStatusMessage.vue +6 -4
- package/src/components/statusmessage/README.md +14 -0
- package/src/components/statusnotification/MStatusNotification.spec.ts +6 -4
- package/src/components/statusnotification/MStatusNotification.stories.ts +1 -1
- package/src/components/statusnotification/MStatusNotification.vue +7 -5
- package/src/components/statusnotification/README.md +14 -0
- package/src/components/stepperbottombar/MStepperBottomBar.spec.ts +134 -0
- package/src/components/stepperbottombar/MStepperBottomBar.stories.ts +72 -0
- package/src/components/stepperbottombar/MStepperBottomBar.vue +131 -0
- package/src/components/stepperbottombar/README.md +40 -0
- package/src/components/steppercompact/README.md +14 -0
- package/src/components/stepperinline/MStepperInline.spec.ts +78 -0
- package/src/components/stepperinline/MStepperInline.stories.ts +49 -0
- package/src/components/stepperinline/MStepperInline.vue +93 -0
- package/src/components/stepperinline/README.md +11 -0
- package/src/components/tabs/MTabs.stories.ts +1 -1
- package/src/components/tabs/README.md +16 -0
- package/src/components/tag/MTag.vue +1 -1
- package/src/components/tag/README.md +14 -0
- package/src/components/textinput/MTextInput.spec.ts +1 -1
- package/src/components/textinput/MTextInput.stories.ts +1 -1
- package/src/components/textinput/MTextInput.vue +1 -1
- package/src/components/toaster/MToaster.spec.ts +6 -4
- package/src/components/toaster/MToaster.vue +7 -5
- package/src/components/toaster/README.md +16 -0
- package/src/components/toggle/README.md +14 -0
- package/src/components/togglegroup/README.md +14 -0
- package/src/main.ts +8 -0
- package/src/components/Introduction.mdx +0 -100
- package/src/components/Support.mdx +0 -18
- package/src/components/usingIcons.mdx +0 -35
|
@@ -13,10 +13,12 @@
|
|
|
13
13
|
|
|
14
14
|
<script setup lang="ts">
|
|
15
15
|
import { computed } from 'vue';
|
|
16
|
-
import
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
import {
|
|
17
|
+
InfoCircleFilled24,
|
|
18
|
+
WarningCircleFilled24,
|
|
19
|
+
CrossCircleFilled24,
|
|
20
|
+
CheckCircleFilled24,
|
|
21
|
+
} from '@mozaic-ds/icons-vue';
|
|
20
22
|
import MLoader from '../loader/MLoader.vue';
|
|
21
23
|
/**
|
|
22
24
|
* A Status Message is a compact component that combines an icon and concise text to communicate system states or user feedback in limited interface space. The icon and message work together as a unified structure to provide clear, immediate understanding of the current status. Status Messages are designed for contexts where space is constrained but clear communication is essential, offering quick recognition through color-coded icons paired with brief, actionable text.
|
|
@@ -9,3 +9,17 @@ A Status Message is a compact component that combines an icon and concise text t
|
|
|
9
9
|
| --- | --- | --- | --- |
|
|
10
10
|
| `status` | Allows to define the status message style. | `"info"` `"warning"` `"error"` `"success"` `"neutral"` `"inprogress"` | `"info"` |
|
|
11
11
|
| `label*` | Label of the status message. | `string` | - |
|
|
12
|
+
|
|
13
|
+
## Dependencies
|
|
14
|
+
|
|
15
|
+
### Depends on
|
|
16
|
+
|
|
17
|
+
- [MLoader](../loader)
|
|
18
|
+
|
|
19
|
+
### Graph
|
|
20
|
+
|
|
21
|
+
```mermaid
|
|
22
|
+
graph TD;
|
|
23
|
+
MStatusMessage --> MLoader
|
|
24
|
+
style MStatusMessage fill:#008240,stroke:#333,stroke-width:4px
|
|
25
|
+
```
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { mount } from '@vue/test-utils';
|
|
2
2
|
import { describe, it, expect } from 'vitest';
|
|
3
3
|
import MStatusNotification from './MStatusNotification.vue';
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
import {
|
|
5
|
+
InfoCircleFilled32,
|
|
6
|
+
WarningCircleFilled32,
|
|
7
|
+
CrossCircleFilled32,
|
|
8
|
+
CheckCircleFilled32,
|
|
9
|
+
} from '@mozaic-ds/icons-vue';
|
|
8
10
|
|
|
9
11
|
describe('MStatusNotification.vue', () => {
|
|
10
12
|
it('should render correctly with the default props', () => {
|
|
@@ -3,7 +3,7 @@ import MStatusNotification from './MStatusNotification.vue';
|
|
|
3
3
|
import { action } from 'storybook/actions';
|
|
4
4
|
import MButton from '../button/MButton.vue';
|
|
5
5
|
import MLink from '../link/MLink.vue';
|
|
6
|
-
import ArrowNext20 from '@mozaic-ds/icons-vue
|
|
6
|
+
import { ArrowNext20 } from '@mozaic-ds/icons-vue';
|
|
7
7
|
|
|
8
8
|
const meta: Meta<typeof MStatusNotification> = {
|
|
9
9
|
title: 'Status/Status Notification',
|
|
@@ -34,11 +34,13 @@
|
|
|
34
34
|
|
|
35
35
|
<script setup lang="ts">
|
|
36
36
|
import { computed, type VNode } from 'vue';
|
|
37
|
-
import
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
import {
|
|
38
|
+
Cross20,
|
|
39
|
+
InfoCircleFilled32,
|
|
40
|
+
WarningCircleFilled32,
|
|
41
|
+
CrossCircleFilled32,
|
|
42
|
+
CheckCircleFilled32,
|
|
43
|
+
} from '@mozaic-ds/icons-vue';
|
|
42
44
|
import MIconButton from '../iconbutton/MIconButton.vue';
|
|
43
45
|
/**
|
|
44
46
|
* 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.
|
|
@@ -23,3 +23,17 @@ A Status Notification is used to draw the user’s attention to important inform
|
|
|
23
23
|
| Name | Description | Type |
|
|
24
24
|
| --- | --- | --- |
|
|
25
25
|
| `close` | Emits when closing the notification. | [] |
|
|
26
|
+
|
|
27
|
+
## Dependencies
|
|
28
|
+
|
|
29
|
+
### Depends on
|
|
30
|
+
|
|
31
|
+
- [MIconButton](../iconbutton)
|
|
32
|
+
|
|
33
|
+
### Graph
|
|
34
|
+
|
|
35
|
+
```mermaid
|
|
36
|
+
graph TD;
|
|
37
|
+
MStatusNotification --> MIconButton
|
|
38
|
+
style MStatusNotification fill:#008240,stroke:#333,stroke-width:4px
|
|
39
|
+
```
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { mount } from '@vue/test-utils';
|
|
3
|
+
import MStepperBottomBar from './MStepperBottomBar.vue';
|
|
4
|
+
|
|
5
|
+
const globalStubs = {
|
|
6
|
+
MButton: {
|
|
7
|
+
emits: ['click'],
|
|
8
|
+
template: `<button @click="$emit('click', $event)"><slot /></button>`,
|
|
9
|
+
},
|
|
10
|
+
MDivider: {
|
|
11
|
+
template: `<hr />`,
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
describe('MStepperBottomBar component', () => {
|
|
16
|
+
it('renders cancel button by default', () => {
|
|
17
|
+
const wrapper = mount(MStepperBottomBar, {
|
|
18
|
+
global: { stubs: globalStubs },
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
expect(wrapper.text()).toContain('Cancel');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('does not render cancel button when cancel is false', () => {
|
|
25
|
+
const wrapper = mount(MStepperBottomBar, {
|
|
26
|
+
props: { cancel: false },
|
|
27
|
+
global: { stubs: globalStubs },
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
expect(wrapper.text()).not.toContain('Cancel');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('does not render previous button when step is 0', () => {
|
|
34
|
+
const wrapper = mount(MStepperBottomBar, {
|
|
35
|
+
props: { modelValue: 0 },
|
|
36
|
+
global: { stubs: globalStubs },
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
expect(wrapper.text()).not.toContain('Previous');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('renders previous button when step > 0', () => {
|
|
43
|
+
const wrapper = mount(MStepperBottomBar, {
|
|
44
|
+
props: { modelValue: 1 },
|
|
45
|
+
global: { stubs: globalStubs },
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
expect(wrapper.text()).toContain('Previous');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('emits update:modelValue with decremented value on previous click', async () => {
|
|
52
|
+
const wrapper = mount(MStepperBottomBar, {
|
|
53
|
+
props: { modelValue: 2 },
|
|
54
|
+
global: { stubs: globalStubs },
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const buttons = wrapper.findAll('button');
|
|
58
|
+
const previousButton = buttons.find((b) => b.text() === 'Previous')!;
|
|
59
|
+
|
|
60
|
+
await previousButton.trigger('click');
|
|
61
|
+
|
|
62
|
+
const emitted = wrapper.emitted('update:modelValue')!;
|
|
63
|
+
expect(emitted.at(-1)).toEqual([1]);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('emits update:modelValue with incremented value on next click', async () => {
|
|
67
|
+
const wrapper = mount(MStepperBottomBar, {
|
|
68
|
+
props: {
|
|
69
|
+
modelValue: 1,
|
|
70
|
+
steps: 3,
|
|
71
|
+
},
|
|
72
|
+
global: { stubs: globalStubs },
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const nextButton = wrapper
|
|
76
|
+
.findAll('button')
|
|
77
|
+
.find((b) => b.text() === 'Next')!;
|
|
78
|
+
|
|
79
|
+
await nextButton.trigger('click');
|
|
80
|
+
|
|
81
|
+
const emitted = wrapper.emitted('update:modelValue')!;
|
|
82
|
+
expect(emitted.at(-1)).toEqual([2]);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('emits validate when clicking next on last step', async () => {
|
|
86
|
+
const wrapper = mount(MStepperBottomBar, {
|
|
87
|
+
props: {
|
|
88
|
+
modelValue: 3,
|
|
89
|
+
steps: 3,
|
|
90
|
+
},
|
|
91
|
+
global: { stubs: globalStubs },
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const validateButton = wrapper
|
|
95
|
+
.findAll('button')
|
|
96
|
+
.find((b) => b.text() === 'Validate')!;
|
|
97
|
+
|
|
98
|
+
await validateButton.trigger('click');
|
|
99
|
+
|
|
100
|
+
expect(wrapper.emitted('validate')).toBeTruthy();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('emits cancel when cancel button is clicked', async () => {
|
|
104
|
+
const wrapper = mount(MStepperBottomBar, {
|
|
105
|
+
global: { stubs: globalStubs },
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const cancelButton = wrapper
|
|
109
|
+
.findAll('button')
|
|
110
|
+
.find((b) => b.text() === 'Cancel')!;
|
|
111
|
+
|
|
112
|
+
await cancelButton.trigger('click');
|
|
113
|
+
|
|
114
|
+
expect(wrapper.emitted('cancel')).toBeTruthy();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('renders custom labels', () => {
|
|
118
|
+
const wrapper = mount(MStepperBottomBar, {
|
|
119
|
+
props: {
|
|
120
|
+
cancelLabel: 'Abort',
|
|
121
|
+
previousLabel: 'Back',
|
|
122
|
+
nextLabel: 'Continue',
|
|
123
|
+
validateLabel: 'Submit',
|
|
124
|
+
modelValue: 1,
|
|
125
|
+
steps: 1,
|
|
126
|
+
},
|
|
127
|
+
global: { stubs: globalStubs },
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
expect(wrapper.text()).toContain('Abort');
|
|
131
|
+
expect(wrapper.text()).toContain('Back');
|
|
132
|
+
expect(wrapper.text()).toContain('Submit');
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
import { action } from 'storybook/actions';
|
|
3
|
+
|
|
4
|
+
import MStepperBottomBar from './MStepperBottomBar.vue';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof MStepperBottomBar> = {
|
|
7
|
+
title: 'Structure/Stepper Bottom Bar',
|
|
8
|
+
component: MStepperBottomBar,
|
|
9
|
+
tags: ['v2'],
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: 'fullscreen',
|
|
12
|
+
docs: {
|
|
13
|
+
story: { height: '200px' },
|
|
14
|
+
description: {
|
|
15
|
+
component:
|
|
16
|
+
'A stepper bottom bar is a persistent navigation component used to guide users through a multi-step process. It typically includes “Previous” and “Next” buttons, along with optional actions such as “Cancel” or “Validate”, ensuring a structured flow. This component is commonly used in forms, onboarding sequences, and checkout processes, improving usability by keeping navigation actions always accessible.',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
argTypes: {
|
|
21
|
+
// @ts-expect-error: custom css property
|
|
22
|
+
'--stepper-bottom-bar-z-index': {
|
|
23
|
+
description: 'Customise the z-index of the stepper bottom bar',
|
|
24
|
+
control: false,
|
|
25
|
+
table: {
|
|
26
|
+
category: 'Custom Properties',
|
|
27
|
+
type: { summary: 'number' },
|
|
28
|
+
defaultValue: { summary: '3' },
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
args: {
|
|
33
|
+
steps: 3,
|
|
34
|
+
modelValue: 0,
|
|
35
|
+
},
|
|
36
|
+
render: (args) => ({
|
|
37
|
+
components: { MStepperBottomBar },
|
|
38
|
+
setup() {
|
|
39
|
+
const onUpdate = action('update:modelValue');
|
|
40
|
+
const onCancel = action('cancel');
|
|
41
|
+
const onValidate = action('validate');
|
|
42
|
+
|
|
43
|
+
return { args, onUpdate, onCancel, onValidate };
|
|
44
|
+
},
|
|
45
|
+
template: `
|
|
46
|
+
<MStepperBottomBar
|
|
47
|
+
v-bind="args"
|
|
48
|
+
@update:modelValue="onUpdate"
|
|
49
|
+
@cancel="onCancel"
|
|
50
|
+
@validate="onValidate"
|
|
51
|
+
/>
|
|
52
|
+
`,
|
|
53
|
+
}),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default meta;
|
|
57
|
+
|
|
58
|
+
type Story = StoryObj<typeof MStepperBottomBar>;
|
|
59
|
+
|
|
60
|
+
export const First: Story = {};
|
|
61
|
+
|
|
62
|
+
export const Middle: Story = {
|
|
63
|
+
args: {
|
|
64
|
+
modelValue: 2,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const Last: Story = {
|
|
69
|
+
args: {
|
|
70
|
+
modelValue: 3,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="mc-stepper-bottom-bar">
|
|
3
|
+
<MDivider class="mc-stepper-bottom-bar__divider" />
|
|
4
|
+
<div class="mc-stepper-bottom-bar__left">
|
|
5
|
+
<MButton
|
|
6
|
+
v-if="cancel"
|
|
7
|
+
type="button"
|
|
8
|
+
ghost
|
|
9
|
+
size="s"
|
|
10
|
+
@click="emit('cancel')"
|
|
11
|
+
>
|
|
12
|
+
{{ cancelLabel }}
|
|
13
|
+
</MButton>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div class="mc-stepper-bottom-bar__right">
|
|
17
|
+
<MButton
|
|
18
|
+
v-if="currentStep > 0"
|
|
19
|
+
type="button"
|
|
20
|
+
outlined
|
|
21
|
+
size="s"
|
|
22
|
+
@click="onPrevious"
|
|
23
|
+
>
|
|
24
|
+
{{ previousLabel }}
|
|
25
|
+
</MButton>
|
|
26
|
+
|
|
27
|
+
<MButton type="button" appearance="accent" size="s" @click="onNext">
|
|
28
|
+
{{ currentStep < steps ? nextLabel : validateLabel }}
|
|
29
|
+
</MButton>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<script setup lang="ts">
|
|
35
|
+
import { ref, watch } from 'vue';
|
|
36
|
+
import MButton from '../button/MButton.vue';
|
|
37
|
+
import MDivider from '../divider/MDivider.vue';
|
|
38
|
+
/**
|
|
39
|
+
* A stepper bottom bar is a persistent navigation component used to guide users through a multi-step process. It typically includes “Previous” and “Next” buttons, along with optional actions such as “Cancel” or “Validate”, ensuring a structured flow. This component is commonly used in forms, onboarding sequences, and checkout processes, improving usability by keeping navigation actions always accessible.
|
|
40
|
+
*/
|
|
41
|
+
const props = withDefaults(
|
|
42
|
+
defineProps<{
|
|
43
|
+
/**
|
|
44
|
+
* Current step of the stepper compact.
|
|
45
|
+
*/
|
|
46
|
+
modelValue?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Total number of steps of the stepper compact.
|
|
49
|
+
*/
|
|
50
|
+
steps?: number;
|
|
51
|
+
/**
|
|
52
|
+
* If `true`, display the cancel button.
|
|
53
|
+
*/
|
|
54
|
+
cancel?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Label for the cancel button.
|
|
57
|
+
*/
|
|
58
|
+
cancelLabel?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Label for the previous button.
|
|
61
|
+
*/
|
|
62
|
+
previousLabel?: string;
|
|
63
|
+
/**
|
|
64
|
+
* Label for the next button.
|
|
65
|
+
*/
|
|
66
|
+
nextLabel?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Label for the validate button.
|
|
69
|
+
*/
|
|
70
|
+
validateLabel?: string;
|
|
71
|
+
}>(),
|
|
72
|
+
{
|
|
73
|
+
steps: 0,
|
|
74
|
+
modelValue: 0,
|
|
75
|
+
cancel: true,
|
|
76
|
+
cancelLabel: 'Cancel',
|
|
77
|
+
previousLabel: 'Previous',
|
|
78
|
+
nextLabel: 'Next',
|
|
79
|
+
validateLabel: 'Validate',
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const emit = defineEmits<{
|
|
84
|
+
/**
|
|
85
|
+
* Emits when the cancel button is clicked.
|
|
86
|
+
*/
|
|
87
|
+
(on: 'cancel'): void;
|
|
88
|
+
/**
|
|
89
|
+
* Emits when the step change.
|
|
90
|
+
*/
|
|
91
|
+
(on: 'update:modelValue', value: number): void;
|
|
92
|
+
/**
|
|
93
|
+
* Emits when the validate button is clicked.
|
|
94
|
+
*/
|
|
95
|
+
(on: 'validate'): void;
|
|
96
|
+
}>();
|
|
97
|
+
|
|
98
|
+
const currentStep = ref(0);
|
|
99
|
+
|
|
100
|
+
watch(
|
|
101
|
+
() => props.modelValue,
|
|
102
|
+
(value) => {
|
|
103
|
+
if (value !== undefined) {
|
|
104
|
+
currentStep.value = value;
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
{ immediate: true },
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
watch(currentStep, (value) => {
|
|
111
|
+
emit('update:modelValue', value);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const onPrevious = () => {
|
|
115
|
+
if (currentStep.value > 0) {
|
|
116
|
+
currentStep.value--;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const onNext = () => {
|
|
121
|
+
if (currentStep.value < props.steps) {
|
|
122
|
+
currentStep.value++;
|
|
123
|
+
} else {
|
|
124
|
+
emit('validate');
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
</script>
|
|
128
|
+
|
|
129
|
+
<style lang="scss" scoped>
|
|
130
|
+
@use '@mozaic-ds/styles/components/stepper-bottom-bar';
|
|
131
|
+
</style>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# MStepperBottomBar
|
|
2
|
+
|
|
3
|
+
A stepper bottom bar is a persistent navigation component used to guide users through a multi-step process. It typically includes “Previous” and “Next” buttons, along with optional actions such as “Cancel” or “Validate”, ensuring a structured flow. This component is commonly used in forms, onboarding sequences, and checkout processes, improving usability by keeping navigation actions always accessible.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Props
|
|
7
|
+
|
|
8
|
+
| Name | Description | Type | Default |
|
|
9
|
+
| --- | --- | --- | --- |
|
|
10
|
+
| `modelValue` | Current step of the stepper compact. | `number` | `0` |
|
|
11
|
+
| `steps` | Total number of steps of the stepper compact. | `number` | `0` |
|
|
12
|
+
| `cancel` | If `true`, display the cancel button. | `boolean` | `true` |
|
|
13
|
+
| `cancelLabel` | Label for the cancel button. | `string` | `"Cancel"` |
|
|
14
|
+
| `previousLabel` | Label for the previous button. | `string` | `"Previous"` |
|
|
15
|
+
| `nextLabel` | Label for the next button. | `string` | `"Next"` |
|
|
16
|
+
| `validateLabel` | Label for the validate button. | `string` | `"Validate"` |
|
|
17
|
+
|
|
18
|
+
## Events
|
|
19
|
+
|
|
20
|
+
| Name | Description | Type |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| `update:modelValue` | Emits when the step change. | [value: number] |
|
|
23
|
+
| `cancel` | Emits when the cancel button is clicked. | [] |
|
|
24
|
+
| `validate` | Emits when the validate button is clicked. | [] |
|
|
25
|
+
|
|
26
|
+
## Dependencies
|
|
27
|
+
|
|
28
|
+
### Depends on
|
|
29
|
+
|
|
30
|
+
- [MButton](../button)
|
|
31
|
+
- [MDivider](../divider)
|
|
32
|
+
|
|
33
|
+
### Graph
|
|
34
|
+
|
|
35
|
+
```mermaid
|
|
36
|
+
graph TD;
|
|
37
|
+
MStepperBottomBar --> MButton
|
|
38
|
+
MStepperBottomBar --> MDivider
|
|
39
|
+
style MStepperBottomBar fill:#008240,stroke:#333,stroke-width:4px
|
|
40
|
+
```
|
|
@@ -11,3 +11,17 @@ A stepper is a navigation component that guides users through a sequence of step
|
|
|
11
11
|
| `maxSteps` | Maximum number of steps for the stepper compact. | `number` | `4` |
|
|
12
12
|
| `label*` | Label of the stepper compact. | `string` | - |
|
|
13
13
|
| `description` | Description displayed below the label of the stepper compact. | `string` | - |
|
|
14
|
+
|
|
15
|
+
## Dependencies
|
|
16
|
+
|
|
17
|
+
### Depends on
|
|
18
|
+
|
|
19
|
+
- [MCircularProgressbar](../circularprogressbar)
|
|
20
|
+
|
|
21
|
+
### Graph
|
|
22
|
+
|
|
23
|
+
```mermaid
|
|
24
|
+
graph TD;
|
|
25
|
+
MStepperCompact --> MCircularProgressbar
|
|
26
|
+
style MStepperCompact fill:#008240,stroke:#333,stroke-width:4px
|
|
27
|
+
```
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import MStepperInline from './MStepperInline.vue';
|
|
3
|
+
import { describe, it, expect } from 'vitest';
|
|
4
|
+
|
|
5
|
+
describe('MStepperInline', () => {
|
|
6
|
+
const defaultSteps = [
|
|
7
|
+
{ label: 'Step 1' },
|
|
8
|
+
{ label: 'Step 2' },
|
|
9
|
+
{ label: 'Step 3' },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
it('renders correctly with default props', () => {
|
|
13
|
+
const wrapper = mount(MStepperInline, {
|
|
14
|
+
props: {
|
|
15
|
+
currentStep: 1,
|
|
16
|
+
steps: defaultSteps,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
expect(wrapper.exists()).toBe(true);
|
|
21
|
+
expect(wrapper.findAll('.mc-stepper-inline__item').length).toBe(
|
|
22
|
+
defaultSteps.length,
|
|
23
|
+
);
|
|
24
|
+
expect(wrapper.find('.mc-stepper-inline__label').text()).toContain(
|
|
25
|
+
'Step 1',
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('displays additional information when provided', () => {
|
|
30
|
+
const stepsWithInfo = [
|
|
31
|
+
{ label: 'Step 1', additionalInfo: 'Info 1' },
|
|
32
|
+
{ label: 'Step 2', additionalInfo: 'Info 2' },
|
|
33
|
+
];
|
|
34
|
+
const wrapper = mount(MStepperInline, {
|
|
35
|
+
props: {
|
|
36
|
+
currentStep: 1,
|
|
37
|
+
steps: stepsWithInfo,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
expect(wrapper.findAll('.mc-stepper-inline__additional').length).toBe(
|
|
42
|
+
stepsWithInfo.length,
|
|
43
|
+
);
|
|
44
|
+
expect(wrapper.find('.mc-stepper-inline__additional').text()).toBe(
|
|
45
|
+
'Info 1',
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('marks the correct step as active', async () => {
|
|
50
|
+
const wrapper = mount(MStepperInline, {
|
|
51
|
+
props: {
|
|
52
|
+
currentStep: 2,
|
|
53
|
+
steps: defaultSteps,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const labels = wrapper.findAll('.mc-stepper-inline__label');
|
|
58
|
+
expect(labels[1].classes()).toContain('is-current');
|
|
59
|
+
expect(labels[0].classes()).not.toContain('is-current');
|
|
60
|
+
|
|
61
|
+
await wrapper.setProps({ currentStep: 3 });
|
|
62
|
+
expect(labels[2].classes()).toContain('is-current');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('marks completed steps', () => {
|
|
66
|
+
const wrapper = mount(MStepperInline, {
|
|
67
|
+
props: {
|
|
68
|
+
currentStep: 3,
|
|
69
|
+
steps: defaultSteps,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const items = wrapper.findAll('.mc-stepper-inline__item');
|
|
74
|
+
expect(items[0].classes()).toContain('is-completed');
|
|
75
|
+
expect(items[1].classes()).toContain('is-completed');
|
|
76
|
+
expect(items[2].classes()).not.toContain('is-completed');
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
import MStepperInline from './MStepperInline.vue';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof MStepperInline> = {
|
|
5
|
+
title: 'Indicators/Stepper Inline',
|
|
6
|
+
component: MStepperInline,
|
|
7
|
+
tags: ['v2'],
|
|
8
|
+
parameters: {
|
|
9
|
+
docs: {
|
|
10
|
+
description: {
|
|
11
|
+
component:
|
|
12
|
+
'A stepper is a navigation component that guides users through a sequence of steps in a structured process. It visually represents progress, completed steps, and upcoming steps, helping users understand their position within a workflow. Steppers are commonly used in multi-step forms, onboarding flows, checkout processes, and task completion sequences to improve clarity and reduce cognitive load.',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
args: {
|
|
17
|
+
currentStep: 1,
|
|
18
|
+
steps: [
|
|
19
|
+
{ label: 'Cart' },
|
|
20
|
+
{ label: 'Delivery address' },
|
|
21
|
+
{ label: 'Payment' },
|
|
22
|
+
{ label: 'Order confirmation' },
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
render: (args) => ({
|
|
26
|
+
components: { MStepperInline },
|
|
27
|
+
setup() {
|
|
28
|
+
return { args };
|
|
29
|
+
},
|
|
30
|
+
template: `<MStepperInline v-bind="args" />`,
|
|
31
|
+
}),
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default meta;
|
|
35
|
+
type Story = StoryObj<typeof MStepperInline>;
|
|
36
|
+
|
|
37
|
+
export const Default: Story = {};
|
|
38
|
+
|
|
39
|
+
export const AditionnalInfo: Story = {
|
|
40
|
+
args: {
|
|
41
|
+
currentStep: 2,
|
|
42
|
+
steps: [
|
|
43
|
+
{ label: 'Cart', additionalInfo: 'Additional information' },
|
|
44
|
+
{ label: 'Delivery address', additionalInfo: 'Additional information' },
|
|
45
|
+
{ label: 'Payment', additionalInfo: 'Additional information' },
|
|
46
|
+
{ label: 'Order confirmation', additionalInfo: 'Additional information' },
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
};
|