@mozaic-ds/vue 1.0.0-rc.3 → 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 +111 -159
- 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 -31341
- package/dist/mozaic-vue.common.js +0 -31331
- package/dist/mozaic-vue.common.js.map +0 -1
- package/dist/mozaic-vue.umd.js +0 -31342
- 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 -380
- 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 -204
- package/src/components/tabs/index.js +0 -7
- package/src/components/tags/MTag.vue +0 -175
- 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 -452
- package/src/tokens/adeo/android/font_dimens.xml +0 -18
- package/src/tokens/adeo/css/_variables.scss +0 -446
- package/src/tokens/adeo/css/root.scss +0 -448
- package/src/tokens/adeo/ios/StyleDictionaryColor.h +0 -460
- package/src/tokens/adeo/ios/StyleDictionaryColor.m +0 -472
- package/src/tokens/adeo/ios/StyleDictionaryColor.swift +0 -455
- 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 -544
- package/src/tokens/adeo/js/tokensObject.js +0 -11733
- package/src/tokens/adeo/scss/_tokens.scss +0 -1522
- package/src/utils/mozaicClasses.js +0 -16
- package/src/utils/theme.validator.js +0 -19
- package/types/index.d.ts +0 -104
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import MButton from './MButton.vue';
|
|
4
|
+
import ChevronRight24 from '@mozaic-ds/icons-vue/src/components/ChevronRight24/ChevronRight24.vue';
|
|
5
|
+
import MLoader from '../loader/MLoader.vue';
|
|
6
|
+
|
|
7
|
+
describe('MButton component', () => {
|
|
8
|
+
it('renders with a label', () => {
|
|
9
|
+
const wrapper = mount(MButton, {
|
|
10
|
+
slots: {
|
|
11
|
+
default: 'Click Me',
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
expect(wrapper.text()).toContain('Click Me');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('applies the correct appearance class based on the appearance prop', () => {
|
|
18
|
+
const wrapper = mount(MButton, {
|
|
19
|
+
props: {
|
|
20
|
+
appearance: 'accent',
|
|
21
|
+
},
|
|
22
|
+
slots: {
|
|
23
|
+
default: 'Styled Button',
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
expect(wrapper.classes()).toContain('mc-button--accent');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('applies the correct size class based on the size prop', () => {
|
|
31
|
+
const wrapper = mount(MButton, {
|
|
32
|
+
props: {
|
|
33
|
+
label: 'Sized Button',
|
|
34
|
+
size: 'l',
|
|
35
|
+
},
|
|
36
|
+
slots: {
|
|
37
|
+
default: 'Sized Button',
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
expect(wrapper.classes()).toContain('mc-button--l');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('disables the button when the disabled prop is true', async () => {
|
|
45
|
+
const wrapper = mount(MButton, {
|
|
46
|
+
props: {
|
|
47
|
+
disabled: true,
|
|
48
|
+
},
|
|
49
|
+
slots: {
|
|
50
|
+
default: 'Disabled Button',
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const button = wrapper.find('button');
|
|
55
|
+
expect(button.attributes('disabled')).toBeDefined();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('applies the correct ghost class when ghost prop is true', () => {
|
|
59
|
+
const wrapper = mount(MButton, {
|
|
60
|
+
props: {
|
|
61
|
+
ghost: true,
|
|
62
|
+
},
|
|
63
|
+
slots: {
|
|
64
|
+
default: 'Ghost Button',
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
expect(wrapper.classes()).toContain('mc-button--ghost');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('applies the outlined class when outlined prop is true', () => {
|
|
72
|
+
const wrapper = mount(MButton, {
|
|
73
|
+
props: {
|
|
74
|
+
outlined: true,
|
|
75
|
+
},
|
|
76
|
+
slots: {
|
|
77
|
+
default: 'Outlined Button',
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
expect(wrapper.classes()).toContain('mc-button--outlined');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('has type="button" by default', () => {
|
|
85
|
+
const wrapper = mount(MButton, {
|
|
86
|
+
slots: {
|
|
87
|
+
default: 'Default Button',
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const button = wrapper.find('button');
|
|
92
|
+
expect(button.attributes('type')).toBe('button');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('can have type="submit" when the type prop is "submit"', () => {
|
|
96
|
+
const wrapper = mount(MButton, {
|
|
97
|
+
props: {
|
|
98
|
+
type: 'submit',
|
|
99
|
+
},
|
|
100
|
+
slots: {
|
|
101
|
+
default: 'Submit Button',
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const button = wrapper.find('button');
|
|
106
|
+
expect(button.attributes('type')).toBe('submit');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('renders with an icon in the left position', () => {
|
|
110
|
+
const wrapper = mount(MButton, {
|
|
111
|
+
props: {
|
|
112
|
+
iconPosition: 'left',
|
|
113
|
+
},
|
|
114
|
+
slots: {
|
|
115
|
+
default: 'Button with Icon',
|
|
116
|
+
icon: ChevronRight24,
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const icon = wrapper.findComponent(ChevronRight24);
|
|
121
|
+
expect(icon.exists()).toBe(true);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('renders with an icon in the right position', () => {
|
|
125
|
+
const wrapper = mount(MButton, {
|
|
126
|
+
props: {
|
|
127
|
+
iconPosition: 'right',
|
|
128
|
+
},
|
|
129
|
+
slots: {
|
|
130
|
+
default: 'Button with Icon',
|
|
131
|
+
icon: ChevronRight24,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const icon = wrapper.findComponent(ChevronRight24);
|
|
136
|
+
expect(icon.exists()).toBe(true);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('renders with only an icon when iconPosition is "only"', () => {
|
|
140
|
+
const wrapper = mount(MButton, {
|
|
141
|
+
props: {
|
|
142
|
+
iconPosition: 'only',
|
|
143
|
+
},
|
|
144
|
+
slots: {
|
|
145
|
+
default: 'Icon Only Button',
|
|
146
|
+
icon: ChevronRight24,
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const icon = wrapper.findComponent(ChevronRight24);
|
|
151
|
+
expect(icon.exists()).toBe(true);
|
|
152
|
+
|
|
153
|
+
const label = wrapper.find('.mc-button__label');
|
|
154
|
+
expect(label.exists()).toBe(false);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('renders loader when isLoading prop is true', () => {
|
|
158
|
+
const wrapper = mount(MButton, {
|
|
159
|
+
props: {
|
|
160
|
+
isLoading: true,
|
|
161
|
+
},
|
|
162
|
+
slots: {
|
|
163
|
+
default: 'Loading Button',
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const loader = wrapper.findComponent(MLoader);
|
|
168
|
+
expect(loader.exists()).toBe(true);
|
|
169
|
+
|
|
170
|
+
const label = wrapper.find('.mc-button__label');
|
|
171
|
+
expect(label.attributes('style')).toContain('visibility: hidden');
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('does not render loader when isLoading prop is false', () => {
|
|
175
|
+
const wrapper = mount(MButton, {
|
|
176
|
+
props: {
|
|
177
|
+
isLoading: false,
|
|
178
|
+
},
|
|
179
|
+
slots: {
|
|
180
|
+
default: 'Normal Button',
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const loader = wrapper.findComponent(MLoader);
|
|
185
|
+
expect(loader.exists()).toBe(false);
|
|
186
|
+
|
|
187
|
+
const label = wrapper.find('.mc-button__label');
|
|
188
|
+
expect(label.exists()).toBe(true);
|
|
189
|
+
expect(label.text()).toBe('Normal Button');
|
|
190
|
+
});
|
|
191
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
|
|
3
|
+
import MButton from './MButton.vue';
|
|
4
|
+
import Download24 from '@mozaic-ds/icons-vue/src/components/Download24/Download24.vue';
|
|
5
|
+
import ChevronRight24 from '@mozaic-ds/icons-vue/src/components/ChevronRight24/ChevronRight24.vue';
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof MButton> = {
|
|
8
|
+
title: 'Action/Button',
|
|
9
|
+
component: MButton,
|
|
10
|
+
parameters: {
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component:
|
|
14
|
+
'Buttons are key interactive elements used to perform actions and can be used as standalone element, or as part of another component. Their appearance depends on the type of action required from the user and the context in which they are used.',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
args: { default: 'Button Label' },
|
|
19
|
+
render: (args) => ({
|
|
20
|
+
components: { MButton, Download24, ChevronRight24 },
|
|
21
|
+
setup() {
|
|
22
|
+
return { args };
|
|
23
|
+
},
|
|
24
|
+
template: `
|
|
25
|
+
<MButton
|
|
26
|
+
v-bind="args"
|
|
27
|
+
>
|
|
28
|
+
<template v-if="${'icon' in args}" v-slot:icon>${args.icon}</template>
|
|
29
|
+
<template v-if="${'default' in args}" v-slot>${args.default}</template>
|
|
30
|
+
</MButton>
|
|
31
|
+
`,
|
|
32
|
+
}),
|
|
33
|
+
};
|
|
34
|
+
export default meta;
|
|
35
|
+
type Story = StoryObj<typeof MButton>;
|
|
36
|
+
|
|
37
|
+
export const Filled: Story = {};
|
|
38
|
+
|
|
39
|
+
export const Outline: Story = {
|
|
40
|
+
args: { outlined: true },
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const Ghost: Story = {
|
|
44
|
+
args: { ghost: true },
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const Icon: Story = {
|
|
48
|
+
args: {
|
|
49
|
+
iconPosition: 'left',
|
|
50
|
+
icon: '<ChevronRight24/>',
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const Loading: Story = {
|
|
55
|
+
args: {
|
|
56
|
+
isLoading: true,
|
|
57
|
+
ariaLabel: 'Loading button',
|
|
58
|
+
},
|
|
59
|
+
};
|
|
@@ -1,169 +1,113 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<a v-if="href" :href="href" class="mc-button" :class="setClasses" :aria-label="ariaLabel">
|
|
3
|
-
<m-icon
|
|
4
|
-
v-if="icon && iconPosition === 'left'"
|
|
5
|
-
:id="`mc-button__${iconPosition}-icon-${id}`"
|
|
6
|
-
:class="`mc-button__icon mc-button__icon--${iconPosition}`"
|
|
7
|
-
:name="icon"
|
|
8
|
-
/>
|
|
9
|
-
<span v-if="label" class="mc-button__label">
|
|
10
|
-
{{ label }}
|
|
11
|
-
</span>
|
|
12
|
-
<m-icon
|
|
13
|
-
v-if="icon && iconPosition === 'right'"
|
|
14
|
-
:id="`mc-button__${iconPosition}-icon-${id}`"
|
|
15
|
-
:class="`mc-button__icon mc-button__icon--${iconPosition}`"
|
|
16
|
-
:name="icon"
|
|
17
|
-
/>
|
|
18
|
-
</a>
|
|
19
2
|
<button
|
|
20
|
-
v-else
|
|
21
3
|
class="mc-button"
|
|
4
|
+
:class="classObject"
|
|
22
5
|
:disabled="disabled"
|
|
23
|
-
:
|
|
24
|
-
:aria-label="ariaLabel"
|
|
25
|
-
@click="$emit('click', $event)"
|
|
6
|
+
:type="type"
|
|
26
7
|
>
|
|
27
|
-
<
|
|
28
|
-
v-if="icon && iconPosition
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<span
|
|
34
|
-
|
|
8
|
+
<span
|
|
9
|
+
v-if="$slots.icon && iconPosition == 'left' && !isLoading"
|
|
10
|
+
class="mc-button__icon"
|
|
11
|
+
>
|
|
12
|
+
<slot name="icon" />
|
|
13
|
+
</span>
|
|
14
|
+
<span
|
|
15
|
+
v-if="isLoading"
|
|
16
|
+
class="mc-button__icon"
|
|
17
|
+
:style="{ position: 'absolute' }"
|
|
18
|
+
>
|
|
19
|
+
<MLoader :style="{ color: 'currentColor' }" size="s" />
|
|
20
|
+
</span>
|
|
21
|
+
<span v-if="$slots.icon && iconPosition == 'only'" class="mc-button__icon">
|
|
22
|
+
<slot name="icon" />
|
|
23
|
+
</span>
|
|
24
|
+
<span
|
|
25
|
+
v-else
|
|
26
|
+
class="mc-button__label"
|
|
27
|
+
:style="{ visibility: isLoading ? 'hidden' : 'visible' }"
|
|
28
|
+
>
|
|
29
|
+
<slot>Button Label</slot>
|
|
30
|
+
</span>
|
|
31
|
+
<span
|
|
32
|
+
v-if="$slots.icon && iconPosition == 'right' && !isLoading"
|
|
33
|
+
class="mc-button__icon"
|
|
34
|
+
>
|
|
35
|
+
<slot name="icon" />
|
|
35
36
|
</span>
|
|
36
|
-
<m-icon
|
|
37
|
-
v-if="icon && iconPosition === 'right'"
|
|
38
|
-
:id="`mc-button__${iconPosition}-icon-${id}`"
|
|
39
|
-
:class="`mc-button__icon mc-button__icon--${iconPosition}`"
|
|
40
|
-
:name="icon"
|
|
41
|
-
/>
|
|
42
37
|
</button>
|
|
43
38
|
</template>
|
|
44
39
|
|
|
45
|
-
<script>
|
|
46
|
-
import {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
'l@from-xl',
|
|
91
|
-
'l@from-xxl',
|
|
92
|
-
]),
|
|
93
|
-
},
|
|
94
|
-
width: {
|
|
95
|
-
type: String,
|
|
96
|
-
default: null,
|
|
97
|
-
validator: (value) =>
|
|
98
|
-
responsiveModifierValidators(value, [
|
|
99
|
-
'fit',
|
|
100
|
-
'fit@from-m',
|
|
101
|
-
'fit@from-l',
|
|
102
|
-
'fit@from-xl',
|
|
103
|
-
'fit@from-xxl',
|
|
104
|
-
'full',
|
|
105
|
-
'full@from-m',
|
|
106
|
-
'full@from-l',
|
|
107
|
-
'full@from-xl',
|
|
108
|
-
'full@from-xxl',
|
|
109
|
-
]),
|
|
110
|
-
},
|
|
111
|
-
disabled: {
|
|
112
|
-
type: Boolean,
|
|
113
|
-
default: false,
|
|
114
|
-
},
|
|
115
|
-
icon: {
|
|
116
|
-
type: String,
|
|
117
|
-
default: null,
|
|
118
|
-
},
|
|
119
|
-
iconPosition: {
|
|
120
|
-
type: String,
|
|
121
|
-
default: 'left',
|
|
122
|
-
validator: (value) => ['left', 'right'].includes(value),
|
|
123
|
-
},
|
|
124
|
-
ariaLabel: {
|
|
125
|
-
type: String,
|
|
126
|
-
default: null,
|
|
127
|
-
},
|
|
40
|
+
<script setup lang="ts">
|
|
41
|
+
import { computed, type VNode } from 'vue';
|
|
42
|
+
import MLoader from '../loader/MLoader.vue';
|
|
43
|
+
/**
|
|
44
|
+
* Buttons are used to trigger actions. Their appearance is depending on the type of action required from the user, or the context.
|
|
45
|
+
*/
|
|
46
|
+
const props = withDefaults(
|
|
47
|
+
defineProps<{
|
|
48
|
+
/**
|
|
49
|
+
* Defines the visual style of the button.
|
|
50
|
+
*/
|
|
51
|
+
appearance?: 'standard' | 'accent' | 'danger' | 'inverse';
|
|
52
|
+
/**
|
|
53
|
+
* Determines the size of the button.
|
|
54
|
+
*/
|
|
55
|
+
size?: 's' | 'm' | 'l';
|
|
56
|
+
/**
|
|
57
|
+
* If `true`, disables the button, making it non-interactive.
|
|
58
|
+
*/
|
|
59
|
+
disabled?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* If `true`, applies a "ghost" style to the button, typically a transparent background with a border.
|
|
62
|
+
*/
|
|
63
|
+
ghost?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* If `true`, the button gets an outlined style, usually with just the border and no solid background.
|
|
66
|
+
*/
|
|
67
|
+
outlined?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Controls the positioning of an icon in the button.
|
|
70
|
+
*/
|
|
71
|
+
iconPosition?: 'left' | 'right' | 'only';
|
|
72
|
+
/**
|
|
73
|
+
* Specifies the button's HTML `type` attribute.
|
|
74
|
+
*/
|
|
75
|
+
type?: 'button' | 'reset' | 'submit';
|
|
76
|
+
/**
|
|
77
|
+
* If `true`, a loading state is displayed.
|
|
78
|
+
*/
|
|
79
|
+
isLoading?: boolean;
|
|
80
|
+
}>(),
|
|
81
|
+
{
|
|
82
|
+
appearance: 'standard',
|
|
83
|
+
size: 'm',
|
|
84
|
+
type: 'button',
|
|
128
85
|
},
|
|
86
|
+
);
|
|
129
87
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (this.theme) {
|
|
141
|
-
classes.push(`mc-button--${this.theme}`);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (this.size) {
|
|
145
|
-
responsiveModifiers('mc-button', this.size, classes);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (this.width) {
|
|
149
|
-
responsiveModifiers('mc-button', this.width, classes);
|
|
150
|
-
}
|
|
88
|
+
defineSlots<{
|
|
89
|
+
/**
|
|
90
|
+
* The content displayed in the button.
|
|
91
|
+
*/
|
|
92
|
+
default: string;
|
|
93
|
+
/**
|
|
94
|
+
* Use this slot to insert an icon for the Button
|
|
95
|
+
*/
|
|
96
|
+
icon?: VNode;
|
|
97
|
+
}>();
|
|
151
98
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
},
|
|
163
|
-
};
|
|
99
|
+
const classObject = computed(() => {
|
|
100
|
+
return {
|
|
101
|
+
[`mc-button--${props.appearance}`]:
|
|
102
|
+
props.appearance && props.appearance != 'standard',
|
|
103
|
+
[`mc-button--${props.size}`]: props.size && props.size != 'm',
|
|
104
|
+
'mc-button--ghost': props.ghost,
|
|
105
|
+
'mc-button--outlined': props.outlined,
|
|
106
|
+
'mc-button--icon-only': props.iconPosition == 'only',
|
|
107
|
+
};
|
|
108
|
+
});
|
|
164
109
|
</script>
|
|
165
110
|
|
|
166
|
-
<style lang="scss">
|
|
167
|
-
@
|
|
168
|
-
@import 'components/c.button';
|
|
111
|
+
<style lang="scss" scoped>
|
|
112
|
+
@use '@mozaic-ds/styles/components/button';
|
|
169
113
|
</style>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import MCheckbox from './MCheckbox.vue';
|
|
3
|
+
import { describe, it, expect } from 'vitest';
|
|
4
|
+
|
|
5
|
+
describe('MCheckbox', () => {
|
|
6
|
+
it('renders with label', () => {
|
|
7
|
+
const wrapper = mount(MCheckbox, {
|
|
8
|
+
props: {
|
|
9
|
+
id: 'test-checkbox',
|
|
10
|
+
label: 'Accept terms',
|
|
11
|
+
modelValue: false,
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
expect(wrapper.find('label').text()).toBe('Accept terms');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('renders the checkbox as checked when modelValue is true', () => {
|
|
19
|
+
const wrapper = mount(MCheckbox, {
|
|
20
|
+
props: {
|
|
21
|
+
id: 'test-checkbox',
|
|
22
|
+
modelValue: true,
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const checkbox = wrapper.find('input');
|
|
27
|
+
expect(checkbox.element.checked).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('renders the checkbox as unchecked when modelValue is false', () => {
|
|
31
|
+
const wrapper = mount(MCheckbox, {
|
|
32
|
+
props: {
|
|
33
|
+
id: 'test-checkbox',
|
|
34
|
+
modelValue: false,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const checkbox = wrapper.find('input');
|
|
39
|
+
expect(checkbox.element.checked).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('emits update:modelValue when clicked', async () => {
|
|
43
|
+
const wrapper = mount(MCheckbox, {
|
|
44
|
+
props: {
|
|
45
|
+
id: 'test-checkbox',
|
|
46
|
+
modelValue: false,
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const checkbox = wrapper.find('input');
|
|
51
|
+
await checkbox.setChecked(true);
|
|
52
|
+
|
|
53
|
+
expect(wrapper.emitted()['update:modelValue'][0]).toEqual([true]);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('emits update:modelValue when unchecked', async () => {
|
|
57
|
+
const wrapper = mount(MCheckbox, {
|
|
58
|
+
props: {
|
|
59
|
+
id: 'test-checkbox',
|
|
60
|
+
modelValue: true,
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const checkbox = wrapper.find('input');
|
|
65
|
+
await checkbox.setChecked(false);
|
|
66
|
+
|
|
67
|
+
expect(wrapper.emitted()['update:modelValue'][0]).toEqual([false]);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('is disabled when the disabled prop is true', () => {
|
|
71
|
+
const wrapper = mount(MCheckbox, {
|
|
72
|
+
props: {
|
|
73
|
+
id: 'test-checkbox',
|
|
74
|
+
disabled: true,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const checkbox = wrapper.find('input');
|
|
79
|
+
expect(checkbox.element.disabled).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('sets the indeterminate state correctly', () => {
|
|
83
|
+
const wrapper = mount(MCheckbox, {
|
|
84
|
+
props: {
|
|
85
|
+
id: 'test-checkbox',
|
|
86
|
+
indeterminate: true,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const checkbox = wrapper.find('input');
|
|
91
|
+
expect(checkbox.element.indeterminate).toBe(true);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('applies is-invalid class when isInvalid is true', () => {
|
|
95
|
+
const wrapper = mount(MCheckbox, {
|
|
96
|
+
props: {
|
|
97
|
+
id: 'test-checkbox',
|
|
98
|
+
isInvalid: true,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
expect(wrapper.find('input').classes()).toContain('is-invalid');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
import { action } from 'storybook/actions';
|
|
3
|
+
|
|
4
|
+
import MCheckbox from './MCheckbox.vue';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof MCheckbox> = {
|
|
7
|
+
title: 'Form Elements/Checkbox',
|
|
8
|
+
component: MCheckbox,
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
'A checkbox is an interactive component used to select or deselect an option, typically within a list of choices. It allows users to make multiple selections independently and is often accompanied by a label for clarity. Checkboxes are commonly used in forms, filters, settings, and preference selections to provide a simple and intuitive way to enable or disable specific options.',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
args: {
|
|
18
|
+
label: 'Label',
|
|
19
|
+
id: 'checkboxId',
|
|
20
|
+
},
|
|
21
|
+
render: (args) => ({
|
|
22
|
+
components: { MCheckbox },
|
|
23
|
+
setup() {
|
|
24
|
+
const handleUpdate = action('update:modelValue');
|
|
25
|
+
|
|
26
|
+
return { args, handleUpdate };
|
|
27
|
+
},
|
|
28
|
+
template: `
|
|
29
|
+
<MCheckbox
|
|
30
|
+
v-bind="args"
|
|
31
|
+
@update:modelValue="handleUpdate"
|
|
32
|
+
/>
|
|
33
|
+
`,
|
|
34
|
+
}),
|
|
35
|
+
};
|
|
36
|
+
export default meta;
|
|
37
|
+
type Story = StoryObj<typeof MCheckbox>;
|
|
38
|
+
|
|
39
|
+
export const Default: Story = {};
|
|
40
|
+
|
|
41
|
+
export const Checked: Story = {
|
|
42
|
+
args: {
|
|
43
|
+
modelValue: true,
|
|
44
|
+
id: 'checkedId',
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const Indeterminate: Story = {
|
|
49
|
+
args: {
|
|
50
|
+
indeterminate: true,
|
|
51
|
+
id: 'IndeterminateId',
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const Disabled: Story = {
|
|
56
|
+
args: {
|
|
57
|
+
disabled: true,
|
|
58
|
+
id: 'disabledId',
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const Invalid: Story = {
|
|
63
|
+
args: {
|
|
64
|
+
isInvalid: true,
|
|
65
|
+
id: 'invalidId',
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const IndeterminateDisabled: Story = {
|
|
70
|
+
args: {
|
|
71
|
+
indeterminate: true,
|
|
72
|
+
disabled: true,
|
|
73
|
+
id: 'checkedIndeterminateId',
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const CheckedDisabled: Story = {
|
|
78
|
+
args: {
|
|
79
|
+
modelValue: true,
|
|
80
|
+
disabled: true,
|
|
81
|
+
id: 'checkedDisabledId',
|
|
82
|
+
},
|
|
83
|
+
};
|