@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.
Files changed (224) 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 +1718 -0
  5. package/dist/mozaic-vue.js +1971 -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/tooltip/MTooltip.spec.ts +47 -0
  115. package/src/components/tooltip/MTooltip.stories.ts +59 -0
  116. package/src/components/tooltip/MTooltip.vue +49 -32
  117. package/src/components/usingIcons.mdx +35 -0
  118. package/src/components/usingPresets.mdx +128 -0
  119. package/src/main.ts +33 -0
  120. package/dist/demo.html +0 -1
  121. package/dist/mozaic-vue.adeo.css +0 -47
  122. package/dist/mozaic-vue.adeo.umd.js +0 -31341
  123. package/dist/mozaic-vue.common.js +0 -31331
  124. package/dist/mozaic-vue.common.js.map +0 -1
  125. package/dist/mozaic-vue.umd.js +0 -31342
  126. package/dist/mozaic-vue.umd.js.map +0 -1
  127. package/dist/mozaic-vue.umd.min.js +0 -4
  128. package/dist/mozaic-vue.umd.min.js.map +0 -1
  129. package/postinstall.js +0 -3
  130. package/src/components/accordion/MAccordion.vue +0 -128
  131. package/src/components/accordion/index.js +0 -7
  132. package/src/components/autocomplete/MAutocomplete.vue +0 -380
  133. package/src/components/autocomplete/index.js +0 -7
  134. package/src/components/badge/MBadge.vue +0 -43
  135. package/src/components/badge/index.js +0 -7
  136. package/src/components/breadcrumb/index.js +0 -7
  137. package/src/components/button/index.js +0 -7
  138. package/src/components/card/MCard.vue +0 -78
  139. package/src/components/card/index.js +0 -7
  140. package/src/components/checkbox/MCheckboxGroup.vue +0 -163
  141. package/src/components/checkbox/index.js +0 -12
  142. package/src/components/container/MContainer.vue +0 -33
  143. package/src/components/container/index.js +0 -7
  144. package/src/components/datatable/MDataTable.vue +0 -651
  145. package/src/components/datatable/MDataTableHeader.vue +0 -55
  146. package/src/components/datatable/MDataTableTop.vue +0 -35
  147. package/src/components/datatable/helpers.js +0 -132
  148. package/src/components/datatable/index.js +0 -12
  149. package/src/components/dropdown/MDropdown.vue +0 -317
  150. package/src/components/dropdown/index.js +0 -7
  151. package/src/components/field/index.js +0 -7
  152. package/src/components/fileuploader/MFileResult.vue +0 -149
  153. package/src/components/fileuploader/MFileUploader.vue +0 -142
  154. package/src/components/fileuploader/index.js +0 -7
  155. package/src/components/flag/index.js +0 -7
  156. package/src/components/heading/MHeading.vue +0 -75
  157. package/src/components/heading/index.js +0 -7
  158. package/src/components/hero/MHero.vue +0 -93
  159. package/src/components/hero/index.js +0 -7
  160. package/src/components/icon/MIcon.vue +0 -136
  161. package/src/components/icon/index.js +0 -7
  162. package/src/components/index.js +0 -44
  163. package/src/components/layer/MLayer.vue +0 -208
  164. package/src/components/layer/index.js +0 -7
  165. package/src/components/link/index.js +0 -7
  166. package/src/components/listbox/MListBox.vue +0 -146
  167. package/src/components/listbox/MListBoxActions.vue +0 -251
  168. package/src/components/listbox/index.js +0 -12
  169. package/src/components/loader/index.js +0 -7
  170. package/src/components/modal/index.js +0 -7
  171. package/src/components/notification/MNotification.vue +0 -110
  172. package/src/components/notification/index.js +0 -7
  173. package/src/components/optionbutton/MOptionButton.vue +0 -67
  174. package/src/components/optionbutton/index.js +0 -7
  175. package/src/components/optioncard/MOptionCard.vue +0 -132
  176. package/src/components/optioncard/index.js +0 -7
  177. package/src/components/optiongroup/MOptionGroup.vue +0 -18
  178. package/src/components/optiongroup/index.js +0 -7
  179. package/src/components/overlay/MOverlayLoader.vue +0 -43
  180. package/src/components/overlay/index.js +0 -12
  181. package/src/components/pagination/index.js +0 -7
  182. package/src/components/passwordinput/index.js +0 -7
  183. package/src/components/phonenumber/MPhoneNumber.vue +0 -398
  184. package/src/components/phonenumber/index.js +0 -7
  185. package/src/components/progressbar/MProgress.vue +0 -102
  186. package/src/components/progressbar/index.js +0 -7
  187. package/src/components/quantityselector/index.js +0 -7
  188. package/src/components/radio/MRadioGroup.vue +0 -111
  189. package/src/components/radio/index.js +0 -12
  190. package/src/components/ratingstars/MStarsInput.vue +0 -119
  191. package/src/components/ratingstars/MStarsResult.vue +0 -89
  192. package/src/components/ratingstars/index.js +0 -12
  193. package/src/components/select/index.js +0 -7
  194. package/src/components/stepper/MStepper.vue +0 -111
  195. package/src/components/stepper/index.js +0 -7
  196. package/src/components/tabs/MTab.vue +0 -204
  197. package/src/components/tabs/index.js +0 -7
  198. package/src/components/tags/MTag.vue +0 -175
  199. package/src/components/tags/index.js +0 -7
  200. package/src/components/textarea/index.js +0 -7
  201. package/src/components/textinput/MTextInputField.vue +0 -105
  202. package/src/components/textinput/MTextInputIcon.vue +0 -42
  203. package/src/components/textinput/index.js +0 -7
  204. package/src/components/toggle/index.js +0 -7
  205. package/src/components/tooltip/index.js +0 -7
  206. package/src/index.js +0 -63
  207. package/src/shims-tsx.d.ts +0 -13
  208. package/src/shims.vue.d.ts +0 -4
  209. package/src/tokens/adeo/android/colors.xml +0 -452
  210. package/src/tokens/adeo/android/font_dimens.xml +0 -18
  211. package/src/tokens/adeo/css/_variables.scss +0 -446
  212. package/src/tokens/adeo/css/root.scss +0 -448
  213. package/src/tokens/adeo/ios/StyleDictionaryColor.h +0 -460
  214. package/src/tokens/adeo/ios/StyleDictionaryColor.m +0 -472
  215. package/src/tokens/adeo/ios/StyleDictionaryColor.swift +0 -455
  216. package/src/tokens/adeo/ios/StyleDictionarySize.h +0 -69
  217. package/src/tokens/adeo/ios/StyleDictionarySize.m +0 -70
  218. package/src/tokens/adeo/ios/StyleDictionarySize.swift +0 -71
  219. package/src/tokens/adeo/js/tokens.js +0 -544
  220. package/src/tokens/adeo/js/tokensObject.js +0 -11733
  221. package/src/tokens/adeo/scss/_tokens.scss +0 -1522
  222. package/src/utils/mozaicClasses.js +0 -16
  223. package/src/utils/theme.validator.js +0 -19
  224. package/types/index.d.ts +0 -104
