@mozaic-ds/vue 2.4.0 → 2.5.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 +527 -338
- package/dist/mozaic-vue.js +941 -795
- package/dist/mozaic-vue.js.map +1 -1
- package/dist/mozaic-vue.umd.cjs +1 -1
- package/dist/mozaic-vue.umd.cjs.map +1 -1
- package/package.json +4 -4
- package/src/components/avatar/MAvatar.spec.ts +49 -0
- package/src/components/avatar/MAvatar.stories.ts +53 -0
- package/src/components/avatar/MAvatar.vue +47 -0
- package/src/components/callout/MCallout.spec.ts +99 -0
- package/src/components/callout/MCallout.stories.ts +87 -0
- package/src/components/callout/MCallout.vue +66 -0
- package/src/components/checkbox/MCheckbox.spec.ts +54 -4
- package/src/components/checkbox/MCheckbox.vue +11 -1
- package/src/components/checkboxgroup/MCheckboxGroup.vue +2 -0
- package/src/components/container/MContainer.vue +8 -1
- package/src/components/divider/MDivider.vue +8 -1
- package/src/components/drawer/MDrawer.stories.ts +11 -0
- package/src/components/loadingoverlay/MLoadingOverlay.stories.ts +11 -0
- package/src/components/modal/MModal.stories.ts +11 -0
- package/src/components/overlay/MOverlay.stories.ts +11 -0
- package/src/components/textinput/MTextInput.spec.ts +2 -2
- package/src/components/textinput/MTextInput.stories.ts +9 -3
- package/src/components/textinput/MTextInput.vue +3 -5
- package/src/components/toaster/MToaster.spec.ts +122 -0
- package/src/components/toaster/MToaster.stories.ts +105 -0
- package/src/components/toaster/MToaster.vue +181 -0
- package/src/components/tooltip/MTooltip.stories.ts +11 -0
- package/src/main.ts +3 -0
|
@@ -17,6 +17,17 @@ const meta: Meta<typeof MOverlay> = {
|
|
|
17
17
|
args: {
|
|
18
18
|
isVisible: true,
|
|
19
19
|
},
|
|
20
|
+
argTypes: {
|
|
21
|
+
'--overlay-z-index': {
|
|
22
|
+
description: 'Customise the z-index of the overlay',
|
|
23
|
+
control: false,
|
|
24
|
+
table: {
|
|
25
|
+
category: 'Custom Properties',
|
|
26
|
+
type: { summary: 'number' },
|
|
27
|
+
defaultValue: { summary: '2' },
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
20
31
|
render: (args) => ({
|
|
21
32
|
components: { MOverlay },
|
|
22
33
|
setup() {
|
|
@@ -79,8 +79,8 @@ describe('MTextInput component', () => {
|
|
|
79
79
|
const clearButton = wrapper.find('.mc-controls-options__button');
|
|
80
80
|
await clearButton.trigger('click');
|
|
81
81
|
|
|
82
|
-
expect(wrapper.
|
|
83
|
-
expect(wrapper.emitted()['update:modelValue'][0]).toEqual(['']);
|
|
82
|
+
expect(wrapper.emitted()['update:modelValue']).toBeTruthy();
|
|
83
|
+
expect(wrapper.emitted()['update:modelValue'].slice(-1)[0]).toEqual(['']);
|
|
84
84
|
});
|
|
85
85
|
|
|
86
86
|
it('should not render the clear button if isClearable is false', () => {
|
|
@@ -3,6 +3,7 @@ import { action } from 'storybook/actions';
|
|
|
3
3
|
|
|
4
4
|
import MTextInput from './MTextInput.vue';
|
|
5
5
|
import Search24 from '@mozaic-ds/icons-vue/src/components/Search24/Search24.vue';
|
|
6
|
+
import { ref } from 'vue';
|
|
6
7
|
|
|
7
8
|
const meta: Meta<typeof MTextInput> = {
|
|
8
9
|
title: 'Form Elements/TextInput',
|
|
@@ -22,13 +23,18 @@ const meta: Meta<typeof MTextInput> = {
|
|
|
22
23
|
render: (args) => ({
|
|
23
24
|
components: { MTextInput, Search24 },
|
|
24
25
|
setup() {
|
|
25
|
-
const
|
|
26
|
+
const modelValue = ref(args.modelValue);
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
const handleUpdate = (val: string | number) => {
|
|
29
|
+
modelValue.value = val;
|
|
30
|
+
action('update:modelValue')(val);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return { args, modelValue, handleUpdate };
|
|
28
34
|
},
|
|
29
35
|
template: `
|
|
30
36
|
<MTextInput
|
|
31
|
-
v-bind="args"
|
|
37
|
+
v-bind="{ ...args, modelValue }"
|
|
32
38
|
@update:modelValue="handleUpdate"
|
|
33
39
|
/>
|
|
34
40
|
`,
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<input
|
|
8
8
|
:id="id"
|
|
9
9
|
class="mc-text-input__control"
|
|
10
|
-
|
|
10
|
+
:value="modelValue"
|
|
11
11
|
:type="inputType"
|
|
12
12
|
:name="name"
|
|
13
13
|
:placeholder="placeholder"
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
</template>
|
|
38
38
|
|
|
39
39
|
<script setup lang="ts">
|
|
40
|
-
import { computed,
|
|
40
|
+
import { computed, type VNode } from 'vue';
|
|
41
41
|
import CrossCircleFilled24 from '@mozaic-ds/icons-vue/src/components/CrossCircleFilled24/CrossCircleFilled24.vue';
|
|
42
42
|
|
|
43
43
|
/**
|
|
@@ -118,9 +118,7 @@ const classObject = computed(() => {
|
|
|
118
118
|
};
|
|
119
119
|
});
|
|
120
120
|
|
|
121
|
-
const modelValue = ref(props.modelValue);
|
|
122
121
|
const clearValue = () => {
|
|
123
|
-
modelValue.value = '';
|
|
124
122
|
emit('update:modelValue', '');
|
|
125
123
|
};
|
|
126
124
|
|
|
@@ -135,4 +133,4 @@ const emit = defineEmits<{
|
|
|
135
133
|
<style lang="scss" scoped>
|
|
136
134
|
@use '@mozaic-ds/styles/components/controls-options';
|
|
137
135
|
@use '@mozaic-ds/styles/components/text-input';
|
|
138
|
-
</style>
|
|
136
|
+
</style>
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { mount } from '@vue/test-utils';
|
|
3
|
+
import MToaster from './MToaster.vue';
|
|
4
|
+
import CrossCircleFilled32 from '@mozaic-ds/icons-vue/src/components/CrossCircleFilled32/CrossCircleFilled32.vue';
|
|
5
|
+
import CheckCircleFilled32 from '@mozaic-ds/icons-vue/src/components/CheckCircleFilled32/CheckCircleFilled32.vue';
|
|
6
|
+
import WarningCircleFilled32 from '@mozaic-ds/icons-vue/src/components/WarningCircleFilled32/WarningCircleFilled32.vue';
|
|
7
|
+
import InfoCircleFilled32 from '@mozaic-ds/icons-vue/src/components/InfoCircleFilled32/InfoCircleFilled32.vue';
|
|
8
|
+
|
|
9
|
+
describe('MToaster.vue', () => {
|
|
10
|
+
it('renders description text', () => {
|
|
11
|
+
const wrapper = mount(MToaster, {
|
|
12
|
+
props: { description: 'Test message' },
|
|
13
|
+
});
|
|
14
|
+
expect(wrapper.text()).toContain('Test message');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('renders correct icon for each status', () => {
|
|
18
|
+
const statuses = {
|
|
19
|
+
success: CheckCircleFilled32,
|
|
20
|
+
warning: WarningCircleFilled32,
|
|
21
|
+
error: CrossCircleFilled32,
|
|
22
|
+
info: InfoCircleFilled32,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
for (const [status, component] of Object.entries(statuses)) {
|
|
26
|
+
const wrapper = mount(MToaster, {
|
|
27
|
+
props: { description: 'Test', status },
|
|
28
|
+
});
|
|
29
|
+
expect(wrapper.findComponent(component).exists()).toBe(true);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('applies the correct classes for status and position', () => {
|
|
34
|
+
const wrapper = mount(MToaster, {
|
|
35
|
+
props: {
|
|
36
|
+
description: 'Toast',
|
|
37
|
+
status: 'error',
|
|
38
|
+
position: 'bottom-center',
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
expect(wrapper.classes()).toContain('mc-toaster--error');
|
|
43
|
+
expect(wrapper.classes()).toContain('mc-toaster--bottom-center');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('renders close button when closable is true', () => {
|
|
47
|
+
const wrapper = mount(MToaster, {
|
|
48
|
+
props: { description: 'Closable toast', closable: true },
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
expect(wrapper.find('.mc-toaster__close').exists()).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('does not render close button when closable is false', () => {
|
|
55
|
+
const wrapper = mount(MToaster, {
|
|
56
|
+
props: { description: 'Non-closable toast', closable: false },
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
expect(wrapper.find('.mc-toaster__close').exists()).toBe(false);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('emits update:open event with false when close button is clicked', async () => {
|
|
63
|
+
const wrapper = mount(MToaster, {
|
|
64
|
+
props: { description: 'Closable toast', closable: true },
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
await wrapper.find('.mc-toaster__close').trigger('click');
|
|
68
|
+
expect(wrapper.emitted('update:open')).toBeTruthy();
|
|
69
|
+
expect(wrapper.emitted('update:open')![0]).toEqual([false]);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('renders action slot when provided', () => {
|
|
73
|
+
const wrapper = mount(MToaster, {
|
|
74
|
+
props: { description: 'With action' },
|
|
75
|
+
slots: {
|
|
76
|
+
action: '<button class="custom-action">Retry</button>',
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const action = wrapper.find('.mc-toaster__action');
|
|
81
|
+
expect(action.exists()).toBe(true);
|
|
82
|
+
expect(action.text()).toContain('Retry');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('does not render action slot wrapper if slot is not provided', () => {
|
|
86
|
+
const wrapper = mount(MToaster, {
|
|
87
|
+
props: { description: 'No action' },
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
expect(wrapper.find('.mc-toaster__action').exists()).toBe(false);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('renders progress bar when progress is true', () => {
|
|
94
|
+
const wrapper = mount(MToaster, {
|
|
95
|
+
props: { description: 'Progress toast', progress: true, timeout: 1000 },
|
|
96
|
+
});
|
|
97
|
+
expect(
|
|
98
|
+
wrapper.findComponent({ name: 'MLinearProgressbarBuffer' }).exists(),
|
|
99
|
+
).toBe(true);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('auto-closes after timeout and updates progress bar', async () => {
|
|
103
|
+
vi.useFakeTimers();
|
|
104
|
+
|
|
105
|
+
const wrapper = mount(MToaster, {
|
|
106
|
+
props: { description: 'Auto close toast', progress: true, timeout: 500 },
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
expect(
|
|
110
|
+
wrapper.findComponent({ name: 'MLinearProgressbarBuffer' }).exists(),
|
|
111
|
+
).toBe(true);
|
|
112
|
+
|
|
113
|
+
expect(wrapper.vm.progressValue).toBe(0);
|
|
114
|
+
|
|
115
|
+
vi.advanceTimersByTime(600);
|
|
116
|
+
|
|
117
|
+
expect(wrapper.emitted('update:open')).toBeTruthy();
|
|
118
|
+
expect(wrapper.emitted('update:open')!.pop()).toEqual([false]);
|
|
119
|
+
|
|
120
|
+
vi.useRealTimers();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
import MToaster from './MToaster.vue';
|
|
3
|
+
import { action } from 'storybook/actions';
|
|
4
|
+
import MButton from '../button/MButton.vue';
|
|
5
|
+
import MLink from '../link/MLink.vue';
|
|
6
|
+
import { ref, watch } from 'vue';
|
|
7
|
+
|
|
8
|
+
const meta: Meta<typeof MToaster> = {
|
|
9
|
+
title: 'Overlay/Toaster',
|
|
10
|
+
component: MToaster,
|
|
11
|
+
parameters: {
|
|
12
|
+
layout: 'fullscreen',
|
|
13
|
+
docs: {
|
|
14
|
+
story: { height: '300px' },
|
|
15
|
+
description: {
|
|
16
|
+
component:
|
|
17
|
+
'A toaster is a temporary notification that appears briefly on the screen to provide feedback or updates without interrupting the user’s workflow. It is commonly used for success messages, warnings, errors, or informational updates. Toasters can disappear automatically after a few seconds, be dismissed manually via a close button, or be removed when the user performs a relevant action. They typically include an icon, a short message, and an optional close button for better usability.',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
args: {
|
|
22
|
+
open: true,
|
|
23
|
+
description: 'This message must be short, be concise.',
|
|
24
|
+
},
|
|
25
|
+
argTypes: {
|
|
26
|
+
'--toaster-z-index': {
|
|
27
|
+
description: 'Customise the z-index of the toaster',
|
|
28
|
+
control: false,
|
|
29
|
+
table: {
|
|
30
|
+
category: 'Custom Properties',
|
|
31
|
+
type: { summary: 'number' },
|
|
32
|
+
defaultValue: { summary: '4' },
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
render: (args) => ({
|
|
37
|
+
components: { MToaster, MButton, MLink },
|
|
38
|
+
setup() {
|
|
39
|
+
const handleUpdate = action('update:open');
|
|
40
|
+
const openState = ref(args.open);
|
|
41
|
+
|
|
42
|
+
watch(
|
|
43
|
+
() => args.open,
|
|
44
|
+
(val) => {
|
|
45
|
+
openState.value = val;
|
|
46
|
+
},
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const onUpdateOpen = (val: boolean) => {
|
|
50
|
+
openState.value = val;
|
|
51
|
+
handleUpdate(val);
|
|
52
|
+
args.open = val;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return { args, openState, onUpdateOpen };
|
|
56
|
+
},
|
|
57
|
+
template: `
|
|
58
|
+
<MToaster
|
|
59
|
+
v-bind="args"
|
|
60
|
+
@update:open="onUpdateOpen"
|
|
61
|
+
v-model:open="openState"
|
|
62
|
+
>
|
|
63
|
+
<template v-if="${'action' in args}" v-slot:action>${args.action}</template>
|
|
64
|
+
</MToaster>
|
|
65
|
+
`,
|
|
66
|
+
}),
|
|
67
|
+
};
|
|
68
|
+
export default meta;
|
|
69
|
+
type Story = StoryObj<typeof MToaster>;
|
|
70
|
+
|
|
71
|
+
export const Info: Story = {};
|
|
72
|
+
|
|
73
|
+
export const Success: Story = {
|
|
74
|
+
args: { status: 'success' },
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const Warning: Story = {
|
|
78
|
+
args: { status: 'warning' },
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const Error: Story = {
|
|
82
|
+
args: { status: 'error' },
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const Timeout: Story = {
|
|
86
|
+
args: { timeout: 5000 },
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const WithButton = {
|
|
90
|
+
args: {
|
|
91
|
+
action: `
|
|
92
|
+
<MButton size="s" appearance="inverse" outlined>Undo</MButton>
|
|
93
|
+
`,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const WithLink = {
|
|
98
|
+
args: {
|
|
99
|
+
action: `
|
|
100
|
+
<MLink href="#" appearance="inverse">
|
|
101
|
+
Learn more
|
|
102
|
+
</MLink>
|
|
103
|
+
`,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<section class="mc-toaster" :class="classObject" role="status">
|
|
3
|
+
<component
|
|
4
|
+
:is="iconComponent"
|
|
5
|
+
class="mc-toaster__icon"
|
|
6
|
+
aria-hidden="true"
|
|
7
|
+
/>
|
|
8
|
+
<div class="mc-toaster__content">
|
|
9
|
+
<p class="mc-toaster__message">
|
|
10
|
+
{{ description }}
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
<div v-if="$slots.action" class="mc-toaster__action">
|
|
14
|
+
<slot name="action" />
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
<MIconButton
|
|
18
|
+
v-if="closable"
|
|
19
|
+
class="mc-toaster__close"
|
|
20
|
+
appearance="inverse"
|
|
21
|
+
size="s"
|
|
22
|
+
ghost
|
|
23
|
+
aria-label="Close"
|
|
24
|
+
@click="onClose"
|
|
25
|
+
>
|
|
26
|
+
<template #icon>
|
|
27
|
+
<Cross20 class="mc-button__icon" aria-hidden="true" />
|
|
28
|
+
</template>
|
|
29
|
+
</MIconButton>
|
|
30
|
+
|
|
31
|
+
<MLinearProgressbarBuffer
|
|
32
|
+
v-if="progress"
|
|
33
|
+
class="mc-toaster__indicator"
|
|
34
|
+
:value="progressValue"
|
|
35
|
+
></MLinearProgressbarBuffer>
|
|
36
|
+
</section>
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<script setup lang="ts">
|
|
40
|
+
import {
|
|
41
|
+
computed,
|
|
42
|
+
onBeforeUnmount,
|
|
43
|
+
onMounted,
|
|
44
|
+
ref,
|
|
45
|
+
watch,
|
|
46
|
+
type VNode,
|
|
47
|
+
} from 'vue';
|
|
48
|
+
import Cross20 from '@mozaic-ds/icons-vue/src/components/Cross20/Cross20.vue';
|
|
49
|
+
import InfoCircleFilled32 from '@mozaic-ds/icons-vue/src/components/InfoCircleFilled32/InfoCircleFilled32.vue';
|
|
50
|
+
import WarningCircleFilled32 from '@mozaic-ds/icons-vue/src/components/WarningCircleFilled32/WarningCircleFilled32.vue';
|
|
51
|
+
import CrossCircleFilled32 from '@mozaic-ds/icons-vue/src/components/CrossCircleFilled32/CrossCircleFilled32.vue';
|
|
52
|
+
import CheckCircleFilled32 from '@mozaic-ds/icons-vue/src/components/CheckCircleFilled32/CheckCircleFilled32.vue';
|
|
53
|
+
import MIconButton from '../iconbutton/MIconButton.vue';
|
|
54
|
+
import MLinearProgressbarBuffer from '../linearprogressbarbuffer/MLinearProgressbarBuffer.vue';
|
|
55
|
+
/**
|
|
56
|
+
* A toaster is a temporary notification that appears briefly on the screen to provide feedback or updates without interrupting the user’s workflow. It is commonly used for success messages, warnings, errors, or informational updates. Toasters can disappear automatically after a few seconds, be dismissed manually via a close button, or be removed when the user performs a relevant action. They typically include an icon, a short message, and an optional close button for better usability.
|
|
57
|
+
*/
|
|
58
|
+
const props = withDefaults(
|
|
59
|
+
defineProps<{
|
|
60
|
+
/**
|
|
61
|
+
* if `true`, display the Toaster.
|
|
62
|
+
*/
|
|
63
|
+
open?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Position of the toaster
|
|
66
|
+
*/
|
|
67
|
+
position?: 'top' | 'bottom' | 'top-center' | 'bottom-center';
|
|
68
|
+
/**
|
|
69
|
+
* Description of the toaster.
|
|
70
|
+
*/
|
|
71
|
+
description: string;
|
|
72
|
+
/**
|
|
73
|
+
* Allows to define the toaster style.
|
|
74
|
+
*/
|
|
75
|
+
status?: 'info' | 'success' | 'warning' | 'error';
|
|
76
|
+
/**
|
|
77
|
+
* if `true`, display the close button.
|
|
78
|
+
*/
|
|
79
|
+
closable?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* if `true`, display the progress bar of the duration.
|
|
82
|
+
*/
|
|
83
|
+
progress?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Duration of the toaster
|
|
86
|
+
*/
|
|
87
|
+
timeout?: number;
|
|
88
|
+
}>(),
|
|
89
|
+
{
|
|
90
|
+
status: 'info',
|
|
91
|
+
closable: true,
|
|
92
|
+
},
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
defineSlots<{
|
|
96
|
+
/**
|
|
97
|
+
* Use this slot to insert a button or a link in the toaster
|
|
98
|
+
*/
|
|
99
|
+
action?: VNode;
|
|
100
|
+
}>();
|
|
101
|
+
|
|
102
|
+
const classObject = computed(() => {
|
|
103
|
+
return {
|
|
104
|
+
'is-open': props.open,
|
|
105
|
+
[`mc-toaster--${props.status}`]: props.status && props.status != 'info',
|
|
106
|
+
[`mc-toaster--${props.position}`]:
|
|
107
|
+
props.position && props.position != 'top',
|
|
108
|
+
};
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const iconComponent = computed(() => {
|
|
112
|
+
switch (props.status) {
|
|
113
|
+
case 'success':
|
|
114
|
+
return CheckCircleFilled32;
|
|
115
|
+
case 'warning':
|
|
116
|
+
return WarningCircleFilled32;
|
|
117
|
+
case 'error':
|
|
118
|
+
return CrossCircleFilled32;
|
|
119
|
+
case 'info':
|
|
120
|
+
default:
|
|
121
|
+
return InfoCircleFilled32;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
watch(
|
|
126
|
+
() => props.open,
|
|
127
|
+
(newValue) => {
|
|
128
|
+
emit('update:open', newValue);
|
|
129
|
+
},
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const onClose = () => {
|
|
133
|
+
emit('update:open', false);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const emit = defineEmits<{
|
|
137
|
+
/**
|
|
138
|
+
* Emits when the checkbox value changes, updating the modelValue prop.
|
|
139
|
+
*/
|
|
140
|
+
(on: 'update:open', value: boolean): void;
|
|
141
|
+
}>();
|
|
142
|
+
|
|
143
|
+
const progressValue = ref(0);
|
|
144
|
+
let intervalId: ReturnType<typeof setInterval> | null = null;
|
|
145
|
+
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
|
146
|
+
|
|
147
|
+
onMounted(() => {
|
|
148
|
+
if (props.timeout) {
|
|
149
|
+
if (props.progress) {
|
|
150
|
+
const intervalDuration = 100; // ms
|
|
151
|
+
const steps = props.timeout / intervalDuration;
|
|
152
|
+
const increment = 100 / steps;
|
|
153
|
+
|
|
154
|
+
intervalId = setInterval(() => {
|
|
155
|
+
progressValue.value += increment;
|
|
156
|
+
|
|
157
|
+
if (progressValue.value >= 100) {
|
|
158
|
+
progressValue.value = 100;
|
|
159
|
+
onClose();
|
|
160
|
+
clearInterval(intervalId!);
|
|
161
|
+
}
|
|
162
|
+
}, intervalDuration);
|
|
163
|
+
} else {
|
|
164
|
+
timeoutId = setTimeout(() => {
|
|
165
|
+
onClose();
|
|
166
|
+
}, props.timeout);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
onBeforeUnmount(() => {
|
|
172
|
+
if (props.timeout) {
|
|
173
|
+
if (intervalId) clearInterval(intervalId);
|
|
174
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
</script>
|
|
178
|
+
|
|
179
|
+
<style lang="scss" scoped>
|
|
180
|
+
@use '@mozaic-ds/styles/components/toaster';
|
|
181
|
+
</style>
|
|
@@ -17,6 +17,17 @@ const meta: Meta<typeof MTooltip> = {
|
|
|
17
17
|
text: 'Keep the tooltip text concise.',
|
|
18
18
|
default: 'Tooltip on the top',
|
|
19
19
|
},
|
|
20
|
+
argTypes: {
|
|
21
|
+
'--tooltip-z-index': {
|
|
22
|
+
description: 'Customise the z-index of the tooltip',
|
|
23
|
+
control: false,
|
|
24
|
+
table: {
|
|
25
|
+
category: 'Custom Properties',
|
|
26
|
+
type: { summary: 'number' },
|
|
27
|
+
defaultValue: { summary: '1' },
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
20
31
|
render: (args) => ({
|
|
21
32
|
components: { MTooltip },
|
|
22
33
|
setup() {
|
package/src/main.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
export { default as MAvatar } from './components/avatar/MAvatar.vue';
|
|
1
2
|
export { default as MBreadcrumb } from './components/breadcrumb/MBreadcrumb.vue';
|
|
2
3
|
export { default as MButton } from './components/button/MButton.vue';
|
|
3
4
|
export { default as MCheckbox } from './components/checkbox/MCheckbox.vue';
|
|
4
5
|
export { default as MCheckboxGroup } from './components/checkboxgroup/MCheckboxGroup.vue';
|
|
5
6
|
export { default as MCircularProgressbar } from './components/circularprogressbar/MCircularProgressbar.vue';
|
|
7
|
+
export { default as MCallout } from './components/callout/MCallout.vue';
|
|
6
8
|
export { default as MContainer } from './components/container/MContainer.vue';
|
|
7
9
|
export { default as MDatepicker } from './components/datepicker/MDatepicker.vue';
|
|
8
10
|
export { default as MDivider } from './components/divider/MDivider.vue';
|
|
@@ -32,6 +34,7 @@ export { default as MTabs } from './components/tabs/MTabs.vue';
|
|
|
32
34
|
export { default as MTag } from './components/tag/MTag.vue';
|
|
33
35
|
export { default as MTextArea } from './components/textarea/MTextArea.vue';
|
|
34
36
|
export { default as MTextInput } from './components/textinput/MTextInput.vue';
|
|
37
|
+
export { default as MToaster } from './components/toaster/MToaster.vue';
|
|
35
38
|
export { default as MToggle } from './components/toggle/MToggle.vue';
|
|
36
39
|
export { default as MTooltip } from './components/tooltip/MTooltip.vue';
|
|
37
40
|
export { default as MToggleGroup } from './components/togglegroup/MToggleGroup.vue';
|