@mozaic-ds/vue 1.0.0-rc.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +51 -0
- package/README.md +76 -77
- package/dist/mozaic-vue.css +1 -1
- package/dist/mozaic-vue.d.ts +1664 -0
- package/dist/mozaic-vue.js +1943 -0
- package/dist/mozaic-vue.js.map +1 -0
- package/dist/mozaic-vue.umd.cjs +2 -0
- package/dist/mozaic-vue.umd.cjs.map +1 -0
- package/env.d.ts +1 -0
- package/package.json +78 -51
- package/src/components/Contributing.mdx +118 -0
- package/src/components/GettingStarted.mdx +45 -0
- package/src/components/Introduction.mdx +100 -0
- package/src/components/Support.mdx +18 -0
- package/src/components/breadcrumb/MBreadcrumb.spec.ts +105 -0
- package/src/components/breadcrumb/MBreadcrumb.stories.ts +82 -0
- package/src/components/breadcrumb/MBreadcrumb.vue +52 -55
- package/src/components/button/MButton.spec.ts +191 -0
- package/src/components/button/MButton.stories.ts +59 -0
- package/src/components/button/MButton.vue +98 -154
- package/src/components/checkbox/MCheckbox.spec.ts +104 -0
- package/src/components/checkbox/MCheckbox.stories.ts +83 -0
- package/src/components/checkbox/MCheckbox.vue +60 -101
- package/src/components/checkboxgroup/MCheckboxGroup.spec.ts +78 -0
- package/src/components/checkboxgroup/MCheckboxGroup.stories.ts +61 -0
- package/src/components/checkboxgroup/MCheckboxGroup.vue +97 -0
- package/src/components/datepicker/MDatepicker.spec.ts +95 -0
- package/src/components/datepicker/MDatepicker.stories.ts +75 -0
- package/src/components/datepicker/MDatepicker.vue +114 -0
- package/src/components/divider/MDivider.spec.ts +57 -0
- package/src/components/divider/MDivider.stories.ts +64 -0
- package/src/components/divider/MDivider.vue +56 -0
- package/src/components/drawer/MDrawer.spec.ts +100 -0
- package/src/components/drawer/MDrawer.stories.ts +128 -0
- package/src/components/drawer/MDrawer.vue +140 -0
- package/src/components/field/MField.spec.ts +166 -0
- package/src/components/field/MField.stories.ts +369 -0
- package/src/components/field/MField.vue +78 -61
- package/src/components/fieldgroup/MFieldGroup.spec.ts +165 -0
- package/src/components/fieldgroup/MFieldGroup.stories.ts +416 -0
- package/src/components/fieldgroup/MFieldGroup.vue +79 -0
- package/src/components/flag/MFlag.spec.ts +46 -0
- package/src/components/flag/MFlag.stories.ts +46 -0
- package/src/components/flag/MFlag.vue +28 -39
- package/src/components/iconbutton/MIconButton.spec.ts +108 -0
- package/src/components/iconbutton/MIconButton.stories.ts +74 -0
- package/src/components/iconbutton/MIconButton.vue +73 -0
- package/src/components/link/MLink.spec.ts +154 -0
- package/src/components/link/MLink.stories.ts +89 -0
- package/src/components/link/MLink.vue +86 -120
- package/src/components/loader/MLoader.spec.ts +104 -0
- package/src/components/loader/MLoader.stories.ts +43 -0
- package/src/components/loader/MLoader.vue +66 -55
- package/src/components/loadingoverlay/MLoadingOverlay.spec.ts +37 -0
- package/src/components/loadingoverlay/MLoadingOverlay.stories.ts +40 -0
- package/src/components/loadingoverlay/MLoadingOverlay.vue +28 -0
- package/src/components/modal/MModal.spec.ts +103 -0
- package/src/components/modal/MModal.stories.ts +127 -0
- package/src/components/modal/MModal.vue +106 -154
- package/src/components/numberbadge/MNumberBadge.spec.ts +56 -0
- package/src/components/numberbadge/MNumberBadge.stories.ts +48 -0
- package/src/components/numberbadge/MNumberBadge.vue +45 -0
- package/src/components/overlay/MOverlay.spec.ts +51 -0
- package/src/components/overlay/MOverlay.stories.ts +35 -0
- package/src/components/overlay/MOverlay.vue +27 -19
- package/src/components/pagination/MPagination.spec.ts +123 -0
- package/src/components/pagination/MPagination.stories.ts +83 -0
- package/src/components/pagination/MPagination.vue +120 -140
- package/src/components/passwordinput/MPasswordInput.spec.ts +104 -0
- package/src/components/passwordinput/MPasswordInput.stories.ts +75 -0
- package/src/components/passwordinput/MPasswordInput.vue +126 -77
- package/src/components/pincode/MPincode.spec.ts +126 -0
- package/src/components/pincode/MPincode.stories.ts +68 -0
- package/src/components/pincode/MPincode.vue +148 -0
- package/src/components/quantityselector/MQuantitySelector.spec.ts +262 -0
- package/src/components/quantityselector/MQuantitySelector.stories.ts +89 -0
- package/src/components/quantityselector/MQuantitySelector.vue +159 -148
- package/src/components/radio/MRadio.spec.ts +104 -0
- package/src/components/radio/MRadio.stories.ts +68 -0
- package/src/components/radio/MRadio.vue +56 -39
- package/src/components/radiogroup/MRadioGroup.spec.ts +54 -0
- package/src/components/radiogroup/MRadioGroup.stories.ts +61 -0
- package/src/components/radiogroup/MRadioGroup.vue +79 -0
- package/src/components/select/MSelect.spec.ts +114 -0
- package/src/components/select/MSelect.stories.ts +101 -0
- package/src/components/select/MSelect.vue +77 -119
- package/src/components/statusbadge/MStatusBadge.stories.ts +45 -0
- package/src/components/statusbadge/MStatusBadge.vue +40 -0
- package/src/components/statusbadge/MstatusBadge.spec.ts +16 -0
- package/src/components/statusdot/MStatusDot.spec.ts +51 -0
- package/src/components/statusdot/MStatusDot.stories.ts +48 -0
- package/src/components/statusdot/MStatusDot.vue +36 -0
- package/src/components/statusnotification/MStatusNotification.spec.ts +103 -0
- package/src/components/statusnotification/MStatusNotification.stories.ts +89 -0
- package/src/components/statusnotification/MStatusNotification.vue +106 -0
- package/src/components/tabs/MTabs.stories.ts +104 -0
- package/src/components/tabs/MTabs.vue +113 -0
- package/src/components/tabs/Mtabs.spec.ts +149 -0
- package/src/components/tag/MTag.spec.ts +107 -0
- package/src/components/tag/MTag.stories.ts +75 -0
- package/src/components/tag/MTag.vue +151 -0
- package/src/components/textarea/MTextArea.spec.ts +112 -0
- package/src/components/textarea/MTextArea.stories.ts +67 -0
- package/src/components/textarea/MTextArea.vue +81 -43
- package/src/components/textinput/MTextInput.spec.ts +121 -0
- package/src/components/textinput/MTextInput.stories.ts +107 -0
- package/src/components/textinput/MTextInput.vue +127 -47
- package/src/components/toggle/MToggle.spec.ts +99 -0
- package/src/components/toggle/MToggle.stories.ts +68 -0
- package/src/components/toggle/MToggle.vue +63 -103
- package/src/components/togglegroup/MToggleGroup.spec.ts +78 -0
- package/src/components/togglegroup/MToggleGroup.stories.ts +61 -0
- package/src/components/togglegroup/MToggleGroup.vue +97 -0
- package/src/components/usingIcons.mdx +35 -0
- package/src/components/usingPresets.mdx +128 -0
- package/src/main.ts +32 -0
- package/dist/demo.html +0 -1
- package/dist/mozaic-vue.adeo.css +0 -47
- package/dist/mozaic-vue.adeo.umd.js +0 -31109
- package/dist/mozaic-vue.common.js +0 -31099
- package/dist/mozaic-vue.common.js.map +0 -1
- package/dist/mozaic-vue.umd.js +0 -31110
- package/dist/mozaic-vue.umd.js.map +0 -1
- package/dist/mozaic-vue.umd.min.js +0 -4
- package/dist/mozaic-vue.umd.min.js.map +0 -1
- package/postinstall.js +0 -3
- package/src/components/accordion/MAccordion.vue +0 -128
- package/src/components/accordion/index.js +0 -7
- package/src/components/autocomplete/MAutocomplete.vue +0 -381
- package/src/components/autocomplete/index.js +0 -7
- package/src/components/badge/MBadge.vue +0 -43
- package/src/components/badge/index.js +0 -7
- package/src/components/breadcrumb/index.js +0 -7
- package/src/components/button/index.js +0 -7
- package/src/components/card/MCard.vue +0 -78
- package/src/components/card/index.js +0 -7
- package/src/components/checkbox/MCheckboxGroup.vue +0 -163
- package/src/components/checkbox/index.js +0 -12
- package/src/components/container/MContainer.vue +0 -33
- package/src/components/container/index.js +0 -7
- package/src/components/datatable/MDataTable.vue +0 -651
- package/src/components/datatable/MDataTableHeader.vue +0 -55
- package/src/components/datatable/MDataTableTop.vue +0 -35
- package/src/components/datatable/helpers.js +0 -132
- package/src/components/datatable/index.js +0 -12
- package/src/components/dropdown/MDropdown.vue +0 -317
- package/src/components/dropdown/index.js +0 -7
- package/src/components/field/index.js +0 -7
- package/src/components/fileuploader/MFileResult.vue +0 -149
- package/src/components/fileuploader/MFileUploader.vue +0 -142
- package/src/components/fileuploader/index.js +0 -7
- package/src/components/flag/index.js +0 -7
- package/src/components/heading/MHeading.vue +0 -75
- package/src/components/heading/index.js +0 -7
- package/src/components/hero/MHero.vue +0 -93
- package/src/components/hero/index.js +0 -7
- package/src/components/icon/MIcon.vue +0 -136
- package/src/components/icon/index.js +0 -7
- package/src/components/index.js +0 -44
- package/src/components/layer/MLayer.vue +0 -208
- package/src/components/layer/index.js +0 -7
- package/src/components/link/index.js +0 -7
- package/src/components/listbox/MListBox.vue +0 -146
- package/src/components/listbox/MListBoxActions.vue +0 -251
- package/src/components/listbox/index.js +0 -12
- package/src/components/loader/index.js +0 -7
- package/src/components/modal/index.js +0 -7
- package/src/components/notification/MNotification.vue +0 -110
- package/src/components/notification/index.js +0 -7
- package/src/components/optionbutton/MOptionButton.vue +0 -67
- package/src/components/optionbutton/index.js +0 -7
- package/src/components/optioncard/MOptionCard.vue +0 -132
- package/src/components/optioncard/index.js +0 -7
- package/src/components/optiongroup/MOptionGroup.vue +0 -18
- package/src/components/optiongroup/index.js +0 -7
- package/src/components/overlay/MOverlayLoader.vue +0 -43
- package/src/components/overlay/index.js +0 -12
- package/src/components/pagination/index.js +0 -7
- package/src/components/passwordinput/index.js +0 -7
- package/src/components/phonenumber/MPhoneNumber.vue +0 -398
- package/src/components/phonenumber/index.js +0 -7
- package/src/components/progressbar/MProgress.vue +0 -102
- package/src/components/progressbar/index.js +0 -7
- package/src/components/quantityselector/index.js +0 -7
- package/src/components/radio/MRadioGroup.vue +0 -111
- package/src/components/radio/index.js +0 -12
- package/src/components/ratingstars/MStarsInput.vue +0 -119
- package/src/components/ratingstars/MStarsResult.vue +0 -89
- package/src/components/ratingstars/index.js +0 -12
- package/src/components/select/index.js +0 -7
- package/src/components/stepper/MStepper.vue +0 -111
- package/src/components/stepper/index.js +0 -7
- package/src/components/tabs/MTab.vue +0 -198
- package/src/components/tabs/index.js +0 -7
- package/src/components/tags/MTag.vue +0 -173
- package/src/components/tags/index.js +0 -7
- package/src/components/textarea/index.js +0 -7
- package/src/components/textinput/MTextInputField.vue +0 -105
- package/src/components/textinput/MTextInputIcon.vue +0 -42
- package/src/components/textinput/index.js +0 -7
- package/src/components/toggle/index.js +0 -7
- package/src/components/tooltip/MTooltip.vue +0 -42
- package/src/components/tooltip/index.js +0 -7
- package/src/index.js +0 -63
- package/src/shims-tsx.d.ts +0 -13
- package/src/shims.vue.d.ts +0 -4
- package/src/tokens/adeo/android/colors.xml +0 -448
- package/src/tokens/adeo/android/font_dimens.xml +0 -18
- package/src/tokens/adeo/css/_variables.scss +0 -442
- package/src/tokens/adeo/css/root.scss +0 -444
- package/src/tokens/adeo/ios/StyleDictionaryColor.h +0 -456
- package/src/tokens/adeo/ios/StyleDictionaryColor.m +0 -468
- package/src/tokens/adeo/ios/StyleDictionaryColor.swift +0 -451
- package/src/tokens/adeo/ios/StyleDictionarySize.h +0 -69
- package/src/tokens/adeo/ios/StyleDictionarySize.m +0 -70
- package/src/tokens/adeo/ios/StyleDictionarySize.swift +0 -71
- package/src/tokens/adeo/js/tokens.js +0 -540
- package/src/tokens/adeo/js/tokensObject.js +0 -11641
- package/src/tokens/adeo/scss/_tokens.scss +0 -1514
- package/src/utils/mozaicClasses.js +0 -16
- package/src/utils/theme.validator.js +0 -19
- package/types/index.d.ts +0 -104
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
import { action } from 'storybook/actions';
|
|
3
|
+
|
|
4
|
+
import MRadioGroup from './MRadioGroup.vue';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof MRadioGroup> = {
|
|
7
|
+
title: 'Form Elements/Radio Group',
|
|
8
|
+
component: MRadioGroup,
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
'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).',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
args: {
|
|
18
|
+
name: 'radioGroupName',
|
|
19
|
+
modelValue: 'radio2',
|
|
20
|
+
options: [
|
|
21
|
+
{
|
|
22
|
+
id: 'radio-01',
|
|
23
|
+
label: 'Radio button Label',
|
|
24
|
+
value: 'radio1',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 'radio-02',
|
|
28
|
+
label: 'Radio button Label',
|
|
29
|
+
value: 'radio2',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 'radio-03',
|
|
33
|
+
label: 'Radio button Label',
|
|
34
|
+
value: 'radio3',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'radio-04',
|
|
38
|
+
label: 'Radio button Label',
|
|
39
|
+
value: 'radio4',
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
render: (args) => ({
|
|
44
|
+
components: { MRadioGroup },
|
|
45
|
+
setup() {
|
|
46
|
+
const handleUpdate = action('update:modelValue');
|
|
47
|
+
|
|
48
|
+
return { args, handleUpdate };
|
|
49
|
+
},
|
|
50
|
+
template: `
|
|
51
|
+
<MRadioGroup
|
|
52
|
+
v-bind="args"
|
|
53
|
+
@update:modelValue="handleUpdate"
|
|
54
|
+
/>
|
|
55
|
+
`,
|
|
56
|
+
}),
|
|
57
|
+
};
|
|
58
|
+
export default meta;
|
|
59
|
+
type Story = StoryObj<typeof MRadioGroup>;
|
|
60
|
+
|
|
61
|
+
export const Default: Story = {};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="mc-field__container" :class="classObjectContainer">
|
|
3
|
+
<MRadio
|
|
4
|
+
v-for="option in options"
|
|
5
|
+
:id="option.id"
|
|
6
|
+
:key="option.id"
|
|
7
|
+
:label="option.label"
|
|
8
|
+
:is-invalid="isInvalid"
|
|
9
|
+
:name="name"
|
|
10
|
+
class="mc-field__item"
|
|
11
|
+
:class="classObjectItem"
|
|
12
|
+
:model-value="modelValue === option.value"
|
|
13
|
+
:disabled="option.disabled"
|
|
14
|
+
@update:model-value="
|
|
15
|
+
(v: boolean) => (v ? emit('update:modelValue', option.value) : null)
|
|
16
|
+
"
|
|
17
|
+
/>
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script setup lang="ts">
|
|
22
|
+
import { computed } from 'vue';
|
|
23
|
+
import MRadio from '../radio/MRadio.vue';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A radio button is used to offer a unique choice to your user in a form. Unlike checkboxes, it can not be used alone.
|
|
27
|
+
*/
|
|
28
|
+
const props = defineProps<{
|
|
29
|
+
/**
|
|
30
|
+
* The name attribute for the radio element, typically used for form submission.
|
|
31
|
+
*/
|
|
32
|
+
name: string;
|
|
33
|
+
/**
|
|
34
|
+
* Property used to manage the values checked by v-model
|
|
35
|
+
* (Do not use directly)
|
|
36
|
+
*/
|
|
37
|
+
modelValue?: string;
|
|
38
|
+
/**
|
|
39
|
+
* list of properties of each radio button of the radio group
|
|
40
|
+
*/
|
|
41
|
+
options: Array<{
|
|
42
|
+
id: string;
|
|
43
|
+
label: string;
|
|
44
|
+
value: string;
|
|
45
|
+
disabled?: boolean;
|
|
46
|
+
}>;
|
|
47
|
+
/**
|
|
48
|
+
* If `true`, applies an invalid state to the radio group.
|
|
49
|
+
*/
|
|
50
|
+
isInvalid?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* If `true`, make the form element of the group inline.
|
|
53
|
+
*/
|
|
54
|
+
inline?: boolean;
|
|
55
|
+
}>();
|
|
56
|
+
|
|
57
|
+
const classObjectContainer = computed(() => {
|
|
58
|
+
return {
|
|
59
|
+
'mc-field__container--inline': props.inline,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const classObjectItem = computed(() => {
|
|
64
|
+
return {
|
|
65
|
+
'mc-field__container--inline__item': props.inline,
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const emit = defineEmits<{
|
|
70
|
+
/**
|
|
71
|
+
* Emits when the radio group value changes, updating the modelValue prop.
|
|
72
|
+
*/
|
|
73
|
+
(on: 'update:modelValue', value: string): void;
|
|
74
|
+
}>();
|
|
75
|
+
</script>
|
|
76
|
+
|
|
77
|
+
<style lang="scss" scoped>
|
|
78
|
+
@use '@mozaic-ds/styles/components/field';
|
|
79
|
+
</style>
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import MSelect from './MSelect.vue';
|
|
4
|
+
|
|
5
|
+
describe('Select.vue', () => {
|
|
6
|
+
it('renders options correctly', () => {
|
|
7
|
+
const options = [
|
|
8
|
+
{ text: 'Option 1', value: '1' },
|
|
9
|
+
{ text: 'Option 2', value: '2' },
|
|
10
|
+
{ text: 'Option 3', value: '3' },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const wrapper = mount(MSelect, {
|
|
14
|
+
props: {
|
|
15
|
+
id: 'test-select',
|
|
16
|
+
modelValue: '1',
|
|
17
|
+
options,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const optionElements = wrapper.findAll('option');
|
|
22
|
+
expect(optionElements.length).toBe(options.length);
|
|
23
|
+
expect(optionElements[0].text()).toBe('Option 1');
|
|
24
|
+
expect(optionElements[1].text()).toBe('Option 2');
|
|
25
|
+
expect(optionElements[2].text()).toBe('Option 3');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('renders placeholder when provided', () => {
|
|
29
|
+
const options = [
|
|
30
|
+
{ text: 'Option 1', value: '1' },
|
|
31
|
+
{ text: 'Option 2', value: '2' },
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const wrapper = mount(MSelect, {
|
|
35
|
+
props: {
|
|
36
|
+
id: 'test-select',
|
|
37
|
+
modelValue: '',
|
|
38
|
+
options,
|
|
39
|
+
placeholder: 'Select an option',
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const placeholderOption = wrapper.find('option[disabled]');
|
|
44
|
+
expect(placeholderOption.exists()).toBe(true);
|
|
45
|
+
expect(placeholderOption.text()).toBe('-- Select an option --');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('binds and updates the modelValue correctly', async () => {
|
|
49
|
+
const options = [
|
|
50
|
+
{ text: 'Option 1', value: '1' },
|
|
51
|
+
{ text: 'Option 2', value: '2' },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
const wrapper = mount(MSelect, {
|
|
55
|
+
props: {
|
|
56
|
+
id: 'test-select',
|
|
57
|
+
modelValue: '1',
|
|
58
|
+
options,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
await wrapper.find('select').setValue('2');
|
|
63
|
+
|
|
64
|
+
const emitted = wrapper.emitted('update:modelValue');
|
|
65
|
+
expect(emitted).toBeDefined();
|
|
66
|
+
expect(emitted!.length).toBe(1);
|
|
67
|
+
expect(emitted![0]).toEqual(['2']);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('disables the select when the disabled prop is true', () => {
|
|
71
|
+
const wrapper = mount(MSelect, {
|
|
72
|
+
props: {
|
|
73
|
+
id: 'test-select',
|
|
74
|
+
modelValue: '1',
|
|
75
|
+
options: [{ text: 'Option 1', value: '1' }],
|
|
76
|
+
disabled: true,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const select = wrapper.find('select');
|
|
81
|
+
expect(select.attributes('disabled')).toBeDefined();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('applies the correct classes based on props', () => {
|
|
85
|
+
const wrapper = mount(MSelect, {
|
|
86
|
+
props: {
|
|
87
|
+
id: 'test-select',
|
|
88
|
+
modelValue: '1',
|
|
89
|
+
options: [{ text: 'Option 1', value: '1' }],
|
|
90
|
+
size: 's',
|
|
91
|
+
isInvalid: true,
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const select = wrapper.find('select');
|
|
96
|
+
|
|
97
|
+
expect(select.classes()).toContain('mc-select--s');
|
|
98
|
+
|
|
99
|
+
expect(select.classes()).toContain('is-invalid');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('does not apply invalid class if isInvalid is not set', () => {
|
|
103
|
+
const wrapper = mount(MSelect, {
|
|
104
|
+
props: {
|
|
105
|
+
id: 'test-select',
|
|
106
|
+
modelValue: '1',
|
|
107
|
+
options: [{ text: 'Option 1', value: '1' }],
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const select = wrapper.find('select');
|
|
112
|
+
expect(select.classes()).not.toContain('is-invalid');
|
|
113
|
+
});
|
|
114
|
+
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
import { action } from 'storybook/actions';
|
|
3
|
+
|
|
4
|
+
import MSelect from './MSelect.vue';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof MSelect> = {
|
|
7
|
+
title: 'Form Elements/Select',
|
|
8
|
+
component: MSelect,
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
'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).',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
argTypes: {
|
|
18
|
+
ariaLabel: {
|
|
19
|
+
table: {
|
|
20
|
+
disable: true,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
args: {
|
|
25
|
+
id: 'selectId',
|
|
26
|
+
placeholder: 'Choose an option',
|
|
27
|
+
options: [
|
|
28
|
+
{
|
|
29
|
+
text: 'Option 1',
|
|
30
|
+
value: 'option1',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
text: 'Option 2',
|
|
34
|
+
value: 'option2',
|
|
35
|
+
disabled: true,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
text: 'Option 3',
|
|
39
|
+
value: 'option3',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
text: 'Option 4',
|
|
43
|
+
value: 'option4',
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
ariaLabel: 'Choose an option',
|
|
47
|
+
},
|
|
48
|
+
render: (args) => ({
|
|
49
|
+
components: { MSelect },
|
|
50
|
+
setup() {
|
|
51
|
+
const handleUpdate = action('update:modelValue');
|
|
52
|
+
|
|
53
|
+
return { args, handleUpdate };
|
|
54
|
+
},
|
|
55
|
+
template: `
|
|
56
|
+
<MSelect
|
|
57
|
+
v-bind="args"
|
|
58
|
+
@update:modelValue="handleUpdate"
|
|
59
|
+
/>
|
|
60
|
+
`,
|
|
61
|
+
}),
|
|
62
|
+
};
|
|
63
|
+
export default meta;
|
|
64
|
+
type Story = StoryObj<typeof MSelect>;
|
|
65
|
+
|
|
66
|
+
export const WithValue: Story = {
|
|
67
|
+
args: {
|
|
68
|
+
id: 'withValueId',
|
|
69
|
+
modelValue: 'option1',
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const Default: Story = {};
|
|
74
|
+
|
|
75
|
+
export const Small: Story = {
|
|
76
|
+
args: {
|
|
77
|
+
id: 'smallId',
|
|
78
|
+
size: 's',
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const Disabled: Story = {
|
|
83
|
+
args: {
|
|
84
|
+
id: 'disabledId',
|
|
85
|
+
disabled: true,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const ReadOnly: Story = {
|
|
90
|
+
args: {
|
|
91
|
+
id: 'readonlyId',
|
|
92
|
+
readonly: true,
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const Invalid: Story = {
|
|
97
|
+
args: {
|
|
98
|
+
id: 'invalidId',
|
|
99
|
+
isInvalid: true,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<select
|
|
3
3
|
:id="id"
|
|
4
|
-
ref="select"
|
|
5
4
|
class="mc-select"
|
|
6
|
-
:
|
|
7
|
-
:value="
|
|
5
|
+
:name="name"
|
|
6
|
+
:value="modelValue"
|
|
7
|
+
:class="classObject"
|
|
8
8
|
:disabled="disabled"
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
v-bind="$attrs"
|
|
10
|
+
@change="
|
|
11
|
+
emit('update:modelValue', ($event.target as HTMLSelectElement).value)
|
|
12
|
+
"
|
|
11
13
|
>
|
|
12
|
-
<option v-if="placeholder" value="" disabled
|
|
14
|
+
<option v-if="placeholder" value="" disabled>
|
|
13
15
|
-- {{ placeholder }} --
|
|
14
16
|
</option>
|
|
15
17
|
<option
|
|
@@ -19,127 +21,83 @@
|
|
|
19
21
|
v-bind="option.attributes"
|
|
20
22
|
:disabled="option.disabled"
|
|
21
23
|
>
|
|
22
|
-
|
|
23
|
-
{{ option.text }}
|
|
24
|
-
</slot>
|
|
24
|
+
{{ option.text }}
|
|
25
25
|
</option>
|
|
26
|
-
<slot name="options" />
|
|
27
26
|
</select>
|
|
28
27
|
</template>
|
|
29
28
|
|
|
30
|
-
<script>
|
|
31
|
-
|
|
32
|
-
name: 'MSelect',
|
|
33
|
-
inject: {
|
|
34
|
-
cssFieldElementClass: {
|
|
35
|
-
default: '',
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
model: {
|
|
40
|
-
prop: 'value',
|
|
41
|
-
event: 'change',
|
|
42
|
-
},
|
|
29
|
+
<script setup lang="ts">
|
|
30
|
+
import { computed } from 'vue';
|
|
43
31
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
32
|
+
/**
|
|
33
|
+
* A select is a form element for multi-line text input, ideal for longer content like comments or descriptions.
|
|
34
|
+
*/
|
|
35
|
+
const props = withDefaults(
|
|
36
|
+
defineProps<{
|
|
37
|
+
/**
|
|
38
|
+
* A unique identifier for the select, used to associate the label with the form element.
|
|
39
|
+
*/
|
|
40
|
+
id: string;
|
|
41
|
+
/**
|
|
42
|
+
* The name attribute for the select element, used for form submission.
|
|
43
|
+
*/
|
|
44
|
+
name?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Define the available choices for the select element.
|
|
47
|
+
*/
|
|
48
|
+
options: Array<{
|
|
49
|
+
id?: string;
|
|
50
|
+
text: string;
|
|
51
|
+
value: string | number;
|
|
52
|
+
attributes?: Record<string, string | boolean | number>;
|
|
53
|
+
disabled?: boolean;
|
|
54
|
+
}>;
|
|
55
|
+
/**
|
|
56
|
+
* The current value of the select.
|
|
57
|
+
*/
|
|
58
|
+
modelValue?: string | number;
|
|
59
|
+
/**
|
|
60
|
+
* Text displayed when the select has no selected value.
|
|
61
|
+
*/
|
|
62
|
+
placeholder?: string;
|
|
63
|
+
/**
|
|
64
|
+
* If `true`, the select is marked as invalid.
|
|
65
|
+
*/
|
|
66
|
+
isInvalid?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* If `true`, the select is disabled and non-interactive.
|
|
69
|
+
*/
|
|
70
|
+
disabled?: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Determines the size of the select
|
|
73
|
+
*/
|
|
74
|
+
size?: 's' | 'm';
|
|
75
|
+
/**
|
|
76
|
+
* If `true`, the select is read-only (cannot be edited).
|
|
77
|
+
*/
|
|
78
|
+
readonly?: boolean;
|
|
79
|
+
}>(),
|
|
80
|
+
{
|
|
81
|
+
size: 'm',
|
|
78
82
|
},
|
|
83
|
+
);
|
|
79
84
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
getSelectValue() {
|
|
88
|
-
return this.optionValue ? this.optionValue : this.value;
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
setClasses() {
|
|
92
|
-
const classes = [
|
|
93
|
-
{
|
|
94
|
-
'is-valid': this.isValid,
|
|
95
|
-
'is-invalid': this.isInvalid,
|
|
96
|
-
},
|
|
97
|
-
];
|
|
98
|
-
|
|
99
|
-
if (this.size) {
|
|
100
|
-
classes.push(`mc-select--${this.size}`);
|
|
101
|
-
}
|
|
85
|
+
const classObject = computed(() => {
|
|
86
|
+
return {
|
|
87
|
+
[`mc-select--${props.size}`]: props.size && props.size != 'm',
|
|
88
|
+
'mc-select--readonly': props.readonly,
|
|
89
|
+
'is-invalid': props.isInvalid,
|
|
90
|
+
};
|
|
91
|
+
});
|
|
102
92
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
change: function (event) {
|
|
110
|
-
vm.$emit('change', event.target.value);
|
|
111
|
-
},
|
|
112
|
-
});
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
|
|
116
|
-
mounted() {
|
|
117
|
-
this.getOptionValue();
|
|
118
|
-
},
|
|
119
|
-
|
|
120
|
-
methods: {
|
|
121
|
-
getOptionValue() {
|
|
122
|
-
if (!this.value) {
|
|
123
|
-
const firstOption = this.$el.querySelector('option');
|
|
124
|
-
this.optionValue = firstOption.value;
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
onChange(value) {
|
|
128
|
-
const optionText = this.$refs.select
|
|
129
|
-
.querySelector(`option[value="${value}"]`)
|
|
130
|
-
.textContent.trim();
|
|
131
|
-
const optionData = {
|
|
132
|
-
text: optionText,
|
|
133
|
-
value: value,
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
this.$emit('change', value, optionData);
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
};
|
|
93
|
+
const emit = defineEmits<{
|
|
94
|
+
/**
|
|
95
|
+
* Emits when the select value changes, updating the modelValue prop.
|
|
96
|
+
*/
|
|
97
|
+
(on: 'update:modelValue', value: string | number): void;
|
|
98
|
+
}>();
|
|
140
99
|
</script>
|
|
141
100
|
|
|
142
|
-
<style lang="scss">
|
|
143
|
-
@
|
|
144
|
-
@import 'components/_c.select';
|
|
101
|
+
<style lang="scss" scoped>
|
|
102
|
+
@use '@mozaic-ds/styles/components/select';
|
|
145
103
|
</style>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
import MStatusBadge from './MStatusBadge.vue';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof MStatusBadge> = {
|
|
5
|
+
title: 'Status/Status Badge',
|
|
6
|
+
component: MStatusBadge,
|
|
7
|
+
parameters: {
|
|
8
|
+
docs: {
|
|
9
|
+
description: {
|
|
10
|
+
component:
|
|
11
|
+
'A status badge indicates the status of an entity and can evolve at any time.',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
args: { label: 'Badge label' },
|
|
16
|
+
render: (args) => ({
|
|
17
|
+
components: { MStatusBadge },
|
|
18
|
+
setup() {
|
|
19
|
+
return { args };
|
|
20
|
+
},
|
|
21
|
+
template: `
|
|
22
|
+
<MStatusBadge v-bind="args"></MStatusBadge>
|
|
23
|
+
`,
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
export default meta;
|
|
27
|
+
type Story = StoryObj<typeof MStatusBadge>;
|
|
28
|
+
|
|
29
|
+
export const Info: Story = {};
|
|
30
|
+
|
|
31
|
+
export const Success: Story = {
|
|
32
|
+
args: { status: 'success' },
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const Warning: Story = {
|
|
36
|
+
args: { status: 'warning' },
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const Error: Story = {
|
|
40
|
+
args: { status: 'error' },
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const Neutral: Story = {
|
|
44
|
+
args: { status: 'neutral' },
|
|
45
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="mc-status-badge" :class="classObject">
|
|
3
|
+
<MStatusDot :status="status" />
|
|
4
|
+
<span class="mc-status-badge__label">{{ label }}</span>
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script setup lang="ts">
|
|
9
|
+
import { computed } from 'vue';
|
|
10
|
+
import MStatusDot from '../statusdot/MStatusDot.vue';
|
|
11
|
+
/**
|
|
12
|
+
* A status badge indicates the status of an entity and can evolve at any time.
|
|
13
|
+
*/
|
|
14
|
+
const props = withDefaults(
|
|
15
|
+
defineProps<{
|
|
16
|
+
/**
|
|
17
|
+
* Content of the Status Badge
|
|
18
|
+
*/
|
|
19
|
+
label: string;
|
|
20
|
+
/**
|
|
21
|
+
* Allows to define the Status Badge style
|
|
22
|
+
*/
|
|
23
|
+
status?: 'info' | 'success' | 'warning' | 'error' | 'neutral';
|
|
24
|
+
}>(),
|
|
25
|
+
{
|
|
26
|
+
status: 'info',
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const classObject = computed(() => {
|
|
31
|
+
return {
|
|
32
|
+
[`mc-status-badge--${props.status}`]:
|
|
33
|
+
props.status && props.status != 'info',
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<style lang="scss" scoped>
|
|
39
|
+
@use '@mozaic-ds/styles/components/status-badge';
|
|
40
|
+
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { mount } from '@vue/test-utils';
|
|
4
|
+
import MStatusBadge from './MStatusBadge.vue';
|
|
5
|
+
|
|
6
|
+
describe('MStatusBadge component', () => {
|
|
7
|
+
it('renders properly', () => {
|
|
8
|
+
const wrapper = mount(MStatusBadge, {
|
|
9
|
+
props: {
|
|
10
|
+
label: 'Badge Label',
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
expect(wrapper.text()).toContain('Badge Label');
|
|
15
|
+
});
|
|
16
|
+
});
|