@mozaic-ds/vue 2.13.0 → 2.14.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 +1088 -378
- package/dist/mozaic-vue.js +2662 -1854
- 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 +4 -4
- package/src/components/actionlistbox/MActionListbox.spec.ts +53 -59
- package/src/components/actionlistbox/MActionListbox.stories.ts +22 -1
- package/src/components/actionlistbox/MActionListbox.vue +91 -28
- package/src/components/actionlistbox/README.md +15 -0
- package/src/components/breadcrumb/MBreadcrumb.vue +5 -0
- package/src/components/button/README.md +4 -0
- package/src/components/checkbox/README.md +2 -0
- package/src/components/divider/README.md +4 -0
- package/src/components/iconbutton/MIconButton.stories.ts +12 -0
- package/src/components/iconbutton/MIconButton.vue +13 -1
- package/src/components/iconbutton/README.md +27 -0
- package/src/components/loader/README.md +2 -0
- package/src/components/navigationindicator/MNavigationIndicator.spec.ts +152 -0
- package/src/components/navigationindicator/MNavigationIndicator.stories.ts +41 -0
- package/src/components/navigationindicator/MNavigationIndicator.vue +132 -0
- package/src/components/navigationindicator/README.md +37 -0
- package/src/components/pageheader/MPageHeader.spec.ts +142 -0
- package/src/components/pageheader/MPageHeader.stories.ts +125 -0
- package/src/components/pageheader/MPageHeader.vue +133 -0
- package/src/components/pageheader/README.md +46 -0
- package/src/components/popover/MPopover.spec.ts +106 -0
- package/src/components/popover/MPopover.stories.ts +126 -0
- package/src/components/popover/MPopover.vue +131 -0
- package/src/components/popover/README.md +42 -0
- package/src/components/radio/README.md +2 -0
- package/src/components/select/MSelect.spec.ts +2 -1
- package/src/components/select/MSelect.vue +30 -25
- package/src/components/sidebar/MSidebar.const.ts +6 -0
- package/src/components/sidebar/MSidebar.spec.ts +110 -0
- package/src/components/sidebar/MSidebar.stories.ts +108 -0
- package/src/components/sidebar/MSidebar.vue +124 -0
- package/src/components/sidebar/README.md +59 -0
- package/src/components/sidebar/stories/DefaultCase.stories.vue +120 -0
- package/src/components/sidebar/stories/README.md +27 -0
- package/src/components/sidebar/stories/WithExpandOnly.stories.vue +112 -0
- package/src/components/sidebar/stories/WithProfileInfoOnly.stories.vue +119 -0
- package/src/components/sidebar/stories/WithSingleLevel.stories.vue +98 -0
- package/src/components/sidebar/use-floating-item.composable.ts +135 -0
- package/src/components/sidebar/use-floating-item.spec.ts +251 -0
- package/src/components/sidebarexpandableitem/MSidebarExpandableItem.spec.ts +151 -0
- package/src/components/sidebarexpandableitem/MSidebarExpandableItem.vue +113 -0
- package/src/components/sidebarexpandableitem/README.md +36 -0
- package/src/components/sidebarfooter/MSidebarFooter.spec.ts +276 -0
- package/src/components/sidebarfooter/MSidebarFooter.vue +201 -0
- package/src/components/sidebarfooter/README.md +52 -0
- package/src/components/sidebarfooter/_MSidebarFooterMenu.vue +64 -0
- package/src/components/sidebarheader/MSidebarHeader.vue +36 -0
- package/src/components/sidebarheader/README.md +31 -0
- package/src/components/sidebarnavitem/MSidebarNavItem.spec.ts +127 -0
- package/src/components/sidebarnavitem/MSidebarNavItem.vue +113 -0
- package/src/components/sidebarnavitem/README.md +56 -0
- package/src/components/sidebarshortcutitem/MSidebarShortcutItem.spec.ts +59 -0
- package/src/components/sidebarshortcutitem/MSidebarShortcutItem.vue +52 -0
- package/src/components/sidebarshortcutitem/README.md +32 -0
- package/src/components/sidebarshortcuts/MSidebarShortcuts.spec.ts +87 -0
- package/src/components/sidebarshortcuts/MSidebarShortcuts.vue +101 -0
- package/src/components/sidebarshortcuts/README.md +36 -0
- package/src/components/statusbadge/README.md +12 -0
- package/src/components/textinput/MTextInput.stories.ts +13 -1
- package/src/components/textinput/MTextInput.vue +12 -0
- package/src/components/textinput/README.md +3 -1
- package/src/components/tile/MTile.spec.ts +61 -0
- package/src/components/tile/MTile.stories.ts +102 -0
- package/src/components/tile/MTile.vue +68 -0
- package/src/components/tile/README.md +19 -0
- package/src/components/tileclickable/MTileClickable.spec.ts +130 -0
- package/src/components/tileclickable/MTileClickable.stories.ts +60 -0
- package/src/components/tileclickable/MTileClickable.vue +106 -0
- package/src/components/tileclickable/README.md +30 -0
- package/src/components/tileexpandable/MTileExpandable.spec.ts +121 -0
- package/src/components/tileexpandable/MTileExpandable.stories.ts +50 -0
- package/src/components/tileexpandable/MTileExpandable.vue +131 -0
- package/src/components/tileexpandable/README.md +36 -0
- package/src/components/tileselectable/MTileSelectable.spec.ts +177 -0
- package/src/components/tileselectable/MTileSelectable.stories.ts +55 -0
- package/src/components/tileselectable/MTileSelectable.vue +142 -0
- package/src/components/tileselectable/README.md +44 -0
- package/src/components/toaster/README.md +1 -1
- package/src/components/tooltip/MTooltip.vue +5 -0
- package/src/components/tooltip/README.md +16 -1
- package/src/main.ts +12 -2
- package/src/utils/use-is-mobile.composable.ts +20 -0
- package/src/utils/use-is-mobile.spec.ts +70 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { defineComponent, inject, ref } from 'vue';
|
|
2
|
+
import { mount } from '@vue/test-utils';
|
|
3
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
4
|
+
import MSidebar from './MSidebar.vue';
|
|
5
|
+
import { EXPANDED_SIDEBAR_KEY, TOGGLE_SIDEBAR_KEY } from './MSidebar.const';
|
|
6
|
+
|
|
7
|
+
const isMobile = ref(false);
|
|
8
|
+
|
|
9
|
+
vi.mock('../../utils/use-is-mobile.composable.ts', () => {
|
|
10
|
+
return {
|
|
11
|
+
useIsMobile: () => {
|
|
12
|
+
return {
|
|
13
|
+
isMobile: isMobile.value,
|
|
14
|
+
};
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const MockedFooter = defineComponent({
|
|
20
|
+
name: 'MockedFooter',
|
|
21
|
+
setup() {
|
|
22
|
+
const expanded = inject(EXPANDED_SIDEBAR_KEY);
|
|
23
|
+
const toggle = inject(TOGGLE_SIDEBAR_KEY);
|
|
24
|
+
return { expanded, toggle };
|
|
25
|
+
},
|
|
26
|
+
template: `
|
|
27
|
+
<div>
|
|
28
|
+
<button data-test="toggle" @click="toggle">Toggle</button>
|
|
29
|
+
</div>
|
|
30
|
+
`,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('MSidebar', () => {
|
|
34
|
+
it('toggles expanded state and emits event when consumer calls toggle', async () => {
|
|
35
|
+
const wrapper = mount(MSidebar, {
|
|
36
|
+
global: { components: { MockedFooter } },
|
|
37
|
+
props: {
|
|
38
|
+
modelValue: true,
|
|
39
|
+
},
|
|
40
|
+
slots: {
|
|
41
|
+
header: '',
|
|
42
|
+
shortcuts: '',
|
|
43
|
+
nav: '',
|
|
44
|
+
footer: '<MockedFooter />',
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const toggleBtn = wrapper.find('[data-test="toggle"]');
|
|
49
|
+
await toggleBtn.trigger('click');
|
|
50
|
+
|
|
51
|
+
const emitted = wrapper.emitted('update:modelValue') || [];
|
|
52
|
+
expect(emitted.length).toBe(1);
|
|
53
|
+
expect(emitted[0]).toEqual([false]);
|
|
54
|
+
|
|
55
|
+
await wrapper.setProps({ modelValue: emitted[0][0] as boolean });
|
|
56
|
+
|
|
57
|
+
const aside = wrapper.find('aside');
|
|
58
|
+
expect(aside.classes()).toContain('mc-sidebar--collapsed');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('emits "close" when the close button is clicked', async () => {
|
|
62
|
+
const wrapper = mount(MSidebar, {
|
|
63
|
+
props: { modelValue: true },
|
|
64
|
+
global: {
|
|
65
|
+
stubs: ['MIconButton', 'Cross24'],
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const btn = wrapper.find('.mc-sidebar__close-button');
|
|
70
|
+
await btn.trigger('click');
|
|
71
|
+
|
|
72
|
+
expect(wrapper.emitted()).toHaveProperty('close');
|
|
73
|
+
expect(wrapper.emitted('close')?.length).toBe(1);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('Resize handling', () => {
|
|
77
|
+
let addSpy: ReturnType<typeof vi.spyOn>;
|
|
78
|
+
let removeSpy: ReturnType<typeof vi.spyOn>;
|
|
79
|
+
|
|
80
|
+
beforeEach(() => {
|
|
81
|
+
vi.resetModules();
|
|
82
|
+
addSpy = vi.spyOn(window, 'addEventListener');
|
|
83
|
+
removeSpy = vi.spyOn(window, 'removeEventListener');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
afterEach(() => {
|
|
87
|
+
addSpy.mockRestore();
|
|
88
|
+
removeSpy.mockRestore();
|
|
89
|
+
vi.clearAllMocks();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('registers/unregisters resize listener and does not emit when isMobile is false', async () => {
|
|
93
|
+
isMobile.value = false;
|
|
94
|
+
|
|
95
|
+
const wrapper = mount(MSidebar, {
|
|
96
|
+
props: { modelValue: false },
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
expect(addSpy).toHaveBeenCalledWith('resize', expect.any(Function));
|
|
100
|
+
|
|
101
|
+
window.dispatchEvent(new Event('resize'));
|
|
102
|
+
|
|
103
|
+
const emitted = wrapper.emitted('update:modelValue');
|
|
104
|
+
expect(emitted).toBeUndefined();
|
|
105
|
+
|
|
106
|
+
wrapper.unmount();
|
|
107
|
+
expect(removeSpy).toHaveBeenCalledWith('resize', expect.any(Function));
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
|
|
3
|
+
import DefaultStory from './stories/DefaultCase.stories.vue';
|
|
4
|
+
import WithExpandOnlyStory from './stories/WithExpandOnly.stories.vue';
|
|
5
|
+
import WithProfileInfoOnlyStory from './stories/WithProfileInfoOnly.stories.vue';
|
|
6
|
+
import WithSingleLevelStory from './stories/WithSingleLevel.stories.vue';
|
|
7
|
+
import SourceCode from './stories/DefaultCase.stories.vue?raw';
|
|
8
|
+
import MSidebar from './MSidebar.vue';
|
|
9
|
+
import MSidebarHeader from '../sidebarheader/MSidebarHeader.vue';
|
|
10
|
+
import MSidebarFooter from '../sidebarfooter/MSidebarFooter.vue';
|
|
11
|
+
import MSidebarNavItem from '../sidebarnavitem/MSidebarNavItem.vue';
|
|
12
|
+
import MSidebarShortcutItem from '../sidebarshortcutitem/MSidebarShortcutItem.vue';
|
|
13
|
+
import MSidebarShortcuts from '../sidebarshortcuts/MSidebarShortcuts.vue';
|
|
14
|
+
import MSidebarExpandableItem from '../sidebarexpandableitem/MSidebarExpandableItem.vue';
|
|
15
|
+
import { action } from 'storybook/actions';
|
|
16
|
+
|
|
17
|
+
const meta: Meta<typeof MSidebar> = {
|
|
18
|
+
title: 'Structure/Sidebar',
|
|
19
|
+
component: MSidebar,
|
|
20
|
+
subcomponents: {
|
|
21
|
+
MSidebarExpandableItem,
|
|
22
|
+
MSidebarHeader,
|
|
23
|
+
MSidebarFooter,
|
|
24
|
+
MSidebarNavItem,
|
|
25
|
+
MSidebarShortcuts,
|
|
26
|
+
MSidebarShortcutItem,
|
|
27
|
+
},
|
|
28
|
+
tags: ['v2'],
|
|
29
|
+
parameters: {
|
|
30
|
+
layout: 'fullscreen',
|
|
31
|
+
docs: {
|
|
32
|
+
source: {
|
|
33
|
+
code: SourceCode,
|
|
34
|
+
},
|
|
35
|
+
description: {
|
|
36
|
+
component:
|
|
37
|
+
'A sidebar is a vertical navigation component that provides quick access to key sections and functionalities within an application or website. It contains expandable menus, and shortcuts, allowing users to navigate efficiently while keeping the main content area uncluttered. Sidebars can be collapsible or persistent, adapting to different screen sizes and user preferences. They are commonly used in dashboards, content management systems, and productivity tools.',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
globals: {
|
|
42
|
+
backgrounds: { value: 'secondary' },
|
|
43
|
+
},
|
|
44
|
+
render: () => ({
|
|
45
|
+
setup() {
|
|
46
|
+
const handleClose = action('close');
|
|
47
|
+
const handleUpdateModelValue = action('update:modelValue');
|
|
48
|
+
const handleLogOut = action('log-out');
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
handleClose,
|
|
52
|
+
handleUpdateModelValue,
|
|
53
|
+
handleLogOut,
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
components: { DefaultStory },
|
|
57
|
+
template: `
|
|
58
|
+
<DefaultStory
|
|
59
|
+
@close="handleClose"
|
|
60
|
+
@update:model-value="handleUpdateModelValue"
|
|
61
|
+
@log-out="handleLogOut"
|
|
62
|
+
/>
|
|
63
|
+
`,
|
|
64
|
+
}),
|
|
65
|
+
};
|
|
66
|
+
export default meta;
|
|
67
|
+
type Story = StoryObj<typeof MSidebar>;
|
|
68
|
+
|
|
69
|
+
export const Default: Story = {};
|
|
70
|
+
|
|
71
|
+
export const ExpandOnly: Story = {
|
|
72
|
+
render: () => ({
|
|
73
|
+
components: { WithExpandOnlyStory },
|
|
74
|
+
template: `
|
|
75
|
+
<WithExpandOnlyStory
|
|
76
|
+
@close="handleClose"
|
|
77
|
+
@update:model-value="handleUpdateModelValue"
|
|
78
|
+
@log-out="handleLogOut"
|
|
79
|
+
/>
|
|
80
|
+
`,
|
|
81
|
+
}),
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const ProfileInfoOnly: Story = {
|
|
85
|
+
render: () => ({
|
|
86
|
+
components: { WithProfileInfoOnlyStory },
|
|
87
|
+
template: `
|
|
88
|
+
<WithProfileInfoOnlyStory
|
|
89
|
+
@close="handleClose"
|
|
90
|
+
@update:model-value="handleUpdateModelValue"
|
|
91
|
+
@log-out="handleLogOut"
|
|
92
|
+
/>
|
|
93
|
+
`,
|
|
94
|
+
}),
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const SingleLevel: Story = {
|
|
98
|
+
render: () => ({
|
|
99
|
+
components: { WithSingleLevelStory },
|
|
100
|
+
template: `
|
|
101
|
+
<WithSingleLevelStory
|
|
102
|
+
@close="handleClose"
|
|
103
|
+
@update:model-value="handleUpdateModelValue"
|
|
104
|
+
@log-out="handleLogOut"
|
|
105
|
+
/>
|
|
106
|
+
`,
|
|
107
|
+
}),
|
|
108
|
+
};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<aside
|
|
3
|
+
:class="[
|
|
4
|
+
'mc-sidebar',
|
|
5
|
+
`mc-sidebar--${expanded ? 'expanded' : 'collapsed'}`,
|
|
6
|
+
]"
|
|
7
|
+
>
|
|
8
|
+
<div class="mc-sidebar__wrapper">
|
|
9
|
+
<slot name="header" />
|
|
10
|
+
|
|
11
|
+
<slot name="shortcuts" />
|
|
12
|
+
|
|
13
|
+
<section class="mc-sidebar__container">
|
|
14
|
+
<nav
|
|
15
|
+
class="mc-sidebar__menu"
|
|
16
|
+
role="navigation"
|
|
17
|
+
aria-label="navigation items"
|
|
18
|
+
>
|
|
19
|
+
<ul class="mc-sidebar__list">
|
|
20
|
+
<slot name="nav" />
|
|
21
|
+
</ul>
|
|
22
|
+
</nav>
|
|
23
|
+
</section>
|
|
24
|
+
|
|
25
|
+
<slot name="footer" />
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<MIconButton
|
|
29
|
+
class="mc-sidebar__close-button"
|
|
30
|
+
ghost
|
|
31
|
+
aria-label="Sidebar close button"
|
|
32
|
+
@click="emit('close')"
|
|
33
|
+
>
|
|
34
|
+
<template #icon>
|
|
35
|
+
<Cross24 />
|
|
36
|
+
</template>
|
|
37
|
+
</MIconButton>
|
|
38
|
+
</aside>
|
|
39
|
+
</template>
|
|
40
|
+
|
|
41
|
+
<script setup lang="ts">
|
|
42
|
+
import { computed, onMounted, onUnmounted, provide, type VNode } from 'vue';
|
|
43
|
+
import { EXPANDED_SIDEBAR_KEY, TOGGLE_SIDEBAR_KEY } from './MSidebar.const';
|
|
44
|
+
import MIconButton from '../iconbutton/MIconButton.vue';
|
|
45
|
+
import { Cross24 } from '@mozaic-ds/icons-vue';
|
|
46
|
+
import { useIsMobile } from '@/utils/use-is-mobile.composable';
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A sidebar is a vertical navigation component that provides quick access to key sections and functionalities within an application or website. It contains expandable menus, and shortcuts, allowing users to navigate efficiently while keeping the main content area uncluttered. Sidebars can be collapsible or persistent, adapting to different screen sizes and user preferences. They are commonly used in dashboards, content management systems, and productivity tools.
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
const props = defineProps<{
|
|
53
|
+
/**
|
|
54
|
+
* the state of the expanded sidebar, bound via v-model.
|
|
55
|
+
*/
|
|
56
|
+
modelValue: boolean;
|
|
57
|
+
}>();
|
|
58
|
+
|
|
59
|
+
const emit = defineEmits<{
|
|
60
|
+
/**
|
|
61
|
+
* Emits when the sidebar state changes.
|
|
62
|
+
*/
|
|
63
|
+
(on: 'update:modelValue', value: boolean): void; /**
|
|
64
|
+
* Emits when the sidebar close button is clicked (mobile only).
|
|
65
|
+
*/
|
|
66
|
+
(on: 'close'): void;
|
|
67
|
+
}>();
|
|
68
|
+
|
|
69
|
+
defineSlots<{
|
|
70
|
+
/**
|
|
71
|
+
* Slot for the sidebar header. Should contain an `MSidebarHeader` component.
|
|
72
|
+
*/
|
|
73
|
+
header: VNode[];
|
|
74
|
+
/**
|
|
75
|
+
* Slot for sidebar shortcuts. Should contain an `MSidebarShortcuts` component
|
|
76
|
+
* with one or more `MSidebarShortcutItem` components inside.
|
|
77
|
+
*/
|
|
78
|
+
shortcuts: VNode[];
|
|
79
|
+
/**
|
|
80
|
+
* Slot for the main navigation items. Should contain one or more `MSidebarNavItem` components.
|
|
81
|
+
*/
|
|
82
|
+
nav: VNode[];
|
|
83
|
+
/**
|
|
84
|
+
* Slot for the sidebar footer. Should contain an `MSidebarFooter` component.
|
|
85
|
+
*/
|
|
86
|
+
footer: VNode[];
|
|
87
|
+
}>();
|
|
88
|
+
|
|
89
|
+
const expanded = computed({
|
|
90
|
+
get() {
|
|
91
|
+
return props.modelValue;
|
|
92
|
+
},
|
|
93
|
+
set(value) {
|
|
94
|
+
emit('update:modelValue', value);
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
function toggleSidebar() {
|
|
99
|
+
expanded.value = !expanded.value;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
provide(EXPANDED_SIDEBAR_KEY, expanded);
|
|
103
|
+
provide(TOGGLE_SIDEBAR_KEY, toggleSidebar);
|
|
104
|
+
|
|
105
|
+
const { isMobile } = useIsMobile();
|
|
106
|
+
|
|
107
|
+
function handleResize() {
|
|
108
|
+
if (isMobile.value) {
|
|
109
|
+
expanded.value = true;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
onMounted(() => {
|
|
114
|
+
window.addEventListener('resize', handleResize);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
onUnmounted(() => {
|
|
118
|
+
window.removeEventListener('resize', handleResize);
|
|
119
|
+
});
|
|
120
|
+
</script>
|
|
121
|
+
|
|
122
|
+
<style lang="scss" scoped>
|
|
123
|
+
@use '@mozaic-ds/styles/components/sidebar';
|
|
124
|
+
</style>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# MSidebar
|
|
2
|
+
|
|
3
|
+
A sidebar is a vertical navigation component that provides quick access to key sections and functionalities within an application or website. It contains expandable menus, and shortcuts, allowing users to navigate efficiently while keeping the main content area uncluttered. Sidebars can be collapsible or persistent, adapting to different screen sizes and user preferences. They are commonly used in dashboards, content management systems, and productivity tools.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Props
|
|
7
|
+
|
|
8
|
+
| Name | Description | Type | Default |
|
|
9
|
+
| --- | --- | --- | --- |
|
|
10
|
+
| `modelValue*` | the state of the expanded sidebar, bound via v-model. | `boolean` | - |
|
|
11
|
+
|
|
12
|
+
## Slots
|
|
13
|
+
|
|
14
|
+
| Name | Description |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| `header` | Slot for the sidebar header. Should contain an `MSidebarHeader` component. |
|
|
17
|
+
| `shortcuts` | Slot for sidebar shortcuts. Should contain an `MSidebarShortcuts` component
|
|
18
|
+
with one or more `MSidebarShortcutItem` components inside. |
|
|
19
|
+
| `nav` | Slot for the main navigation items. Should contain one or more `MSidebarNavItem` components. |
|
|
20
|
+
| `footer` | Slot for the sidebar footer. Should contain an `MSidebarFooter` component. |
|
|
21
|
+
|
|
22
|
+
## Events
|
|
23
|
+
|
|
24
|
+
| Name | Description | Type |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| `update:modelValue` | Emits when the sidebar state changes. | [value: boolean] |
|
|
27
|
+
| `close` | Emits when the sidebar close button is clicked (mobile only). | [] |
|
|
28
|
+
|
|
29
|
+
## Dependencies
|
|
30
|
+
|
|
31
|
+
### Depends on
|
|
32
|
+
|
|
33
|
+
- [MIconButton](../iconbutton)
|
|
34
|
+
|
|
35
|
+
### Graph
|
|
36
|
+
|
|
37
|
+
```mermaid
|
|
38
|
+
graph TD;
|
|
39
|
+
MSidebar --> MIconButton
|
|
40
|
+
style MSidebar fill:#008240,stroke:#333,stroke-width:4px
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Used By
|
|
44
|
+
|
|
45
|
+
- [DefaultCase.stories](stories)
|
|
46
|
+
- [WithExpandOnly.stories](stories)
|
|
47
|
+
- [WithProfileInfoOnly.stories](stories)
|
|
48
|
+
- [WithSingleLevel.stories](stories)
|
|
49
|
+
|
|
50
|
+
### Graph
|
|
51
|
+
|
|
52
|
+
```mermaid
|
|
53
|
+
graph TD;
|
|
54
|
+
DefaultCase.stories --> MSidebar
|
|
55
|
+
WithExpandOnly.stories --> MSidebar
|
|
56
|
+
WithProfileInfoOnly.stories --> MSidebar
|
|
57
|
+
WithSingleLevel.stories --> MSidebar
|
|
58
|
+
style MSidebar fill:#008240,stroke:#333,stroke-width:4px
|
|
59
|
+
```
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<MSidebar
|
|
3
|
+
v-model="expanded"
|
|
4
|
+
@update:model-value="emit('update:modelValue')"
|
|
5
|
+
@close="emit('close')"
|
|
6
|
+
>
|
|
7
|
+
<template #header>
|
|
8
|
+
<MSidebarHeader title="Adeo Design System" logo="/logo.svg" />
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<template #shortcuts>
|
|
12
|
+
<MSidebarShortcuts stacked>
|
|
13
|
+
<MSidebarShortcutItem
|
|
14
|
+
v-for="(item, index) in shortcutItems"
|
|
15
|
+
:key="index"
|
|
16
|
+
v-bind="item"
|
|
17
|
+
/>
|
|
18
|
+
</MSidebarShortcuts>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<template #nav>
|
|
22
|
+
<template v-for="(item, index) in navigationItems" :key="index">
|
|
23
|
+
<MSidebarExpandableItem
|
|
24
|
+
v-if="item.items"
|
|
25
|
+
menu-label="Sublist menu label"
|
|
26
|
+
:label="item.label"
|
|
27
|
+
:icon="item.icon"
|
|
28
|
+
>
|
|
29
|
+
<MSidebarNavItem
|
|
30
|
+
v-for="(subItem, subIndex) in item.items"
|
|
31
|
+
:key="subIndex"
|
|
32
|
+
v-bind="subItem"
|
|
33
|
+
:active="active === `subNav-${subIndex}`"
|
|
34
|
+
@click="active = `subNav-${subIndex}`"
|
|
35
|
+
/>
|
|
36
|
+
</MSidebarExpandableItem>
|
|
37
|
+
|
|
38
|
+
<MSidebarNavItem
|
|
39
|
+
v-else
|
|
40
|
+
v-bind="item"
|
|
41
|
+
:active="active === `nav-${index}`"
|
|
42
|
+
@click="active = `nav-${index}`"
|
|
43
|
+
/>
|
|
44
|
+
</template>
|
|
45
|
+
</template>
|
|
46
|
+
|
|
47
|
+
<template #footer>
|
|
48
|
+
<MSidebarFooter
|
|
49
|
+
title="Dieter Rams"
|
|
50
|
+
subtitle="Industrial designer"
|
|
51
|
+
href="#"
|
|
52
|
+
avatar="/images/Avatar.png"
|
|
53
|
+
@log-out="emit('log-out')"
|
|
54
|
+
>
|
|
55
|
+
<MSidebarNavItem
|
|
56
|
+
v-for="(item, index) in footerMenuItems"
|
|
57
|
+
:key="index"
|
|
58
|
+
v-bind="item"
|
|
59
|
+
:active="active === `footer-${index}`"
|
|
60
|
+
@click="active = `footer-${index}`"
|
|
61
|
+
/>
|
|
62
|
+
</MSidebarFooter>
|
|
63
|
+
</template>
|
|
64
|
+
</MSidebar>
|
|
65
|
+
</template>
|
|
66
|
+
|
|
67
|
+
<script setup lang="ts">
|
|
68
|
+
import { ref } from 'vue';
|
|
69
|
+
import {
|
|
70
|
+
Coffee24,
|
|
71
|
+
Course24,
|
|
72
|
+
Sample24,
|
|
73
|
+
Release24,
|
|
74
|
+
Palette24,
|
|
75
|
+
Pantone24,
|
|
76
|
+
Admin24,
|
|
77
|
+
} from '@mozaic-ds/icons-vue';
|
|
78
|
+
|
|
79
|
+
import MSidebar from '../MSidebar.vue';
|
|
80
|
+
import MSidebarExpandableItem from '../../sidebarexpandableitem/MSidebarExpandableItem.vue';
|
|
81
|
+
import MSidebarFooter from '../../sidebarfooter/MSidebarFooter.vue';
|
|
82
|
+
import MSidebarHeader from '../../sidebarheader/MSidebarHeader.vue';
|
|
83
|
+
import MSidebarNavItem from '../../sidebarnavitem/MSidebarNavItem.vue';
|
|
84
|
+
import MSidebarShortcutItem from '../../sidebarshortcutitem/MSidebarShortcutItem.vue';
|
|
85
|
+
import MSidebarShortcuts from '../../sidebarshortcuts/MSidebarShortcuts.vue';
|
|
86
|
+
|
|
87
|
+
const emit = defineEmits(['close', 'update:modelValue', 'log-out']);
|
|
88
|
+
|
|
89
|
+
const expanded = ref(true);
|
|
90
|
+
|
|
91
|
+
const active = ref('');
|
|
92
|
+
|
|
93
|
+
const shortcutItems = [
|
|
94
|
+
{ label: 'Shortcut 01', icon: Coffee24, href: '#' },
|
|
95
|
+
{ label: 'Shortcut 02', icon: Course24, href: '#' },
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
const navigationItems = [
|
|
99
|
+
{ label: 'Get Started', href: '#', icon: Release24 },
|
|
100
|
+
{
|
|
101
|
+
label: 'Design Tokens',
|
|
102
|
+
icon: Sample24,
|
|
103
|
+
items: [
|
|
104
|
+
{ label: 'Subsection menu label 1', href: '#', locked: true },
|
|
105
|
+
{ label: 'Subsection menu label 2', href: '#', external: true },
|
|
106
|
+
{ label: 'Subsection menu label 2', href: '#' },
|
|
107
|
+
{ label: 'Subsection menu label 2', href: '#' },
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
{ label: 'Styles', href: '#', icon: Palette24 },
|
|
111
|
+
{ label: 'Components', href: '#', icon: Pantone24 },
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
const footerMenuItems = [
|
|
115
|
+
{ label: 'Action 01', icon: Admin24, href: '#' },
|
|
116
|
+
{ label: 'Action 02', icon: Admin24, href: '#' },
|
|
117
|
+
{ label: 'Action 03', icon: Admin24, href: '#' },
|
|
118
|
+
{ label: 'Action 04', icon: Admin24, href: '#' },
|
|
119
|
+
];
|
|
120
|
+
</script>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# WithSingleLevel.stories
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
## Dependencies
|
|
6
|
+
|
|
7
|
+
### Depends on
|
|
8
|
+
|
|
9
|
+
- [MSidebar](..)
|
|
10
|
+
- [MSidebarFooter](../../sidebarfooter)
|
|
11
|
+
- [MSidebarHeader](../../sidebarheader)
|
|
12
|
+
- [MSidebarNavItem](../../sidebarnavitem)
|
|
13
|
+
- [MSidebarShortcutItem](../../sidebarshortcutitem)
|
|
14
|
+
- [MSidebarShortcuts](../../sidebarshortcuts)
|
|
15
|
+
|
|
16
|
+
### Graph
|
|
17
|
+
|
|
18
|
+
```mermaid
|
|
19
|
+
graph TD;
|
|
20
|
+
WithSingleLevel.stories --> MSidebar
|
|
21
|
+
WithSingleLevel.stories --> MSidebarFooter
|
|
22
|
+
WithSingleLevel.stories --> MSidebarHeader
|
|
23
|
+
WithSingleLevel.stories --> MSidebarNavItem
|
|
24
|
+
WithSingleLevel.stories --> MSidebarShortcutItem
|
|
25
|
+
WithSingleLevel.stories --> MSidebarShortcuts
|
|
26
|
+
style WithSingleLevel.stories fill:#008240,stroke:#333,stroke-width:4px
|
|
27
|
+
```
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<MSidebar
|
|
3
|
+
v-model="expanded"
|
|
4
|
+
@update:model-value="emit('update:modelValue')"
|
|
5
|
+
@close="emit('close')"
|
|
6
|
+
>
|
|
7
|
+
<template #header>
|
|
8
|
+
<MSidebarHeader title="Adeo Design System" logo="/logo.svg" />
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<template #shortcuts>
|
|
12
|
+
<MSidebarShortcuts>
|
|
13
|
+
<MSidebarShortcutItem
|
|
14
|
+
v-for="(item, index) in shortcutItems"
|
|
15
|
+
:key="index"
|
|
16
|
+
v-bind="item"
|
|
17
|
+
/>
|
|
18
|
+
</MSidebarShortcuts>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<template #nav>
|
|
22
|
+
<template v-for="(item, index) in navigationItems" :key="index">
|
|
23
|
+
<MSidebarExpandableItem
|
|
24
|
+
v-if="item.items"
|
|
25
|
+
menu-label="Sublist menu label"
|
|
26
|
+
:label="item.label"
|
|
27
|
+
:icon="item.icon"
|
|
28
|
+
>
|
|
29
|
+
<MSidebarNavItem
|
|
30
|
+
v-for="(subItem, subIndex) in item.items"
|
|
31
|
+
:key="subIndex"
|
|
32
|
+
v-bind="subItem"
|
|
33
|
+
:active="active === `subNav-${subIndex}`"
|
|
34
|
+
@click="active = `subNav-${subIndex}`"
|
|
35
|
+
/>
|
|
36
|
+
</MSidebarExpandableItem>
|
|
37
|
+
|
|
38
|
+
<MSidebarNavItem
|
|
39
|
+
v-else
|
|
40
|
+
v-bind="item"
|
|
41
|
+
:active="active === `nav-${index}`"
|
|
42
|
+
@click="active = `nav-${index}`"
|
|
43
|
+
/>
|
|
44
|
+
</template>
|
|
45
|
+
</template>
|
|
46
|
+
|
|
47
|
+
<template #footer>
|
|
48
|
+
<MSidebarFooter @log-out="emit('log-out')">
|
|
49
|
+
<MSidebarNavItem
|
|
50
|
+
v-for="(item, index) in footerMenuItems"
|
|
51
|
+
:key="index"
|
|
52
|
+
v-bind="item"
|
|
53
|
+
:active="active === `footer-${index}`"
|
|
54
|
+
@click="active = `footer-${index}`"
|
|
55
|
+
/>
|
|
56
|
+
</MSidebarFooter>
|
|
57
|
+
</template>
|
|
58
|
+
</MSidebar>
|
|
59
|
+
</template>
|
|
60
|
+
|
|
61
|
+
<script setup lang="ts">
|
|
62
|
+
import { ref } from 'vue';
|
|
63
|
+
import {
|
|
64
|
+
Coffee24,
|
|
65
|
+
Course24,
|
|
66
|
+
Sample24,
|
|
67
|
+
Release24,
|
|
68
|
+
Palette24,
|
|
69
|
+
Pantone24,
|
|
70
|
+
Admin24,
|
|
71
|
+
} from '@mozaic-ds/icons-vue';
|
|
72
|
+
|
|
73
|
+
import MSidebar from '../MSidebar.vue';
|
|
74
|
+
import MSidebarExpandableItem from '../../sidebarexpandableitem/MSidebarExpandableItem.vue';
|
|
75
|
+
import MSidebarFooter from '../../sidebarfooter/MSidebarFooter.vue';
|
|
76
|
+
import MSidebarHeader from '../../sidebarheader/MSidebarHeader.vue';
|
|
77
|
+
import MSidebarNavItem from '../../sidebarnavitem/MSidebarNavItem.vue';
|
|
78
|
+
import MSidebarShortcutItem from '../../sidebarshortcutitem/MSidebarShortcutItem.vue';
|
|
79
|
+
import MSidebarShortcuts from '../../sidebarshortcuts/MSidebarShortcuts.vue';
|
|
80
|
+
|
|
81
|
+
const emit = defineEmits(['close', 'update:modelValue', 'log-out']);
|
|
82
|
+
|
|
83
|
+
const expanded = ref(true);
|
|
84
|
+
|
|
85
|
+
const active = ref('');
|
|
86
|
+
|
|
87
|
+
const shortcutItems = [
|
|
88
|
+
{ label: 'Shortcut 01', icon: Coffee24, href: '#' },
|
|
89
|
+
{ label: 'Shortcut 02', icon: Course24, href: '#' },
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
const navigationItems = [
|
|
93
|
+
{ label: 'Get Started', href: '#', icon: Release24 },
|
|
94
|
+
{
|
|
95
|
+
label: 'Design Tokens',
|
|
96
|
+
icon: Sample24,
|
|
97
|
+
items: [
|
|
98
|
+
{ label: 'Subsection menu label 1', href: '#', locked: true },
|
|
99
|
+
{ label: 'Subsection menu label 2', href: '#', external: true },
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
{ label: 'Styles', href: '#', icon: Palette24 },
|
|
103
|
+
{ label: 'Components', href: '#', icon: Pantone24 },
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
const footerMenuItems = [
|
|
107
|
+
{ label: 'Action 01', icon: Admin24, href: '#' },
|
|
108
|
+
{ label: 'Action 02', icon: Admin24, href: '#' },
|
|
109
|
+
{ label: 'Action 03', icon: Admin24, href: '#' },
|
|
110
|
+
{ label: 'Action 04', icon: Admin24, href: '#' },
|
|
111
|
+
];
|
|
112
|
+
</script>
|