@@ -0,0 +1,68 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
+ import { action } from 'storybook/actions';
3
+
4
+ import MToggle from './MToggle.vue';
5
+
6
+ const meta: Meta<typeof MToggle> = {
7
+ title: 'Form Elements/Toggle',
8
+ component: MToggle,
9
+ parameters: {
10
+ docs: {
11
+ description: {
12
+ component:
13
+ 'A toggle is a switch component that allows users to enable or disable a setting, representing a binary state such as on/off or active/inactive. It provides a quick and intuitive way to control preferences or system settings. Toggles are commonly used in settings menus, dark mode switches, and feature activations, offering an alternative to checkboxes for immediate visual feedback.',
14
+ },
15
+ },
16
+ },
17
+ args: {
18
+ id: 'ToggleId',
19
+ label: 'Toggle Label',
20
+ },
21
+ render: (args) => ({
22
+ components: { MToggle },
23
+ setup() {
24
+ const handleUpdate = action('update:modelValue');
25
+
26
+ return { args, handleUpdate };
27
+ },
28
+ template: `
29
+ <MToggle
30
+ v-bind="args"
31
+ @update:modelValue="handleUpdate"
32
+ />
33
+ `,
34
+ }),
35
+ };
36
+ export default meta;
37
+ type Story = StoryObj<typeof MToggle>;
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 Disabled: Story = {
49
+ args: {
50
+ disabled: true,
51
+ id: 'disabledId',
52
+ },
53
+ };
54
+
55
+ export const Size: Story = {
56
+ args: {
57
+ id: 'sizeId',
58
+ size: 's',
59
+ },
60
+ };
61
+
62
+ export const HideLabel: Story = {
63
+ args: {
64
+ id: 'hideLabelId',
65
+ label: undefined,
66
+ ariaLabel: 'Label',
67
+ },
68
+ };
@@ -1,117 +1,77 @@
1
1
  <template>
