@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.
Files changed (222) hide show
  1. package/LICENSE +51 -0
  2. package/README.md +76 -77
  3. package/dist/mozaic-vue.css +1 -1
  4. package/dist/mozaic-vue.d.ts +1664 -0
  5. package/dist/mozaic-vue.js +1943 -0
  6. package/dist/mozaic-vue.js.map +1 -0
  7. package/dist/mozaic-vue.umd.cjs +2 -0
  8. package/dist/mozaic-vue.umd.cjs.map +1 -0
  9. package/env.d.ts +1 -0
  10. package/package.json +78 -51
  11. package/src/components/Contributing.mdx +118 -0
  12. package/src/components/GettingStarted.mdx +45 -0
  13. package/src/components/Introduction.mdx +100 -0
  14. package/src/components/Support.mdx +18 -0
  15. package/src/components/breadcrumb/MBreadcrumb.spec.ts +105 -0
  16. package/src/components/breadcrumb/MBreadcrumb.stories.ts +82 -0
  17. package/src/components/breadcrumb/MBreadcrumb.vue +52 -55
  18. package/src/components/button/MButton.spec.ts +191 -0
  19. package/src/components/button/MButton.stories.ts +59 -0
  20. package/src/components/button/MButton.vue +98 -154
  21. package/src/components/checkbox/MCheckbox.spec.ts +104 -0
  22. package/src/components/checkbox/MCheckbox.stories.ts +83 -0
  23. package/src/components/checkbox/MCheckbox.vue +60 -101
  24. package/src/components/checkboxgroup/MCheckboxGroup.spec.ts +78 -0
  25. package/src/components/checkboxgroup/MCheckboxGroup.stories.ts +61 -0
  26. package/src/components/checkboxgroup/MCheckboxGroup.vue +97 -0
  27. package/src/components/datepicker/MDatepicker.spec.ts +95 -0
  28. package/src/components/datepicker/MDatepicker.stories.ts +75 -0
  29. package/src/components/datepicker/MDatepicker.vue +114 -0
  30. package/src/components/divider/MDivider.spec.ts +57 -0
  31. package/src/components/divider/MDivider.stories.ts +64 -0
  32. package/src/components/divider/MDivider.vue +56 -0
  33. package/src/components/drawer/MDrawer.spec.ts +100 -0
  34. package/src/components/drawer/MDrawer.stories.ts +128 -0
  35. package/src/components/drawer/MDrawer.vue +140 -0
  36. package/src/components/field/MField.spec.ts +166 -0
  37. package/src/components/field/MField.stories.ts +369 -0
  38. package/src/components/field/MField.vue +78 -61
  39. package/src/components/fieldgroup/MFieldGroup.spec.ts +165 -0
  40. package/src/components/fieldgroup/MFieldGroup.stories.ts +416 -0
  41. package/src/components/fieldgroup/MFieldGroup.vue +79 -0
  42. package/src/components/flag/MFlag.spec.ts +46 -0
  43. package/src/components/flag/MFlag.stories.ts +46 -0
  44. package/src/components/flag/MFlag.vue +28 -39
  45. package/src/components/iconbutton/MIconButton.spec.ts +108 -0
  46. package/src/components/iconbutton/MIconButton.stories.ts +74 -0
  47. package/src/components/iconbutton/MIconButton.vue +73 -0
  48. package/src/components/link/MLink.spec.ts +154 -0
  49. package/src/components/link/MLink.stories.ts +89 -0
  50. package/src/components/link/MLink.vue +86 -120
  51. package/src/components/loader/MLoader.spec.ts +104 -0
  52. package/src/components/loader/MLoader.stories.ts +43 -0
  53. package/src/components/loader/MLoader.vue +66 -55
  54. package/src/components/loadingoverlay/MLoadingOverlay.spec.ts +37 -0
  55. package/src/components/loadingoverlay/MLoadingOverlay.stories.ts +40 -0
  56. package/src/components/loadingoverlay/MLoadingOverlay.vue +28 -0
  57. package/src/components/modal/MModal.spec.ts +103 -0
  58. package/src/components/modal/MModal.stories.ts +127 -0
  59. package/src/components/modal/MModal.vue +111 -159
  60. package/src/components/numberbadge/MNumberBadge.spec.ts +56 -0
  61. package/src/components/numberbadge/MNumberBadge.stories.ts +48 -0
  62. package/src/components/numberbadge/MNumberBadge.vue +45 -0
  63. package/src/components/overlay/MOverlay.spec.ts +51 -0
  64. package/src/components/overlay/MOverlay.stories.ts +35 -0
  65. package/src/components/overlay/MOverlay.vue +27 -19
  66. package/src/components/pagination/MPagination.spec.ts +123 -0
  67. package/src/components/pagination/MPagination.stories.ts +83 -0
  68. package/src/components/pagination/MPagination.vue +120 -140
  69. package/src/components/passwordinput/MPasswordInput.spec.ts +104 -0
  70. package/src/components/passwordinput/MPasswordInput.stories.ts +75 -0
  71. package/src/components/passwordinput/MPasswordInput.vue +126 -77
  72. package/src/components/pincode/MPincode.spec.ts +126 -0
  73. package/src/components/pincode/MPincode.stories.ts +68 -0
  74. package/src/components/pincode/MPincode.vue +148 -0
  75. package/src/components/quantityselector/MQuantitySelector.spec.ts +262 -0
  76. package/src/components/quantityselector/MQuantitySelector.stories.ts +89 -0
  77. package/src/components/quantityselector/MQuantitySelector.vue +159 -148
  78. package/src/components/radio/MRadio.spec.ts +104 -0
  79. package/src/components/radio/MRadio.stories.ts +68 -0
  80. package/src/components/radio/MRadio.vue +56 -39
  81. package/src/components/radiogroup/MRadioGroup.spec.ts +54 -0
  82. package/src/components/radiogroup/MRadioGroup.stories.ts +61 -0
  83. package/src/components/radiogroup/MRadioGroup.vue +79 -0
  84. package/src/components/select/MSelect.spec.ts +114 -0
  85. package/src/components/select/MSelect.stories.ts +101 -0
  86. package/src/components/select/MSelect.vue +77 -119
  87. package/src/components/statusbadge/MStatusBadge.stories.ts +45 -0
  88. package/src/components/statusbadge/MStatusBadge.vue +40 -0
  89. package/src/components/statusbadge/MstatusBadge.spec.ts +16 -0
  90. package/src/components/statusdot/MStatusDot.spec.ts +51 -0
  91. package/src/components/statusdot/MStatusDot.stories.ts +48 -0
  92. package/src/components/statusdot/MStatusDot.vue +36 -0
  93. package/src/components/statusnotification/MStatusNotification.spec.ts +103 -0
  94. package/src/components/statusnotification/MStatusNotification.stories.ts +89 -0
  95. package/src/components/statusnotification/MStatusNotification.vue +106 -0
  96. package/src/components/tabs/MTabs.stories.ts +104 -0
  97. package/src/components/tabs/MTabs.vue +113 -0
  98. package/src/components/tabs/Mtabs.spec.ts +149 -0
  99. package/src/components/tag/MTag.spec.ts +107 -0
  100. package/src/components/tag/MTag.stories.ts +75 -0
  101. package/src/components/tag/MTag.vue +151 -0
  102. package/src/components/textarea/MTextArea.spec.ts +112 -0
  103. package/src/components/textarea/MTextArea.stories.ts +67 -0
  104. package/src/components/textarea/MTextArea.vue +81 -43
  105. package/src/components/textinput/MTextInput.spec.ts +121 -0
  106. package/src/components/textinput/MTextInput.stories.ts +107 -0
  107. package/src/components/textinput/MTextInput.vue +127 -47
  108. package/src/components/toggle/MToggle.spec.ts +99 -0
  109. package/src/components/toggle/MToggle.stories.ts +68 -0
  110. package/src/components/toggle/MToggle.vue +63 -103
  111. package/src/components/togglegroup/MToggleGroup.spec.ts +78 -0
  112. package/src/components/togglegroup/MToggleGroup.stories.ts +61 -0
  113. package/src/components/togglegroup/MToggleGroup.vue +97 -0
  114. package/src/components/usingIcons.mdx +35 -0
  115. package/src/components/usingPresets.mdx +128 -0
  116. package/src/main.ts +32 -0
  117. package/dist/demo.html +0 -1
  118. package/dist/mozaic-vue.adeo.css +0 -47
  119. package/dist/mozaic-vue.adeo.umd.js +0 -31341
  120. package/dist/mozaic-vue.common.js +0 -31331
  121. package/dist/mozaic-vue.common.js.map +0 -1
  122. package/dist/mozaic-vue.umd.js +0 -31342
  123. package/dist/mozaic-vue.umd.js.map +0 -1
  124. package/dist/mozaic-vue.umd.min.js +0 -4
  125. package/dist/mozaic-vue.umd.min.js.map +0 -1
  126. package/postinstall.js +0 -3
  127. package/src/components/accordion/MAccordion.vue +0 -128
  128. package/src/components/accordion/index.js +0 -7
  129. package/src/components/autocomplete/MAutocomplete.vue +0 -380
  130. package/src/components/autocomplete/index.js +0 -7
  131. package/src/components/badge/MBadge.vue +0 -43
  132. package/src/components/badge/index.js +0 -7
  133. package/src/components/breadcrumb/index.js +0 -7
  134. package/src/components/button/index.js +0 -7
  135. package/src/components/card/MCard.vue +0 -78
  136. package/src/components/card/index.js +0 -7
  137. package/src/components/checkbox/MCheckboxGroup.vue +0 -163
  138. package/src/components/checkbox/index.js +0 -12
  139. package/src/components/container/MContainer.vue +0 -33
  140. package/src/components/container/index.js +0 -7
  141. package/src/components/datatable/MDataTable.vue +0 -651
  142. package/src/components/datatable/MDataTableHeader.vue +0 -55
  143. package/src/components/datatable/MDataTableTop.vue +0 -35
  144. package/src/components/datatable/helpers.js +0 -132
  145. package/src/components/datatable/index.js +0 -12
  146. package/src/components/dropdown/MDropdown.vue +0 -317
  147. package/src/components/dropdown/index.js +0 -7
  148. package/src/components/field/index.js +0 -7
  149. package/src/components/fileuploader/MFileResult.vue +0 -149
  150. package/src/components/fileuploader/MFileUploader.vue +0 -142
  151. package/src/components/fileuploader/index.js +0 -7
  152. package/src/components/flag/index.js +0 -7
  153. package/src/components/heading/MHeading.vue +0 -75
  154. package/src/components/heading/index.js +0 -7
  155. package/src/components/hero/MHero.vue +0 -93
  156. package/src/components/hero/index.js +0 -7
  157. package/src/components/icon/MIcon.vue +0 -136
  158. package/src/components/icon/index.js +0 -7
  159. package/src/components/index.js +0 -44
  160. package/src/components/layer/MLayer.vue +0 -208
  161. package/src/components/layer/index.js +0 -7
  162. package/src/components/link/index.js +0 -7
  163. package/src/components/listbox/MListBox.vue +0 -146
  164. package/src/components/listbox/MListBoxActions.vue +0 -251
  165. package/src/components/listbox/index.js +0 -12
  166. package/src/components/loader/index.js +0 -7
  167. package/src/components/modal/index.js +0 -7
  168. package/src/components/notification/MNotification.vue +0 -110
  169. package/src/components/notification/index.js +0 -7
  170. package/src/components/optionbutton/MOptionButton.vue +0 -67
  171. package/src/components/optionbutton/index.js +0 -7
  172. package/src/components/optioncard/MOptionCard.vue +0 -132
  173. package/src/components/optioncard/index.js +0 -7
  174. package/src/components/optiongroup/MOptionGroup.vue +0 -18
  175. package/src/components/optiongroup/index.js +0 -7
  176. package/src/components/overlay/MOverlayLoader.vue +0 -43
  177. package/src/components/overlay/index.js +0 -12
  178. package/src/components/pagination/index.js +0 -7
  179. package/src/components/passwordinput/index.js +0 -7
  180. package/src/components/phonenumber/MPhoneNumber.vue +0 -398
  181. package/src/components/phonenumber/index.js +0 -7
  182. package/src/components/progressbar/MProgress.vue +0 -102
  183. package/src/components/progressbar/index.js +0 -7
  184. package/src/components/quantityselector/index.js +0 -7
  185. package/src/components/radio/MRadioGroup.vue +0 -111
  186. package/src/components/radio/index.js +0 -12
  187. package/src/components/ratingstars/MStarsInput.vue +0 -119
  188. package/src/components/ratingstars/MStarsResult.vue +0 -89
  189. package/src/components/ratingstars/index.js +0 -12
  190. package/src/components/select/index.js +0 -7
  191. package/src/components/stepper/MStepper.vue +0 -111
  192. package/src/components/stepper/index.js +0 -7
  193. package/src/components/tabs/MTab.vue +0 -204
  194. package/src/components/tabs/index.js +0 -7
  195. package/src/components/tags/MTag.vue +0 -175
  196. package/src/components/tags/index.js +0 -7
  197. package/src/components/textarea/index.js +0 -7
  198. package/src/components/textinput/MTextInputField.vue +0 -105
  199. package/src/components/textinput/MTextInputIcon.vue +0 -42
  200. package/src/components/textinput/index.js +0 -7
  201. package/src/components/toggle/index.js +0 -7
  202. package/src/components/tooltip/MTooltip.vue +0 -42
  203. package/src/components/tooltip/index.js +0 -7
  204. package/src/index.js +0 -63
  205. package/src/shims-tsx.d.ts +0 -13
  206. package/src/shims.vue.d.ts +0 -4
  207. package/src/tokens/adeo/android/colors.xml +0 -452
  208. package/src/tokens/adeo/android/font_dimens.xml +0 -18
  209. package/src/tokens/adeo/css/_variables.scss +0 -446
  210. package/src/tokens/adeo/css/root.scss +0 -448
  211. package/src/tokens/adeo/ios/StyleDictionaryColor.h +0 -460
  212. package/src/tokens/adeo/ios/StyleDictionaryColor.m +0 -472
  213. package/src/tokens/adeo/ios/StyleDictionaryColor.swift +0 -455
  214. package/src/tokens/adeo/ios/StyleDictionarySize.h +0 -69
  215. package/src/tokens/adeo/ios/StyleDictionarySize.m +0 -70
  216. package/src/tokens/adeo/ios/StyleDictionarySize.swift +0 -71
  217. package/src/tokens/adeo/js/tokens.js +0 -544
  218. package/src/tokens/adeo/js/tokensObject.js +0 -11733
  219. package/src/tokens/adeo/scss/_tokens.scss +0 -1522
  220. package/src/utils/mozaicClasses.js +0 -16
  221. package/src/utils/theme.validator.js +0 -19
  222. 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
- <component :is="htmlTag" class="mc-flag" :class="setClasses">
3
- <span class="mc-flag__label">{{ label }}</span>
4
- </component>
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 { checkThemeValue } from '../../utils/theme.validator';
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
- export default {
11
- name: 'MFlag',
12
-
13
- props: {
14
- label: {
15
- type: String,
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
- @import 'settings-tools/_all-settings';
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
+ };