@mozaic-ds/vue 1.0.0-rc.3 → 2.2.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 +1718 -0
- package/dist/mozaic-vue.js +1971 -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/tooltip/MTooltip.spec.ts +47 -0
- package/src/components/tooltip/MTooltip.stories.ts +59 -0
- package/src/components/tooltip/MTooltip.vue +49 -32
- package/src/components/usingIcons.mdx +35 -0
- package/src/components/usingPresets.mdx +128 -0
- package/src/main.ts +33 -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/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,46 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3';
|
|
2
|
+
import MFlag from './MFlag.vue';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof MFlag> = {
|
|
5
|
+
title: 'Indicators/Flag',
|
|
6
|
+
component: MFlag,
|
|
7
|
+
parameters: {
|
|
8
|
+
docs: {
|
|
9
|
+
description: {
|
|
10
|
+
component:
|
|
11
|
+
'A flag is used to display meta-information about a product or service, acting as a visual indicator of the main category of content. It is typically placed at the top of an element to ensure immediate visibility.',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
args: {
|
|
16
|
+
label: 'Flag label',
|
|
17
|
+
},
|
|
18
|
+
render: (args) => ({
|
|
19
|
+
components: { MFlag },
|
|
20
|
+
setup() {
|
|
21
|
+
return { args };
|
|
22
|
+
},
|
|
23
|
+
template: `
|
|
24
|
+
<MFlag v-bind="args"></MFlag>
|
|
25
|
+
`,
|
|
26
|
+
}),
|
|
27
|
+
};
|
|
28
|
+
export default meta;
|
|
29
|
+
type Story = StoryObj<typeof MFlag>;
|
|
30
|
+
|
|
31
|
+
export const Standard: Story = {};
|
|
32
|
+
|
|
33
|
+
export const Accent: Story = {
|
|
34
|
+
args: { appearance: 'accent' },
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const Danger: Story = {
|
|
38
|
+
args: { appearance: 'danger' },
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const Inverse: Story = {
|
|
42
|
+
globals: {
|
|
43
|
+
backgrounds: { value: 'inverse' },
|
|
44
|
+
},
|
|
45
|
+
args: { appearance: 'inverse' },
|
|
46
|
+
};
|
|
@@ -1,46 +1,35 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<span class="mc-flag__label">
|
|
4
|
-
|
|
2
|
+
<div class="mc-flag" :class="classObject">
|
|
3
|
+
<span class="mc-flag__label">
|
|
4
|
+
{{ label }}
|
|
5
|
+
</span>
|
|
6
|
+
</div>
|
|
5
7
|
</template>
|
|
6
8
|
|
|
7
|
-
<script>
|
|
8
|
-
import {
|
|
9
|
+
<script setup lang="ts">
|
|
10
|
+
import { computed } from 'vue';
|
|
11
|
+
/**
|
|
12
|
+
* A flag is used to display meta-information about a product or service, acting as a visual indicator of the main category of content. It is typically placed at the top of an element to ensure immediate visibility.
|
|
13
|
+
*/
|
|
14
|
+
const props = defineProps<{
|
|
15
|
+
/**
|
|
16
|
+
* Label of the Flag
|
|
17
|
+
*/
|
|
18
|
+
label: string;
|
|
19
|
+
/**
|
|
20
|
+
* Allows to define the Flag style
|
|
21
|
+
*/
|
|
22
|
+
appearance?: 'danger' | 'accent' | 'inverse' | 'standard';
|
|
23
|
+
}>();
|
|
9
24
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
required: true,
|
|
17
|
-
},
|
|
18
|
-
theme: {
|
|
19
|
-
type: String,
|
|
20
|
-
default: null,
|
|
21
|
-
validator: (value) => checkThemeValue(value),
|
|
22
|
-
},
|
|
23
|
-
htmlTag: {
|
|
24
|
-
type: String,
|
|
25
|
-
default: 'div',
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
|
|
29
|
-
computed: {
|
|
30
|
-
setClasses() {
|
|
31
|
-
const classes = [];
|
|
32
|
-
|
|
33
|
-
if (this.theme) {
|
|
34
|
-
classes.push(`mc-flag--${this.theme}`);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return classes;
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
};
|
|
25
|
+
const classObject = computed(() => {
|
|
26
|
+
return {
|
|
27
|
+
[`mc-flag--${props.appearance}`]:
|
|
28
|
+
props.appearance && props.appearance != 'standard',
|
|
29
|
+
};
|
|
30
|
+
});
|
|
41
31
|
</script>
|
|
42
32
|
|
|
43
|
-
<style lang="scss">
|
|
44
|
-
@
|
|
45
|
-
@import 'components/_c.flag';
|
|
33
|
+
<style lang="scss" scoped>
|
|
34
|
+
@use '@mozaic-ds/styles/components/flag';
|
|
46
35
|
</style>
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import MIconButton from './MIconButton.vue';
|
|
4
|
+
import ChevronRight24 from '@mozaic-ds/icons-vue/src/components/ChevronRight24/ChevronRight24.vue';
|
|
5
|
+
|
|
6
|
+
describe('MButton component', () => {
|
|
7
|
+
it('renders with an icon', () => {
|
|
8
|
+
const wrapper = mount(MIconButton, {
|
|
9
|
+
slots: {
|
|
10
|
+
icon: [ChevronRight24],
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const icon = wrapper.findComponent(ChevronRight24);
|
|
15
|
+
expect(icon.exists()).toBe(true);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('applies the correct appearance class based on the appearance prop', () => {
|
|
19
|
+
const wrapper = mount(MIconButton, {
|
|
20
|
+
props: {
|
|
21
|
+
appearance: 'accent',
|
|
22
|
+
},
|
|
23
|
+
slots: {
|
|
24
|
+
icon: [ChevronRight24],
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
expect(wrapper.classes()).toContain('mc-button--accent');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('applies the correct size class based on the size prop', () => {
|
|
32
|
+
const wrapper = mount(MIconButton, {
|
|
33
|
+
props: {
|
|
34
|
+
size: 'l',
|
|
35
|
+
},
|
|
36
|
+
slots: {
|
|
37
|
+
icon: [ChevronRight24],
|
|
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(MIconButton, {
|
|
46
|
+
props: {
|
|
47
|
+
disabled: true,
|
|
48
|
+
},
|
|
49
|
+
slots: {
|
|
50
|
+
icon: [ChevronRight24],
|
|
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(MIconButton, {
|
|
60
|
+
props: {
|
|
61
|
+
ghost: true,
|
|
62
|
+
},
|
|
63
|
+
slots: {
|
|
64
|
+
icon: [ChevronRight24],
|
|
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(MIconButton, {
|
|
73
|
+
props: {
|
|
74
|
+
outlined: true,
|
|
75
|
+
},
|
|
76
|
+
slots: {
|
|
77
|
+
icon: [ChevronRight24],
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
expect(wrapper.classes()).toContain('mc-button--outlined');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('has type="button" by default', () => {
|
|
85
|
+
const wrapper = mount(MIconButton, {
|
|
86
|
+
slots: {
|
|
87
|
+
icon: [ChevronRight24],
|
|
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(MIconButton, {
|
|
97
|
+
props: {
|
|
98
|
+
type: 'submit',
|
|
99
|
+
},
|
|
100
|
+
slots: {
|
|
101
|
+
icon: [ChevronRight24],
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const button = wrapper.find('button');
|
|
106
|
+
expect(button.attributes('type')).toBe('submit');
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
|
|
3
|
+
import MIconButton from './MIconButton.vue';
|
|
4
|
+
import ChevronRight20 from '@mozaic-ds/icons-vue/src/components/ChevronRight20/ChevronRight20.vue';
|
|
5
|
+
import ChevronRight24 from '@mozaic-ds/icons-vue/src/components/ChevronRight24/ChevronRight24.vue';
|
|
6
|
+
import ChevronRight32 from '@mozaic-ds/icons-vue/src/components/ChevronRight32/ChevronRight32.vue';
|
|
7
|
+
|
|
8
|
+
const meta: Meta<typeof MIconButton> = {
|
|
9
|
+
title: 'Action/Icon Button',
|
|
10
|
+
component: MIconButton,
|
|
11
|
+
parameters: {
|
|
12
|
+
docs: {
|
|
13
|
+
description: {
|
|
14
|
+
component:
|
|
15
|
+
'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.',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
args: {
|
|
20
|
+
icon: '<ChevronRight24/>',
|
|
21
|
+
ariaLabel: 'Go to next page',
|
|
22
|
+
},
|
|
23
|
+
argTypes: {
|
|
24
|
+
ariaLabel: {
|
|
25
|
+
table: {
|
|
26
|
+
disable: true,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
$slots: {
|
|
30
|
+
table: {
|
|
31
|
+
disable: true,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
render: (args) => ({
|
|
36
|
+
components: { MIconButton, ChevronRight20, ChevronRight24, ChevronRight32 },
|
|
37
|
+
setup() {
|
|
38
|
+
return { args };
|
|
39
|
+
},
|
|
40
|
+
template: `
|
|
41
|
+
<MIconButton
|
|
42
|
+
v-bind="args"
|
|
43
|
+
>
|
|
44
|
+
<template v-if="${'icon' in args}" v-slot:icon>${args.icon}</template>
|
|
45
|
+
</MIconButton>
|
|
46
|
+
`,
|
|
47
|
+
}),
|
|
48
|
+
};
|
|
49
|
+
export default meta;
|
|
50
|
+
type Story = StoryObj<typeof MIconButton>;
|
|
51
|
+
|
|
52
|
+
export const Standard: Story = {};
|
|
53
|
+
|
|
54
|
+
export const Outline: Story = {
|
|
55
|
+
args: { outlined: true },
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const Ghost: Story = {
|
|
59
|
+
args: { ghost: true },
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const SizeS: Story = {
|
|
63
|
+
args: {
|
|
64
|
+
size: 's',
|
|
65
|
+
icon: '<ChevronRight20/>',
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const SizeL: Story = {
|
|
70
|
+
args: {
|
|
71
|
+
size: 'l',
|
|
72
|
+
icon: '<ChevronRight32/>',
|
|
73
|
+
},
|
|
74
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<button
|
|
3
|
+
class="mc-button mc-button--icon-button"
|
|
4
|
+
:class="classObject"
|
|
5
|
+
:disabled="disabled"
|
|
6
|
+
:type="type"
|
|
7
|
+
>
|
|
8
|
+
<span class="mc-button__icon">
|
|
9
|
+
<slot name="icon" />
|
|
10
|
+
</span>
|
|
11
|
+
</button>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup lang="ts">
|
|
15
|
+
import { computed, type VNode } from 'vue';
|
|
16
|
+
/**
|
|
17
|
+
* Icon Buttons are used to trigger actions. Their appearance is depending on the type of action required from the user, or the context.
|
|
18
|
+
*/
|
|
19
|
+
const props = withDefaults(
|
|
20
|
+
defineProps<{
|
|
21
|
+
/**
|
|
22
|
+
* Defines the visual style of the icon button.
|
|
23
|
+
*/
|
|
24
|
+
appearance?: 'standard' | 'accent' | 'danger' | 'inverse';
|
|
25
|
+
/**
|
|
26
|
+
* Determines the size of the icon button.
|
|
27
|
+
*/
|
|
28
|
+
size?: 's' | 'm' | 'l';
|
|
29
|
+
/**
|
|
30
|
+
* If `true`, disables the icon button, making it non-interactive.
|
|
31
|
+
*/
|
|
32
|
+
disabled?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* If `true`, applies a "ghost" style to the icon button.
|
|
35
|
+
*/
|
|
36
|
+
ghost?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* If `true`, the icon button gets an outlined style.
|
|
39
|
+
*/
|
|
40
|
+
outlined?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Specifies the button's HTML `type` attribute.
|
|
43
|
+
*/
|
|
44
|
+
type?: 'button' | 'reset' | 'submit';
|
|
45
|
+
}>(),
|
|
46
|
+
{
|
|
47
|
+
appearance: 'standard',
|
|
48
|
+
size: 'm',
|
|
49
|
+
type: 'button',
|
|
50
|
+
},
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
defineSlots<{
|
|
54
|
+
/**
|
|
55
|
+
* Use this slot to insert the form element of your choice
|
|
56
|
+
*/
|
|
57
|
+
icon: VNode;
|
|
58
|
+
}>();
|
|
59
|
+
|
|
60
|
+
const classObject = computed(() => {
|
|
61
|
+
return {
|
|
62
|
+
[`mc-button--${props.appearance}`]:
|
|
63
|
+
props.appearance && props.appearance != 'standard',
|
|
64
|
+
[`mc-button--${props.size}`]: props.size && props.size != 'm',
|
|
65
|
+
'mc-button--ghost': props.ghost,
|
|
66
|
+
'mc-button--outlined': props.outlined,
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<style lang="scss" scoped>
|
|
72
|
+
@use '@mozaic-ds/styles/components/button';
|
|
73
|
+
</style>
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import MLink from './MLink.vue';
|
|
3
|
+
import { describe, it, expect } from 'vitest';
|
|
4
|
+
|
|
5
|
+
describe('MLink component', () => {
|
|
6
|
+
it('renders a link with default props', () => {
|
|
7
|
+
const wrapper = mount(MLink);
|
|
8
|
+
|
|
9
|
+
const link = wrapper.get('a');
|
|
10
|
+
expect(link.classes()).toContain('mc-link');
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('renders as router-link when the "router" prop is true', () => {
|
|
14
|
+
const wrapper = mount(MLink, {
|
|
15
|
+
props: {
|
|
16
|
+
router: true,
|
|
17
|
+
href: '/internal',
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const link = wrapper.getComponent('router-link');
|
|
22
|
+
expect(link.exists()).toBe(true);
|
|
23
|
+
expect(link.attributes('to')).toBe('/internal');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('renders as a regular anchor when the "router" prop is false or undefined', () => {
|
|
27
|
+
const wrapper = mount(MLink, {
|
|
28
|
+
props: {
|
|
29
|
+
href: 'https://example.com',
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const link = wrapper.get('a');
|
|
34
|
+
expect(link.exists()).toBe(true);
|
|
35
|
+
expect(link.attributes('href')).toBe('https://example.com');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('renders without an icon', () => {
|
|
39
|
+
const wrapper = mount(MLink, {
|
|
40
|
+
slots: {
|
|
41
|
+
default: 'Link text',
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const icon = wrapper.find('.mc-link__icon');
|
|
46
|
+
const label = wrapper.find('.mc-link__label');
|
|
47
|
+
expect(icon.exists()).toBe(false);
|
|
48
|
+
expect(label.text()).toBe('Link text');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('renders with an icon on the left when "iconPosition" is "left"', () => {
|
|
52
|
+
const wrapper = mount(MLink, {
|
|
53
|
+
props: {
|
|
54
|
+
iconPosition: 'left',
|
|
55
|
+
},
|
|
56
|
+
slots: {
|
|
57
|
+
icon: '<span>Left Icon</span>',
|
|
58
|
+
default: 'Link text',
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const leftIcon = wrapper.find('.mc-link__icon');
|
|
63
|
+
const label = wrapper.find('.mc-link__label');
|
|
64
|
+
expect(leftIcon.exists()).toBe(true);
|
|
65
|
+
expect(leftIcon.text()).toBe('Left Icon');
|
|
66
|
+
expect(label.text()).toBe('Link text');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('renders with an icon on the right when "iconPosition" is "right"', () => {
|
|
70
|
+
const wrapper = mount(MLink, {
|
|
71
|
+
props: {
|
|
72
|
+
iconPosition: 'right',
|
|
73
|
+
},
|
|
74
|
+
slots: {
|
|
75
|
+
icon: '<span>Right Icon</span>',
|
|
76
|
+
default: 'Link text',
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const rightIcon = wrapper.find('.mc-link__icon');
|
|
81
|
+
const label = wrapper.find('.mc-link__label');
|
|
82
|
+
expect(rightIcon.exists()).toBe(true);
|
|
83
|
+
expect(rightIcon.text()).toBe('Right Icon');
|
|
84
|
+
expect(label.text()).toBe('Link text');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('applies the correct appearance class', () => {
|
|
88
|
+
const wrapper = mount(MLink, {
|
|
89
|
+
props: {
|
|
90
|
+
appearance: 'accent',
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const link = wrapper.get('a');
|
|
95
|
+
expect(link.classes()).toContain('mc-link--accent');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('applies the correct size class', () => {
|
|
99
|
+
const wrapper = mount(MLink, {
|
|
100
|
+
props: {
|
|
101
|
+
size: 'm',
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const link = wrapper.get('a');
|
|
106
|
+
expect(link.classes()).toContain('mc-link--m');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('adds "mc-link--inline" class when inline', () => {
|
|
110
|
+
const wrapper = mount(MLink, {
|
|
111
|
+
props: {
|
|
112
|
+
inline: true,
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const link = wrapper.get('a');
|
|
117
|
+
expect(link.classes()).toContain('mc-link--inline');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('applies the href and target attributes correctly', () => {
|
|
121
|
+
const wrapper = mount(MLink, {
|
|
122
|
+
props: {
|
|
123
|
+
href: 'https://example.com',
|
|
124
|
+
target: '_blank',
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const link = wrapper.get('a');
|
|
129
|
+
expect(link.attributes('href')).toBe('https://example.com');
|
|
130
|
+
expect(link.attributes('target')).toBe('_blank');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('renders default slot content', () => {
|
|
134
|
+
const wrapper = mount(MLink, {
|
|
135
|
+
slots: {
|
|
136
|
+
default: 'Custom Link Text',
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const linkText = wrapper.get('.mc-link__label');
|
|
141
|
+
expect(linkText.text()).toBe('Custom Link Text');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('binds custom attributes correctly', () => {
|
|
145
|
+
const wrapper = mount(MLink, {
|
|
146
|
+
attrs: {
|
|
147
|
+
'data-test-id': 'custom-id',
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const link = wrapper.get('a');
|
|
152
|
+
expect(link.attributes('data-test-id')).toBe('custom-id');
|
|
153
|
+
});
|
|
154
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
import MLink from './MLink.vue';
|
|
3
|
+
import ChevronLeft24 from '@mozaic-ds/icons-vue/src/components/ChevronLeft24/ChevronLeft24.vue';
|
|
4
|
+
import ChevronRight24 from '@mozaic-ds/icons-vue/src/components/ChevronRight24/ChevronRight24.vue';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof MLink> = {
|
|
7
|
+
title: 'Navigation/Link (stand alone)',
|
|
8
|
+
component: MLink,
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
'A link is a component used exclusively to navigate to internal or external webpages or to anchors in the current page.',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
args: {
|
|
18
|
+
default: 'Stand-alone link',
|
|
19
|
+
href: '#',
|
|
20
|
+
},
|
|
21
|
+
render: (args) => ({
|
|
22
|
+
components: { MLink, ChevronRight24, ChevronLeft24 },
|
|
23
|
+
setup() {
|
|
24
|
+
return { args };
|
|
25
|
+
},
|
|
26
|
+
template: `
|
|
27
|
+
<MLink v-bind="args">
|
|
28
|
+
<template v-if="${'icon' in args}" v-slot:icon>${args.icon}</template>
|
|
29
|
+
${args.default}
|
|
30
|
+
</MLink>
|
|
31
|
+
`,
|
|
32
|
+
}),
|
|
33
|
+
};
|
|
34
|
+
export default meta;
|
|
35
|
+
type Story = StoryObj<typeof MLink>;
|
|
36
|
+
|
|
37
|
+
export const Standard: Story = {};
|
|
38
|
+
|
|
39
|
+
export const ExternalLink: Story = {
|
|
40
|
+
name: 'For External Link',
|
|
41
|
+
args: {
|
|
42
|
+
href: 'https://example.com',
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const InternalLink: Story = {
|
|
47
|
+
name: 'For Internal Link with Vue Router',
|
|
48
|
+
args: {
|
|
49
|
+
href: '/about',
|
|
50
|
+
router: true,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const Secondary: Story = {
|
|
55
|
+
args: { appearance: 'secondary' },
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const Accent: Story = {
|
|
59
|
+
args: { appearance: 'accent' },
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const Inverse: Story = {
|
|
63
|
+
globals: {
|
|
64
|
+
backgrounds: { value: 'inverse' },
|
|
65
|
+
},
|
|
66
|
+
args: { appearance: 'inverse' },
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const Size: Story = {
|
|
70
|
+
args: { size: 'm' },
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const Inline: Story = {
|
|
74
|
+
args: { inline: true },
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const IconLeft: Story = {
|
|
78
|
+
args: {
|
|
79
|
+
iconPosition: 'left',
|
|
80
|
+
icon: '<ChevronLeft24/>',
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const IconRight: Story = {
|
|
85
|
+
args: {
|
|
86
|
+
iconPosition: 'right',
|
|
87
|
+
icon: '<ChevronRight24/>',
|
|
88
|
+
},
|
|
89
|
+
};
|