@mozaic-ds/vue 2.6.1 → 2.8.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 (96) hide show
  1. package/README.md +3 -3
  2. package/dist/mozaic-vue.css +1 -1
  3. package/dist/mozaic-vue.d.ts +211 -101
  4. package/dist/mozaic-vue.js +3034 -1070
  5. package/dist/mozaic-vue.js.map +1 -1
  6. package/dist/mozaic-vue.umd.cjs +5 -1
  7. package/dist/mozaic-vue.umd.cjs.map +1 -1
  8. package/package.json +10 -7
  9. package/src/components/Contributing.mdx +1 -1
  10. package/src/components/GettingStarted.mdx +1 -1
  11. package/src/components/Introduction.mdx +1 -1
  12. package/src/components/Support.mdx +1 -1
  13. package/src/components/avatar/MAvatar.stories.ts +1 -0
  14. package/src/components/avatar/README.md +16 -0
  15. package/src/components/breadcrumb/README.md +11 -0
  16. package/src/components/button/MButton.stories.ts +1 -2
  17. package/src/components/button/MButton.vue +6 -1
  18. package/src/components/button/README.md +24 -0
  19. package/src/components/callout/MCallout.stories.ts +1 -0
  20. package/src/components/callout/README.md +19 -0
  21. package/src/components/checkbox/README.md +23 -0
  22. package/src/components/checkboxgroup/README.md +20 -0
  23. package/src/components/circularprogressbar/MCircularProgressbar.stories.ts +1 -0
  24. package/src/components/circularprogressbar/README.md +14 -0
  25. package/src/components/container/MContainer.stories.ts +8 -0
  26. package/src/components/container/MContainer.vue +1 -1
  27. package/src/components/container/README.md +16 -0
  28. package/src/components/datepicker/MDatepicker.stories.ts +1 -0
  29. package/src/components/datepicker/README.md +24 -0
  30. package/src/components/divider/MDivider.stories.ts +1 -0
  31. package/src/components/divider/README.md +18 -0
  32. package/src/components/drawer/MDrawer.spec.ts +95 -0
  33. package/src/components/drawer/MDrawer.stories.ts +1 -0
  34. package/src/components/drawer/MDrawer.vue +34 -3
  35. package/src/components/drawer/README.md +30 -0
  36. package/src/components/field/MField.vue +1 -1
  37. package/src/components/field/README.md +24 -0
  38. package/src/components/fieldgroup/README.md +22 -0
  39. package/src/components/flag/README.md +11 -0
  40. package/src/components/iconbutton/MIconButton.stories.ts +1 -0
  41. package/src/components/iconbutton/MIconButton.vue +6 -1
  42. package/src/components/iconbutton/README.md +21 -0
  43. package/src/components/linearprogressbarbuffer/MLinearProgressbarBuffer.stories.ts +1 -0
  44. package/src/components/linearprogressbarbuffer/README.md +11 -0
  45. package/src/components/linearprogressbarpercentage/MLinearProgressbarPercentage.stories.ts +1 -0
  46. package/src/components/linearprogressbarpercentage/README.md +10 -0
  47. package/src/components/link/MLink.vue +0 -2
  48. package/src/components/link/README.md +23 -0
  49. package/src/components/loader/MLoader.vue +1 -1
  50. package/src/components/loader/README.md +12 -0
  51. package/src/components/loadingoverlay/MLoadingOverlay.stories.ts +1 -1
  52. package/src/components/loadingoverlay/README.md +11 -0
  53. package/src/components/modal/MModal.spec.ts +36 -1
  54. package/src/components/modal/MModal.vue +11 -1
  55. package/src/components/modal/README.md +29 -0
  56. package/src/components/numberbadge/README.md +12 -0
  57. package/src/components/overlay/README.md +17 -0
  58. package/src/components/pagination/README.md +20 -0
  59. package/src/components/passwordinput/README.md +25 -0
  60. package/src/components/phonenumber/MPhoneNumber.spec.ts +294 -0
  61. package/src/components/phonenumber/MPhoneNumber.stories.ts +88 -0
  62. package/src/components/phonenumber/MPhoneNumber.vue +271 -0
  63. package/src/components/phonenumber/README.md +26 -0
  64. package/src/components/pincode/MPincode.spec.ts +4 -1
  65. package/src/components/pincode/MPincode.stories.ts +1 -0
  66. package/src/components/pincode/MPincode.vue +5 -1
  67. package/src/components/pincode/README.md +22 -0
  68. package/src/components/quantityselector/MQuantitySelector.stories.ts +0 -7
  69. package/src/components/quantityselector/README.md +27 -0
  70. package/src/components/radio/README.md +21 -0
  71. package/src/components/radiogroup/README.md +21 -0
  72. package/src/components/segmentedcontrol/MSegmentedControl.spec.ts +116 -0
  73. package/src/components/segmentedcontrol/MSegmentedControl.stories.ts +78 -0
  74. package/src/components/segmentedcontrol/MSegmentedControl.vue +92 -0
  75. package/src/components/segmentedcontrol/README.md +19 -0
  76. package/src/components/select/README.md +24 -0
  77. package/src/components/statusbadge/README.md +11 -0
  78. package/src/components/statusdot/MStatusDot.stories.ts +1 -0
  79. package/src/components/statusdot/README.md +11 -0
  80. package/src/components/statusnotification/README.md +25 -0
  81. package/src/components/tabs/MTabs.stories.ts +23 -1
  82. package/src/components/tabs/MTabs.vue +8 -0
  83. package/src/components/tabs/Mtabs.spec.ts +29 -8
  84. package/src/components/tabs/README.md +20 -0
  85. package/src/components/tag/README.md +25 -0
  86. package/src/components/textarea/README.md +25 -0
  87. package/src/components/textinput/README.md +32 -0
  88. package/src/components/toaster/MToaster.stories.ts +1 -0
  89. package/src/components/toaster/README.md +28 -0
  90. package/src/components/toggle/README.md +21 -0
  91. package/src/components/togglegroup/MToggleGroup.vue +1 -3
  92. package/src/components/togglegroup/README.md +20 -0
  93. package/src/components/tooltip/README.md +19 -0
  94. package/src/components/usingIcons.mdx +1 -1
  95. package/src/components/usingPresets.mdx +1 -1
  96. package/src/main.ts +2 -0
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="mc-pincode-input" :class="classObject" @paste="onPaste">
2
+ <div class="mc-pincode-input" @paste="onPaste">
3
3
  <input
