@mozaic-ds/vue 2.8.0 → 2.9.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/dist/mozaic-vue.css +1 -1
- package/dist/mozaic-vue.d.ts +18 -3
- package/dist/mozaic-vue.js +1077 -1046
- package/dist/mozaic-vue.js.map +1 -1
- package/dist/mozaic-vue.umd.cjs +5 -5
- package/dist/mozaic-vue.umd.cjs.map +1 -1
- package/package.json +1 -1
- package/src/components/drawer/MDrawer.spec.ts +81 -9
- package/src/components/drawer/MDrawer.vue +76 -46
- package/src/components/drawer/README.md +1 -0
- package/src/components/field/MField.spec.ts +94 -85
- package/src/components/field/MField.stories.ts +16 -0
- package/src/components/field/MField.vue +8 -1
- package/src/components/field/README.md +1 -0
- package/src/components/loader/MLoader.spec.ts +41 -0
- package/src/components/loader/MLoader.vue +7 -1
- package/src/components/loader/README.md +1 -1
- package/src/components/modal/MModal.spec.ts +34 -9
- package/src/components/modal/MModal.vue +39 -7
- package/src/components/modal/README.md +1 -0
|
@@ -101,4 +101,45 @@ describe('MLoader component', () => {
|
|
|
101
101
|
await wrapper.setProps({ size: 'l' });
|
|
102
102
|
expect(circle.attributes('r')).toBe('19');
|
|
103
103
|
});
|
|
104
|
+
|
|
105
|
+
it('applies mc-loader--text-visible class when text prop is provided', () => {
|
|
106
|
+
const wrapper = mount(MLoader, {
|
|
107
|
+
props: { text: 'Loading data...' },
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const loader = wrapper.find('.mc-loader');
|
|
111
|
+
expect(loader.classes()).toContain('mc-loader--text-visible');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('does not apply mc-loader--text-visible class when no text is provided', () => {
|
|
115
|
+
const wrapper = mount(MLoader);
|
|
116
|
+
const loader = wrapper.find('.mc-loader');
|
|
117
|
+
expect(loader.classes()).not.toContain('mc-loader--text-visible');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('uses default props correctly (appearance=standard, size=m)', () => {
|
|
121
|
+
const wrapper = mount(MLoader);
|
|
122
|
+
const loader = wrapper.find('.mc-loader');
|
|
123
|
+
|
|
124
|
+
expect(loader.classes()).not.toContain('mc-loader--standard');
|
|
125
|
+
expect(loader.classes()).not.toContain('mc-loader--m');
|
|
126
|
+
|
|
127
|
+
const svg = wrapper.find('svg.mc-loader__icon');
|
|
128
|
+
expect(svg.attributes('viewBox')).toBe('0 0 32 32');
|
|
129
|
+
|
|
130
|
+
const circle = wrapper.find('circle.mc-loader__path');
|
|
131
|
+
expect(circle.attributes('r')).toBe('9');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('sets correct viewBox for xs size', async () => {
|
|
135
|
+
const wrapper = mount(MLoader, { props: { size: 'xs' } });
|
|
136
|
+
const svg = wrapper.find('svg.mc-loader__icon');
|
|
137
|
+
expect(svg.attributes('viewBox')).toBe('0 0 24 24');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('sets correct circle radius for xs size', async () => {
|
|
141
|
+
const wrapper = mount(MLoader, { props: { size: 'xs' } });
|
|
142
|
+
const circle = wrapper.find('circle.mc-loader__path');
|
|
143
|
+
expect(circle.attributes('r')).toBe('3');
|
|
144
|
+
});
|
|
104
145
|
});
|
|
@@ -34,7 +34,7 @@ const props = withDefaults(
|
|
|
34
34
|
/**
|
|
35
35
|
* Defines the size of the loader.
|
|
36
36
|
*/
|
|
37
|
-
size?: 's' | 'm' | 'l';
|
|
37
|
+
size?: 'xs' | 's' | 'm' | 'l';
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
40
|
* Text to display alongside the loader when using the loader inside an `Overlay`.
|
|
@@ -60,6 +60,9 @@ const setViewBox = computed(() => {
|
|
|
60
60
|
let viewBox: string;
|
|
61
61
|
|
|
62
62
|
switch (props.size) {
|
|
63
|
+
case 'xs':
|
|
64
|
+
viewBox = '0 0 24 24';
|
|
65
|
+
break;
|
|
63
66
|
case 's':
|
|
64
67
|
viewBox = '0 0 24 24';
|
|
65
68
|
break;
|
|
@@ -76,6 +79,9 @@ const setCircleRadius = computed(() => {
|
|
|
76
79
|
let circleRadius: number;
|
|
77
80
|
|
|
78
81
|
switch (props.size) {
|
|
82
|
+
case 'xs':
|
|
83
|
+
circleRadius = 3;
|
|
84
|
+
break;
|
|
79
85
|
case 's':
|
|
80
86
|
circleRadius = 6;
|
|
81
87
|
break;
|
|
@@ -8,5 +8,5 @@ A loader is a visual indicator used to inform users that a process is in progres
|
|
|
8
8
|
| Name | Description | Type | Default |
|
|
9
9
|
| --- | --- | --- | --- |
|
|
10
10
|
| `appearance` | Specifies the visual appearance of the loader. | `"standard"` `"inverse"` `"accent"` | `"standard"` |
|
|
11
|
-
| `size` | Defines the size of the loader. | `"s"` `"m"` `"l"` | `"m"` |
|
|
11
|
+
| `size` | Defines the size of the loader. | `"s"` `"m"` `"l"` `"xs"` | `"m"` |
|
|
12
12
|
| `text` | Text to display alongside the loader when using the loader inside an `Overlay`. | `string` | - |
|
|
@@ -54,8 +54,9 @@ describe('MModal component', () => {
|
|
|
54
54
|
|
|
55
55
|
await wrapper.find('button.mc-modal__close').trigger('click');
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
expect(
|
|
57
|
+
const emitted = wrapper.emitted('update:open');
|
|
58
|
+
expect(emitted).toBeTruthy();
|
|
59
|
+
expect(emitted![emitted!.length - 1]).toEqual([false]);
|
|
59
60
|
});
|
|
60
61
|
|
|
61
62
|
it('renders slots content', () => {
|
|
@@ -110,8 +111,10 @@ describe('MModal component', () => {
|
|
|
110
111
|
|
|
111
112
|
await wrapper.findComponent({ name: 'MOverlay' }).trigger('click');
|
|
112
113
|
|
|
113
|
-
|
|
114
|
-
expect(
|
|
114
|
+
const emitted = wrapper.emitted('update:open');
|
|
115
|
+
expect(emitted).toBeTruthy();
|
|
116
|
+
|
|
117
|
+
expect(emitted![emitted!.length - 1]).toEqual([false]);
|
|
115
118
|
});
|
|
116
119
|
|
|
117
120
|
it('does not emit update:open when overlay clicked and closeOnOverlay is false', async () => {
|
|
@@ -122,17 +125,39 @@ describe('MModal component', () => {
|
|
|
122
125
|
|
|
123
126
|
await wrapper.findComponent({ name: 'MOverlay' }).trigger('click');
|
|
124
127
|
|
|
125
|
-
|
|
128
|
+
const emitted = wrapper.emitted('update:open');
|
|
129
|
+
|
|
130
|
+
if (emitted) {
|
|
131
|
+
const lastValue = emitted[emitted.length - 1][0];
|
|
132
|
+
expect(lastValue).not.toBe(false);
|
|
133
|
+
} else {
|
|
134
|
+
expect(emitted).toBeFalsy();
|
|
135
|
+
}
|
|
126
136
|
});
|
|
127
137
|
|
|
128
|
-
it('
|
|
138
|
+
it('locks scroll when open and unlocks when closed', async () => {
|
|
129
139
|
const wrapper = mount(MModal, {
|
|
130
|
-
props: { open:
|
|
140
|
+
props: { open: false, title: 'Title', scroll: false },
|
|
131
141
|
global: { stubs },
|
|
132
142
|
});
|
|
133
143
|
|
|
134
|
-
await wrapper.
|
|
144
|
+
await wrapper.setProps({ open: true });
|
|
145
|
+
expect(document.body.style.overflow).toBe('hidden');
|
|
146
|
+
expect(document.documentElement.style.overflow).toBe('hidden');
|
|
147
|
+
|
|
148
|
+
await wrapper.setProps({ open: false });
|
|
149
|
+
expect(document.body.style.overflow).toBe('');
|
|
150
|
+
expect(document.documentElement.style.overflow).toBe('');
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('does not lock scroll if scroll prop is true', async () => {
|
|
154
|
+
const wrapper = mount(MModal, {
|
|
155
|
+
props: { open: false, title: 'Title', scroll: true },
|
|
156
|
+
global: { stubs },
|
|
157
|
+
});
|
|
135
158
|
|
|
136
|
-
|
|
159
|
+
await wrapper.setProps({ open: true });
|
|
160
|
+
expect(document.body.style.overflow).toBe('');
|
|
161
|
+
expect(document.documentElement.style.overflow).toBe('');
|
|
137
162
|
});
|
|
138
163
|
});
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
:aria-hidden="!open"
|
|
11
11
|
v-bind="$attrs"
|
|
12
12
|
@keydown.esc="onClose"
|
|
13
|
+
@click.stop
|
|
13
14
|
>
|
|
14
15
|
<div class="mc-modal__dialog" role="document">
|
|
15
16
|
<header class="mc-modal__header">
|
|
@@ -47,7 +48,7 @@
|
|
|
47
48
|
</template>
|
|
48
49
|
|
|
49
50
|
<script setup lang="ts">
|
|
50
|
-
import { computed, watch, type VNode } from 'vue';
|
|
51
|
+
import { computed, onMounted, onUnmounted, watch, type VNode } from 'vue';
|
|
51
52
|
import Cross24 from '@mozaic-ds/icons-vue/src/components/Cross24/Cross24.vue';
|
|
52
53
|
import MIconButton from '../iconbutton/MIconButton.vue';
|
|
53
54
|
import MOverlay from '../overlay/MOverlay.vue';
|
|
@@ -72,6 +73,10 @@ const props = withDefaults(
|
|
|
72
73
|
* if `true`, display the close button.
|
|
73
74
|
*/
|
|
74
75
|
closable?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* if `false`, lock the scroll when open.
|
|
78
|
+
*/
|
|
79
|
+
scroll?: boolean;
|
|
75
80
|
/**
|
|
76
81
|
* if `true`, close the modal when clicking the overlay.
|
|
77
82
|
*/
|
|
@@ -79,6 +84,7 @@ const props = withDefaults(
|
|
|
79
84
|
}>(),
|
|
80
85
|
{
|
|
81
86
|
closable: true,
|
|
87
|
+
scroll: true,
|
|
82
88
|
},
|
|
83
89
|
);
|
|
84
90
|
|
|
@@ -107,12 +113,38 @@ const classObject = computed(() => {
|
|
|
107
113
|
};
|
|
108
114
|
});
|
|
109
115
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
+
const isClient =
|
|
117
|
+
typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
118
|
+
|
|
119
|
+
const lockScroll = () => {
|
|
120
|
+
if (!isClient) return;
|
|
121
|
+
document.body.style.overflow = 'hidden';
|
|
122
|
+
document.documentElement.style.overflow = 'hidden';
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const unlockScroll = () => {
|
|
126
|
+
if (!isClient) return;
|
|
127
|
+
document.body.style.overflow = '';
|
|
128
|
+
document.documentElement.style.overflow = '';
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
onMounted(() => {
|
|
132
|
+
watch(
|
|
133
|
+
() => props.open,
|
|
134
|
+
(isOpen) => {
|
|
135
|
+
emit('update:open', isOpen);
|
|
136
|
+
if (props.scroll === false) {
|
|
137
|
+
if (isOpen) lockScroll();
|
|
138
|
+
else unlockScroll();
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
{ immediate: true },
|
|
142
|
+
);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
onUnmounted(() => {
|
|
146
|
+
unlockScroll();
|
|
147
|
+
});
|
|
116
148
|
|
|
117
149
|
const onClickOverlay = () => {
|
|
118
150
|
if (props.closeOnOverlay) {
|
|
@@ -11,6 +11,7 @@ A modal is a dialog window that appears on top of the main content, requiring us
|
|
|
11
11
|
| `title*` | Title of the modal. | `string` | - |
|
|
12
12
|
| `description` | Description of the modal. | `string` | - |
|
|
13
13
|
| `closable` | if `true`, display the close button. | `boolean` | `true` |
|
|
14
|
+
| `scroll` | if `false`, lock the scroll when open. | `boolean` | `true` |
|
|
14
15
|
| `closeOnOverlay` | if `true`, close the modal when clicking the overlay. | `boolean` | - |
|
|
15
16
|
|
|
16
17
|
## Slots
|