@mozaic-ds/vue 1.0.0-beta.5 → 1.0.0-beta.8
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/README.md +19 -160
- package/dist/mozaic-vue.css +1 -1
- package/dist/mozaic-vue.d.ts +324 -141
- package/dist/mozaic-vue.js +870 -542
- 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 +2 -2
- package/src/components/GettingStarted.mdx +1 -1
- package/src/components/Introduction.mdx +35 -9
- package/src/components/Support.mdx +1 -1
- package/src/components/breadcrumb/MBreadcrumb.stories.ts +27 -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/link/MLink.vue +1 -1
- package/src/components/numberbadge/MNumberBadge.spec.ts +56 -0
- package/src/components/{badge/MBadge.stories.ts → numberbadge/MNumberBadge.stories.ts} +8 -8
- package/src/components/{badge/MBadge.vue → numberbadge/MNumberBadge.vue} +4 -4
- package/src/components/pagination/MPagination.spec.ts +123 -0
- package/src/components/pagination/MPagination.stories.ts +83 -0
- package/src/components/pagination/MPagination.vue +140 -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 +154 -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 +154 -0
- package/src/main.ts +26 -47
- package/src/components/badge/MBadge.spec.ts +0 -16
|
@@ -17,18 +17,22 @@ const meta: Meta<typeof MBreadcrumb> = {
|
|
|
17
17
|
{
|
|
18
18
|
label: 'Home',
|
|
19
19
|
href: '#',
|
|
20
|
+
router: true
|
|
20
21
|
},
|
|
21
22
|
{
|
|
22
23
|
label: 'level 01',
|
|
23
24
|
href: '#',
|
|
25
|
+
router: true
|
|
24
26
|
},
|
|
25
27
|
{
|
|
26
28
|
label: 'level 02',
|
|
27
29
|
href: '#',
|
|
30
|
+
router: true
|
|
28
31
|
},
|
|
29
32
|
{
|
|
30
33
|
label: 'Current Page',
|
|
31
34
|
href: '#',
|
|
35
|
+
router: true
|
|
32
36
|
},
|
|
33
37
|
],
|
|
34
38
|
},
|
|
@@ -55,3 +59,26 @@ export const Inverse: Story = {
|
|
|
55
59
|
},
|
|
56
60
|
args: { appearance: 'inverse' },
|
|
57
61
|
};
|
|
62
|
+
|
|
63
|
+
export const WithoutRouter: Story = {
|
|
64
|
+
args: {
|
|
65
|
+
links: [
|
|
66
|
+
{
|
|
67
|
+
label: 'Home',
|
|
68
|
+
href: '#'
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
label: 'level 01',
|
|
72
|
+
href: '#'
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
label: 'level 02',
|
|
76
|
+
href: '#'
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
label: 'Current Page',
|
|
80
|
+
href: '#'
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import MDivider from './MDivider.vue';
|
|
4
|
+
|
|
5
|
+
describe('MDivider component', () => {
|
|
6
|
+
it('renders correctly with default props', () => {
|
|
7
|
+
const wrapper = mount(MDivider);
|
|
8
|
+
expect(wrapper.classes()).toContain('mc-divider');
|
|
9
|
+
|
|
10
|
+
const innerDiv = wrapper.find('.mc-divider > div');
|
|
11
|
+
expect(innerDiv.classes()).toContain('mc-divider-horizontal');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('renders with vertical orientation', () => {
|
|
15
|
+
const wrapper = mount(MDivider, {
|
|
16
|
+
props: { orientation: 'vertical' },
|
|
17
|
+
});
|
|
18
|
+
const innerDiv = wrapper.find('.mc-divider > div');
|
|
19
|
+
expect(innerDiv.classes()).toContain('mc-divider-vertical');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('applies the correct style class', () => {
|
|
23
|
+
const wrapper = mount(MDivider, {
|
|
24
|
+
props: { style: 'secondary' },
|
|
25
|
+
});
|
|
26
|
+
const innerDiv = wrapper.find('.mc-divider > div');
|
|
27
|
+
expect(innerDiv.classes()).toContain('mc-divider-horizontal--secondary');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('applies the correct size class', () => {
|
|
31
|
+
const wrapper = mount(MDivider, {
|
|
32
|
+
props: { size: 'm' },
|
|
33
|
+
});
|
|
34
|
+
const innerDiv = wrapper.find('.mc-divider > div');
|
|
35
|
+
expect(innerDiv.classes()).toContain('mc-divider-horizontal--m');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('uses default props when none are provided', () => {
|
|
39
|
+
const wrapper = mount(MDivider);
|
|
40
|
+
expect(wrapper.props().orientation).toBe('horizontal');
|
|
41
|
+
expect(wrapper.props().style).toBe('primary');
|
|
42
|
+
expect(wrapper.props().size).toBe('s');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('handles custom props correctly', () => {
|
|
46
|
+
const wrapper = mount(MDivider, {
|
|
47
|
+
props: {
|
|
48
|
+
orientation: 'vertical',
|
|
49
|
+
style: 'tertiary',
|
|
50
|
+
size: 'l',
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
expect(wrapper.props().orientation).toBe('vertical');
|
|
54
|
+
expect(wrapper.props().style).toBe('tertiary');
|
|
55
|
+
expect(wrapper.props().size).toBe('l');
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3';
|
|
2
|
+
import MDivider from './MDivider.vue';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof MDivider> = {
|
|
5
|
+
title: 'Structure/Divider',
|
|
6
|
+
component: MDivider,
|
|
7
|
+
argTypes: {
|
|
8
|
+
orientation: {
|
|
9
|
+
control: 'radio',
|
|
10
|
+
options: ['horizontal', 'vertical'],
|
|
11
|
+
},
|
|
12
|
+
style: {
|
|
13
|
+
control: 'radio',
|
|
14
|
+
options: ['primary', 'secondary', 'tertiary', 'inverse'],
|
|
15
|
+
},
|
|
16
|
+
size: {
|
|
17
|
+
control: 'radio',
|
|
18
|
+
options: ['s', 'm', 'l'],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
render: (args) => ({
|
|
22
|
+
components: { MDivider },
|
|
23
|
+
setup() {
|
|
24
|
+
return { args };
|
|
25
|
+
},
|
|
26
|
+
template: `
|
|
27
|
+
<div>
|
|
28
|
+
<MDivider v-bind="args"></MDivider>
|
|
29
|
+
<p style="padding: 1rem">Horizontal Divider</p>
|
|
30
|
+
</div>
|
|
31
|
+
`,
|
|
32
|
+
}),
|
|
33
|
+
};
|
|
34
|
+
export default meta;
|
|
35
|
+
type Story = StoryObj<typeof MDivider>;
|
|
36
|
+
|
|
37
|
+
export const Standard: Story = {};
|
|
38
|
+
|
|
39
|
+
export const Vertical: Story = {
|
|
40
|
+
args: {
|
|
41
|
+
orientation: 'vertical'
|
|
42
|
+
},
|
|
43
|
+
render: (args) => ({
|
|
44
|
+
components: { MDivider },
|
|
45
|
+
setup() {
|
|
46
|
+
return { args };
|
|
47
|
+
},
|
|
48
|
+
template: `
|
|
49
|
+
<div>
|
|
50
|
+
<MDivider v-bind="args">
|
|
51
|
+
<p style="padding: 1rem">Vertical Divider</p>
|
|
52
|
+
</MDivider>
|
|
53
|
+
</div>
|
|
54
|
+
`,
|
|
55
|
+
}),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const Size: Story = {
|
|
59
|
+
args: { size: 'm' },
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const Secondary: Story = {
|
|
63
|
+
args: { style: 'secondary' },
|
|
64
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="mc-divider">
|
|
3
|
+
<div :class="classObject"></div>
|
|
4
|
+
<slot/>
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script setup lang="ts">
|
|
9
|
+
import { computed } from 'vue';
|
|
10
|
+
/**
|
|
11
|
+
* A Divider serves as a visual divider to separate content, providing a clear distinction between sections.
|
|
12
|
+
*/
|
|
13
|
+
const props = withDefaults(
|
|
14
|
+
defineProps<{
|
|
15
|
+
/**
|
|
16
|
+
* Determines the orientation of the divider
|
|
17
|
+
*/
|
|
18
|
+
orientation?: 'vertical' | 'horizontal';
|
|
19
|
+
/**
|
|
20
|
+
* Determines the style of the divider
|
|
21
|
+
*/
|
|
22
|
+
style?: 'primary' | 'secondary' | 'tertiary' | 'inverse';
|
|
23
|
+
/**
|
|
24
|
+
* Determines the size of the divider
|
|
25
|
+
*/
|
|
26
|
+
size?: 's' | 'm' | 'l';
|
|
27
|
+
}>(),
|
|
28
|
+
{
|
|
29
|
+
orientation: 'horizontal',
|
|
30
|
+
style: 'primary',
|
|
31
|
+
size: 's',
|
|
32
|
+
},
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const classObject = computed(() => {
|
|
36
|
+
return {
|
|
37
|
+
[`mc-divider-${props.orientation}`]: props.orientation,
|
|
38
|
+
[`mc-divider-horizontal--${props.style}`]:
|
|
39
|
+
props.style && props.style != 'primary',
|
|
40
|
+
[`mc-divider-horizontal--${props.size}`]: props.size && props.size != 's',
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<style lang="scss" scoped>
|
|
46
|
+
@use '@mozaic-ds/styles/components/divider';
|
|
47
|
+
|
|
48
|
+
.mc-divider-vertical {
|
|
49
|
+
content: "";
|
|
50
|
+
display: block;
|
|
51
|
+
height: 100%;
|
|
52
|
+
position: absolute;
|
|
53
|
+
top: 50%;
|
|
54
|
+
transform: translateY(-50%);
|
|
55
|
+
}
|
|
56
|
+
</style>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import MNumberBadge from './MNumberBadge.vue';
|
|
4
|
+
|
|
5
|
+
describe('MNumberBadge component', () => {
|
|
6
|
+
it('renders the label correctly', () => {
|
|
7
|
+
const wrapper = mount(MNumberBadge, {
|
|
8
|
+
props: { label: 42 },
|
|
9
|
+
});
|
|
10
|
+
expect(wrapper.text()).toBe('42');
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('applies no modifier class by default', () => {
|
|
14
|
+
const wrapper = mount(MNumberBadge, {
|
|
15
|
+
props: { label: 1 },
|
|
16
|
+
});
|
|
17
|
+
expect(wrapper.classes()).toContain('mc-number-badge');
|
|
18
|
+
expect(wrapper.classes()).not.toContain('mc-number-badge--standard');
|
|
19
|
+
expect(wrapper.classes()).not.toContain('mc-number-badge--s');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('applies appearance modifier class when set to danger', () => {
|
|
23
|
+
const wrapper = mount(MNumberBadge, {
|
|
24
|
+
props: {
|
|
25
|
+
label: 5,
|
|
26
|
+
appearance: 'danger',
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
expect(wrapper.classes()).toContain('mc-number-badge');
|
|
30
|
+
expect(wrapper.classes()).toContain('mc-number-badge--danger');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('applies size modifier class when size is m', () => {
|
|
34
|
+
const wrapper = mount(MNumberBadge, {
|
|
35
|
+
props: {
|
|
36
|
+
label: 10,
|
|
37
|
+
size: 'm',
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
expect(wrapper.classes()).toContain('mc-number-badge');
|
|
41
|
+
expect(wrapper.classes()).toContain('mc-number-badge--m');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('applies both appearance and size modifier classes when set', () => {
|
|
45
|
+
const wrapper = mount(MNumberBadge, {
|
|
46
|
+
props: {
|
|
47
|
+
label: 3,
|
|
48
|
+
appearance: 'accent',
|
|
49
|
+
size: 'm',
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
expect(wrapper.classes()).toContain('mc-number-badge');
|
|
53
|
+
expect(wrapper.classes()).toContain('mc-number-badge--accent');
|
|
54
|
+
expect(wrapper.classes()).toContain('mc-number-badge--m');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/vue3';
|
|
2
|
-
import
|
|
2
|
+
import MNumberBadge from './MNumberBadge.vue';
|
|
3
3
|
|
|
4
|
-
const meta: Meta<typeof
|
|
5
|
-
title: 'Indicators/Badge
|
|
6
|
-
component:
|
|
4
|
+
const meta: Meta<typeof MNumberBadge> = {
|
|
5
|
+
title: 'Indicators/Number Badge',
|
|
6
|
+
component: MNumberBadge,
|
|
7
7
|
parameters: {
|
|
8
8
|
docs: {
|
|
9
9
|
description: {
|
|
10
10
|
component:
|
|
11
|
-
'A Badge represents a numeric count, often used to indicate notifications, updates, or items requiring attention. Its distinct appearance makes it easy to spot changes at a glance, ensuring users stay informed without breaking their workflow. Badges are commonly attached to icons, buttons, or tabs to provide contextual awareness.',
|
|
11
|
+
'A Number Badge represents a numeric count, often used to indicate notifications, updates, or items requiring attention. Its distinct appearance makes it easy to spot changes at a glance, ensuring users stay informed without breaking their workflow. Badges are commonly attached to icons, buttons, or tabs to provide contextual awareness.',
|
|
12
12
|
},
|
|
13
13
|
},
|
|
14
14
|
},
|
|
15
15
|
args: { label: 99 },
|
|
16
16
|
render: (args) => ({
|
|
17
|
-
components: {
|
|
17
|
+
components: { MNumberBadge },
|
|
18
18
|
setup() {
|
|
19
19
|
return { args };
|
|
20
20
|
},
|
|
21
21
|
template: `
|
|
22
|
-
<
|
|
22
|
+
<MNumberBadge v-bind="args"></MNumberBadge>
|
|
23
23
|
`,
|
|
24
24
|
}),
|
|
25
25
|
};
|
|
26
26
|
export default meta;
|
|
27
|
-
type Story = StoryObj<typeof
|
|
27
|
+
type Story = StoryObj<typeof MNumberBadge>;
|
|
28
28
|
|
|
29
29
|
export const Standard: Story = {};
|
|
30
30
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<span class="mc-badge" :class="classObject">
|
|
2
|
+
<span class="mc-number-badge" :class="classObject">
|
|
3
3
|
{{ label }}
|
|
4
4
|
</span>
|
|
5
5
|
</template>
|
|
@@ -33,13 +33,13 @@ const props = withDefaults(
|
|
|
33
33
|
|
|
34
34
|
const classObject = computed(() => {
|
|
35
35
|
return {
|
|
36
|
-
[`mc-badge--${props.appearance}`]:
|
|
36
|
+
[`mc-number-badge--${props.appearance}`]:
|
|
37
37
|
props.appearance && props.appearance != 'standard',
|
|
38
|
-
[`mc-badge--${props.size}`]: props.size && props.size != 's',
|
|
38
|
+
[`mc-number-badge--${props.size}`]: props.size && props.size != 's',
|
|
39
39
|
};
|
|
40
40
|
});
|
|
41
41
|
</script>
|
|
42
42
|
|
|
43
43
|
<style lang="scss" scoped>
|
|
44
|
-
@use '@mozaic-ds/styles/components/badge';
|
|
44
|
+
@use '@mozaic-ds/styles/components/number-badge';
|
|
45
45
|
</style>
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { mount } from '@vue/test-utils';
|
|
3
|
+
import MPagination from './MPagination.vue';
|
|
4
|
+
|
|
5
|
+
const options = [
|
|
6
|
+
{ value: 1, text: 'Page 1' },
|
|
7
|
+
{ value: 2, text: 'Page 2' },
|
|
8
|
+
{ value: 3, text: 'Page 3' },
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
describe('MPagination component', () => {
|
|
12
|
+
it('renders correctly with select when compact is false', () => {
|
|
13
|
+
const wrapper = mount(MPagination, {
|
|
14
|
+
props: {
|
|
15
|
+
id: 'test-pagination',
|
|
16
|
+
modelValue: 2,
|
|
17
|
+
options,
|
|
18
|
+
compact: false,
|
|
19
|
+
selectLabel: 'Select page',
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Check buttons rendered as MButton (not MIconButton)
|
|
24
|
+
expect(wrapper.findAllComponents({ name: 'MButton' }).length).toBe(2);
|
|
25
|
+
expect(wrapper.findAllComponents({ name: 'MIconButton' }).length).toBe(0);
|
|
26
|
+
|
|
27
|
+
// Check select is present
|
|
28
|
+
expect(wrapper.find('select').exists()).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('renders icon buttons only when compact is true', () => {
|
|
32
|
+
const wrapper = mount(MPagination, {
|
|
33
|
+
props: {
|
|
34
|
+
id: 'test-pagination',
|
|
35
|
+
modelValue: 2,
|
|
36
|
+
options,
|
|
37
|
+
compact: true,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// MIconButton rendered for previous and next
|
|
42
|
+
expect(wrapper.findAllComponents({ name: 'MIconButton' }).length).toBe(2);
|
|
43
|
+
// No MButton when compact
|
|
44
|
+
expect(wrapper.findAllComponents({ name: 'MButton' }).length).toBe(0);
|
|
45
|
+
|
|
46
|
+
// No select rendered
|
|
47
|
+
expect(wrapper.find('select').exists()).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('disables previous button if on first page', async () => {
|
|
51
|
+
const wrapper = mount(MPagination, {
|
|
52
|
+
props: {
|
|
53
|
+
id: 'test-pagination',
|
|
54
|
+
modelValue: 1,
|
|
55
|
+
options,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
const prevButton = wrapper.findAllComponents({ name: 'MButton' })[0];
|
|
59
|
+
expect(prevButton.attributes('disabled')).toBeDefined();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('disables next button if on last page', async () => {
|
|
63
|
+
const wrapper = mount(MPagination, {
|
|
64
|
+
props: {
|
|
65
|
+
id: 'test-pagination',
|
|
66
|
+
modelValue: 3,
|
|
67
|
+
options,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
const buttons = wrapper.findAllComponents({ name: 'MButton' });
|
|
71
|
+
const nextButton = buttons[buttons.length - 1];
|
|
72
|
+
expect(nextButton.attributes('disabled')).toBeDefined();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('clicking previous button updates the modelValue', async () => {
|
|
76
|
+
const wrapper = mount(MPagination, {
|
|
77
|
+
props: {
|
|
78
|
+
id: 'test-pagination',
|
|
79
|
+
modelValue: 2,
|
|
80
|
+
options,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
await wrapper.findAllComponents({ name: 'MButton' })[0].trigger('click');
|
|
85
|
+
// Should emit update:modelValue with value 1 (previous page)
|
|
86
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy();
|
|
87
|
+
expect(wrapper.emitted('update:modelValue')![0]).toEqual([1]);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('clicking next button updates the modelValue', async () => {
|
|
91
|
+
const wrapper = mount(MPagination, {
|
|
92
|
+
props: {
|
|
93
|
+
id: 'test-pagination',
|
|
94
|
+
modelValue: 2,
|
|
95
|
+
options,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const buttons = wrapper.findAllComponents({ name: 'MButton' });
|
|
100
|
+
await buttons[buttons.length - 1].trigger('click');
|
|
101
|
+
|
|
102
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy();
|
|
103
|
+
expect(wrapper.emitted('update:modelValue')![0]).toEqual([3]);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('emits update:modelValue when select value changes', async () => {
|
|
107
|
+
const wrapper = mount(MPagination, {
|
|
108
|
+
props: {
|
|
109
|
+
id: 'test-pagination',
|
|
110
|
+
modelValue: 1,
|
|
111
|
+
options,
|
|
112
|
+
compact: false,
|
|
113
|
+
selectLabel: 'Select page',
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const select = wrapper.find('select');
|
|
118
|
+
await select.setValue('3');
|
|
119
|
+
|
|
120
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy();
|
|
121
|
+
expect(wrapper.emitted('update:modelValue')![0]).toEqual([3]);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3';
|
|
2
|
+
import { action } from '@storybook/addon-actions';
|
|
3
|
+
|
|
4
|
+
import MPagination from './MPagination.vue';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof MPagination> = {
|
|
7
|
+
title: 'Navgation/Pagination',
|
|
8
|
+
component: MPagination,
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
'Pagination is a navigation component that allows users to browse through large sets of content by dividing it into discrete pages. It typically includes previous and next buttons, numeric page selectors, or dropdowns to jump between pages efficiently. Pagination improves usability and performance in content-heavy applications such as tables, search results, and articles by preventing long scrolls and reducing page load times.',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
args: {
|
|
18
|
+
id: 'paginationId',
|
|
19
|
+
modelValue: 10,
|
|
20
|
+
options: [
|
|
21
|
+
{
|
|
22
|
+
text: 'Page 1 of 99',
|
|
23
|
+
value: 1,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
text: 'Page 2 of 99',
|
|
27
|
+
value: 2,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
text: 'Page 3 of 99',
|
|
31
|
+
value: 3,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
text: 'Page 10 of 99',
|
|
35
|
+
value: 10,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
text: 'Page 99 of 99',
|
|
39
|
+
value: 99,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
selectLabel: 'Select page',
|
|
43
|
+
},
|
|
44
|
+
render: (args) => ({
|
|
45
|
+
components: { MPagination },
|
|
46
|
+
setup() {
|
|
47
|
+
const handleUpdate = action('update:modelValue');
|
|
48
|
+
|
|
49
|
+
return { args, handleUpdate };
|
|
50
|
+
},
|
|
51
|
+
template: `
|
|
52
|
+
<MPagination
|
|
53
|
+
v-bind="args"
|
|
54
|
+
@update:modelValue="handleUpdate"
|
|
55
|
+
/>
|
|
56
|
+
`,
|
|
57
|
+
}),
|
|
58
|
+
};
|
|
59
|
+
export default meta;
|
|
60
|
+
type Story = StoryObj<typeof MPagination>;
|
|
61
|
+
|
|
62
|
+
export const Default: Story = {};
|
|
63
|
+
|
|
64
|
+
export const First: Story = {
|
|
65
|
+
args: {
|
|
66
|
+
id: 'firstId',
|
|
67
|
+
modelValue: 1,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const Last: Story = {
|
|
72
|
+
args: {
|
|
73
|
+
id: 'lastId',
|
|
74
|
+
modelValue: 99,
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const Compact: Story = {
|
|
79
|
+
args: {
|
|
80
|
+
id: 'compactId',
|
|
81
|
+
compact: true,
|
|
82
|
+
},
|
|
83
|
+
};
|