2
- <div class="mc-toggle" :class="setClasses">
3
- <input
4
- :id="id"
5
- :name="name"
6
- type="checkbox"
7
- class="mc-toggle__input"
8
- :checked="checked"
9
- :disabled="disabled"
10
- @change="$emit('change', $event.target.checked)"
11
- />
12
- <label :for="id" class="mc-toggle__label">
13
- <span class="mc-toggle__content">
2
+ <div class="mc-toggle" :class="classObject">
3
+ <label class="mc-toggle__container" :for="id">
4
+ <input
5
+ :id="id"
6
+ type="checkbox"
7
+ class="mc-toggle__input"
8
+ :name="name"
9
+ :checked="modelValue"
10
+ :disabled="disabled"
11
+ v-bind="$attrs"
12
+ @change="
13
+ emit('update:modelValue', ($event.target as HTMLInputElement).checked)
14
+ "
15
+ />
16
+ <span v-if="label" :for="id" class="mc-toggle__label">
14
17
  {{ label }}
15
- <span
16
- v-if="stateLabelOff && stateLabelOn"
17
- class="mc-toggle__state"
18
- aria-hidden="true"
19
- >
20
- <span class="mc-toggle__off">{{ stateLabelOff }}</span>
21
- <span class="mc-toggle__on">{{ stateLabelOn }}</span>
22
- </span>
23
18
  </span>
24
19
  </label>
25
20
  </div>
26
21
  </template>
27
22
 
28
- <script>
29
- import {
30
- responsiveModifierValidators,
31
- responsiveModifiers,
32
- } from '../../utils/mozaicClasses';
23
+ <script setup lang="ts">
24
+ import { computed } from 'vue';
33
25
 
