@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.
Files changed (32) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/@vcita/design-system.esm.js +1072 -910
  3. package/dist/@vcita/design-system.min.js +2 -2
  4. package/dist/@vcita/design-system.ssr.js +939 -804
  5. package/package.json +1 -1
  6. package/src/components/.DS_Store +0 -0
  7. package/src/components/VcButton/VcButton.stories.js +23 -23
  8. package/src/components/VcChip/VcChip.stories.js +3 -2
  9. package/src/components/VcChipList/VcChipList.stories.js +34 -21
  10. package/src/components/VcIcon/VcIcon.stories.js +30 -7
  11. package/src/components/VcIcon/VcIcon.vue +11 -2
  12. package/src/components/VcMenu/.DS_Store +0 -0
  13. package/src/components/VcSideNav/VcSideNav.spec.js +105 -0
  14. package/src/components/VcSideNav/VcSideNav.stories.js +117 -0
  15. package/src/components/VcSideNav/VcSideNav.vue +136 -0
  16. package/src/components/VcTextField/VcTextField.stories.js +60 -101
  17. package/src/components/VcTextField/VcTextField.vue +4 -0
  18. package/src/components/index.js +1 -0
  19. package/src/components/list/VcList/pattern/VcMobilePickerPattern.stories.js +22 -8
  20. package/src/components/list/VcListEntity/VcListEntity.stories.js +14 -19
  21. package/src/components/modal/VcConfirmModal/VcConfirmModal.stories.js +73 -46
  22. package/src/components/modal/VcConfirmModal/VcConfirmModal.vue +12 -2
  23. package/src/components/modal/VcConfirmProminentModal/VcConfirmProminentModal.stories.js +6 -10
  24. package/src/components/modal/VcConfirmProminentModal/VcConfirmProminentModal.vue +5 -0
  25. package/src/components/modal/VcInputModal/VcInputModal.stories.js +47 -56
  26. package/src/components/modal/VcInputModal/VcInputModal.vue +2 -1
  27. package/src/components/modal/VcNoticeModal/VcNoticeModal.stories.js +36 -45
  28. package/src/components/modal/VcNoticeModal/VcNoticeModal.vue +5 -0
  29. package/src/components/modal/elements/VcModalContainer.stories.js +35 -12
  30. package/src/components/modal/elements/VcModalContainer.vue +8 -1
  31. package/src/components/modal/elements/VcModalFooter.stories.js +10 -6
  32. package/src/components/modal/elements/VcModalWrapper.stories.js +13 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcita/design-system",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "vcita design system",
5
5
  "author": "vcita",
6
6
  "scripts": {
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
- <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>`,
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('@/stories/assets/pics/avatar1.png')
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 `and ${this.hiddenNumber} more`;
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 "more" indicator.</div>
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>It's not editable as a prop in this example, because it's computed in order to include the number of hidden chips.</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 content.</div>
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
- items
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 `and ${this.hiddenNumber} more`;
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 "more" indicator.</div>
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>It's not editable as a prop in this example, because it's computed in order to include the number of hidden chips.</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
- <template #chipLabel="{item}">
79
- <span style="color:gray;margin-inline-end:4px;">{{item.label}} |</span>
80
- <span>Custom content</span>
81
- </template>
82
- <template #tooltipSlot="{items}">
83
- <div v-for="item in items">
84
- <span style="font-weight:400;">{{item.label}} |</span>
85
- <span style="font-weight:600;">Custom content</span>
86
- </div>
87
- </template>
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
- items
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
- iconName: 'success',
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
- iconName: 'success',
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
- iconName: 'success',
38
- color: 'black'
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>