@vcita/design-system 1.2.1 → 1.2.2
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/CHANGELOG.md +5 -0
- package/dist/@vcita/design-system.esm.js +1072 -910
- package/dist/@vcita/design-system.min.js +2 -2
- package/dist/@vcita/design-system.ssr.js +939 -804
- package/package.json +1 -1
- package/src/components/.DS_Store +0 -0
- package/src/components/VcButton/VcButton.stories.js +23 -23
- package/src/components/VcChip/VcChip.stories.js +3 -2
- package/src/components/VcChipList/VcChipList.stories.js +34 -21
- package/src/components/VcIcon/VcIcon.stories.js +30 -7
- package/src/components/VcIcon/VcIcon.vue +11 -2
- package/src/components/VcMenu/.DS_Store +0 -0
- package/src/components/VcSideNav/VcSideNav.spec.js +105 -0
- package/src/components/VcSideNav/VcSideNav.stories.js +117 -0
- package/src/components/VcSideNav/VcSideNav.vue +136 -0
- package/src/components/VcTextField/VcTextField.stories.js +60 -101
- package/src/components/VcTextField/VcTextField.vue +4 -0
- package/src/components/index.js +1 -0
- package/src/components/list/VcList/pattern/VcMobilePickerPattern.stories.js +22 -8
- package/src/components/list/VcListEntity/VcListEntity.stories.js +14 -19
- package/src/components/modal/VcConfirmModal/VcConfirmModal.stories.js +73 -46
- package/src/components/modal/VcConfirmModal/VcConfirmModal.vue +12 -2
- package/src/components/modal/VcConfirmProminentModal/VcConfirmProminentModal.stories.js +6 -10
- package/src/components/modal/VcConfirmProminentModal/VcConfirmProminentModal.vue +5 -0
- package/src/components/modal/VcInputModal/VcInputModal.stories.js +47 -56
- package/src/components/modal/VcInputModal/VcInputModal.vue +2 -1
- package/src/components/modal/VcNoticeModal/VcNoticeModal.stories.js +36 -45
- package/src/components/modal/VcNoticeModal/VcNoticeModal.vue +5 -0
- package/src/components/modal/elements/VcModalContainer.stories.js +35 -12
- package/src/components/modal/elements/VcModalContainer.vue +8 -1
- package/src/components/modal/elements/VcModalFooter.stories.js +10 -6
- package/src/components/modal/elements/VcModalWrapper.stories.js +13 -6
package/package.json
CHANGED
|
Binary file
|
|
@@ -28,28 +28,28 @@ const GeneralTemplate = (args, {argTypes}) => ({
|
|
|
28
28
|
components: {VcButton: VcButtonCmp},
|
|
29
29
|
props: Object.keys(argTypes),
|
|
30
30
|
template: `
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
31
|
+
<div>
|
|
32
|
+
<p v-if="description">{{ description }}</p>
|
|
33
|
+
<VcButton :color="color"
|
|
34
|
+
:flavor="flavor"
|
|
35
|
+
:ghost="ghost"
|
|
36
|
+
:x-small="xSmall"
|
|
37
|
+
:small="small"
|
|
38
|
+
:large="large"
|
|
39
|
+
:x-large="xLarge"
|
|
40
|
+
:icon="icon"
|
|
41
|
+
:fab="fab"
|
|
42
|
+
:pill="pill"
|
|
43
|
+
:outlined="outlined"
|
|
44
|
+
:loading="loading"
|
|
45
|
+
:width="width"
|
|
46
|
+
:disabled="disabled"
|
|
47
|
+
:href="href"
|
|
48
|
+
:prepend-default-icon="prependDefaultIcon"
|
|
49
|
+
@click="onClick">
|
|
50
|
+
{{ label }}
|
|
51
|
+
</VcButton>
|
|
52
|
+
</div>`,
|
|
53
53
|
})
|
|
54
54
|
|
|
55
55
|
export const Playground = GeneralTemplate.bind({});
|
|
@@ -296,7 +296,7 @@ export default {
|
|
|
296
296
|
fab: {table: {category: 'Shape'}},
|
|
297
297
|
pill: {table: {category: 'Shape'}},
|
|
298
298
|
outlined: {table: {category: 'Shape'}},
|
|
299
|
-
onClick: {action: 'onClick',table: {disable: true}},
|
|
299
|
+
onClick: {action: 'onClick', table: {disable: true}},
|
|
300
300
|
},
|
|
301
301
|
parameters: {
|
|
302
302
|
docs: {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import VcChipCmp from "./VcChip";
|
|
2
|
-
import {action} from "@storybook/addon-actions";
|
|
3
2
|
import VcBaseDocs from "@/stories/VcBaseDocs.mdx";
|
|
4
3
|
|
|
5
4
|
const GeneralTemplate = (args, {argTypes}) => ({
|
|
@@ -36,13 +35,15 @@ Playground.args = {
|
|
|
36
35
|
invalid: false,
|
|
37
36
|
dataQa: 'vc-chip',
|
|
38
37
|
isRipple: true,
|
|
39
|
-
onClose: action('close'),
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
export default {
|
|
43
41
|
title: 'Content Display / VcChip',
|
|
44
42
|
id: 'VcChip',
|
|
45
43
|
component: VcChipCmp,
|
|
44
|
+
argTypes: {
|
|
45
|
+
onClose: {action: 'close', table: {disable: true}},
|
|
46
|
+
},
|
|
46
47
|
parameters: {
|
|
47
48
|
design: {
|
|
48
49
|
type: 'figma',
|
|
@@ -3,14 +3,20 @@ import VcChipListCmp from './VcChipList';
|
|
|
3
3
|
const chip = {
|
|
4
4
|
label: 'Chip name',
|
|
5
5
|
avatar: {
|
|
6
|
-
imagePath: require(
|
|
6
|
+
imagePath: require(`@/stories/assets/pics/avatar1.png`)
|
|
7
7
|
}
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
const items = [];
|
|
11
11
|
|
|
12
12
|
for (let i = 0; i < 30; i++) {
|
|
13
|
-
items.push(chip);
|
|
13
|
+
items.push({...chip, label: chip.label + ' ' + (i + 1)});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const baseProps = {
|
|
17
|
+
items,
|
|
18
|
+
moreText: 'and $NUMBER more',
|
|
19
|
+
dataQa: 'VcChipList',
|
|
14
20
|
}
|
|
15
21
|
|
|
16
22
|
const PlaygroundTemplate = (args, {argTypes}) => ({
|
|
@@ -23,21 +29,26 @@ const PlaygroundTemplate = (args, {argTypes}) => ({
|
|
|
23
29
|
},
|
|
24
30
|
computed: {
|
|
25
31
|
moreString() {
|
|
26
|
-
return
|
|
32
|
+
return this.moreText.replace('$NUMBER', this.hiddenNumber);
|
|
27
33
|
}
|
|
28
34
|
},
|
|
29
35
|
template: `
|
|
30
36
|
<div>
|
|
31
37
|
<div>VcChipList renders a list of VcChip components according to an array of items.</div>
|
|
32
|
-
<div>If some of the items don't fit within 2 rows, their data will be displayed in a tooltip while hovering the
|
|
38
|
+
<div>If some of the items don't fit within 2 rows, their data will be displayed in a tooltip while hovering the
|
|
39
|
+
"more" indicator.
|
|
40
|
+
</div>
|
|
33
41
|
<br>
|
|
34
42
|
<div>The "moreText" prop will determine the text for the "more" indicator.</div>
|
|
35
|
-
<div>
|
|
43
|
+
<div>This example shows one way for including the number of hidden items in the "moreText" label.</div>
|
|
36
44
|
<br>
|
|
37
|
-
<div>This example shows the default content of the VcChip (label) and the default display of the tooltip
|
|
45
|
+
<div>This example shows the default content of the VcChip (label) and the default display of the tooltip
|
|
46
|
+
content.
|
|
47
|
+
</div>
|
|
38
48
|
<br>
|
|
39
49
|
<VcChipList :items="items"
|
|
40
50
|
:more-text="moreString"
|
|
51
|
+
:data-qa="dataQa"
|
|
41
52
|
@onHiddenChipsChange="(num) => this.hiddenNumber = num"/>
|
|
42
53
|
</div>
|
|
43
54
|
`
|
|
@@ -46,7 +57,7 @@ const PlaygroundTemplate = (args, {argTypes}) => ({
|
|
|
46
57
|
export const Playground = PlaygroundTemplate.bind({});
|
|
47
58
|
|
|
48
59
|
Playground.args = {
|
|
49
|
-
|
|
60
|
+
...baseProps,
|
|
50
61
|
};
|
|
51
62
|
|
|
52
63
|
const CustomTemplate = (args, {argTypes}) => ({
|
|
@@ -59,32 +70,34 @@ const CustomTemplate = (args, {argTypes}) => ({
|
|
|
59
70
|
},
|
|
60
71
|
computed: {
|
|
61
72
|
moreString() {
|
|
62
|
-
return
|
|
73
|
+
return this.moreText.replace('$NUMBER', this.hiddenNumber);
|
|
63
74
|
}
|
|
64
75
|
},
|
|
65
76
|
template: `
|
|
66
77
|
<div>
|
|
67
78
|
<div>VcChipList renders a list of VcChip components according to an array of items.</div>
|
|
68
|
-
<div>If some of the items don't fit within 2 rows, their data will be displayed in a tooltip while hovering the
|
|
79
|
+
<div>If some of the items don't fit within 2 rows, their data will be displayed in a tooltip while hovering the
|
|
80
|
+
"more" indicator.
|
|
81
|
+
</div>
|
|
69
82
|
<br>
|
|
70
83
|
<div>The "moreText" prop will determine the text for the "more" indicator.</div>
|
|
71
|
-
<div>
|
|
84
|
+
<div>This example shows one way for including the number of hidden items in the "moreText" label.</div>
|
|
72
85
|
<br>
|
|
73
86
|
<div>This example shows the VcChip with custom content and the custom display of the tooltip content.</div>
|
|
74
87
|
<br>
|
|
75
88
|
<VcChipList :items="items"
|
|
76
89
|
:more-text="moreString"
|
|
77
90
|
@onHiddenChipsChange="(num) => this.hiddenNumber = num">
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
<template #chipLabel="{item}">
|
|
92
|
+
<span style="color:gray;margin-inline-end:4px;">{{ item.label }} |</span>
|
|
93
|
+
<span>Custom content</span>
|
|
94
|
+
</template>
|
|
95
|
+
<template #tooltipSlot="{items}">
|
|
96
|
+
<div v-for="item in items">
|
|
97
|
+
<span style="font-weight:400;">{{ item.label }} |</span>
|
|
98
|
+
<span style="font-weight:600;">Custom content</span>
|
|
99
|
+
</div>
|
|
100
|
+
</template>
|
|
88
101
|
</VcChipList>
|
|
89
102
|
</div>
|
|
90
103
|
`
|
|
@@ -93,7 +106,7 @@ const CustomTemplate = (args, {argTypes}) => ({
|
|
|
93
106
|
export const CustomContent = CustomTemplate.bind({});
|
|
94
107
|
|
|
95
108
|
CustomContent.args = {
|
|
96
|
-
|
|
109
|
+
...baseProps,
|
|
97
110
|
}
|
|
98
111
|
|
|
99
112
|
export default {
|
|
@@ -2,40 +2,63 @@ import VcIconCmp from './VcIcon';
|
|
|
2
2
|
import icons from "../../../init/SvgIcons";
|
|
3
3
|
import VcBaseDocs from "@/stories/VcBaseDocs.mdx";
|
|
4
4
|
|
|
5
|
+
const baseProps = {
|
|
6
|
+
iconName: 'success',
|
|
7
|
+
color: 'black',
|
|
8
|
+
dataQa: 'VcIcon',
|
|
9
|
+
small: false,
|
|
10
|
+
};
|
|
11
|
+
|
|
5
12
|
const Template = (args, {argTypes}) => ({
|
|
6
13
|
components: {VcIcon: VcIconCmp},
|
|
7
14
|
props: Object.keys(argTypes),
|
|
8
|
-
template: '<div><VcIcon :color="color">{{`$${iconName}`}}</VcIcon></div>',
|
|
15
|
+
template: '<div><VcIcon :color="color" :data-qa="dataQa">{{`$${iconName}`}}</VcIcon></div>',
|
|
9
16
|
})
|
|
10
17
|
|
|
11
18
|
export const Playground = Template.bind({});
|
|
12
19
|
|
|
13
20
|
// Set default values
|
|
14
21
|
Playground.args = {
|
|
15
|
-
|
|
16
|
-
color: 'black'
|
|
22
|
+
...baseProps,
|
|
17
23
|
}
|
|
18
24
|
|
|
19
25
|
export const WithColor = Template.bind({});
|
|
20
26
|
|
|
21
27
|
// Set default values
|
|
22
28
|
WithColor.args = {
|
|
23
|
-
|
|
29
|
+
...baseProps,
|
|
24
30
|
color: 'orange',
|
|
25
31
|
}
|
|
26
32
|
|
|
33
|
+
export const WithColorFromVar = Template.bind({});
|
|
34
|
+
|
|
35
|
+
// Set default values
|
|
36
|
+
WithColorFromVar.args = {
|
|
37
|
+
...baseProps,
|
|
38
|
+
color: 'var(--gray-darken-2)',
|
|
39
|
+
}
|
|
40
|
+
|
|
27
41
|
const TemplateSmall = (args, {argTypes}) => ({
|
|
28
42
|
components: {VcIcon: VcIconCmp},
|
|
29
43
|
props: Object.keys(argTypes),
|
|
30
|
-
template: '<div><VcIcon :color="color" small>{{iconName}}</VcIcon></div>',
|
|
44
|
+
template: '<div><VcIcon :color="color" :small="small" :size="size" :data-qa="dataQa">{{iconName}}</VcIcon></div>',
|
|
31
45
|
})
|
|
32
46
|
|
|
33
47
|
export const Small = TemplateSmall.bind({});
|
|
34
48
|
|
|
35
49
|
// Set default values
|
|
36
50
|
Small.args = {
|
|
37
|
-
|
|
38
|
-
|
|
51
|
+
...baseProps,
|
|
52
|
+
small: true,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const SizeInPixels = TemplateSmall.bind({});
|
|
56
|
+
|
|
57
|
+
// Set default values
|
|
58
|
+
SizeInPixels.args = {
|
|
59
|
+
...baseProps,
|
|
60
|
+
iconName: 'check_circle',
|
|
61
|
+
size: 30,
|
|
39
62
|
}
|
|
40
63
|
|
|
41
64
|
export default {
|
|
@@ -5,13 +5,22 @@ export default {
|
|
|
5
5
|
dataQa: {
|
|
6
6
|
type: String,
|
|
7
7
|
default: 'VcIcon'
|
|
8
|
-
}
|
|
8
|
+
},
|
|
9
|
+
color: {
|
|
10
|
+
type: String,
|
|
11
|
+
default: 'black',
|
|
12
|
+
},
|
|
9
13
|
},
|
|
10
14
|
render: function (createElement) {
|
|
11
15
|
const props = {
|
|
12
16
|
attrs: {...this.$attrs, 'data-qa': this.dataQa},
|
|
13
|
-
on: this.$listeners
|
|
17
|
+
on: this.$listeners,
|
|
18
|
+
style: {
|
|
19
|
+
fill: this.$props.color,
|
|
20
|
+
color: this.$props.color,
|
|
21
|
+
},
|
|
14
22
|
};
|
|
23
|
+
|
|
15
24
|
return createElement('v-icon', props, this.$slots.default);
|
|
16
25
|
}
|
|
17
26
|
}
|
|
Binary file
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
2
|
+
import VcSideNav from "./VcSideNav.vue";
|
|
3
|
+
import Vue from 'vue';
|
|
4
|
+
import Vuetify from 'vuetify';
|
|
5
|
+
import {render} from "@testing-library/vue";
|
|
6
|
+
import init from "../../../testing-library.config";
|
|
7
|
+
import userEvent from "@testing-library/user-event";
|
|
8
|
+
|
|
9
|
+
init();
|
|
10
|
+
|
|
11
|
+
Vue.use(Vuetify);
|
|
12
|
+
|
|
13
|
+
describe("VcSideNav.vue", () => {
|
|
14
|
+
const renderWithVuetify = (component, options, callback, isMobile = false) => {
|
|
15
|
+
const root = document.createElement('div')
|
|
16
|
+
root.setAttribute('data-app', 'true')
|
|
17
|
+
|
|
18
|
+
const vuetify = new Vuetify()
|
|
19
|
+
if (isMobile) {
|
|
20
|
+
const breakpoint = {
|
|
21
|
+
init: jest.fn(),
|
|
22
|
+
framework: {},
|
|
23
|
+
smAndDown: true,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
vuetify.framework.breakpoint = breakpoint;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return render(
|
|
30
|
+
component,
|
|
31
|
+
{
|
|
32
|
+
container: document.body.appendChild(root),
|
|
33
|
+
// for Vuetify components that use the vuetify instance property
|
|
34
|
+
vuetify,
|
|
35
|
+
...options,
|
|
36
|
+
mocks: {
|
|
37
|
+
$t: value => value,
|
|
38
|
+
$dst: value => value, // <- for the design system
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
callback,
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const navGroupsData = [
|
|
46
|
+
{id: 1, label: 'Group 1', items: [{id: '1', label: 'Item 1'},{id: '2', label: 'Item 2'}]},
|
|
47
|
+
{id: 2, label: 'Group 2', items: [{id: '3', label: 'Item 3'},{id: '4', label: 'Item 4'}]}
|
|
48
|
+
]
|
|
49
|
+
const slotItemText = 'item as slot';
|
|
50
|
+
const slotGroupHeaderText = 'group header as slot';
|
|
51
|
+
|
|
52
|
+
it ("mount with all elements", async ()=> {
|
|
53
|
+
const {container, getByTestId} = renderWithVuetify(VcSideNav, {props: {navGroups: navGroupsData}})
|
|
54
|
+
|
|
55
|
+
expect(container).toHaveAttribute('data-app', "true")
|
|
56
|
+
const component = getByTestId('VcSideNav');
|
|
57
|
+
expect(component).toBeInTheDocument()
|
|
58
|
+
navGroupsData.forEach((group) => {
|
|
59
|
+
// Verify Groups
|
|
60
|
+
let groupElement = getByTestId(group.id)
|
|
61
|
+
expect(groupElement).toBeInTheDocument()
|
|
62
|
+
group.items.forEach((item) => {
|
|
63
|
+
// Verify Items
|
|
64
|
+
let itemElement = getByTestId(`item-${item.id}`)
|
|
65
|
+
expect(itemElement).toBeInTheDocument()
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it ("check selected items", async () => {
|
|
71
|
+
const {emitted, getByTestId, updateProps} = renderWithVuetify(VcSideNav, {props: {navGroups: navGroupsData, selected: '4'}})
|
|
72
|
+
const selectedCmp = getByTestId(`item-4`);
|
|
73
|
+
expect(selectedCmp).toBeInTheDocument()
|
|
74
|
+
expect(selectedCmp).toHaveClass("selected")
|
|
75
|
+
|
|
76
|
+
let item2 = getByTestId('item-2')
|
|
77
|
+
await userEvent.click(item2)
|
|
78
|
+
expect(emitted().change.length).toBe(1);
|
|
79
|
+
expect(emitted().change[0]).toEqual(["2"]);
|
|
80
|
+
|
|
81
|
+
await updateProps({selected: '2'})
|
|
82
|
+
item2 = getByTestId('item-2')
|
|
83
|
+
expect(item2).toHaveClass("selected")
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it ("check slot usage", async () => {
|
|
87
|
+
const {getByText} = renderWithVuetify(VcSideNav, {
|
|
88
|
+
props: {navGroups: navGroupsData, selected: '2'}
|
|
89
|
+
,
|
|
90
|
+
slots: {
|
|
91
|
+
"item-2" : slotItemText,
|
|
92
|
+
"group-1-header" : slotGroupHeaderText,
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
const slotItem = getByText(slotItemText);
|
|
96
|
+
expect(slotItem).toBeInTheDocument()
|
|
97
|
+
expect(slotItem).toHaveClass("selected")
|
|
98
|
+
|
|
99
|
+
const slotGroupHeader = getByText(slotGroupHeaderText);
|
|
100
|
+
expect(slotGroupHeader).toBeInTheDocument()
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
})
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import VcSideNav from './VcSideNav';
|
|
2
|
+
import VcIcon from "@/components/VcIcon/VcIcon";
|
|
3
|
+
import VcBadge from "@/components/VcBadge/VcBadge";
|
|
4
|
+
import VcBaseDocs from "@/stories/VcBaseDocs.mdx";
|
|
5
|
+
|
|
6
|
+
const basicProps = {
|
|
7
|
+
navGroups: [
|
|
8
|
+
{
|
|
9
|
+
label: 'GROUP 1',
|
|
10
|
+
id: 1,
|
|
11
|
+
items: [
|
|
12
|
+
{id: '1', label: 'Menu Item'},
|
|
13
|
+
{id: '2', label: 'Menu Item'},
|
|
14
|
+
{id: '3', label: 'Menu Item'},
|
|
15
|
+
{id: '4', label: 'Menu Item'},
|
|
16
|
+
{id: '5', label: 'Menu Item', disabled: true},
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
label: 'GROUP 2',
|
|
21
|
+
id: 2,
|
|
22
|
+
items: [
|
|
23
|
+
{id: '6', label: 'Menu Item'},
|
|
24
|
+
{id: '7', label: 'Menu Item'},
|
|
25
|
+
{id: '8', label: 'Menu Item'},
|
|
26
|
+
{id: '9', label: 'Menu Item'},
|
|
27
|
+
{id: '10', label: 'Menu Item'},
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
dataQa: 'VcSideNav',
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
const Template = (args, {argTypes}) => ({
|
|
36
|
+
components: {VcSideNav: VcSideNav},
|
|
37
|
+
props: Object.keys(argTypes),
|
|
38
|
+
data: () => ({
|
|
39
|
+
selectedIdx: '1',
|
|
40
|
+
}),
|
|
41
|
+
template: `<div>
|
|
42
|
+
<VcSideNav :navGroups="navGroups" v-model="selectedIdx" @change="onChange">
|
|
43
|
+
</VcSideNav>
|
|
44
|
+
</div>`,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
export const Playground = Template.bind({});
|
|
48
|
+
|
|
49
|
+
Playground.args = {
|
|
50
|
+
...basicProps,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const UsingSlotsTemplate = (args, {argTypes}) => ({
|
|
54
|
+
components: {VcSideNav: VcSideNav, VcIcon: VcIcon, VcBadge: VcBadge},
|
|
55
|
+
props: Object.keys(argTypes),
|
|
56
|
+
data: () => ({
|
|
57
|
+
selectedIdx: '',
|
|
58
|
+
navGroupsData: [{id: 1, label: 'GROUP', items: [{id: '0', label: 'This is place holder'},{id: '1', label: 'This is place holder'}]}]
|
|
59
|
+
}),
|
|
60
|
+
template: `
|
|
61
|
+
<div>
|
|
62
|
+
<VcSideNav :navGroups="navGroupsData" v-model="selectedIdx" @change="onChange">
|
|
63
|
+
<template #group-1-header>
|
|
64
|
+
<div class="d-flex align-center">
|
|
65
|
+
<span>Group Title</span>
|
|
66
|
+
<VcBadge class="ps-2" badgeText="new" :offsetX="-2" :offsetY="0"></VcBadge>
|
|
67
|
+
</div>
|
|
68
|
+
</template>
|
|
69
|
+
<template #item-0>
|
|
70
|
+
<div class="d-flex align-center flex-grow-1 justify-space-between px-6">
|
|
71
|
+
<span>Slot Label</span>
|
|
72
|
+
<div class="d-flex align-center">
|
|
73
|
+
<vc-icon size="16" color="black" class="mx-3">$magnify_glass</vc-icon>
|
|
74
|
+
<vc-icon size="16" color="black" class="mx-3">$plus</vc-icon>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</template>
|
|
78
|
+
|
|
79
|
+
<template #item-1>
|
|
80
|
+
<div class="d-flex align-center flex-grow-1 justify-space-between px-6">
|
|
81
|
+
<div class="d-flex align-center">
|
|
82
|
+
<span>Slot Label </span>
|
|
83
|
+
<VcBadge class="ps-2" badgeText="beta" :offsetX="-2" :offsetY="4"></VcBadge>
|
|
84
|
+
</div>
|
|
85
|
+
<vc-icon size="16" color="black" class="mx-3">$plus</vc-icon>
|
|
86
|
+
</div>
|
|
87
|
+
</template>
|
|
88
|
+
</VcSideNav>
|
|
89
|
+
</div>
|
|
90
|
+
`
|
|
91
|
+
})
|
|
92
|
+
export const UsingSlots = UsingSlotsTemplate.bind({});
|
|
93
|
+
|
|
94
|
+
UsingSlots.args = {}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
export default {
|
|
98
|
+
title: 'containers / VcSideNav',
|
|
99
|
+
component: VcSideNav,
|
|
100
|
+
id: 'VcSideNav',
|
|
101
|
+
argTypes: {
|
|
102
|
+
onChange: {action: 'change', table: {disable: true}},
|
|
103
|
+
|
|
104
|
+
},
|
|
105
|
+
parameters: {
|
|
106
|
+
design: {
|
|
107
|
+
type: 'figma',
|
|
108
|
+
url: 'https://www.figma.com/file/xIOY6fBoA1wpy1tHv3i5js/vcita---ui-library?node-id=11638%3A241955',
|
|
109
|
+
},
|
|
110
|
+
status: {
|
|
111
|
+
type: 'stable', // 'beta' | 'stable' | 'deprecated' | 'releaseCandidate'
|
|
112
|
+
},
|
|
113
|
+
docs: {
|
|
114
|
+
page: VcBaseDocs,
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:data-qa="dataQa" class="side-nav d-flex flex-column">
|
|
4
|
+
<div class="side-nav__group"
|
|
5
|
+
v-for="group in navGroups"
|
|
6
|
+
:key="group.id"
|
|
7
|
+
:data-qa="group.id">
|
|
8
|
+
<div class="side-nav__group__header mb-2" >
|
|
9
|
+
<slot :name="`group-${group.id}-header`">
|
|
10
|
+
{{group.label}}
|
|
11
|
+
</slot>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="side-nav__group__container d-flex flex-column mb-5">
|
|
14
|
+
<div @click="$emit('change',item.id)"
|
|
15
|
+
:data-qa="`item-${item.id}`"
|
|
16
|
+
v-if="group.items"
|
|
17
|
+
v-for="(item) in group.items"
|
|
18
|
+
:key="item.id"
|
|
19
|
+
:class="{selected: item.id === selected, disabled: item.disabled, mobile: isMobile, 'rtl': $vuetify.rtl}"
|
|
20
|
+
class="side-nav__group__container__menu-item d-flex align-center flex-grow-1">
|
|
21
|
+
<slot :name="`item-${item.id}`" :item="item">
|
|
22
|
+
<div class="d-flex justify-space-between px-4 align-center flex-grow-1">
|
|
23
|
+
<span>{{item.label}}</span>
|
|
24
|
+
<vcIcon size="12" v-if="isMobile">$chevron_right</vcIcon>
|
|
25
|
+
</div>
|
|
26
|
+
</slot>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</template>
|
|
32
|
+
<script>
|
|
33
|
+
import VcIcon from "@/components/VcIcon/VcIcon.vue";
|
|
34
|
+
export default {
|
|
35
|
+
name: "VcSideNav",
|
|
36
|
+
components: {VcIcon},
|
|
37
|
+
props: {
|
|
38
|
+
dataQa: {
|
|
39
|
+
type: String,
|
|
40
|
+
default: 'VcSideNav'
|
|
41
|
+
},
|
|
42
|
+
selected: {
|
|
43
|
+
type: String,
|
|
44
|
+
required: true,
|
|
45
|
+
},
|
|
46
|
+
navGroups: {
|
|
47
|
+
type: Array,
|
|
48
|
+
validator: prop => prop.every((group) => group.label && group.id)
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
model: {
|
|
52
|
+
prop: 'selected',
|
|
53
|
+
event: 'change'
|
|
54
|
+
},
|
|
55
|
+
computed: {
|
|
56
|
+
isMobile(){
|
|
57
|
+
return !this.$vuetify.breakpoint.mdAndUp
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
<style lang="scss" scoped>
|
|
64
|
+
.side-nav{
|
|
65
|
+
&__group{
|
|
66
|
+
&__header{
|
|
67
|
+
font-size: var(--font-size-xx-small);
|
|
68
|
+
font-weight: var(--font-weight-large);
|
|
69
|
+
line-height: var(--size-value5);
|
|
70
|
+
color: var(--gray-darken-2);
|
|
71
|
+
}
|
|
72
|
+
&__container{
|
|
73
|
+
border-radius: var(--border-radius);
|
|
74
|
+
background-color: var(--modal-bg-color);
|
|
75
|
+
box-shadow: var(--shadow-1);
|
|
76
|
+
&__menu-item{
|
|
77
|
+
cursor: pointer;
|
|
78
|
+
box-sizing: border-box;
|
|
79
|
+
height: var(--size-value11);
|
|
80
|
+
font-weight: var(--font-weight-medium2);
|
|
81
|
+
font-size: var(--font-size-x-small);
|
|
82
|
+
border-inline-start: 3px solid var(--modal-bg-color);
|
|
83
|
+
transition: 0.3s;
|
|
84
|
+
transition-property: border-color, background-color;
|
|
85
|
+
&:first-of-type{
|
|
86
|
+
margin-top: var(--size-value1);
|
|
87
|
+
}
|
|
88
|
+
&:last-of-type{
|
|
89
|
+
margin-bottom: var(--size-value1);
|
|
90
|
+
}
|
|
91
|
+
&:hover{
|
|
92
|
+
border-color: var(--gray-lighten-3);
|
|
93
|
+
background-color: var(--gray-lighten-3);
|
|
94
|
+
}
|
|
95
|
+
&:focus{
|
|
96
|
+
border: 3px solid var(--v-secondary-lighten1);
|
|
97
|
+
}
|
|
98
|
+
&:active:not(.mobile){
|
|
99
|
+
border-color: var(--gray-lighten-1);
|
|
100
|
+
background-color: var(--gray-lighten-1);
|
|
101
|
+
}
|
|
102
|
+
&.selected{
|
|
103
|
+
font-weight: var(--font-weight-large);
|
|
104
|
+
}
|
|
105
|
+
&.selected:not(.mobile){
|
|
106
|
+
border-inline-start: 3px solid var(--v-secondary-base);
|
|
107
|
+
}
|
|
108
|
+
&.disabled{
|
|
109
|
+
cursor: unset;
|
|
110
|
+
pointer-events: none;
|
|
111
|
+
border-color: var(--gray-lighten-3);
|
|
112
|
+
background-color: var(--gray-lighten-3);
|
|
113
|
+
color: var(--gray-darken-2);
|
|
114
|
+
}
|
|
115
|
+
&.mobile{
|
|
116
|
+
color: var(--gray-darken-5);
|
|
117
|
+
height: var(--size-value13);
|
|
118
|
+
::v-deep{
|
|
119
|
+
svg.vc-chevron-right {
|
|
120
|
+
fill: var(--gray-darken-2);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
&.rtl{
|
|
124
|
+
::v-deep{
|
|
125
|
+
svg.vc-chevron-right {
|
|
126
|
+
-webkit-transform: scaleX(-1);
|
|
127
|
+
transform: scaleX(-1);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
</style>
|