@mozaic-ds/vue 1.0.0-rc.3 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +51 -0
- package/README.md +76 -77
- package/dist/mozaic-vue.css +1 -1
- package/dist/mozaic-vue.d.ts +1718 -0
- package/dist/mozaic-vue.js +1971 -0
- package/dist/mozaic-vue.js.map +1 -0
- package/dist/mozaic-vue.umd.cjs +2 -0
- package/dist/mozaic-vue.umd.cjs.map +1 -0
- package/env.d.ts +1 -0
- package/package.json +78 -51
- package/src/components/Contributing.mdx +118 -0
- package/src/components/GettingStarted.mdx +45 -0
- package/src/components/Introduction.mdx +100 -0
- package/src/components/Support.mdx +18 -0
- package/src/components/breadcrumb/MBreadcrumb.spec.ts +105 -0
- package/src/components/breadcrumb/MBreadcrumb.stories.ts +82 -0
- package/src/components/breadcrumb/MBreadcrumb.vue +52 -55
- package/src/components/button/MButton.spec.ts +191 -0
- package/src/components/button/MButton.stories.ts +59 -0
- package/src/components/button/MButton.vue +98 -154
- package/src/components/checkbox/MCheckbox.spec.ts +104 -0
- package/src/components/checkbox/MCheckbox.stories.ts +83 -0
- package/src/components/checkbox/MCheckbox.vue +60 -101
- package/src/components/checkboxgroup/MCheckboxGroup.spec.ts +78 -0
- package/src/components/checkboxgroup/MCheckboxGroup.stories.ts +61 -0
- package/src/components/checkboxgroup/MCheckboxGroup.vue +97 -0
- package/src/components/datepicker/MDatepicker.spec.ts +95 -0
- package/src/components/datepicker/MDatepicker.stories.ts +75 -0
- package/src/components/datepicker/MDatepicker.vue +114 -0
- package/src/components/divider/MDivider.spec.ts +57 -0
- package/src/components/divider/MDivider.stories.ts +64 -0
- package/src/components/divider/MDivider.vue +56 -0
- package/src/components/drawer/MDrawer.spec.ts +100 -0
- package/src/components/drawer/MDrawer.stories.ts +128 -0
- package/src/components/drawer/MDrawer.vue +140 -0
- package/src/components/field/MField.spec.ts +166 -0
- package/src/components/field/MField.stories.ts +369 -0
- package/src/components/field/MField.vue +78 -61
- package/src/components/fieldgroup/MFieldGroup.spec.ts +165 -0
- package/src/components/fieldgroup/MFieldGroup.stories.ts +416 -0
- package/src/components/fieldgroup/MFieldGroup.vue +79 -0
- package/src/components/flag/MFlag.spec.ts +46 -0
- package/src/components/flag/MFlag.stories.ts +46 -0
- package/src/components/flag/MFlag.vue +28 -39
- package/src/components/iconbutton/MIconButton.spec.ts +108 -0
- package/src/components/iconbutton/MIconButton.stories.ts +74 -0
- package/src/components/iconbutton/MIconButton.vue +73 -0
- package/src/components/link/MLink.spec.ts +154 -0
- package/src/components/link/MLink.stories.ts +89 -0
- package/src/components/link/MLink.vue +86 -120
- package/src/components/loader/MLoader.spec.ts +104 -0
- package/src/components/loader/MLoader.stories.ts +43 -0
- package/src/components/loader/MLoader.vue +66 -55
- package/src/components/loadingoverlay/MLoadingOverlay.spec.ts +37 -0
- package/src/components/loadingoverlay/MLoadingOverlay.stories.ts +40 -0
- package/src/components/loadingoverlay/MLoadingOverlay.vue +28 -0
- package/src/components/modal/MModal.spec.ts +103 -0
- package/src/components/modal/MModal.stories.ts +127 -0
- package/src/components/modal/MModal.vue +111 -159
- package/src/components/numberbadge/MNumberBadge.spec.ts +56 -0
- package/src/components/numberbadge/MNumberBadge.stories.ts +48 -0
- package/src/components/numberbadge/MNumberBadge.vue +45 -0
- package/src/components/overlay/MOverlay.spec.ts +51 -0
- package/src/components/overlay/MOverlay.stories.ts +35 -0
- package/src/components/overlay/MOverlay.vue +27 -19
- package/src/components/pagination/MPagination.spec.ts +123 -0
- package/src/components/pagination/MPagination.stories.ts +83 -0
- package/src/components/pagination/MPagination.vue +120 -140
- package/src/components/passwordinput/MPasswordInput.spec.ts +104 -0
- package/src/components/passwordinput/MPasswordInput.stories.ts +75 -0
- package/src/components/passwordinput/MPasswordInput.vue +126 -77
- package/src/components/pincode/MPincode.spec.ts +126 -0
- package/src/components/pincode/MPincode.stories.ts +68 -0
- package/src/components/pincode/MPincode.vue +148 -0
- package/src/components/quantityselector/MQuantitySelector.spec.ts +262 -0
- package/src/components/quantityselector/MQuantitySelector.stories.ts +89 -0
- package/src/components/quantityselector/MQuantitySelector.vue +159 -148
- package/src/components/radio/MRadio.spec.ts +104 -0
- package/src/components/radio/MRadio.stories.ts +68 -0
- package/src/components/radio/MRadio.vue +56 -39
- package/src/components/radiogroup/MRadioGroup.spec.ts +54 -0
- package/src/components/radiogroup/MRadioGroup.stories.ts +61 -0
- package/src/components/radiogroup/MRadioGroup.vue +79 -0
- package/src/components/select/MSelect.spec.ts +114 -0
- package/src/components/select/MSelect.stories.ts +101 -0
- package/src/components/select/MSelect.vue +77 -119
- package/src/components/statusbadge/MStatusBadge.stories.ts +45 -0
- package/src/components/statusbadge/MStatusBadge.vue +40 -0
- package/src/components/statusbadge/MstatusBadge.spec.ts +16 -0
- package/src/components/statusdot/MStatusDot.spec.ts +51 -0
- package/src/components/statusdot/MStatusDot.stories.ts +48 -0
- package/src/components/statusdot/MStatusDot.vue +36 -0
- package/src/components/statusnotification/MStatusNotification.spec.ts +103 -0
- package/src/components/statusnotification/MStatusNotification.stories.ts +89 -0
- package/src/components/statusnotification/MStatusNotification.vue +106 -0
- package/src/components/tabs/MTabs.stories.ts +104 -0
- package/src/components/tabs/MTabs.vue +113 -0
- package/src/components/tabs/Mtabs.spec.ts +149 -0
- package/src/components/tag/MTag.spec.ts +107 -0
- package/src/components/tag/MTag.stories.ts +75 -0
- package/src/components/tag/MTag.vue +151 -0
- package/src/components/textarea/MTextArea.spec.ts +112 -0
- package/src/components/textarea/MTextArea.stories.ts +67 -0
- package/src/components/textarea/MTextArea.vue +81 -43
- package/src/components/textinput/MTextInput.spec.ts +121 -0
- package/src/components/textinput/MTextInput.stories.ts +107 -0
- package/src/components/textinput/MTextInput.vue +127 -47
- package/src/components/toggle/MToggle.spec.ts +99 -0
- package/src/components/toggle/MToggle.stories.ts +68 -0
- package/src/components/toggle/MToggle.vue +63 -103
- package/src/components/togglegroup/MToggleGroup.spec.ts +78 -0
- package/src/components/togglegroup/MToggleGroup.stories.ts +61 -0
- package/src/components/togglegroup/MToggleGroup.vue +97 -0
- package/src/components/tooltip/MTooltip.spec.ts +47 -0
- package/src/components/tooltip/MTooltip.stories.ts +59 -0
- package/src/components/tooltip/MTooltip.vue +49 -32
- package/src/components/usingIcons.mdx +35 -0
- package/src/components/usingPresets.mdx +128 -0
- package/src/main.ts +33 -0
- package/dist/demo.html +0 -1
- package/dist/mozaic-vue.adeo.css +0 -47
- package/dist/mozaic-vue.adeo.umd.js +0 -31341
- package/dist/mozaic-vue.common.js +0 -31331
- package/dist/mozaic-vue.common.js.map +0 -1
- package/dist/mozaic-vue.umd.js +0 -31342
- package/dist/mozaic-vue.umd.js.map +0 -1
- package/dist/mozaic-vue.umd.min.js +0 -4
- package/dist/mozaic-vue.umd.min.js.map +0 -1
- package/postinstall.js +0 -3
- package/src/components/accordion/MAccordion.vue +0 -128
- package/src/components/accordion/index.js +0 -7
- package/src/components/autocomplete/MAutocomplete.vue +0 -380
- package/src/components/autocomplete/index.js +0 -7
- package/src/components/badge/MBadge.vue +0 -43
- package/src/components/badge/index.js +0 -7
- package/src/components/breadcrumb/index.js +0 -7
- package/src/components/button/index.js +0 -7
- package/src/components/card/MCard.vue +0 -78
- package/src/components/card/index.js +0 -7
- package/src/components/checkbox/MCheckboxGroup.vue +0 -163
- package/src/components/checkbox/index.js +0 -12
- package/src/components/container/MContainer.vue +0 -33
- package/src/components/container/index.js +0 -7
- package/src/components/datatable/MDataTable.vue +0 -651
- package/src/components/datatable/MDataTableHeader.vue +0 -55
- package/src/components/datatable/MDataTableTop.vue +0 -35
- package/src/components/datatable/helpers.js +0 -132
- package/src/components/datatable/index.js +0 -12
- package/src/components/dropdown/MDropdown.vue +0 -317
- package/src/components/dropdown/index.js +0 -7
- package/src/components/field/index.js +0 -7
- package/src/components/fileuploader/MFileResult.vue +0 -149
- package/src/components/fileuploader/MFileUploader.vue +0 -142
- package/src/components/fileuploader/index.js +0 -7
- package/src/components/flag/index.js +0 -7
- package/src/components/heading/MHeading.vue +0 -75
- package/src/components/heading/index.js +0 -7
- package/src/components/hero/MHero.vue +0 -93
- package/src/components/hero/index.js +0 -7
- package/src/components/icon/MIcon.vue +0 -136
- package/src/components/icon/index.js +0 -7
- package/src/components/index.js +0 -44
- package/src/components/layer/MLayer.vue +0 -208
- package/src/components/layer/index.js +0 -7
- package/src/components/link/index.js +0 -7
- package/src/components/listbox/MListBox.vue +0 -146
- package/src/components/listbox/MListBoxActions.vue +0 -251
- package/src/components/listbox/index.js +0 -12
- package/src/components/loader/index.js +0 -7
- package/src/components/modal/index.js +0 -7
- package/src/components/notification/MNotification.vue +0 -110
- package/src/components/notification/index.js +0 -7
- package/src/components/optionbutton/MOptionButton.vue +0 -67
- package/src/components/optionbutton/index.js +0 -7
- package/src/components/optioncard/MOptionCard.vue +0 -132
- package/src/components/optioncard/index.js +0 -7
- package/src/components/optiongroup/MOptionGroup.vue +0 -18
- package/src/components/optiongroup/index.js +0 -7
- package/src/components/overlay/MOverlayLoader.vue +0 -43
- package/src/components/overlay/index.js +0 -12
- package/src/components/pagination/index.js +0 -7
- package/src/components/passwordinput/index.js +0 -7
- package/src/components/phonenumber/MPhoneNumber.vue +0 -398
- package/src/components/phonenumber/index.js +0 -7
- package/src/components/progressbar/MProgress.vue +0 -102
- package/src/components/progressbar/index.js +0 -7
- package/src/components/quantityselector/index.js +0 -7
- package/src/components/radio/MRadioGroup.vue +0 -111
- package/src/components/radio/index.js +0 -12
- package/src/components/ratingstars/MStarsInput.vue +0 -119
- package/src/components/ratingstars/MStarsResult.vue +0 -89
- package/src/components/ratingstars/index.js +0 -12
- package/src/components/select/index.js +0 -7
- package/src/components/stepper/MStepper.vue +0 -111
- package/src/components/stepper/index.js +0 -7
- package/src/components/tabs/MTab.vue +0 -204
- package/src/components/tabs/index.js +0 -7
- package/src/components/tags/MTag.vue +0 -175
- package/src/components/tags/index.js +0 -7
- package/src/components/textarea/index.js +0 -7
- package/src/components/textinput/MTextInputField.vue +0 -105
- package/src/components/textinput/MTextInputIcon.vue +0 -42
- package/src/components/textinput/index.js +0 -7
- package/src/components/toggle/index.js +0 -7
- package/src/components/tooltip/index.js +0 -7
- package/src/index.js +0 -63
- package/src/shims-tsx.d.ts +0 -13
- package/src/shims.vue.d.ts +0 -4
- package/src/tokens/adeo/android/colors.xml +0 -452
- package/src/tokens/adeo/android/font_dimens.xml +0 -18
- package/src/tokens/adeo/css/_variables.scss +0 -446
- package/src/tokens/adeo/css/root.scss +0 -448
- package/src/tokens/adeo/ios/StyleDictionaryColor.h +0 -460
- package/src/tokens/adeo/ios/StyleDictionaryColor.m +0 -472
- package/src/tokens/adeo/ios/StyleDictionaryColor.swift +0 -455
- package/src/tokens/adeo/ios/StyleDictionarySize.h +0 -69
- package/src/tokens/adeo/ios/StyleDictionarySize.m +0 -70
- package/src/tokens/adeo/ios/StyleDictionarySize.swift +0 -71
- package/src/tokens/adeo/js/tokens.js +0 -544
- package/src/tokens/adeo/js/tokensObject.js +0 -11733
- package/src/tokens/adeo/scss/_tokens.scss +0 -1522
- package/src/utils/mozaicClasses.js +0 -16
- package/src/utils/theme.validator.js +0 -19
- package/types/index.d.ts +0 -104
|
@@ -1,118 +1,77 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div class="mc-checkbox">
|
|
3
3
|
<input
|
|
4
|
-
v-bind="$attrs"
|
|
5
4
|
:id="id"
|
|
6
|
-
ref="input"
|
|
7
|
-
:name="name"
|
|
8
5
|
type="checkbox"
|
|
9
6
|
class="mc-checkbox__input"
|
|
10
|
-
:class="
|
|
11
|
-
:
|
|
12
|
-
:
|
|
7
|
+
:class="classObject"
|
|
8
|
+
:name="name"
|
|
9
|
+
:checked="modelValue"
|
|
10
|
+
:indeterminate="indeterminate"
|
|
13
11
|
:disabled="disabled"
|
|
14
|
-
|
|
12
|
+
:aria-invalid="isInvalid"
|
|
13
|
+
v-bind="$attrs"
|
|
14
|
+
@change="
|
|
15
|
+
emit('update:modelValue', ($event.target as HTMLInputElement).checked)
|
|
16
|
+
"
|
|
15
17
|
/>
|
|
16
|
-
<label :for="id" class="mc-checkbox__label">
|
|
17
|
-
|
|
18
|
-
{{ label }}
|
|
19
|
-
</slot>
|
|
18
|
+
<label v-if="label" :for="id" class="mc-checkbox__label">
|
|
19
|
+
{{ label }}
|
|
20
20
|
</label>
|
|
21
21
|
</div>
|
|
22
|
-
|
|
23
|
-
<input
|
|
24
|
-
v-else
|
|
25
|
-
v-bind="$attrs"
|
|
26
|
-
:id="id"
|
|
27
|
-
ref="input"
|
|
28
|
-
:name="name"
|
|
29
|
-
type="checkbox"
|
|
30
|
-
class="mc-checkbox__input"
|
|
31
|
-
:class="setInputClasses"
|
|
32
|
-
:checked="checked"
|
|
33
|
-
:required="required"
|
|
34
|
-
:disabled="disabled"
|
|
35
|
-
@change="$emit('change', $event.target.checked)"
|
|
36
|
-
/>
|
|
37
22
|
</template>
|
|
38
23
|
|
|
39
|
-
<script>
|
|
40
|
-
|
|
41
|
-
name: 'MCheckbox',
|
|
42
|
-
|
|
43
|
-
inheritAttrs: false,
|
|
44
|
-
|
|
45
|
-
model: {
|
|
46
|
-
prop: 'checked',
|
|
47
|
-
event: 'change',
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
props: {
|
|
51
|
-
id: {
|
|
52
|
-
type: String,
|
|
53
|
-
required: true,
|
|
54
|
-
},
|
|
55
|
-
name: {
|
|
56
|
-
type: String,
|
|
57
|
-
default: null,
|
|
58
|
-
},
|
|
59
|
-
label: {
|
|
60
|
-
type: String,
|
|
61
|
-
default: null,
|
|
62
|
-
},
|
|
63
|
-
checked: {
|
|
64
|
-
type: Boolean,
|
|
65
|
-
default: false,
|
|
66
|
-
},
|
|
67
|
-
disabled: {
|
|
68
|
-
type: Boolean,
|
|
69
|
-
default: false,
|
|
70
|
-
},
|
|
71
|
-
required: {
|
|
72
|
-
type: Boolean,
|
|
73
|
-
default: false,
|
|
74
|
-
},
|
|
75
|
-
indeterminate: {
|
|
76
|
-
type: Boolean,
|
|
77
|
-
default: false,
|
|
78
|
-
},
|
|
79
|
-
isInvalid: {
|
|
80
|
-
type: Boolean,
|
|
81
|
-
default: false,
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
|
|
85
|
-
computed: {
|
|
86
|
-
hasLabel() {
|
|
87
|
-
return this.label != null || this.$slots.label != null;
|
|
88
|
-
},
|
|
89
|
-
|
|
90
|
-
setInputClasses() {
|
|
91
|
-
return {
|
|
92
|
-
'is-invalid': this.isInvalid,
|
|
93
|
-
};
|
|
94
|
-
},
|
|
95
|
-
},
|
|
24
|
+
<script setup lang="ts">
|
|
25
|
+
import { computed } from 'vue';
|
|
96
26
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Checkboxes are used to select one or multiple options in a list. They usually find their place in forms and are also used to accept some mentions.
|
|
29
|
+
*/
|
|
30
|
+
const props = defineProps<{
|
|
31
|
+
/**
|
|
32
|
+
* A unique identifier for the checkbox, used to associate the label with the form element.
|
|
33
|
+
*/
|
|
34
|
+
id: string;
|
|
35
|
+
/**
|
|
36
|
+
* The name attribute for the checkbox element, typically used for form submission.
|
|
37
|
+
*/
|
|
38
|
+
name?: string;
|
|
39
|
+
/**
|
|
40
|
+
* The text label displayed next to the checkbox.
|
|
41
|
+
*/
|
|
42
|
+
label?: string;
|
|
43
|
+
/**
|
|
44
|
+
* The checkbox's checked state, bound via v-model.
|
|
45
|
+
*/
|
|
46
|
+
modelValue?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Sets the checkbox to an indeterminate state (partially selected).
|
|
49
|
+
*/
|
|
50
|
+
indeterminate?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* If `true`, applies an invalid state to the checkbox.
|
|
53
|
+
*/
|
|
54
|
+
isInvalid?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* If `true`, disables the checkbox, making it non-interactive.
|
|
57
|
+
*/
|
|
58
|
+
disabled?: boolean;
|
|
59
|
+
}>();
|
|
102
60
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
61
|
+
const classObject = computed(() => {
|
|
62
|
+
return {
|
|
63
|
+
'is-invalid': props.isInvalid,
|
|
64
|
+
};
|
|
65
|
+
});
|
|
106
66
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
};
|
|
67
|
+
const emit = defineEmits<{
|
|
68
|
+
/**
|
|
69
|
+
* Emits when the checkbox value changes, updating the modelValue prop.
|
|
70
|
+
*/
|
|
71
|
+
(on: 'update:modelValue', value: boolean): void;
|
|
72
|
+
}>();
|
|
113
73
|
</script>
|
|
114
74
|
|
|
115
|
-
<style lang="scss">
|
|
116
|
-
@
|
|
117
|
-
@import 'components/c.checkbox';
|
|
75
|
+
<style lang="scss" scoped>
|
|
76
|
+
@use '@mozaic-ds/styles/components/checkbox';
|
|
118
77
|
</style>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import MCheckboxGroup from './MCheckboxGroup.vue';
|
|
4
|
+
import MCheckbox from '@/components/checkbox/MCheckbox.vue';
|
|
5
|
+
|
|
6
|
+
describe('MCheckboxGroup.vue', () => {
|
|
7
|
+
it('renders checkboxes 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(MCheckboxGroup, {
|
|
14
|
+
props: {
|
|
15
|
+
name: 'test-name',
|
|
16
|
+
options,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const checkboxes = wrapper.findAllComponents(MCheckbox);
|
|
21
|
+
expect(checkboxes.length).toBe(2);
|
|
22
|
+
|
|
23
|
+
expect(checkboxes[0].props('label')).toBe('Option 1');
|
|
24
|
+
expect(checkboxes[1].props('label')).toBe('Option 2');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('updates modelValue when a checkbox 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(MCheckboxGroup, {
|
|
34
|
+
props: {
|
|
35
|
+
name: 'test-name',
|
|
36
|
+
options,
|
|
37
|
+
modelValue: [],
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const checkbox1 = wrapper.findAllComponents(MCheckbox)[0].find('input');
|
|
42
|
+
await checkbox1.setChecked(true);
|
|
43
|
+
|
|
44
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy();
|
|
45
|
+
expect(wrapper.emitted('update:modelValue')[0]).toEqual([['option1']]);
|
|
46
|
+
|
|
47
|
+
const checkbox2 = wrapper.findAllComponents(MCheckbox)[1].find('input');
|
|
48
|
+
await checkbox2.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(MCheckboxGroup, {
|
|
62
|
+
props: {
|
|
63
|
+
name: 'test-name',
|
|
64
|
+
options,
|
|
65
|
+
modelValue: ['option1'],
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const checkboxes = wrapper.findAllComponents(MCheckbox);
|
|
70
|
+
expect(checkboxes[0].props('modelValue')).toBe(true);
|
|
71
|
+
expect(checkboxes[1].props('modelValue')).toBe(false);
|
|
72
|
+
|
|
73
|
+
await wrapper.setProps({ modelValue: ['option2'] });
|
|
74
|
+
|
|
75
|
+
expect(checkboxes[0].props('modelValue')).toBe(false);
|
|
76
|
+
expect(checkboxes[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 MCheckboxGroup from './MCheckboxGroup.vue';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof MCheckboxGroup> = {
|
|
7
|
+
title: 'Form Elements/Checkbox Group',
|
|
8
|
+
component: MCheckboxGroup,
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
'A field label is a text element that identifies the purpose of an input field, providing users with clear guidance on what information to enter. It is typically placed above the input field and may include indicators for required or optional fields. Field Labels improve form usability, accessibility, and data entry accuracy by ensuring users understand the expected input.<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#checkbox-group).',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
args: {
|
|
18
|
+
name: 'checkboxGroupName',
|
|
19
|
+
modelValue: ['checkbox2'],
|
|
20
|
+
options: [
|
|
21
|
+
{
|
|
22
|
+
id: 'checkbox-01',
|
|
23
|
+
label: 'checkbox Label',
|
|
24
|
+
value: 'checkbox1',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 'checkbox-02',
|
|
28
|
+
label: 'checkbox Label',
|
|
29
|
+
value: 'checkbox2',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 'checkbox-03',
|
|
33
|
+
label: 'checkbox Label',
|
|
34
|
+
value: 'checkbox3',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'checkbox-04',
|
|
38
|
+
label: 'checkbox Label',
|
|
39
|
+
value: 'checkbox4',
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
render: (args) => ({
|
|
44
|
+
components: { MCheckboxGroup },
|
|
45
|
+
setup() {
|
|
46
|
+
const handleUpdate = action('update:modelValue');
|
|
47
|
+
|
|
48
|
+
return { args, handleUpdate };
|
|
49
|
+
},
|
|
50
|
+
template: `
|
|
51
|
+
<MCheckboxGroup
|
|
52
|
+
v-bind="args"
|
|
53
|
+
@update:modelValue="handleUpdate"
|
|
54
|
+
/>
|
|
55
|
+
`,
|
|
56
|
+
}),
|
|
57
|
+
};
|
|
58
|
+
export default meta;
|
|
59
|
+
type Story = StoryObj<typeof MCheckboxGroup>;
|
|
60
|
+
|
|
61
|
+
export const Default: Story = {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="mc-field__container" :class="classObjectContainer">
|
|
3
|
+
<MCheckbox
|
|
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="mc-field__item"
|
|
11
|
+
:class="classObjectItem"
|
|
12
|
+
:model-value="modelValue ? modelValue.includes(option.value) : undefined"
|
|
13
|
+
:disabled="option.disabled"
|
|
14
|
+
@update:model-value="(v: boolean) => onChange(v, option.value)"
|
|
15
|
+
/>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script setup lang="ts">
|
|
20
|
+
import { computed, ref, watch } from 'vue';
|
|
21
|
+
import MCheckbox from '../checkbox/MCheckbox.vue';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Checkboxes are used to select one or multiple options in a list. They usually find their place in forms and are also used to accept some mentions.
|
|
25
|
+
*/
|
|
26
|
+
const props = defineProps<{
|
|
27
|
+
/**
|
|
28
|
+
* The name attribute for the checkbox element, typically used for form submission.
|
|
29
|
+
*/
|
|
30
|
+
name: string;
|
|
31
|
+
/**
|
|
32
|
+
* Property used to manage the values checked by v-model
|
|
33
|
+
* (Do not use directly)
|
|
34
|
+
*/
|
|
35
|
+
modelValue?: Array<string>;
|
|
36
|
+
/**
|
|
37
|
+
* list of properties of each checkbox button of the checkbox group
|
|
38
|
+
*/
|
|
39
|
+
options: Array<{
|
|
40
|
+
id: string;
|
|
41
|
+
label: string;
|
|
42
|
+
value: string;
|
|
43
|
+
disabled?: boolean;
|
|
44
|
+
isInvalid?: boolean;
|
|
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 checkbox 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,95 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { mount } from '@vue/test-utils';
|
|
3
|
+
import MDatepicker from './MDatepicker.vue'; // adjust path accordingly
|
|
4
|
+
|
|
5
|
+
describe('MDatepicker component', () => {
|
|
6
|
+
it('renders correctly with default props', () => {
|
|
7
|
+
const wrapper = mount(MDatepicker, {
|
|
8
|
+
props: {
|
|
9
|
+
id: 'test-id',
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const input = wrapper.get('input');
|
|
14
|
+
expect(input.attributes('id')).toBe('test-id');
|
|
15
|
+
expect(input.element.value).toBe('');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('binds props correctly', () => {
|
|
19
|
+
const wrapper = mount(MDatepicker, {
|
|
20
|
+
props: {
|
|
21
|
+
id: 'date-id',
|
|
22
|
+
name: 'date',
|
|
23
|
+
modelValue: '2025-07-25',
|
|
24
|
+
disabled: true,
|
|
25
|
+
isInvalid: true,
|
|
26
|
+
readonly: true,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const input = wrapper.get('input');
|
|
31
|
+
expect(input.element.value).toBe('2025-07-25');
|
|
32
|
+
expect(input.attributes('disabled')).toBeDefined();
|
|
33
|
+
expect(input.attributes('readonly')).toBeDefined();
|
|
34
|
+
expect(input.attributes('aria-invalid')).toBe('true');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('emits update:modelValue on input change', async () => {
|
|
38
|
+
const wrapper = mount(MDatepicker, {
|
|
39
|
+
props: {
|
|
40
|
+
id: 'date-id',
|
|
41
|
+
modelValue: '',
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const input = wrapper.get('input');
|
|
46
|
+
await input.setValue('2025-01-01');
|
|
47
|
+
|
|
48
|
+
const emitted = wrapper.emitted('update:modelValue');
|
|
49
|
+
expect(emitted).toBeTruthy();
|
|
50
|
+
expect(emitted![0]).toEqual(['2025-01-01']);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('shows clear button when isClearable and modelValue are truthy', () => {
|
|
54
|
+
const wrapper = mount(MDatepicker, {
|
|
55
|
+
props: {
|
|
56
|
+
id: 'date-id',
|
|
57
|
+
modelValue: '2025-01-01',
|
|
58
|
+
isClearable: true,
|
|
59
|
+
clearLabel: 'Clear it',
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
expect(wrapper.find('.mc-controls-options__button').exists()).toBe(true);
|
|
64
|
+
expect(wrapper.text()).toContain('Clear it');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('clears value when clear button is clicked', async () => {
|
|
68
|
+
const wrapper = mount(MDatepicker, {
|
|
69
|
+
props: {
|
|
70
|
+
id: 'date-id',
|
|
71
|
+
modelValue: '2025-01-01',
|
|
72
|
+
isClearable: true,
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const button = wrapper.get('.mc-controls-options__button');
|
|
77
|
+
await button.trigger('click');
|
|
78
|
+
|
|
79
|
+
const emitted = wrapper.emitted('update:modelValue');
|
|
80
|
+
expect(emitted).toBeTruthy();
|
|
81
|
+
expect(emitted!.slice(-1)[0]).toEqual(['']);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('does not show clear button if modelValue is empty', () => {
|
|
85
|
+
const wrapper = mount(MDatepicker, {
|
|
86
|
+
props: {
|
|
87
|
+
id: 'date-id',
|
|
88
|
+
modelValue: '',
|
|
89
|
+
isClearable: true,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
expect(wrapper.find('.mc-controls-options__button').exists()).toBe(false);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
import { action } from 'storybook/actions';
|
|
3
|
+
|
|
4
|
+
import MDatepicker from './MDatepicker.vue';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof MDatepicker> = {
|
|
7
|
+
title: 'Form Elements/Datepicker',
|
|
8
|
+
component: MDatepicker,
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
'A date picker is an input component that allows users to select a date from a calendar interface or manually enter a date value. It enhances usability by providing structured date selection, reducing input errors, and ensuring format consistency. Date Pickers are commonly used in forms, booking systems, scheduling tools, and data filtering interfaces to facilitate accurate date entry.',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
args: {
|
|
18
|
+
id: 'datepickerId',
|
|
19
|
+
ariaLabel: 'enter the date',
|
|
20
|
+
},
|
|
21
|
+
render: (args) => ({
|
|
22
|
+
components: { MDatepicker },
|
|
23
|
+
setup() {
|
|
24
|
+
const handleUpdate = action('update:modelValue');
|
|
25
|
+
|
|
26
|
+
return { args, handleUpdate };
|
|
27
|
+
},
|
|
28
|
+
template: `
|
|
29
|
+
<MDatepicker
|
|
30
|
+
v-bind="args"
|
|
31
|
+
@update:modelValue="handleUpdate"
|
|
32
|
+
></MDatepicker>
|
|
33
|
+
`,
|
|
34
|
+
}),
|
|
35
|
+
};
|
|
36
|
+
export default meta;
|
|
37
|
+
type Story = StoryObj<typeof MDatepicker>;
|
|
38
|
+
|
|
39
|
+
export const WithValue: Story = {
|
|
40
|
+
args: {
|
|
41
|
+
id: 'withValueId',
|
|
42
|
+
modelValue: '2025-07-22',
|
|
43
|
+
isClearable: true,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const Default: Story = {};
|
|
48
|
+
|
|
49
|
+
export const Small: Story = {
|
|
50
|
+
args: {
|
|
51
|
+
id: 'smallId',
|
|
52
|
+
size: 's',
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const Disabled: Story = {
|
|
57
|
+
args: {
|
|
58
|
+
id: 'disableId',
|
|
59
|
+
disabled: true,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const ReadOnly: Story = {
|
|
64
|
+
args: {
|
|
65
|
+
id: 'readonlyId',
|
|
66
|
+
readonly: true,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const Invalid: Story = {
|
|
71
|
+
args: {
|
|
72
|
+
id: 'invalidId',
|
|
73
|
+
isInvalid: true,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="mc-datepicker mc-text-input" :class="classObject">
|
|
3
|
+
<input
|
|
4
|
+
:id="id"
|
|
5
|
+
class="mc-datepicker__control mc-text-input__control"
|
|
6
|
+
:value="modelValue"
|
|
7
|
+
type="date"
|
|
8
|
+
:name="name"
|
|
9
|
+
:disabled="disabled"
|
|
10
|
+
:aria-invalid="isInvalid"
|
|
11
|
+
:readonly="readonly"
|
|
12
|
+
v-bind="$attrs"
|
|
13
|
+
@input="
|
|
14
|
+
emit('update:modelValue', ($event.target as HTMLInputElement).value)
|
|
15
|
+
"
|
|
16
|
+
/>
|
|
17
|
+
|
|
18
|
+
<div
|
|
19
|
+
v-if="isClearable && modelValue"
|
|
20
|
+
class="mc-datepicker__controls-options mc-controls-options"
|
|
21
|
+
>
|
|
22
|
+
<button
|
|
23
|
+
type="button"
|
|
24
|
+
class="mc-controls-options__button"
|
|
25
|
+
@click="clearValue"
|
|
26
|
+
>
|
|
27
|
+
<CrossCircleFilled24
|
|
28
|
+
class="mc-controls-options__icon"
|
|
29
|
+
aria-hidden="true"
|
|
30
|
+
/>
|
|
31
|
+
<span class="mc-controls-options__label">{{ clearLabel }}</span>
|
|
32
|
+
</button>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<script setup lang="ts">
|
|
38
|
+
import { computed, ref } from 'vue';
|
|
39
|
+
import CrossCircleFilled24 from '@mozaic-ds/icons-vue/src/components/CrossCircleFilled24/CrossCircleFilled24.vue';
|
|
40
|
+
/**
|
|
41
|
+
* A date picker is an input component that allows users to select a date from a calendar interface or manually enter a date value. It enhances usability by providing structured date selection, reducing input errors, and ensuring format consistency. Date Pickers are commonly used in forms, booking systems, scheduling tools, and data filtering interfaces to facilitate accurate date entry.
|
|
42
|
+
*/
|
|
43
|
+
const props = withDefaults(
|
|
44
|
+
defineProps<{
|
|
45
|
+
/**
|
|
46
|
+
* A unique identifier for the datepicker element, used to associate the label with the form element.
|
|
47
|
+
*/
|
|
48
|
+
id: string;
|
|
49
|
+
/**
|
|
50
|
+
* The name attribute for the datepicker element, typically used for form submission.
|
|
51
|
+
*/
|
|
52
|
+
name?: string;
|
|
53
|
+
/**
|
|
54
|
+
* The current value of the datepicker field.
|
|
55
|
+
*/
|
|
56
|
+
modelValue?: string | number;
|
|
57
|
+
/**
|
|
58
|
+
* If `true`, applies an invalid state to the datepicker.
|
|
59
|
+
*/
|
|
60
|
+
isInvalid?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* If `true`, disables the datepicker, making it non-interactive.
|
|
63
|
+
*/
|
|
64
|
+
disabled?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Determines the size of the datepicker
|
|
67
|
+
*/
|
|
68
|
+
size?: 's' | 'm';
|
|
69
|
+
/**
|
|
70
|
+
* If `true`, the datepicker is read-only (cannot be edited).
|
|
71
|
+
*/
|
|
72
|
+
readonly?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* If `true`, a clear button will appear when the datepicker has a value.
|
|
75
|
+
*/
|
|
76
|
+
isClearable?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* The label text for the clear button
|
|
79
|
+
*/
|
|
80
|
+
clearLabel?: string;
|
|
81
|
+
}>(),
|
|
82
|
+
{
|
|
83
|
+
size: 'm',
|
|
84
|
+
clearLabel: 'clear content',
|
|
85
|
+
},
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const classObject = computed(() => {
|
|
89
|
+
return {
|
|
90
|
+
[`mc-text-input--${props.size} mc-datepicker--${props.size}`]:
|
|
91
|
+
props.size && props.size != 'm',
|
|
92
|
+
'is-invalid': props.isInvalid,
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const modelValue = ref(props.modelValue);
|
|
97
|
+
const clearValue = () => {
|
|
98
|
+
modelValue.value = '';
|
|
99
|
+
emit('update:modelValue', '');
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const emit = defineEmits<{
|
|
103
|
+
/**
|
|
104
|
+
* Emits when the datepicker value changes, updating the `modelValue` prop.
|
|
105
|
+
*/
|
|
106
|
+
(on: 'update:modelValue', value: string | number): void;
|
|
107
|
+
}>();
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
<style lang="scss" scoped>
|
|
111
|
+
@use '@mozaic-ds/styles/components/text-input';
|
|
112
|
+
@use '@mozaic-ds/styles/components/datepicker';
|
|
113
|
+
@use '@mozaic-ds/styles/components/controls-options';
|
|
114
|
+
</style>
|