4
4
  v-for="(digit, index) in otp"
5
5
  :key="index"
@@ -12,6 +12,7 @@
12
12
  autocomplete="one-time-code"
13
13
  :name="name || `pincode-${id}`"
14
14
  class="mc-pincode-input__control"
15
+ :class="classObject"
15
16
  :disabled="disabled"
16
17
  :readonly="readonly"
17
18
  :value="digit"
@@ -77,6 +78,9 @@ const classObject = computed(() => {
77
78
  });
78
79
 
79
80
  const emit = defineEmits<{
81
+ /**
82
+ * Emits when the pincode value changes, updating the modelValue prop.
83
+ */
80
84
  (on: 'update:modelValue', value: string): void;
81
85
  }>();
82
86
 
@@ -0,0 +1,22 @@
1
+ # MPincode
2
+
3
+ A pincode input is a specialized input field used to enter short numeric codes, such as verification codes, security PINs, or authentication tokens. It typically separates each digit into individual fields to improve readability and ease of entry. This component is commonly used in two-factor authentication (2FA), password recovery, and secure access flows, ensuring a structured and user-friendly experience.<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 section](/docs/form-elements-field--docs#input).
4
+
5
+
6
+ ## Props
7
+
8
+ | Name | Description | Type | Default |
9
+ | --- | --- | --- | --- |
10
+ | `id*` | A unique identifier for the pincode element, used to associate the label with the form element. | `string` | - |
11
+ | `length` | The number of input displayed in the pincode element. | `4` `5` `6` | `6` |
12
+ | `name` | The name attribute for the pincode element, typically used for form submission. | `string` | - |
13
+ | `modelValue` | The current value of the pincode field. | `string` `number` | - |
14
+ | `isInvalid` | If `true`, applies an invalid state to the pincode. | `boolean` | - |
15
+ | `disabled` | If `true`, disables the pincode, making it non-interactive. | `boolean` | - |
16
+ | `readonly` | If `true`, the pincode is read-only (cannot be edited). | `boolean` | - |
17
+
18
+ ## Events
19
+
20
+ | Name | Description | Type |
21
+ | --- | --- | --- |
22
+ | `update:modelValue` | Emits when the pincode value changes, updating the modelValue prop. | [value: string] |
@@ -80,10 +80,3 @@ export const Invalid: Story = {
80
80
  isInvalid: true,
81
81
  },
82
82
  };
