@mozaic-ds/vue 2.18.0 → 2.19.1
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/dist/mozaic-vue.css +1 -1
- package/dist/mozaic-vue.d.ts +961 -2085
- package/dist/mozaic-vue.js +1253 -1143
- package/dist/mozaic-vue.js.map +1 -1
- package/dist/mozaic-vue.umd.cjs +6 -6
- package/dist/mozaic-vue.umd.cjs.map +1 -1
- package/package.json +8 -6
- package/src/components/BrandPresets.mdx +20 -2
- package/src/components/accordionlist/MAccordionList.figma.ts +16 -16
- package/src/components/accordionlist/MAccordionList.stories.ts +1 -1
- package/src/components/accordionlistitem/MAccordionListItem.figma.ts +9 -5
- package/src/components/accordionlistitem/MAccordionListItem.vue +4 -1
- package/src/components/accordionlistitem/README.md +2 -0
- package/src/components/actionbottombar/MActionBottomBar.figma.ts +7 -7
- package/src/components/actionlistbox/MActionListbox.figma.ts +11 -11
- package/src/components/actionlistbox/MActionListbox.spec.ts +113 -0
- package/src/components/actionlistbox/MActionListbox.vue +63 -5
- package/src/components/avatar/MAvatar.figma.ts +5 -5
- package/src/components/breadcrumb/MBreadcrumb.figma.ts +7 -7
- package/src/components/breadcrumb/MBreadcrumb.vue +1 -1
- package/src/components/builtinmenu/MBuiltInMenu.figma.ts +8 -5
- package/src/components/builtinmenu/MBuiltInMenu.spec.ts +3 -1
- package/src/components/button/MButton.figma.ts +21 -6
- package/src/components/button/MButton.spec.ts +26 -0
- package/src/components/button/MButton.vue +2 -0
- package/src/components/callout/MCallout.figma.ts +7 -7
- package/src/components/callout/MCallout.stories.ts +0 -3
- package/src/components/callout/MCallout.vue +4 -3
- package/src/components/callout/README.md +2 -2
- package/src/components/carousel/MCarousel.figma.ts +10 -10
- package/src/components/carousel/MCarousel.spec.ts +26 -2
- package/src/components/carousel/MCarousel.vue +10 -4
- package/src/components/checkbox/MCheckbox.figma.ts +10 -10
- package/src/components/checkboxgroup/MCheckboxGroup.figma.ts +7 -7
- package/src/components/checklistmenu/MCheckListMenu.figma.ts +8 -8
- package/src/components/circularprogressbar/MCircularProgressbar.figma.ts +7 -3
- package/src/components/combobox/MCombobox.figma.ts +10 -10
- package/src/components/combobox/MCombobox.vue +7 -0
- package/src/components/container/MContainer.figma.ts +5 -5
- package/src/components/datatable/DataTable.stories.ts +33 -7
- package/src/components/datatable/DataTableCells.stories.ts +2 -2
- package/src/components/datatable/DataTableEmpty.stories.ts +2 -2
- package/src/components/datatable/DataTableExpandable.stories.ts +2 -2
- package/src/components/datatable/DataTableNested.stories.ts +1 -1
- package/src/components/datatable/DataTableSelectable.stories.ts +2 -3
- package/src/components/datatable/DataTableSortable.stories.ts +1 -1
- package/src/components/datepicker/MDatepicker.figma.ts +3 -3
- package/src/components/divider/MDivider.figma.ts +3 -3
- package/src/components/drawer/MDrawer.figma.ts +13 -13
- package/src/components/drawer/MDrawer.spec.ts +102 -3
- package/src/components/drawer/MDrawer.vue +73 -14
- package/src/components/field/MField.figma.ts +9 -5
- package/src/components/field/MField.vue +1 -0
- package/src/components/fileuploader/MFileUploader.figma.ts +3 -3
- package/src/components/fileuploader/MFileUploader.vue +2 -2
- package/src/components/fileuploaderitem/MFileUploaderItem.figma.ts +7 -3
- package/src/components/fileuploaderitem/MFileUploaderItem.vue +2 -7
- package/src/components/flag/MFlag.figma.ts +3 -3
- package/src/components/iconbutton/MIconButton.figma.ts +16 -16
- package/src/components/iconbutton/MIconButton.spec.ts +15 -0
- package/src/components/iconbutton/MIconButton.vue +1 -0
- package/src/components/kpiitem/MKpiItem.figma.ts +8 -3
- package/src/components/kpiitem/MKpiItem.spec.ts +12 -0
- package/src/components/kpiitem/MKpiItem.vue +7 -1
- package/src/components/linearprogressbarbuffer/MLinearProgressbarBuffer.figma.ts +6 -3
- package/src/components/linearprogressbarpercentage/MLinearProgressbarPercentage.figma.ts +5 -3
- package/src/components/link/MLink.figma.ts +5 -5
- package/src/components/loader/MLoader.figma.ts +3 -3
- package/src/components/loadingoverlay/MLoadingOverlay.figma.ts +3 -3
- package/src/components/modal/MModal.figma.ts +12 -12
- package/src/components/modal/MModal.spec.ts +115 -3
- package/src/components/modal/MModal.vue +91 -11
- package/src/components/modal/README.md +1 -1
- package/src/components/navigationindicator/MNavigationIndicator.figma.ts +7 -3
- package/src/components/numberbadge/MNumberBadge.figma.ts +7 -3
- package/src/components/optionListbox/MOptionListbox.figma.ts +10 -10
- package/src/components/overlay/MOverlay.figma.ts +5 -5
- package/src/components/overlay/MOverlay.spec.ts +1 -1
- package/src/components/overlay/MOverlay.vue +1 -1
- package/src/components/pageheader/MPageHeader.figma.ts +3 -3
- package/src/components/pagination/MPagination.figma.ts +10 -10
- package/src/components/passwordinput/MPasswordInput.figma.ts +9 -9
- package/src/components/phonenumber/MPhoneNumber.figma.ts +9 -9
- package/src/components/phonenumber/MPhoneNumber.spec.ts +6 -2
- package/src/components/phonenumber/MPhoneNumber.vue +21 -15
- package/src/components/pincode/MPincode.figma.ts +9 -9
- package/src/components/popover/MPopover.figma.ts +15 -15
- package/src/components/quantityselector/MQuantitySelector.figma.ts +12 -12
- package/src/components/radio/MRadio.figma.ts +9 -9
- package/src/components/radiogroup/MRadioGroup.figma.ts +7 -7
- package/src/components/segmentedcontrol/MSegmentedControl.figma.ts +8 -8
- package/src/components/select/MSelect.figma.ts +11 -11
- package/src/components/sidebar/MSidebar.figma.ts +8 -8
- package/src/components/sidebar/MSidebar.vue +1 -0
- package/src/components/sidebarexpandableitem/MSidebarExpandableItem.figma.ts +8 -5
- package/src/components/sidebarexpandableitem/MSidebarExpandableItem.spec.ts +12 -0
- package/src/components/sidebarexpandableitem/MSidebarExpandableItem.vue +1 -0
- package/src/components/sidebarfooter/MSidebarFooter.figma.ts +7 -3
- package/src/components/sidebarheader/MSidebarHeader.figma.ts +3 -3
- package/src/components/sidebarnavitem/MSidebarNavItem.figma.ts +3 -3
- package/src/components/sidebarshortcutitem/MSidebarShortcutItem.figma.ts +3 -3
- package/src/components/starrating/MStarRating.figma.ts +7 -7
- package/src/components/statusbadge/MStatusBadge.figma.ts +3 -3
- package/src/components/statusdot/MStatusDot.figma.ts +3 -3
- package/src/components/statusmessage/MStatusMessage.figma.ts +3 -3
- package/src/components/statusnotification/MStatusNotification.figma.ts +7 -7
- package/src/components/stepperbottombar/MStepperBottomBar.figma.ts +3 -3
- package/src/components/steppercompact/MStepperCompact.figma.ts +8 -3
- package/src/components/steppercompact/MStepperCompact.spec.ts +9 -0
- package/src/components/steppercompact/MStepperCompact.vue +1 -1
- package/src/components/stepperinline/MStepperInline.figma.ts +6 -3
- package/src/components/stepperinline/MStepperInline.spec.ts +11 -0
- package/src/components/stepperinline/MStepperInline.stories.ts +5 -1
- package/src/components/stepperinline/MStepperInline.vue +1 -1
- package/src/components/stepperstacked/MStepperStacked.figma.ts +6 -3
- package/src/components/stepperstacked/MStepperStacked.spec.ts +13 -0
- package/src/components/stepperstacked/MStepperStacked.vue +1 -0
- package/src/components/tabs/MTabs.figma.ts +8 -8
- package/src/components/tag/MTag.figma.ts +3 -3
- package/src/components/textarea/MTextArea.figma.ts +8 -8
- package/src/components/textinput/MTextInput.figma.ts +12 -12
- package/src/components/textinput/MTextInput.vue +2 -2
- package/src/components/textinput/README.md +1 -1
- package/src/components/tile/MTile.figma.ts +5 -5
- package/src/components/tileclickable/MTileClickable.figma.ts +6 -6
- package/src/components/tileexpandable/MTileExpandable.figma.ts +6 -6
- package/src/components/tileselectable/MTileSelectable.figma.ts +9 -5
- package/src/components/toaster/MToaster.figma.ts +3 -3
- package/src/components/toggle/MToggle.figma.ts +9 -9
- package/src/components/toggle/MToggle.vue +1 -1
- package/src/components/togglegroup/MToggleGroup.figma.ts +7 -7
- package/src/components/tooltip/MTooltip.figma.ts +10 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
2
|
import { mount } from '@vue/test-utils';
|
|
3
3
|
import MDrawer from '@/components/drawer/MDrawer.vue';
|
|
4
4
|
|
|
@@ -11,7 +11,7 @@ const stubs = {
|
|
|
11
11
|
},
|
|
12
12
|
MOverlay: {
|
|
13
13
|
name: 'MOverlay',
|
|
14
|
-
template: `<div class="overlay" @click="$emit('click')"><slot/></div>`,
|
|
14
|
+
template: `<div class="overlay" @click="$emit('click', $event)"><slot/></div>`,
|
|
15
15
|
},
|
|
16
16
|
};
|
|
17
17
|
|
|
@@ -211,11 +211,39 @@ describe('MDrawer component', () => {
|
|
|
211
211
|
global: { stubs },
|
|
212
212
|
});
|
|
213
213
|
|
|
214
|
-
await wrapper
|
|
214
|
+
await wrapper
|
|
215
|
+
.find('section.mc-drawer')
|
|
216
|
+
.trigger('keydown', { key: 'Escape' });
|
|
215
217
|
expect(wrapper.emitted('update:open')).toBeTruthy();
|
|
216
218
|
expect(wrapper.emitted('update:open')!.at(-1)).toEqual([false]);
|
|
217
219
|
});
|
|
218
220
|
|
|
221
|
+
it('stops Escape propagation after closing', async () => {
|
|
222
|
+
const onDocumentKeydown = vi.fn();
|
|
223
|
+
document.addEventListener('keydown', onDocumentKeydown);
|
|
224
|
+
|
|
225
|
+
const wrapper = mount(MDrawer, {
|
|
226
|
+
props: {
|
|
227
|
+
open: true,
|
|
228
|
+
title: 'Test Title',
|
|
229
|
+
},
|
|
230
|
+
attachTo: document.body,
|
|
231
|
+
global: { stubs },
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
wrapper
|
|
235
|
+
.find('section.mc-drawer')
|
|
236
|
+
.element.dispatchEvent(
|
|
237
|
+
new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }),
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
expect(wrapper.emitted('update:open')!.at(-1)).toEqual([false]);
|
|
241
|
+
expect(onDocumentKeydown).not.toHaveBeenCalled();
|
|
242
|
+
|
|
243
|
+
document.removeEventListener('keydown', onDocumentKeydown);
|
|
244
|
+
wrapper.unmount();
|
|
245
|
+
});
|
|
246
|
+
|
|
219
247
|
it('locks and unlocks scroll when scroll=false and open changes', async () => {
|
|
220
248
|
const wrapper = mount(MDrawer, {
|
|
221
249
|
props: {
|
|
@@ -252,6 +280,77 @@ describe('MDrawer component', () => {
|
|
|
252
280
|
expect(document.body.style.overflow).toBe('');
|
|
253
281
|
});
|
|
254
282
|
|
|
283
|
+
it('sets inert on section when closed', async () => {
|
|
284
|
+
const wrapper = mount(MDrawer, {
|
|
285
|
+
props: { open: false, title: 'Test' },
|
|
286
|
+
global: { stubs },
|
|
287
|
+
});
|
|
288
|
+
// JSDOM renders :inert="true" as "true" — not.toBeUndefined() is the correct check
|
|
289
|
+
expect(
|
|
290
|
+
wrapper.find('section.mc-drawer').attributes('inert'),
|
|
291
|
+
).not.toBeUndefined();
|
|
292
|
+
|
|
293
|
+
await wrapper.setProps({ open: true });
|
|
294
|
+
expect(
|
|
295
|
+
wrapper.find('section.mc-drawer').attributes('inert'),
|
|
296
|
+
).toBeUndefined();
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('does not render aria-modal when closed', async () => {
|
|
300
|
+
const wrapper = mount(MDrawer, {
|
|
301
|
+
props: { open: false, title: 'Test' },
|
|
302
|
+
global: { stubs },
|
|
303
|
+
});
|
|
304
|
+
expect(
|
|
305
|
+
wrapper.find('section.mc-drawer').attributes('aria-modal'),
|
|
306
|
+
).toBeUndefined();
|
|
307
|
+
|
|
308
|
+
await wrapper.setProps({ open: true });
|
|
309
|
+
expect(wrapper.find('section.mc-drawer').attributes('aria-modal')).toBe(
|
|
310
|
+
'true',
|
|
311
|
+
);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it('traps focus forward: Tab from last focusable wraps to first', async () => {
|
|
315
|
+
const wrapper = mount(MDrawer, {
|
|
316
|
+
props: { open: true, title: 'Test', back: true },
|
|
317
|
+
attachTo: document.body,
|
|
318
|
+
global: { stubs },
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
const buttons = wrapper.findAll('button');
|
|
322
|
+
const lastEl = buttons[buttons.length - 1].element as HTMLElement;
|
|
323
|
+
lastEl.focus();
|
|
324
|
+
|
|
325
|
+
await wrapper
|
|
326
|
+
.find('section.mc-drawer')
|
|
327
|
+
.trigger('keydown', { key: 'Tab', shiftKey: false });
|
|
328
|
+
|
|
329
|
+
// focus should wrap to the first focusable button (back button)
|
|
330
|
+
expect(document.activeElement).toBe(buttons[0].element);
|
|
331
|
+
wrapper.unmount();
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it('traps focus backward: Shift+Tab from first focusable wraps to last', async () => {
|
|
335
|
+
const wrapper = mount(MDrawer, {
|
|
336
|
+
props: { open: true, title: 'Test', back: true },
|
|
337
|
+
attachTo: document.body,
|
|
338
|
+
global: { stubs },
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
const buttons = wrapper.findAll('button');
|
|
342
|
+
const firstEl = buttons[0].element as HTMLElement;
|
|
343
|
+
firstEl.focus();
|
|
344
|
+
|
|
345
|
+
await wrapper
|
|
346
|
+
.find('section.mc-drawer')
|
|
347
|
+
.trigger('keydown', { key: 'Tab', shiftKey: true });
|
|
348
|
+
|
|
349
|
+
// focus should wrap to the last focusable button (close button)
|
|
350
|
+
expect(document.activeElement).toBe(buttons[buttons.length - 1].element);
|
|
351
|
+
wrapper.unmount();
|
|
352
|
+
});
|
|
353
|
+
|
|
255
354
|
it('emits update:open on mount reflecting initial state', () => {
|
|
256
355
|
const wrapper = mount(MDrawer, {
|
|
257
356
|
props: {
|
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<MOverlay
|
|
3
3
|
:is-visible="open"
|
|
4
|
-
dialogLabel="drawerTitle"
|
|
4
|
+
:dialogLabel="`drawerTitle-${id}`"
|
|
5
5
|
@click="onClickOverlay"
|
|
6
6
|
>
|
|
7
7
|
<section
|
|
8
|
+
ref="sectionRef"
|
|
8
9
|
class="mc-drawer"
|
|
9
10
|
:class="classObject"
|
|
10
11
|
role="dialog"
|
|
11
|
-
aria-labelledby="drawerTitle"
|
|
12
|
-
:aria-modal="open ? 'true' : 'false'"
|
|
12
|
+
:aria-labelledby="`drawerTitle-${id}`"
|
|
13
13
|
tabindex="-1"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
v-bind="{
|
|
15
|
+
...$attrs,
|
|
16
|
+
...(open
|
|
17
|
+
? {
|
|
18
|
+
onKeydown: handleKeydown,
|
|
19
|
+
'aria-modal': 'true',
|
|
20
|
+
}
|
|
21
|
+
: {
|
|
22
|
+
inert: 'true',
|
|
23
|
+
}),
|
|
24
|
+
}"
|
|
18
25
|
>
|
|
19
26
|
<div class="mc-drawer__dialog" role="document">
|
|
20
27
|
<div class="mc-drawer__header">
|
|
@@ -26,13 +33,13 @@
|
|
|
26
33
|
@click="emit('back')"
|
|
27
34
|
>
|
|
28
35
|
<template #icon>
|
|
29
|
-
<ArrowBack24
|
|
36
|
+
<ArrowBack24 />
|
|
30
37
|
</template>
|
|
31
38
|
</MIconButton>
|
|
32
39
|
<h2
|
|
33
40
|
class="mc-drawer__title"
|
|
34
41
|
tabindex="-1"
|
|
35
|
-
id="drawerTitle"
|
|
42
|
+
:id="`drawerTitle-${id}`"
|
|
36
43
|
ref="titleRef"
|
|
37
44
|
>
|
|
38
45
|
{{ title }}
|
|
@@ -44,12 +51,12 @@
|
|
|
44
51
|
@click="onClose"
|
|
45
52
|
>
|
|
46
53
|
<template #icon>
|
|
47
|
-
<Cross24
|
|
54
|
+
<Cross24 />
|
|
48
55
|
</template>
|
|
49
56
|
</MIconButton>
|
|
50
57
|
</div>
|
|
51
58
|
<div class="mc-drawer__body">
|
|
52
|
-
<div class="mc-drawer__content"
|
|
59
|
+
<div class="mc-drawer__content">
|
|
53
60
|
<h2 v-if="contentTitle" class="mc-drawer__content__title">
|
|
54
61
|
{{ contentTitle }}
|
|
55
62
|
</h2>
|
|
@@ -65,7 +72,15 @@
|
|
|
65
72
|
</template>
|
|
66
73
|
|
|
67
74
|
<script setup lang="ts">
|
|
68
|
-
import {
|
|
75
|
+
import {
|
|
76
|
+
computed,
|
|
77
|
+
watch,
|
|
78
|
+
type VNode,
|
|
79
|
+
ref,
|
|
80
|
+
onMounted,
|
|
81
|
+
onUnmounted,
|
|
82
|
+
useId,
|
|
83
|
+
} from 'vue';
|
|
69
84
|
import { ArrowBack24, Cross24 } from '@mozaic-ds/icons-vue';
|
|
70
85
|
import MIconButton from '../iconbutton/MIconButton.vue';
|
|
71
86
|
import MOverlay from '../overlay/MOverlay.vue';
|
|
@@ -123,6 +138,8 @@ defineSlots<{
|
|
|
123
138
|
footer?: VNode;
|
|
124
139
|
}>();
|
|
125
140
|
|
|
141
|
+
const id = useId();
|
|
142
|
+
|
|
126
143
|
const classObject = computed(() => {
|
|
127
144
|
return {
|
|
128
145
|
'is-open': props.open,
|
|
@@ -133,6 +150,45 @@ const classObject = computed(() => {
|
|
|
133
150
|
});
|
|
134
151
|
|
|
135
152
|
const titleRef = ref<HTMLElement | null>(null);
|
|
153
|
+
const sectionRef = ref<HTMLElement | null>(null);
|
|
154
|
+
|
|
155
|
+
function getFocusableElements(): HTMLElement[] {
|
|
156
|
+
if (!sectionRef.value) return [];
|
|
157
|
+
return Array.from(
|
|
158
|
+
sectionRef.value.querySelectorAll<HTMLElement>(
|
|
159
|
+
'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])',
|
|
160
|
+
),
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function handleKeydown(e: KeyboardEvent) {
|
|
165
|
+
if (e.key === 'Escape') {
|
|
166
|
+
e.preventDefault();
|
|
167
|
+
e.stopPropagation();
|
|
168
|
+
onClose();
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (e.key === 'Tab') {
|
|
172
|
+
const focusable = getFocusableElements();
|
|
173
|
+
if (!focusable.length) {
|
|
174
|
+
e.preventDefault();
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const first = focusable[0];
|
|
178
|
+
const last = focusable[focusable.length - 1];
|
|
179
|
+
if (e.shiftKey) {
|
|
180
|
+
if (document.activeElement === first) {
|
|
181
|
+
e.preventDefault();
|
|
182
|
+
last.focus();
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
if (document.activeElement === last) {
|
|
186
|
+
e.preventDefault();
|
|
187
|
+
first.focus();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
136
192
|
const isClient =
|
|
137
193
|
typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
138
194
|
|
|
@@ -169,8 +225,11 @@ onUnmounted(() => {
|
|
|
169
225
|
unlockScroll();
|
|
170
226
|
});
|
|
171
227
|
|
|
172
|
-
const onClickOverlay = () => {
|
|
173
|
-
if (
|
|
228
|
+
const onClickOverlay = (event: MouseEvent) => {
|
|
229
|
+
if (
|
|
230
|
+
props.closeOnOverlay &&
|
|
231
|
+
!sectionRef.value?.contains(event.target as Node)
|
|
232
|
+
) {
|
|
174
233
|
onClose();
|
|
175
234
|
}
|
|
176
235
|
};
|
|
@@ -20,11 +20,15 @@ figma.connect(
|
|
|
20
20
|
},
|
|
21
21
|
example: ({ label, requirementText }) =>
|
|
22
22
|
html`<script setup>
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
import { MField, MTextInput } from '@mozaic-ds/vue';
|
|
24
|
+
</script>
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
<MField
|
|
27
|
+
id="field-id"
|
|
28
|
+
label=${label}
|
|
29
|
+
requirement-text=${requirementText}
|
|
30
|
+
>
|
|
31
|
+
<MTextInput id="field-id" placeholder="Placeholder"></MTextInput>
|
|
32
|
+
</MField>`,
|
|
29
33
|
},
|
|
30
34
|
);
|
|
@@ -15,9 +15,9 @@ figma.connect(
|
|
|
15
15
|
},
|
|
16
16
|
example: ({ hasDragDrop }) =>
|
|
17
17
|
html`<script setup>
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
import { MFileUploader } from '@mozaic-ds/vue';
|
|
19
|
+
</script>
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
<MFileUploader :model-value="[]" :has-drag-drop=${hasDragDrop} />`,
|
|
22
22
|
},
|
|
23
23
|
);
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
<input
|
|
10
10
|
ref="fileInput"
|
|
11
11
|
type="file"
|
|
12
|
-
aria-
|
|
12
|
+
aria-hidden="true"
|
|
13
|
+
tabindex="-1"
|
|
13
14
|
:accept="props.accept"
|
|
14
15
|
:multiple="props.multiple"
|
|
15
16
|
class="mc-file-uploader__hidden-input"
|
|
16
17
|
:disabled="props.disabled"
|
|
17
|
-
:aria-disabled="props.disabled"
|
|
18
18
|
@change="onChange"
|
|
19
19
|
/>
|
|
20
20
|
|
|
@@ -19,9 +19,13 @@ figma.connect(
|
|
|
19
19
|
},
|
|
20
20
|
example: ({ format, valid }) =>
|
|
21
21
|
html`<script setup>
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
import { MFileUploaderItem } from '@mozaic-ds/vue';
|
|
23
|
+
</script>
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
<MFileUploaderItem
|
|
26
|
+
:file="{ name: 'document.pdf' }"
|
|
27
|
+
format=${format}
|
|
28
|
+
:valid=${valid}
|
|
29
|
+
/>`,
|
|
26
30
|
},
|
|
27
31
|
);
|
|
@@ -40,13 +40,7 @@
|
|
|
40
40
|
<template v-if="isStacked">
|
|
41
41
|
<MDivider />
|
|
42
42
|
<div class="mc-file-uploader-item__actions-container">
|
|
43
|
-
<MButton
|
|
44
|
-
ghost
|
|
45
|
-
size="s"
|
|
46
|
-
icon-position="left"
|
|
47
|
-
aria-label="Delete file"
|
|
48
|
-
@click="emit('delete')"
|
|
49
|
-
>
|
|
43
|
+
<MButton ghost size="s" icon-position="left" @click="emit('delete')">
|
|
50
44
|
{{ props.deleteButtonLabel }}
|
|
51
45
|
|
|
52
46
|
<template #icon>
|
|
@@ -78,6 +72,7 @@
|
|
|
78
72
|
<span
|
|
79
73
|
v-if="!valid && (props.errorMessage || slots.errorMessage)"
|
|
80
74
|
class="mc-file-uploader-item__error-message"
|
|
75
|
+
role="alert"
|
|
81
76
|
>
|
|
82
77
|
<slot name="errorMessage">
|
|
83
78
|
{{ props.errorMessage }}
|
|
@@ -18,9 +18,9 @@ figma.connect(
|
|
|
18
18
|
},
|
|
19
19
|
example: ({ label, appearance }) =>
|
|
20
20
|
html`<script setup>
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
import { MFlag } from '@mozaic-ds/vue';
|
|
22
|
+
</script>
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
<MFlag label=${label} appearance=${appearance}></MFlag>`,
|
|
25
25
|
},
|
|
26
26
|
);
|
|
@@ -33,22 +33,22 @@ figma.connect(
|
|
|
33
33
|
},
|
|
34
34
|
example: ({ appearance, size, disabled, isLoading, outlined, ghost }) =>
|
|
35
35
|
html`<script setup>
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
import { MIconButton } from '@mozaic-ds/vue';
|
|
37
|
+
import { ChevronRight24 } from '@mozaic-ds/icons-vue';
|
|
38
|
+
</script>
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
40
|
+
<MIconButton
|
|
41
|
+
appearance=${appearance}
|
|
42
|
+
size=${size}
|
|
43
|
+
disabled=${disabled}
|
|
44
|
+
:is-loading=${isLoading}
|
|
45
|
+
outlined=${outlined}
|
|
46
|
+
ghost=${ghost}
|
|
47
|
+
aria-label="Action"
|
|
48
|
+
>
|
|
49
|
+
<template #icon>
|
|
50
|
+
<ChevronRight24 />
|
|
51
|
+
</template>
|
|
52
|
+
</MIconButton>`,
|
|
53
53
|
},
|
|
54
54
|
);
|
|
@@ -92,6 +92,21 @@ describe('MButton component', () => {
|
|
|
92
92
|
expect(button.attributes('type')).toBe('button');
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
+
it('sets aria-busy when isLoading is true', () => {
|
|
96
|
+
const wrapper = mount(MIconButton, {
|
|
97
|
+
props: { isLoading: true },
|
|
98
|
+
slots: { icon: [ChevronRight24] },
|
|
99
|
+
});
|
|
100
|
+
expect(wrapper.find('button').attributes('aria-busy')).toBe('true');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('does not set aria-busy when not loading', () => {
|
|
104
|
+
const wrapper = mount(MIconButton, {
|
|
105
|
+
slots: { icon: [ChevronRight24] },
|
|
106
|
+
});
|
|
107
|
+
expect(wrapper.find('button').attributes('aria-busy')).toBeUndefined();
|
|
108
|
+
});
|
|
109
|
+
|
|
95
110
|
it('can have type="submit" when the type prop is "submit"', () => {
|
|
96
111
|
const wrapper = mount(MIconButton, {
|
|
97
112
|
props: {
|
|
@@ -25,9 +25,14 @@ figma.connect(
|
|
|
25
25
|
},
|
|
26
26
|
example: ({ value, label, size, status }) =>
|
|
27
27
|
html`<script setup>
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
import { MKpiItem } from '@mozaic-ds/vue';
|
|
29
|
+
</script>
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
<MKpiItem
|
|
32
|
+
value=${value}
|
|
33
|
+
label=${label}
|
|
34
|
+
size=${size}
|
|
35
|
+
status=${status}
|
|
36
|
+
/>`,
|
|
32
37
|
},
|
|
33
38
|
);
|
|
@@ -67,5 +67,17 @@ describe('MKpiItem component', () => {
|
|
|
67
67
|
|
|
68
68
|
expect(wrapper.find('.mc-kpi__icon').exists()).toBe(true);
|
|
69
69
|
});
|
|
70
|
+
|
|
71
|
+
it.each([['increasing'], ['decreasing'], ['stable']] as const)(
|
|
72
|
+
'gives the trend icon an accessible label for "%s"',
|
|
73
|
+
(trend) => {
|
|
74
|
+
const wrapper = mount(KpiItem, {
|
|
75
|
+
props: { value: '123', trend },
|
|
76
|
+
});
|
|
77
|
+
const icon = wrapper.find('.mc-kpi__icon');
|
|
78
|
+
expect(icon.attributes('role')).toBe('img');
|
|
79
|
+
expect(icon.attributes('aria-label')).toBe(trend);
|
|
80
|
+
},
|
|
81
|
+
);
|
|
70
82
|
});
|
|
71
83
|
});
|
|
@@ -15,7 +15,13 @@
|
|
|
15
15
|
{{ information }}
|
|
16
16
|
</span>
|
|
17
17
|
|
|
18
|
-
<component
|
|
18
|
+
<component
|
|
19
|
+
v-if="trend"
|
|
20
|
+
:is="getIconComponent"
|
|
21
|
+
class="mc-kpi__icon"
|
|
22
|
+
role="img"
|
|
23
|
+
:aria-label="trend"
|
|
24
|
+
/>
|
|
19
25
|
</div>
|
|
20
26
|
</div>
|
|
21
27
|
</div>
|
|
@@ -23,9 +23,12 @@ figma.connect(
|
|
|
23
23
|
},
|
|
24
24
|
example: ({ size, value }) =>
|
|
25
25
|
html`<script setup>
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
import { MLinearProgressbarBuffer } from '@mozaic-ds/vue';
|
|
27
|
+
</script>
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
<MLinearProgressbarBuffer
|
|
30
|
+
size=${size}
|
|
31
|
+
:value=${value}
|
|
32
|
+
></MLinearProgressbarBuffer>`,
|
|
30
33
|
},
|
|
31
34
|
);
|
|
@@ -18,9 +18,11 @@ figma.connect(
|
|
|
18
18
|
},
|
|
19
19
|
example: ({ value }) =>
|
|
20
20
|
html`<script setup>
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
import { MLinearProgressbarPercentage } from '@mozaic-ds/vue';
|
|
22
|
+
</script>
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
<MLinearProgressbarPercentage
|
|
25
|
+
:value=${value}
|
|
26
|
+
></MLinearProgressbarPercentage>`,
|
|
25
27
|
},
|
|
26
28
|
);
|
|
@@ -22,11 +22,11 @@ figma.connect(
|
|
|
22
22
|
},
|
|
23
23
|
example: ({ label, size, appearance }) =>
|
|
24
24
|
html`<script setup>
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
import { MLink } from '@mozaic-ds/vue';
|
|
26
|
+
</script>
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
<MLink href="#" size=${size} appearance=${appearance}>
|
|
29
|
+
${label}
|
|
30
|
+
</MLink>`,
|
|
31
31
|
},
|
|
32
32
|
);
|
|
@@ -22,9 +22,9 @@ figma.connect(
|
|
|
22
22
|
},
|
|
23
23
|
example: ({ appearance, size }) =>
|
|
24
24
|
html`<script setup>
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
import { MLoader } from '@mozaic-ds/vue';
|
|
26
|
+
</script>
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
<MLoader appearance=${appearance} size=${size}></MLoader>`,
|
|
29
29
|
},
|
|
30
30
|
);
|
|
@@ -10,9 +10,9 @@ figma.connect(
|
|
|
10
10
|
props: {},
|
|
11
11
|
example: () =>
|
|
12
12
|
html`<script setup>
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
import { MLoadingOverlay } from '@mozaic-ds/vue';
|
|
14
|
+
</script>
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
<MLoadingOverlay is-visible text="Loading..."></MLoadingOverlay>`,
|
|
17
17
|
},
|
|
18
18
|
);
|
|
@@ -10,18 +10,18 @@ figma.connect(
|
|
|
10
10
|
props: {},
|
|
11
11
|
example: () =>
|
|
12
12
|
html`<script setup>
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
import { MModal, MButton } from '@mozaic-ds/vue';
|
|
14
|
+
</script>
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
<MModal
|
|
17
|
+
open
|
|
18
|
+
title="Modal title"
|
|
19
|
+
description="A modal is a dialog window allowing you to focus the user's attention."
|
|
20
|
+
closable
|
|
21
|
+
>
|
|
22
|
+
<template #footer>
|
|
23
|
+
<MButton>Confirm</MButton>
|
|
24
|
+
</template>
|
|
25
|
+
</MModal>`,
|
|
26
26
|
},
|
|
27
27
|
);
|