34
- export default {
35
- name: 'MToggle',
36
-
37
- props: {
38
- id: {
39
- type: String,
40
- required: true,
41
- },
42
- label: {
43
- type: String,
44
- default: null,
45
- },
46
- name: {
47
- type: String,
48
- default: null,
49
- },
50
- checked: {
51
- type: Boolean,
52
- default: false,
53
- },
54
- disabled: {
55
- type: Boolean,
56
- default: false,
57
- },
58
- size: {
59
- type: String,
60
- default: 'm',
61
- validator: (value) => responsiveModifierValidators(value, ['s', 'm']),
62
- },
63
- // Experimental solution waiting on this issue https://github.com/adeo/mozaic-vue/issues/52
64
- responsiveSizeModifiers: {
65
- type: Array,
66
- default: null,
67
- validator: (array) =>
68
- array.every((e) =>
69
- responsiveModifierValidators(e, [
70
- 's@from-m',
71
- 's@from-l',
72
- 's@from-xl',
73
- 's@from-xxl',
74
- 'm@from-m',
75
- 'm@from-l',
76
- 'm@from-xl',
77
- 'm@from-xxl',
78
- ])
79
- ),
80
- },
81
- stateLabelOff: {
82
- type: String,
83
- default: null,
84
- },
85
- stateLabelOn: {
86
- type: String,
87
- default: null,
88
- },
26
+ /**
27
+ * A toggle is used to choose between two possibilities and when the user needs instant feedback. It is common to use toggles when you need to show or hide content and "on/off" switch.
28
+ */
29
+ const props = withDefaults(
30
+ defineProps<{
31
+ /**
32
+ * A unique identifier for the toggle, used to associate the label with the form element.
33
+ */
34
+ id: string;
35
+ /**
36
+ * The name attribute for the toggle element, typically used for form submission.
37
+ */
38
+ name?: string;
39
+ /**
40
+ * The text label displayed next to the toggle.
41
+ */
42
+ label?: string;
43
+ /**
44
+ * The toggle's checked state, bound via v-model.
45
+ */
46
+ modelValue?: boolean;
47
+ /**
48
+ * Determines the size of the toggle
49
+ */
50
+ size?: 's' | 'm';
51
+ /**
52
+ * If `true`, disables the toggle, making it non-interactive.
53
+ */
54
+ disabled?: boolean;
55
+ }>(),
56
+ {
57
+ size: 's',
89
58
  },
59
+ );
90
60
 
91
- computed: {
92
- setClasses() {
93
- const classes = [];
94
-
95
- if (this.size) {
96
- classes.push(`mc-toggle--${this.size}`);
97
- }
61
+ const classObject = computed(() => {
62
+ return {
63
+ [`mc-toggle--${props.size}`]: props.size && props.size != 's',
64
+ };
65
+ });
98
66
 
99
- if (
100
- this.responsiveSizeModifiers &&
101
- this.responsiveSizeModifiers.length > 0
102
- ) {
103
- for (const modifier of this.responsiveSizeModifiers) {
104
- responsiveModifiers('mc-toggle', modifier, classes);
105
- }
106
- }
107
-
108
- return classes;
109
- },
110
- },
111
- };
67
+ const emit = defineEmits<{
68
+ /**
69
+ * Emits when the toggle value changes, updating the modelValue prop.
70
+ */
71
+ (on: 'update:modelValue', value: boolean): void;
72
+ }>();
112
73
  </script>
113
74
 
114
- <style lang="scss">
115
- @import 'settings-tools/_all-settings';
116
- @import 'components/c.toggle';
75
+ <style lang="scss" scoped>
76
+ @use '@mozaic-ds/styles/components/toggle';
117
77
  </style>
@@ -0,0 +1,78 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import { describe, it, expect } from 'vitest';
3
+ import MToggleGroup from './MToggleGroup.vue';
4
+ import MToggle from '@/components/toggle/MToggle.vue';
5
+
6
+ describe('MToggleGroup.vue', () => {
7
+ it('renders toggles based on options', async () => {
8
+ const options = [
9
+ { id: '1', label: 'Option 1', value: 'option1' },
10
+ { id: '2', label: 'Option 2', value: 'option2' },
11
+ ];
12
+
13
+ const wrapper = mount(MToggleGroup, {
14
+ props: {
15
+ name: 'test-name',
16
+ options,
17
+ },
18
+ });
19
+
20
+ const toggles = wrapper.findAllComponents(MToggle);
21
+ expect(toggles.length).toBe(2);
22
+
23
+ expect(toggles[0].props('label')).toBe('Option 1');
24
+ expect(toggles[1].props('label')).toBe('Option 2');
25
+ });
26
+
27
+ it('updates modelValue when a toggle is checked', async () => {
28
+ const options = [
29
+ { id: '1', label: 'Option 1', value: 'option1' },
30
+ { id: '2', label: 'Option 2', value: 'option2' },
31
+ ];
32
+
33
+ const wrapper = mount(MToggleGroup, {
34
+ props: {
35
+ name: 'test-name',
36
+ options,
37
+ modelValue: [],
38
+ },
39
+ });
40
+
41
+ const toggle1 = wrapper.findAllComponents(MToggle)[0].find('input');
42
+ await toggle1.setChecked(true);
43
+
44
+ expect(wrapper.emitted('update:modelValue')).toBeTruthy();
45
+ expect(wrapper.emitted('update:modelValue')[0]).toEqual([['option1']]);
46
+
47
+ const toggle2 = wrapper.findAllComponents(MToggle)[1].find('input');
48
+ await toggle2.setChecked(true);
49
+
50
+ expect(wrapper.emitted('update:modelValue')[1]).toEqual([
51
+ ['option1', 'option2'],
52
+ ]);
53
+ });
54
+
55
+ it('syncs with the v-model when initial value is passed', async () => {
56
+ const options = [
57
+ { id: '1', label: 'Option 1', value: 'option1' },
58
+ { id: '2', label: 'Option 2', value: 'option2' },
59
+ ];
60
+
61
+ const wrapper = mount(MToggleGroup, {
62
+ props: {
63
+ name: 'test-name',
64
+ options,
65
+ modelValue: ['option1'],
66
+ },
67
+ });
68
+
69
+ const toggles = wrapper.findAllComponents(MToggle);
70
+ expect(toggles[0].props('modelValue')).toBe(true);
71
+ expect(toggles[1].props('modelValue')).toBe(false);
72
+
73
+ await wrapper.setProps({ modelValue: ['option2'] });
74
+
75
+ expect(toggles[0].props('modelValue')).toBe(false);
76
+ expect(toggles[1].props('modelValue')).toBe(true);
77
+ });
78
+ });
@@ -0,0 +1,61 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
+ import { action } from 'storybook/actions';
3
+
4
+ import MToggleGroup from './MToggleGroup.vue';
5
+
6
+ const meta: Meta<typeof MToggleGroup> = {
7
+ title: 'Form Elements/Toggle Group',
8
+ component: MToggleGroup,
9
+ parameters: {
10
+ docs: {
11
+ description: {
12
+ component:
13
+ 'A toggle is a switch component that allows users to enable or disable a setting, representing a binary state such as on/off or active/inactive. It provides a quick and intuitive way to control preferences or system settings. Toggles are commonly used in settings menus, dark mode switches, and feature activations, offering an alternative to checkboxes for immediate visual feedback.<br><br> To put a label, requierement text, help text or to apply a valid or invalid message, the examples are available in the [Field Group section](/docs/form-elements-field-group--docs#toggle-group).',
14
+ },
15
+ },
16
+ },
17
+ args: {
18
+ name: 'toggleGroupName',
19
+ modelValue: ['toggle2'],
20
+ options: [
21
+ {
22
+ id: 'toggle-01',
23
+ label: 'Toggle Label',
24
+ value: 'toggle1',
25
+ },
26
+ {
27
+ id: 'toggle-02',
28
+ label: 'Toggle Label',
29
+ value: 'toggle2',
30
+ },
31
+ {
32
+ id: 'toggle-03',
33
+ label: 'Toggle Label',
34
+ value: 'toggle3',
35
+ },
36
+ {
37
+ id: 'toggle-04',
38
+ label: 'Toggle Label',
39
+ value: 'toggle4',
40
+ },
41
+ ],
42
+ },
43
+ render: (args) => ({
44
+ components: { MToggleGroup },
45
+ setup() {
46
+ const handleUpdate = action('update:modelValue');
47
+
48
+ return { args, handleUpdate };
49
+ },
50
+ template: `
51
+ <MToggleGroup
52
+ v-bind="args"
53
+ @update:modelValue="handleUpdate"
54
+ />
55
+ `,
56
+ }),
57
+ };
58
+ export default meta;
59
+ type Story = StoryObj<typeof MToggleGroup>;
60
+
61
+ export const Default: Story = {};
@@ -0,0 +1,97 @@
1
+ <template>
2
+ <div :class="classObjectContainer">
3
+ <MToggle
4
+ v-for="option in options"
5
+ :id="option.id"
6
+ :key="option.id"
7
+ :label="option.label"
8
+ :is-invalid="option.isInvalid"
9
+ :name="name"
10
+ :class="classObjectItem"
11
+ :model-value="modelValue ? modelValue.includes(option.value) : undefined"
12
+ :disabled="option.disabled"
13
+ @update:model-value="(v: boolean) => onChange(v, option.value)"
14
+ />
15
+ </div>
16
+ </template>
17
+
18
+ <script setup lang="ts">
19
+ import { computed, ref, watch } from 'vue';
20
+ import MToggle from '../toggle/MToggle.vue';
21
+
22
+ /**
23
+ * A toggle is used to choose between two possibilities and when the user needs instant feedback. It is common to use toggles when you need to show or hide content and "on/off" switch.
24
+ */
25
+ const props = defineProps<{
26
+ /**
27
+ * The name attribute for the toggle element, typically used for form submission.
28
+ */
29
+ name: string;
30
+ /**
31
+ * Property used to manage the values checked by v-model
32
+ * (Do not use directly)
33
+ */
34
+ modelValue?: Array<string>;
35
+ /**
36
+ * list of properties of each toggle of the toggle group
37
+ */
38
+ options: Array<{
39
+ id: string;
40
+ label: string;
41
+ value: string;
42
+ disabled?: boolean;
43
+ isInvalid?: boolean;
44
+ size?: 's' | 'm';
45
+ }>;
46
+ /**
47
+ * If `true`, make the form element of the group inline.
48
+ */
49
+ inline?: boolean;
50
+ }>();
51
+
52
+ const selectedValue = ref<string[]>([]);
53
+
54
+ watch(
55
+ () => props.modelValue,
56
+ (newValue) => {
57
+ selectedValue.value = newValue || [];
58
+ },
59
+ { immediate: true },
60
+ );
61
+
62
+ const onChange = (isChecked: boolean, value: string) => {
63
+ let values = [...selectedValue.value];
64
+
65
+ if (isChecked && !values.includes(value)) {
66
+ values.push(value);
67
+ } else {
68
+ values = values.filter((val) => val !== value);
69
+ }
70
+
71
+ emit('update:modelValue', values);
72
+ selectedValue.value = values;
73
+ };
74
+
75
+ const classObjectContainer = computed(() => {
76
+ return {
77
+ 'mc-field__container--inline': props.inline,
78
+ };
79
+ });
80
+
81
+ const classObjectItem = computed(() => {
82
+ return {
83
+ 'mc-field__container--inline__item': props.inline,
84
+ };
85
+ });
86
+
87
+ const emit = defineEmits<{
88
+ /**
89
+ * Emits when the toggle group value changes, updating the modelValue prop.
90
+ */
91
+ (on: 'update:modelValue', value: Array<string>): void;
92
+ }>();
93
+ </script>
94
+
95
+ <style lang="scss" scoped>
96
+ @use '@mozaic-ds/styles/components/field';
97
+ </style>
@@ -0,0 +1,47 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import { describe, it, expect } from 'vitest';
3
+ import MTooltip from './MTooltip.vue';
4
+
5
+ describe('MTooltip.vue', () => {
6
+ const defaultProps = {
7
+ id: 'tooltip-1',
8
+ text: 'Tooltip content',
9
+ };
10
+
11
+ it('renders tooltip text', () => {
12
+ const wrapper = mount(MTooltip, {
13
+ props: { ...defaultProps },
14
+ slots: { default: 'Hover me' }
15
+ });
16
+ expect(wrapper.text()).toContain(defaultProps.text);
17
+ });
18
+
19
+ it('sets aria-describedby attribute correctly', () => {
20
+ const wrapper = mount(MTooltip, {
21
+ props: { ...defaultProps }
22
+ });
23
+ const tooltipDiv = wrapper.find('.mc-tooltip');
24
+ expect(tooltipDiv.attributes('aria-describedby')).toBe(defaultProps.id);
25
+ });
26
+
27
+ it('applies position class based on prop', () => {
28
+ const wrapper = mount(MTooltip, {
29
+ props: { ...defaultProps, position: 'bottom' }
30
+ });
31
+ expect(wrapper.find('.mc-tooltip').classes()).toContain('mc-tooltip--bottom');
32
+ });
33
+
34
+ it('applies no-pointer class when pointer is false', () => {
35
+ const wrapper = mount(MTooltip, {
36
+ props: { ...defaultProps, pointer: false }
37
+ });
38
+ expect(wrapper.find('.mc-tooltip').classes()).toContain('mc-tooltip--no-pointer');
39
+ });
40
+
41
+ it('does not apply no-pointer class when pointer is true', () => {
42
+ const wrapper = mount(MTooltip, {
43
+ props: { ...defaultProps, pointer: true }
44
+ });
45
+ expect(wrapper.find('.mc-tooltip').classes()).not.toContain('mc-tooltip--no-pointer');
46
+ });
47
+ });
@@ -0,0 +1,59 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
+ import MTooltip from './MTooltip.vue';
3
+
4
+ const meta: Meta<typeof MTooltip> = {
5
+ title: 'Overlay/Tooltip',
6
+ component: MTooltip,
7
+ parameters: {
8
+ docs: {
9
+ description: {
10
+ component:
11
+ 'A tooltip is a small, contextual message that appears when users hover over, focus on, or tap an element, providing additional information or guidance without cluttering the interface. Tooltips are commonly used to explain icons, abbreviations, or complex actions. They typically disappear automatically when the user moves away from the trigger element.',
12
+ },
13
+ },
14
+ },
15
+ args: {
16
+ id: 'tooltipId',
17
+ text: 'Keep the tooltip text concise.',
18
+ default: 'Tooltip on the top',
19
+ },
20
+ render: (args) => ({
21
+ components: { MTooltip },
22
+ setup() {
23
+ return { args };
24
+ },
25
+ template: `
26
+ <MTooltip v-bind="args">
27
+ ${args.default}
28
+ </MTooltip>
29
+ `,
30
+ }),
31
+ };
32
+ export default meta;
33
+ type Story = StoryObj<typeof MTooltip>;
34
+
35
+ export const Default: Story = {};
36
+
37
+ export const Pointer: Story = {
38
+ args: {
39
+ pointer: false
40
+ }
41
+ };
42
+
43
+ export const Right: Story = {
44
+ args: {
45
+ position: 'right'
46
+ }
47
+ };
48
+
49
+ export const Left: Story = {
50
+ args: {
51
+ position: 'left'
52
+ }
53
+ };
54
+
55
+ export const Bottom: Story = {
56
+ args: {
57
+ position: 'bottom'
58
+ }
59
+ };
@@ -1,42 +1,59 @@
1
1
  <template>
2
- <div
3
- class="mc-tooltip"
4
- :class="position ? `mc-tooltip--${position}` : ''"
5
- :aria-describedby="id"
6
- >
7
- <slot />
8
-
9
- <span :id="id" class="mc-tooltip__content" role="tooltip">
2
+ <div class="tooltip-story-wrapper">
3
+ <div class="mc-tooltip" :class="classObject" :aria-describedby="id">
4
+ <slot/>
5
+ <span :id="id" class="mc-tooltip__content" role="tooltip">
10
6
  {{ text }}
11
- </span>
7
+ </span>
8
+ </div>
12
9
  </div>
13
10
  </template>
14
11
 
15
- <script>
16
- export default {
17
- name: 'MTooltip',
12
+ <script setup lang="ts">
13
+ import { computed } from 'vue';
14
+ /**
15
+ * A tooltip is a small, contextual message that appears when users hover over, focus on, or tap an element, providing additional information or guidance without cluttering the interface. Tooltips are commonly used to explain icons, abbreviations, or complex actions. They typically disappear automatically when the user moves away from the trigger element.
16
+ */
17
+ const props = withDefaults(
18
+ defineProps<{
19
+ /**
20
+ * A unique identifier for the tooltip, used to describe the tooltip.
21
+ */
22
+ id: string;
23
+ /**
24
+ * Content of the tooltip
25
+ */
26
+ text: string;
27
+ /**
28
+ * Determines the position of the tooltip
29
+ */
30
+ position?: 'top' | 'bottom' | 'left' | 'right';
31
+ /**
32
+ * if `true`, the tooltip display a pointer.
33
+ */
34
+ pointer?: boolean;
35
+ }>(),
36
+ {
37
+ position: 'top',
38
+ pointer: true
39
+ },
40
+ );
18
41
 
19
- inheritAttrs: false,
42
+ defineSlots<{
43
+ /**
44
+ * The tooltip will point to the content of the slot.
45
+ */
46
+ default: string;
47
+ }>();
20
48
 
21
- props: {
22
- id: {
23
- type: String,
24
- required: true,
25
- },
26
- text: {
27
- type: String,
28
- required: true,
29
- },
30
- position: {
31
- type: String,
32
- default: 'top',
33
- validator: (value) => ['top', 'right', 'bottom', 'left'].includes(value),
34
- },
35
- },
36
- };
49
+ const classObject = computed(() => {
50
+ return {
51
+ [`mc-tooltip--${props.position}`]: props.position,
52
+ 'mc-tooltip--no-pointer': !props.pointer,
53
+ };
54
+ });
37
55
  </script>
38
56
 
39
- <style lang="scss">
40
- @import 'settings-tools/_all-settings';
41
- @import 'components/_c.tooltip';
57
+ <style lang="scss" scoped>
58
+ @use '@mozaic-ds/styles/components/tooltip';
42
59
  </style>