83
-
84
- export const readOnly: Story = {
85
- args: {
86
- id: 'readonlyId',
87
- readonly: true,
88
- },
89
- };
@@ -0,0 +1,27 @@
1
+ # MQuantitySelector
2
+
3
+ A quantity selector is an input component that allows users to increment or decrement a numeric value, typically using plus (+) and minus (−) buttons. It provides a simple and efficient way to adjust quantities without manual typing, ensuring controlled input. This component is commonly used in e-commerce, inventory management, and settings where users need to specify amounts.
4
+
5
+
6
+ ## Props
7
+
8
+ | Name | Description | Type | Default |
9
+ | --- | --- | --- | --- |
10
+ | `id*` | A unique identifier for the quantity selector element, used to associate the label with the form element. | `string` | - |
11
+ | `name` | The name attribute for the quantity selector element, typically used for form submission. | `string` | `"quantity-selector-input"` |
12
+ | `modelValue` | The current value of the quantity selector field. | `number` | `1` |
13
+ | `isInvalid` | If `true`, applies an invalid state to the quantity selector. | `boolean` | - |
14
+ | `disabled` | If `true`, disables the quantity selector, making it non-interactive. | `boolean` | - |
15
+ | `size` | Determines the size of the quantity selector. | `"s"` `"m"` | `"m"` |
16
+ | `min` | Minimum acceptable value for the quantity selector. | `number` | `1` |
17
+ | `max` | Maximum acceptable value for the quantity selector. | `number` | `100` |
18
+ | `step` | Determines how much the value will change per click when the quantity is increased or decreased. | `number` | `1` |
19
+ | `readonly` | If `true`, the quantity selector is read-only (cannot be edited). | `boolean` | - |
20
+ | `incrementlabel` | The label text for the increment button. | `string` | `"Increment"` |
21
+ | `decrementLabel` | The label text for the decrement button. | `string` | `"Decrement"` |
22
+
23
+ ## Events
24
+
25
+ | Name | Description | Type |
26
+ | --- | --- | --- |
27
+ | `update:modelValue` | Emits when the quantity selector value changes, updating the `modelValue` prop. | [value: number] |
@@ -0,0 +1,21 @@
1
+ # MRadio
2
+
3
+ A radio button is a selection control that allows users to choose a single option from a list of mutually exclusive choices. Unlike checkboxes, only one option can be selected at a time within the same group. Radio Buttons are commonly used in forms, surveys, and settings where a single choice must be made.
4
+
5
+
6
+ ## Props
7
+
8
+ | Name | Description | Type | Default |
9
+ | --- | --- | --- | --- |
10
+ | `id*` | A unique identifier for the radio, used to associate the label with the form element. | `string` | - |
11
+ | `name` | The name attribute for the radio element, typically used for form submission. | `string` | - |
12
+ | `label` | The text label displayed next to the radio. | `string` | - |
13
+ | `modelValue` | The radio's checked state, bound via v-model. | `boolean` | - |
14
+ | `isInvalid` | If `true`, applies an invalid state to the radio. | `boolean` | - |
15
+ | `disabled` | If `true`, disables the radio, making it non-interactive. | `boolean` | - |
16
+
17
+ ## Events
18
+
19
+ | Name | Description | Type |
20
+ | --- | --- | --- |
21
+ | `update:modelValue` | Emits when the radio value changes, updating the modelValue prop. | [value: boolean] |
@@ -0,0 +1,21 @@
1
+ # MRadioGroup
2
+
3
+ A radio button is a selection control that allows users to choose a single option from a list of mutually exclusive choices. Unlike checkboxes, only one option can be selected at a time within the same group. Radio Buttons are commonly used in forms, surveys, and settings where a single choice must be made.<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#radio-group).
4
+
5
+
6
+ ## Props
7
+
8
+ | Name | Description | Type | Default |
9
+ | --- | --- | --- | --- |
10
+ | `name*` | The name attribute for the radio element, typically used for form submission. | `string` | - |
11
+ | `modelValue` | Property used to manage the values checked by v-model
12
+ (Do not use directly) | `string` | - |
13
+ | `options*` | list of properties of each radio button of the radio group | `{ id: string; label: string; value: string; disabled?: boolean` `undefined; }[]` | - |
14
+ | `isInvalid` | If `true`, applies an invalid state to the radio group. | `boolean` | - |
15
+ | `inline` | If `true`, make the form element of the group inline. | `boolean` | - |
16
+
17
+ ## Events
18
+
19
+ | Name | Description | Type |
20
+ | --- | --- | --- |
21
+ | `update:modelValue` | Emits when the radio group value changes, updating the modelValue prop. | [value: string] |
@@ -0,0 +1,116 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import { describe, it, expect } from 'vitest';
3
+ import MSegmentedControl from './MSegmentedControl.vue';
4
+
5
+ describe('MSegmentedControl.vue', () => {
6
+ const segments = [
7
+ { label: 'First' },
8
+ { label: 'Second' },
9
+ { label: 'Third' },
10
+ ];
11
+
12
+ it('renders segments with correct labels', () => {
13
+ const wrapper = mount(MSegmentedControl, {
14
+ props: { segments },
15
+ });
16
+
17
+ const buttons = wrapper.findAll('button');
18
+ expect(buttons).toHaveLength(segments.length);
19
+ buttons.forEach((btn, i) => {
20
+ expect(btn.text()).toBe(segments[i].label);
21
+ });
22
+ });
23
+
24
+ it('sets default active segment based on modelValue prop', () => {
25
+ const wrapper = mount(MSegmentedControl, {
26
+ props: { segments, modelValue: 1 },
27
+ });
28
+
29
+ const buttons = wrapper.findAll('button');
30
+ expect(buttons[1].classes()).toContain(
31
+ 'mc-segmented-control__segment--selected',
32
+ );
33
+ expect(buttons[1].attributes('aria-checked')).toBe('true');
34
+ });
35
+
36
+ it('emits update:modelValue and changes active segment on click', async () => {
37
+ const wrapper = mount(MSegmentedControl, {
38
+ props: { segments, modelValue: 0 },
39
+ });
40
+
41
+ const buttons = wrapper.findAll('button');
42
+ await buttons[2].trigger('click');
43
+
44
+ expect(wrapper.emitted('update:modelValue')).toBeTruthy();
45
+ expect(wrapper.emitted('update:modelValue')![0]).toEqual([2]);
46
+
47
+ expect(buttons[2].classes()).toContain(
48
+ 'mc-segmented-control__segment--selected',
49
+ );
50
+ expect(buttons[2].attributes('aria-checked')).toBe('true');
51
+ });
52
+
53
+ it('does not emit update event if clicking already active segment', async () => {
54
+ const wrapper = mount(MSegmentedControl, {
55
+ props: { segments, modelValue: 1 },
56
+ });
57
+
58
+ const buttons = wrapper.findAll('button');
59
+ await buttons[1].trigger('click');
60
+
61
+ expect(wrapper.emitted('update:modelValue')).toBeFalsy();
62
+ });
63
+
64
+ it('applies full width class when full prop is true', () => {
65
+ const wrapper = mount(MSegmentedControl, {
66
+ props: { segments, full: true },
67
+ });
68
+
69
+ expect(wrapper.classes()).toContain('mc-segmented-control--full');
70
+ });
71
+
72
+ it('applies size class when size prop is "m"', () => {
73
+ const wrapper = mount(MSegmentedControl, {
74
+ props: { segments, size: 'm' },
75
+ });
76
+
77
+ expect(wrapper.classes()).toContain('mc-segmented-control--m');
78
+ });
79
+
80
+ it('does not apply size class when size is "s" (default)', () => {
81
+ const wrapper = mount(MSegmentedControl, {
82
+ props: { segments },
83
+ });
84
+
85
+ expect(wrapper.classes()).not.toContain('mc-segmented-control--s');
86
+ });
87
+
88
+ it('updates active segment when modelValue prop changes', async () => {
89
+ const wrapper = mount(MSegmentedControl, {
90
+ props: { segments, modelValue: 0 },
91
+ });
92
+
93
+ const buttons = wrapper.findAll('button');
94
+ expect(buttons[0].classes()).toContain(
95
+ 'mc-segmented-control__segment--selected',
96
+ );
97
+
98
+ await wrapper.setProps({ modelValue: 2 });
99
+
100
+ expect(buttons[2].classes()).toContain(
101
+ 'mc-segmented-control__segment--selected',
102
+ );
103
+ expect(buttons[2].attributes('aria-checked')).toBe('true');
104
+ });
105
+
106
+ it('adds role="radio" attribute to buttons', () => {
107
+ const wrapper = mount(MSegmentedControl, {
108
+ props: { segments },
109
+ });
110
+
111
+ const buttons = wrapper.findAll('button');
112
+ buttons.forEach((button) => {
113
+ expect(button.attributes('role')).toBe('radio');
114
+ });
115
+ });
116
+ });
@@ -0,0 +1,78 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
+ import { action } from 'storybook/actions';
3
+
4
+ import MSegmentedControl from './MSegmentedControl.vue';
5
+
6
+ const meta: Meta<typeof MSegmentedControl> = {
7
+ title: 'Action/Segmented Control',
8
+ component: MSegmentedControl,
9
+ parameters: {
10
+ docs: {
11
+ description: {
12
+ component:
13
+ 'A Segmented Control allows users to switch between multiple options or views within a single container. It provides a compact and efficient way to toggle between sections without requiring a dropdown or separate navigation. Segmented Controls are commonly used in filters, tabbed navigation, and content selection to enhance user interaction and accessibility.',
14
+ },
15
+ },
16
+ },
17
+ args: {
18
+ segments: [
19
+ {
20
+ label: 'Label',
21
+ },
22
+ {
23
+ label: 'Label',
24
+ },
25
+ {
26
+ label: 'Label',
27
+ },
28
+ {
29
+ label: 'Label',
30
+ },
31
+ ],
32
+ },
33
+ render: (args) => ({
34
+ components: { MSegmentedControl },
35
+ setup() {
36
+ const handleUpdate = action('update:modelValue');
37
+
38
+ return { args, handleUpdate };
39
+ },
40
+ template: `
41
+ <MSegmentedControl
42
+ v-bind="args"
43
+ @update:modelValue="handleUpdate"
44
+ ></MSegmentedControl>
45
+ `,
46
+ }),
47
+ };
48
+ export default meta;
49
+ type Story = StoryObj<typeof MSegmentedControl>;
50
+
51
+ export const Default: Story = {};
52
+
53
+ export const Icons: Story = {
54
+ args: {
55
+ segments: [
56
+ {
57
+ label: 'Label',
58
+ },
59
+ {
60
+ label: 'Label',
61
+ },
62
+ {
63
+ label: 'Label',
64
+ },
65
+ {
66
+ label: 'Label',
67
+ },
68
+ ],
69
+ },
70
+ };
71
+
72
+ export const Size: Story = {
73
+ args: { size: 'm' },
74
+ };
75
+
76
+ export const Full: Story = {
77
+ args: { full: true },
78
+ };
@@ -0,0 +1,92 @@
1
+ <template>
2
+ <div class="mc-segmented-control" :class="classObject" role="radiogroup">
3
+ <button
4
+ v-for="(segment, index) in segments"
5
+ :key="`segment-${index}`"
6
+ type="button"
7
+ class="mc-segmented-control__segment"
8
+ :class="{
9
+ 'mc-segmented-control__segment--selected': isSegmentSelected(index),
10
+ }"
11
+ :aria-checked="isSegmentSelected(index)"
12
+ role="radio"
13
+ @click="onClickSegment(index)"
14
+ >
15
+ {{ segment.label }}
16
+ </button>
17
+ </div>
18
+ </template>
19
+
20
+ <script setup lang="ts">
21
+ import { computed, ref, watch } from 'vue';
22
+ /**
23
+ * A Segmented Control allows users to switch between multiple options or views within a single container. It provides a compact and efficient way to toggle between sections without requiring a dropdown or separate navigation. Segmented Controls are commonly used in filters, tabbed navigation, and content selection to enhance user interaction and accessibility.
24
+ */
25
+ const props = withDefaults(
26
+ defineProps<{
27
+ /**
28
+ * The selected segment index, bound via v-model.
29
+ */
30
+ modelValue?: number;
31
+ /**
32
+ * if `true`, the segmented control take the full width.
33
+ */
34
+ full?: boolean;
35
+ /**
36
+ * Determines the size of the segmented control.
37
+ */
38
+ size?: 's' | 'm';
39
+ /**
40
+ * An array of objects that allows you to provide all the data needed to generate the content for each segment.
41
+ */
42
+ segments: Array<{
43
+ /**
44
+ * The label displayed for the segment.
45
+ */
46
+ label: string;
47
+ }>;
48
+ }>(),
49
+ {
50
+ modelValue: 0,
51
+ size: 's',
52
+ },
53
+ );
54
+
55
+ const classObject = computed(() => {
56
+ return {
57
+ 'mc-segmented-control--full': props.full,
58
+ [`mc-segmented-control--${props.size}`]: props.size && props.size != 's',
59
+ };
60
+ });
61
+
62
+ const modelValue = ref(props.modelValue);
63
+
64
+ watch(
65
+ () => props.modelValue,
66
+ (newVal) => {
67
+ modelValue.value = newVal;
68
+ },
69
+ );
70
+
71
+ const onClickSegment = (index: number) => {
72
+ if (index !== modelValue.value) {
73
+ modelValue.value = index;
74
+ emit('update:modelValue', index);
75
+ }
76
+ };
77
+
78
+ const isSegmentSelected = (index: number) => {
79
+ return modelValue.value === index;
80
+ };
81
+
82
+ const emit = defineEmits<{
83
+ /**
84
+ * Emits when the selected segment changes, updating the modelValue prop.
85
+ */
86
+ (on: 'update:modelValue', value: number): void;
87
+ }>();
88
+ </script>
89
+
90
+ <style lang="scss" scoped>
91
+ @use '@mozaic-ds/styles/components/segmented-control';
92
+ </style>
@@ -0,0 +1,19 @@
1
+ # MSegmentedControl
2
+
3
+ A Segmented Control allows users to switch between multiple options or views within a single container. It provides a compact and efficient way to toggle between sections without requiring a dropdown or separate navigation. Segmented Controls are commonly used in filters, tabbed navigation, and content selection to enhance user interaction and accessibility.
4
+
5
+
6
+ ## Props
7
+
8
+ | Name | Description | Type | Default |
9
+ | --- | --- | --- | --- |
10
+ | `modelValue` | The selected segment index, bound via v-model. | `number` | `0` |
11
+ | `full` | if `true`, the segmented control take the full width. | `boolean` | - |
12
+ | `size` | Determines the size of the segmented control. | `"s"` `"m"` | `"s"` |
13
+ | `segments*` | An array of objects that allows you to provide all the data needed to generate the content for each segment. | `{ label: string; }[]` | - |
14
+
15
+ ## Events
16
+
17
+ | Name | Description | Type |
18
+ | --- | --- | --- |
19
+ | `update:modelValue` | Emits when the selected segment changes, updating the modelValue prop. | [value: number] |
@@ -0,0 +1,24 @@
1
+ # MSelect
2
+
3
+ A select component allows users to choose a single option from a predefined list within a native dropdown menu. It helps simplify input by displaying only relevant choices, reducing the need for manual text entry. Select components are commonly used in forms, settings, and filters where structured selection is required.<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 section](/docs/form-elements-field--docs#select).
4
+
5
+
6
+ ## Props
7
+
8
+ | Name | Description | Type | Default |
9
+ | --- | --- | --- | --- |
10
+ | `id*` | A unique identifier for the select, used to associate the label with the form element. | `string` | - |
11
+ | `name` | The name attribute for the select element, used for form submission. | `string` | - |
12
+ | `options*` | Define the available choices for the select element. | `{ id?: string` `undefined; text: string; value: string` `number; attributes?: Record<string` `string` `number` `boolean>` `undefined; disabled?: boolean` `undefined; }[]` | - |
13
+ | `modelValue` | The current value of the select. | `string` `number` | - |
14
+ | `placeholder` | Text displayed when the select has no selected value. | `string` | - |
15
+ | `isInvalid` | If `true`, the select is marked as invalid. | `boolean` | - |
16
+ | `disabled` | If `true`, the select is disabled and non-interactive. | `boolean` | - |
17
+ | `size` | Determines the size of the select. | `"s"` `"m"` | `"m"` |
18
+ | `readonly` | If `true`, the select is read-only (cannot be edited). | `boolean` | - |
19
+
20
+ ## Events
21
+
22
+ | Name | Description | Type |
23
+ | --- | --- | --- |
24
+ | `update:modelValue` | Emits when the select value changes, updating the modelValue prop. | [value: string | number] |
@@ -0,0 +1,11 @@
1
+ # MStatusBadge
2
+
3
+ A Status Badge is used to indicate the current status of an element, providing a clear and concise visual cue. The status can change dynamically based on updates, events, or conditions within the system. Status Badges help users quickly identify the state of an item, such as an order status, system health, or process completion. They are often color-coded to enhance readability and recognition.
4
+
5
+
6
+ ## Props
7
+
8
+ | Name | Description | Type | Default |
9
+ | --- | --- | --- | --- |
10
+ | `label*` | Content of the status badge | `string` | - |
11
+ | `status` | Allows to define the status badge type | `"info"` `"success"` `"warning"` `"error"` `"neutral"` | `"info"` |
@@ -4,6 +4,7 @@ import MStatusDot from './MStatusDot.vue';
4
4
  const meta: Meta<typeof MStatusDot> = {
5
5
  title: 'Status/Status Dot',
6
6
  component: MStatusDot,
7
+ tags: ['v2'],
7
8
  parameters: {
8
9
  docs: {
9
10
  description: {
@@ -0,0 +1,11 @@
1
+ # MStatusDot
2
+
3
+ A Status dot is a small visual indicator used to represent the state or condition of an element. It is often color-coded to convey different statuses at a glance, such as availability, activity, or urgency. Status Dots are commonly found in user presence indicators, system statuses, or process tracking to provide quick, unobtrusive feedback.
4
+
5
+
6
+ ## Props
7
+
8
+ | Name | Description | Type | Default |
9
+ | --- | --- | --- | --- |
10
+ | `status` | Allows to define the status dot type. | `"info"` `"success"` `"warning"` `"error"` `"neutral"` | `"info"` |
11
+ | `size` | Determines the size of the status dot. | `"s"` `"m"` `"l"` | - |
@@ -0,0 +1,25 @@
1
+ # MStatusNotification
2
+
3
+ A Status Notification is used to draw the user’s attention to important information that needs to be acknowledged. It often provides feedback on a process, highlights a status update, or alerts users about an issue. Notifications are typically triggered by user actions or system events and are designed to be easily noticeable while maintaining a non-intrusive experience.
4
+
5
+
6
+ ## Props
7
+
8
+ | Name | Description | Type | Default |
9
+ | --- | --- | --- | --- |
10
+ | `title*` | Title of the status notification. | `string` | - |
11
+ | `description*` | Description of the status notification. | `string` | - |
12
+ | `status` | Allows to define the status notification type. | `"info"` `"success"` `"warning"` `"error"` | `"info"` |
13
+ | `closable` | if `true`, display the close button. | `boolean` | - |
14
+
15
+ ## Slots
16
+
17
+ | Name | Description |
18
+ | --- | --- |
19
+ | `footer` | Use this slot to insert a button or a link in the footer |
20
+
21
+ ## Events
22
+
23
+ | Name | Description | Type |
24
+ | --- | --- | --- |
25
+ | `close` | Emits when closing the notification. | [] |
@@ -39,7 +39,7 @@ const meta: Meta<typeof Mtabs> = {
39
39
  return { args, handleUpdate };
40
40
  },
41
41
  template: `
42
- <Mtabs
42
+ <Mtabs
43
43
  v-bind="args"
44
44
  @update:modelValue="handleUpdate"
45
45
  ></Mtabs>
@@ -102,3 +102,25 @@ export const Disabled: Story = {
102
102
  ],
103
103
  },
104
104
  };
105
+
106
+ export const WithBadges: Story = {
107
+ args: {
108
+ tabs: [
109
+ {
110
+ label: 'Label',
111
+ badge: 3,
112
+ },
113
+ {
114
+ label: 'Label',
115
+ },
116
+ {
117
+ label: 'Label',
118
+ badge: 99,
119
+ },
120
+ {
121
+ label: 'Label',
122
+ badge: 100,
123
+ },
124
+ ],
125
+ },
126
+ };
@@ -25,6 +25,9 @@
25
25
  <div class="mc-tabs__label">
26
26
  <span>{{ tab.label }}</span>
27
27
  </div>
28
+ <span v-if="tab.badge" class="mc-tabs__badge">
29
+ <MNumberBadge :label="tab.badge" />
30
+ </span>
28
31
  </button>
29
32
  </li>
30
33
  </ul>
@@ -35,6 +38,7 @@
35
38
  <script setup lang="ts">
36
39
  import { computed, ref, type Component } from 'vue';
37
40
  import MDivider from '../divider/MDivider.vue';
41
+ import MNumberBadge from '../numberbadge/MNumberBadge.vue';
38
42
  /**
39
43
  * Tabs are a navigation component that allows users to switch between different sections within the same context. They help organize content efficiently by displaying only one section at a time, reducing clutter and improving accessibility. Tabs can include icons, labels, and notification badges to provide additional context. They are commonly used in dashboards, product management, and settings interfaces.
40
44
  */
@@ -64,6 +68,10 @@ const props = withDefaults(
64
68
  * The icon displayed for the tab from Mozaic-icon-vue.
65
69
  */
66
70
  icon?: Component;
71
+ /**
72
+ * The number badge displayed for the tab.
73
+ */
74
+ badge?: number;
67
75
  /**
68
76
  * The label displayed for the tab.
69
77
  */
@@ -119,14 +119,16 @@ describe('MTabs.vue', () => {
119
119
  });
120
120
 
121
121
  it('renders icon component when icon prop is provided', () => {
122
- const DummyIcon = markRaw(defineComponent({
123
- name: 'DummyIcon',
124
- render() {
125
- return h('svg', { class: 'dummy-icon' }, [
126
- h('circle', { cx: 10, cy: 10, r: 10 }),
127
- ]);
128
- },
129
- }));
122
+ const DummyIcon = markRaw(
123
+ defineComponent({
124
+ name: 'DummyIcon',
125
+ render() {
126
+ return h('svg', { class: 'dummy-icon' }, [
127
+ h('circle', { cx: 10, cy: 10, r: 10 }),
128
+ ]);
129
+ },
130
+ }),
131
+ );
130
132
 
131
133
  const tabsWithIcon = [
132
134
  { label: 'Tab 1', icon: DummyIcon },
@@ -146,4 +148,23 @@ describe('MTabs.vue', () => {
146
148
  const secondTabButton = wrapper.findAll('button.mc-tabs__tab')[1];
147
149
  expect(secondTabButton.findComponent(DummyIcon).exists()).toBe(false);
148
150
  });
151
+
152
+ it('renders badge when badge prop is provided', () => {
153
+ const tabsWithBadges = [{ label: 'Tab 1', badge: 5 }, { label: 'Tab 2' }];
154
+
155
+ const wrapper = mount(MTabs, {
156
+ props: {
157
+ tabs: tabsWithBadges,
158
+ },
159
+ });
160
+
161
+ const firstTabButton = wrapper.findAll('button.mc-tabs__tab')[0];
162
+ expect(firstTabButton.find('span.mc-tabs__badge').exists()).toBe(true);
163
+ expect(
164
+ firstTabButton.find('span.mc-tabs__badge .mc-number-badge').text(),
165
+ ).toBe('5');
166
+
167
+ const secondTabButton = wrapper.findAll('button.mc-tabs__tab')[1];
168
+ expect(secondTabButton.find('span.mc-tabs__badge').exists()).toBe(false);
169
+ });
149
170
  });
@@ -0,0 +1,20 @@
1
+ # MTabs
2
+
3
+ Tabs are a navigation component that allows users to switch between different sections within the same context. They help organize content efficiently by displaying only one section at a time, reducing clutter and improving accessibility. Tabs can include icons, labels, and notification badges to provide additional context. They are commonly used in dashboards, product management, and settings interfaces.
4
+
5
+
6
+ ## Props
7
+
8
+ | Name | Description | Type | Default |
9
+ | --- | --- | --- | --- |
10
+ | `description` | A description indicating the purpose of the set of tabs. Useful for improving the accessibility of the component. | `string` | - |
11
+ | `divider` | If `true`, the divider will appear. | `boolean` | `true` |
12
+ | `centered` | If `true`, the tabs of the component will be centered. | `boolean` | - |
13
+ | `modelValue` | The selected tab index, bound via v-model. | `number` | `0` |
14
+ | `tabs*` | An array of objects that allows you to provide all the data needed to generate the content for each tab. | `{ icon?: Component` `undefined; badge?: number` `undefined; label: string; disabled?: boolean` `undefined; }[]` | - |
15
+
16
+ ## Events
17
+
18
+ | Name | Description | Type |
19
+ | --- | --- | --- |
20
+ | `update:modelValue` | Emits when the selected tab changes, updating the modelValue prop. | [value: number] |