@vcita/design-system 1.3.2 → 1.3.4

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 (56) hide show
  1. package/config/locales/ds.en.yml +4 -0
  2. package/dist/@vcita/design-system.esm.js +1882 -1140
  3. package/dist/@vcita/design-system.min.js +2 -2
  4. package/dist/@vcita/design-system.ssr.js +1688 -965
  5. package/init/DesignSystem.js +3 -1
  6. package/init/initI18n.js +24 -16
  7. package/package.json +2 -1
  8. package/src/components/VcActionList/VcActionList.spec.js +16 -7
  9. package/src/components/VcActionList/VcActionList.stories.js +16 -3
  10. package/src/components/VcActionList/VcActionList.vue +35 -11
  11. package/src/components/VcBottomActions/VcBottomActions.vue +2 -1
  12. package/src/components/VcBottomSheet/VcBottomSheet.stories.js +6 -13
  13. package/src/components/VcBottomSheet/VcBottomSheet.vue +2 -3
  14. package/src/components/VcButton/VcButton.vue +1 -1
  15. package/src/components/VcCheckbox/VcCheckbox.vue +8 -1
  16. package/src/components/VcColorPicker/VcColorPicker.spec.js +206 -0
  17. package/src/components/VcColorPicker/VcColorPicker.stories.js +107 -0
  18. package/src/components/VcColorPicker/VcColorPicker.vue +270 -0
  19. package/src/components/VcFilterPanel/VcFilterPanel.spec.js +15 -0
  20. package/src/components/VcFilterPanel/VcFilterPanel.stories.js +9 -1
  21. package/src/components/VcFilterPanel/VcFilterPanel.vue +24 -3
  22. package/src/components/VcGalleryItem/VcGalleryItem.stories.js +2 -0
  23. package/src/components/VcGroupedItems/VcGroupedItems.spec.js +148 -0
  24. package/src/components/VcGroupedItems/VcGroupedItems.stories.js +135 -0
  25. package/src/components/VcGroupedItems/VcGroupedItems.vue +155 -0
  26. package/src/components/VcLink/VcLink.spec.js +3 -3
  27. package/src/components/VcLink/VcLink.stories.js +2 -6
  28. package/src/components/VcLink/VcLink.vue +1 -18
  29. package/src/components/VcMenu/VcDropdown.spec.js +120 -0
  30. package/src/components/VcMenu/VcDropdown.stories.js +272 -0
  31. package/src/components/VcMenu/VcDropdown.vue +93 -0
  32. package/src/components/VcMenu/VcMenu.spec.js +61 -10
  33. package/src/components/VcMenu/VcMenu.stories.js +38 -33
  34. package/src/components/VcMenu/VcMenu.vue +19 -3
  35. package/src/components/VcPopover/VcPopover.stories.js +2 -2
  36. package/src/components/VcRadioGroup/VcRadioGroup.spec.js +28 -0
  37. package/src/components/VcRadioGroup/VcRadioGroup.stories.js +3 -1
  38. package/src/components/VcRadioGroup/VcRadioGroup.vue +6 -1
  39. package/src/components/VcSearchPicker/VcSearchPicker.stories.js +3 -4
  40. package/src/components/VcSelectField/VcSelectField.vue +6 -0
  41. package/src/components/VcSideNav/VcSideNav.spec.js +1 -1
  42. package/src/components/VcSideNav/VcSideNav.vue +21 -104
  43. package/src/components/VcTextField/VcTextField.spec.js +13 -0
  44. package/src/components/VcTextField/VcTextField.stories.js +2 -1
  45. package/src/components/VcTextField/VcTextField.vue +11 -0
  46. package/src/components/VcTooltip/VcTooltip.stories.js +3 -1
  47. package/src/components/VcTooltip/VcTooltip.vue +6 -1
  48. package/src/components/index.js +4 -0
  49. package/src/components/list/VcBaseListItem/VcBaseListItem.stories.js +22 -13
  50. package/src/components/list/VcBaseListItem/VcBaseListItem.vue +4 -1
  51. package/src/components/list/VcList/VcList.stories.js +245 -240
  52. package/src/components/list/VcList/VcList.vue +11 -4
  53. package/src/components/page/layouts/centeredPage/CenteredPageLayout.stories.js +17 -16
  54. package/styles/variables.scss +1 -0
  55. package/styles/vuetify-variables.scss +9 -1
  56. package/CHANGELOG.md +0 -342
@@ -0,0 +1,155 @@
1
+ <template>
2
+ <VcLayout column :data-qa="dataQa" class="grouped-items">
3
+ <div class="grouped-items__group mt-5"
4
+ v-for="(group, groupIndex) in itemGroups"
5
+ :key="group.id"
6
+ :data-qa="`group-${group.id}`">
7
+ <div :class="`grouped-items__group__header ${flavor} mb-2`" >
8
+ <slot :name="`group-${group.id}-header`" :group="group">
9
+ {{group.label}}
10
+ </slot>
11
+ </div>
12
+ <VcLayout column :class="`grouped-items__group__container ${flavor}`">
13
+ <VcLayout @click="$emit('change',item.id)"
14
+ :data-qa="`item-${item.id}`"
15
+ v-if="group.items"
16
+ v-for="(item) in group.items"
17
+ :key="item.id"
18
+ :class="{selected: item.id === selected, disabled: item.disabled, mobile: isMobile, 'rtl': $vuetify.rtl}"
19
+ class="grouped-items__group__container__menu-item d-flex align-center flex-grow-1">
20
+ <slot :name="`item-${item.id}`" :item="item">
21
+ <VcLayout justify-space-between align-center class="px-4 flex-grow-1">
22
+ <span>{{item.label}}</span>
23
+ <vcIcon size="12" v-if="isMobile">$chevron_right</vcIcon>
24
+ </VcLayout>
25
+ </slot>
26
+ </VcLayout>
27
+ </VcLayout>
28
+ <v-divider v-if="showDividers && groupIndex < itemGroups.length - 1"></v-divider>
29
+ </div>
30
+ </VcLayout>
31
+ </template>
32
+ <script>
33
+
34
+ import VcIcon from "@/components/VcIcon/VcIcon.vue";
35
+ import VcLayout from "@/components/VcLayout/VcLayout.vue";
36
+
37
+ export default {
38
+ name: "VcGroupedItems",
39
+ components: {VcLayout, VcIcon},
40
+ props: {
41
+ dataQa: {
42
+ type: String,
43
+ default: 'VcGroupedItems'
44
+ },
45
+ selected: {
46
+ type: String,
47
+ required: false,
48
+ },
49
+ itemGroups: {
50
+ type: Array,
51
+ validator: prop => prop.every((group) => group.label && group.id),
52
+ required: true,
53
+ },
54
+ flavor: {
55
+ type: String,
56
+ default: 'flat',
57
+ validator: value => ['flat', 'elevated'].includes(value),
58
+ },
59
+ showDividers: {
60
+ type: Boolean,
61
+ default: false,
62
+ }
63
+ },
64
+ model: {
65
+ prop: 'selected',
66
+ event: 'change'
67
+ },
68
+ computed: {
69
+ isMobile(){
70
+ return !this.$vuetify.breakpoint.mdAndUp
71
+ }
72
+ }
73
+ }
74
+ </script>
75
+
76
+ <style lang="scss" scoped>
77
+ .grouped-items{
78
+ &__group{
79
+ &__header{
80
+ font-size: var(--font-size-xx-small);
81
+ font-weight: var(--font-weight-large);
82
+ line-height: var(--size-value5);
83
+ color: var(--gray-darken-2);
84
+
85
+ &.flat {
86
+ padding-left: var(--size-value4);
87
+ font-size: var(--font-size-xxx-small);
88
+ }
89
+ }
90
+ &__container{
91
+ border-radius: var(--border-radius);
92
+ background-color: var(--modal-bg-color);
93
+ &.elevated {
94
+ box-shadow: var(--shadow-1);
95
+ }
96
+ &__menu-item{
97
+ cursor: pointer;
98
+ box-sizing: border-box;
99
+ height: var(--size-value11);
100
+ font-weight: var(--font-weight-medium2);
101
+ font-size: var(--font-size-x-small);
102
+ border-inline-start: 3px solid var(--modal-bg-color);
103
+ transition: 0.3s;
104
+ transition-property: border-color, background-color;
105
+ &:first-of-type{
106
+ margin-top: var(--size-value1);
107
+ }
108
+ &:last-of-type{
109
+ margin-bottom: var(--size-value1);
110
+ }
111
+ &:hover{
112
+ border-color: var(--gray-lighten-3);
113
+ background-color: var(--gray-lighten-3);
114
+ }
115
+ &:focus{
116
+ border: 3px solid var(--v-secondary-lighten1);
117
+ }
118
+ &:active:not(.mobile){
119
+ border-color: var(--gray-lighten-1);
120
+ background-color: var(--gray-lighten-1);
121
+ }
122
+ &.selected{
123
+ font-weight: var(--font-weight-large);
124
+ }
125
+ &.selected:not(.mobile){
126
+ border-inline-start: 3px solid var(--v-secondary-base);
127
+ }
128
+ &.disabled{
129
+ cursor: unset;
130
+ pointer-events: none;
131
+ border-color: var(--gray-lighten-3);
132
+ background-color: var(--gray-lighten-3);
133
+ color: var(--gray-darken-2);
134
+ }
135
+ &.mobile{
136
+ color: var(--gray-darken-5);
137
+ height: var(--size-value13);
138
+ ::v-deep{
139
+ svg.vc-chevron-right {
140
+ fill: var(--gray-darken-2);
141
+ }
142
+ }
143
+ &.rtl{
144
+ ::v-deep{
145
+ svg.vc-chevron-right {
146
+ transform: scaleX(-1);
147
+ }
148
+ }
149
+ }
150
+ }
151
+ }
152
+ }
153
+ }
154
+ }
155
+ </style>
@@ -87,7 +87,7 @@ describe("VcLink.vue", () => {
87
87
  const vcIconComponent = getByTestId('VcIcon');
88
88
  expect(vcIconComponent).toBeInTheDocument();
89
89
  expect(vcIconComponent).toHaveClass('prepend-icon');
90
- expect(vcIconComponent).toHaveTextContent('$trash');
90
+ expect(vcIconComponent).toHaveTextContent('trash');
91
91
  });
92
92
 
93
93
  it("prepend icon - copy icon shows", () => {
@@ -101,7 +101,7 @@ describe("VcLink.vue", () => {
101
101
  const vcIconComponent = getByTestId('VcIcon');
102
102
  expect(vcIconComponent).toBeInTheDocument();
103
103
  expect(vcIconComponent).toHaveClass('prepend-icon');
104
- expect(vcIconComponent).toHaveTextContent('$copy');
104
+ expect(vcIconComponent).toHaveTextContent('copy');
105
105
  });
106
106
 
107
107
  it("prepend icon - left icon shows", () => {
@@ -115,7 +115,7 @@ describe("VcLink.vue", () => {
115
115
  const vcIconComponent = getByTestId('VcIcon');
116
116
  expect(vcIconComponent).toBeInTheDocument();
117
117
  expect(vcIconComponent).toHaveClass('prepend-icon');
118
- expect(vcIconComponent).toHaveTextContent('$chevron_left');
118
+ expect(vcIconComponent).toHaveTextContent('left');
119
119
  });
120
120
 
121
121
  it('link click emits event', async () => {
@@ -1,4 +1,4 @@
1
- import {default as VcLinkCmp, VcLinkIcons} from './VcLink';
1
+ import {default as VcLinkCmp} from './VcLink';
2
2
  import VcBaseDocs from "@/stories/VcBaseDocs.mdx";
3
3
 
4
4
  const baseProps = {
@@ -41,7 +41,7 @@ export const WithPrependIcon = Template.bind({});
41
41
  // Set default values
42
42
  WithPrependIcon.args = {
43
43
  ...baseProps,
44
- prependIcon: 'left'
44
+ prependIcon: 'copy'
45
45
  }
46
46
 
47
47
  export default {
@@ -50,10 +50,6 @@ export default {
50
50
  component: VcLinkCmp,
51
51
  argTypes: {
52
52
  onClick: {action: 'onClick', table: {disable: true}},
53
- prependIcon: {
54
- options: Object.values(VcLinkIcons),
55
- control: {type: 'select'}
56
- },
57
53
  target:{
58
54
  options: ['_blank', '_self', '_parent', '_top', '_system'],
59
55
  control: {type: 'radio'}
@@ -4,16 +4,13 @@
4
4
  :class="{'link-secondary': secondary, 'disabled' : disabled}"
5
5
  :data-qa="dataQa"
6
6
  @click="$emit('click')">
7
- <VcIcon v-if="!!prependIcon" class="prepend-icon" small>{{ getIcon }}</VcIcon>
7
+ <VcIcon v-if="!!prependIcon" class="prepend-icon" small>{{ prependIcon }}</VcIcon>
8
8
  <label>{{ label }}</label>
9
9
  </a>
10
10
  </template>
11
11
 
12
12
  <script>
13
13
  import VcIcon from "@/components/VcIcon/VcIcon.vue";
14
-
15
- export const VcLinkIcons = ['', 'copy', 'trash', 'left'];
16
-
17
14
  export default {
18
15
  name: "VcLink",
19
16
  components: {VcIcon},
@@ -33,7 +30,6 @@ export default {
33
30
  prependIcon: {
34
31
  type: String,
35
32
  required: false,
36
- validator: prop => VcLinkIcons.includes(prop)
37
33
  },
38
34
  dataQa: {
39
35
  type: String,
@@ -48,19 +44,6 @@ export default {
48
44
  type: Boolean,
49
45
  default: false,
50
46
  }
51
- },
52
- computed: {
53
- getIcon() {
54
- switch (this.prependIcon) {
55
- case 'copy':
56
- return '$copy';
57
- case 'trash':
58
- return '$trash';
59
- case 'left':
60
- default:
61
- return '$chevron_left';
62
- }
63
- },
64
47
  }
65
48
  }
66
49
  </script>
@@ -0,0 +1,120 @@
1
+ import '@testing-library/jest-dom'
2
+ import VcDropdown from "./VcDropdown.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
+
8
+ init();
9
+
10
+ Vue.use(Vuetify)
11
+
12
+ describe("VcDropdown.vue", () => {
13
+
14
+ const renderWithVuetify = (component, options, callback, isMobile = false) => {
15
+ const root = document.createElement('div');
16
+ root.setAttribute('data-app', 'true');
17
+ root.setAttribute('id', 'root');
18
+
19
+ const vuetify = new Vuetify()
20
+ if (isMobile) {
21
+ const breakpoint = {
22
+ init: jest.fn(),
23
+ framework: {},
24
+ smAndDown: true,
25
+ }
26
+
27
+ vuetify.framework.breakpoint = breakpoint;
28
+ }
29
+
30
+ return render(
31
+ component,
32
+ {
33
+ container: document.body.appendChild(root),
34
+ // for Vuetify components that use the vuetify instance property
35
+ vuetify,
36
+ ...options,
37
+ mocks: {
38
+ $t: value => value,
39
+ $dst: value => value, // <- for the design system
40
+ },
41
+ },
42
+ callback,
43
+ )
44
+ }
45
+
46
+ it("mounts", () => {
47
+ // Queries: https://testing-library.com/docs/queries/about#types-of-queries
48
+ const {container, getByTestId, getByText} = renderWithVuetify(VcDropdown, {
49
+ props: {
50
+ attach: '#root',
51
+ value: true,
52
+ },
53
+ slots: {
54
+ header: '<div>slot header</div>',
55
+ default: '<div>slot content</div>',
56
+ footer: '<div>slot footer</div>',
57
+ },
58
+ })
59
+
60
+ // Expect options: https://github.com/testing-library/jest-dom
61
+ expect(container).toHaveAttribute('data-app', 'true');
62
+
63
+ // Make sure the component has the data-qa attribute
64
+ const header = getByTestId('VcDropdown-header');
65
+ expect(header).toBeInTheDocument();
66
+ const headerSlot = getByText('slot header');
67
+ expect(headerSlot).toBeInTheDocument();
68
+
69
+ const content = getByTestId('VcDropdown-content');
70
+ expect(content).toBeInTheDocument();
71
+ const contentSlot = getByText('slot content');
72
+ expect(contentSlot).toBeInTheDocument();
73
+
74
+ const footer = getByTestId('VcDropdown-footer');
75
+ expect(footer).toBeInTheDocument();
76
+ const footerSlot = getByText('slot footer');
77
+ expect(footerSlot).toBeInTheDocument();
78
+ });
79
+
80
+ it("shows add another", () => {
81
+ // Queries: https://testing-library.com/docs/queries/about#types-of-queries
82
+ const {getByTestId, debug} = renderWithVuetify(VcDropdown, {
83
+ props: {
84
+ attach: '#root',
85
+ value: true,
86
+ showAddAnother: true,
87
+ },
88
+ slots: {
89
+ header: '<div>slot header</div>',
90
+ default: '<div>slot content</div>',
91
+ },
92
+ });
93
+
94
+ expect(getByTestId('VcDropdown-add')).toBeInTheDocument();
95
+
96
+ debug();
97
+
98
+
99
+ });
100
+
101
+ it("overrides add another label", () => {
102
+ // Queries: https://testing-library.com/docs/queries/about#types-of-queries
103
+ const {getByTestId, getByText} = renderWithVuetify(VcDropdown, {
104
+ props: {
105
+ attach: '#root',
106
+ value: true,
107
+ showAddAnother: true,
108
+ addAnotherLabel: 'override label',
109
+ },
110
+ slots: {
111
+ header: '<div>slot header</div>',
112
+ default: '<div>slot content</div>',
113
+ },
114
+ });
115
+
116
+ expect(getByTestId('VcDropdown-add')).toBeInTheDocument();
117
+ expect(getByText('override label')).toBeInTheDocument();
118
+ });
119
+
120
+ });
@@ -0,0 +1,272 @@
1
+ import VcDropdown from './VcDropdown';
2
+ import VcBaseDocs from '@/stories/VcBaseDocs.mdx'
3
+ import VcButton from "@/components/VcButton/VcButton";
4
+ import VcLayout from "@/components/VcLayout/VcLayout";
5
+ import VcSearchBar from "@/components/VcSearchBar/VcSearchBar";
6
+ import VcGroupedItems from "@/components/VcGroupedItems/VcGroupedItems";
7
+ import VcCheckbox from "@/components/VcCheckbox/VcCheckbox";
8
+ import VcList from "@/components/list/VcList/VcList";
9
+ import VcBadge from "@/components/VcBadge/VcBadge";
10
+
11
+ const Template = (args, {argTypes}) => ({
12
+ components: {VcDropdown, VcButton, VcLayout, VcSearchBar, VcGroupedItems, VcList, VcCheckbox, VcBadge},
13
+ props: Object.keys(argTypes),
14
+ data: () => ({
15
+ filter: '',
16
+ }),
17
+ template: `
18
+ <div>
19
+ You can use any props and events on this component that you can use on VcMenu
20
+ <br>
21
+ <VcDropdown :max-height="maxHeight" :dataQa="dataQa"
22
+ :show-add-another="showAddAnother" :add-another-label="addAnotherLabel"
23
+ @onAddItem="onAddItem">
24
+ <template #activator="{ on, attrs }">
25
+ ${args.activator}
26
+ </template>
27
+ <template #header v-if="header">
28
+ ${args.header}
29
+ </template>
30
+ ${args.default}
31
+ <template #footer v-if="footer">
32
+ ${args.footer}
33
+ </template>
34
+ </VcDropdown>
35
+ </div>`,
36
+ methods: {
37
+ onSearch(data) {
38
+ this.onSearchEvent(data);
39
+ this.filter = data;
40
+ },
41
+ },
42
+ computed: {
43
+ filteredItems() {
44
+ return this.listItems.filter(item => {
45
+ if (item.avatar?.name)
46
+ return item.avatar.name.toLowerCase().includes(this.filter);
47
+ else
48
+ return true;
49
+ });
50
+ },
51
+ }
52
+ });
53
+
54
+ export const Playground = Template.bind({});
55
+
56
+ // Set default values
57
+ Playground.args = {
58
+ dataQa: 'VcDropdown',
59
+ maxHeight: 297,
60
+ activator: `<VcButton v-bind='attrs' v-on='on'>Click me</VcButton>`,
61
+ header: `<VcLayout :style="{ minHeight: '48px', minWidth: '220px' ,backgroundColor: 'var(--green-lighten-2)', border: 'dashed var(--green)'}">header slot (sticky)</VcLayout>`,
62
+ default: `<VcLayout :style="{ minHeight: '400px', backgroundColor: 'var(--green-lighten-2)',border: 'dashed var(--green)'}">content slot (scrolling)</VcLayout>`,
63
+ footer: `<VcLayout align-center justify-center :style="{ minHeight: '48px', backgroundColor: 'var(--green-lighten-2)', border: 'dashed var(--green)'}">footer slot (sticky)</VcLayout>`,
64
+ showAddAnother: false,
65
+ addAnotherLabel: '',
66
+ }
67
+
68
+ const listItems = [
69
+ {
70
+ disabled: true,
71
+ avatar:
72
+ {
73
+ name: 'Person One',
74
+ path: require('@/stories/assets/pics/avatar4.png'),
75
+ },
76
+ identifier: 0
77
+ },
78
+ {
79
+ disabled: true,
80
+ avatar: {
81
+ name: 'Person Two',
82
+ path: require('@/stories/assets/pics/avatar2.png'),
83
+ },
84
+ identifier: 1
85
+ },
86
+ {
87
+ selected: true,
88
+ avatar: {
89
+ name: 'Person Three',
90
+ path: require('@/stories/assets/pics/avatar1.png'),
91
+ },
92
+ identifier: 2
93
+ },
94
+ {
95
+ selected: true,
96
+ avatar: {
97
+ name: 'Person Four',
98
+ colorId: 3,
99
+ },
100
+ identifier: 3
101
+ },
102
+ {
103
+ avatar: {
104
+ name: 'Person Five',
105
+ colorId: 4,
106
+ },
107
+ identifier: 4
108
+ },
109
+ ];
110
+
111
+ export const SimpleListMenu = Template.bind({});
112
+
113
+ // Set default values
114
+ SimpleListMenu.args = {
115
+ dataQa: 'VcDropdown',
116
+ maxHeight: 297,
117
+ activator: `<VcButton v-bind='attrs' v-on='on'>Click me</VcButton>`,
118
+ default: `<VcList :items='filteredItems' multiple @select='onSelect'>
119
+ <template #default='item'>
120
+ <VcCheckbox :label='item.avatar.name'
121
+ :avatar='item.avatar'
122
+ :checked='item.selected'
123
+ :disabled='item.disabled'
124
+ :show-border='false'
125
+ style='padding: 0; margin: 0; flex: 1 1 auto'/>
126
+ </template>
127
+ </VcList>`,
128
+ listItems,
129
+ }
130
+
131
+ export const WithSearchAndAddItem = Template.bind({});
132
+
133
+ // Set default values
134
+ WithSearchAndAddItem.args = {
135
+ dataQa: 'VcDropdown',
136
+ activator: `<VcButton v-bind='attrs' v-on='on'>Click me</VcButton>`,
137
+ header: `<VcLayout :style="{margin: '4px'}"><VcSearchBar size='medium' @search='onSearch'></VcSearchBar></VcLayout>`,
138
+ default: `<VcList :items='filteredItems' multiple @select='onSelect'>
139
+ <template #default='item'>
140
+ <VcCheckbox :label='item.avatar.name'
141
+ :avatar='item.avatar'
142
+ :checked='item.selected'
143
+ :disabled='item.disabled'
144
+ show-border='false'
145
+ style='padding: 0; margin: 0; flex: 1 1 auto'/>
146
+ </template>
147
+ </VcList>`,
148
+ showAddAnother: true,
149
+ listItems,
150
+ }
151
+
152
+ const menuItems = [
153
+ {
154
+ label: 'GROUP 1',
155
+ id: 1,
156
+ items: [
157
+ {id: '1', label: 'Menu Item 1'},
158
+ {id: '2', label: 'Menu Item 2'},
159
+ {id: '3', label: 'Menu Item 3'},
160
+ {id: '4', label: 'Menu Item 4'},
161
+ {id: '5', label: 'Menu Item 5', disabled: true},
162
+ ]
163
+ },
164
+ {
165
+ label: 'GROUP 2',
166
+ id: 2,
167
+ items: [
168
+ {id: '6', label: 'Menu Item 6'},
169
+ {id: '7', label: 'Menu Item 7'},
170
+ {id: '8', label: 'Menu Item 8'},
171
+ {id: '9', label: 'Menu Item 9'},
172
+ {id: '10', label: 'Menu Item 10'},
173
+ ]
174
+ },
175
+ ];
176
+
177
+ const GroupedTemplate = (args, {argTypes}) => ({
178
+ components: {VcDropdown, VcButton, VcLayout, VcGroupedItems, VcCheckbox},
179
+ props: Object.keys(argTypes),
180
+ template: `
181
+ <div>
182
+ You can use any props and events on this component that you can use on VcMenu
183
+ <br>
184
+ <VcDropdown :max-height="maxHeight" :dataQa="dataQa"
185
+ :show-add-another="showAddAnother" :add-another-label="addAnotherLabel"
186
+ @onAddItem="onAddItem">
187
+ <template #activator="{ on, attrs }">
188
+ ${args.activator}
189
+ </template>
190
+ <template #header v-if="header">
191
+ ${args.header}
192
+ </template>
193
+ ${args.default}
194
+ <template #footer v-if="footer">
195
+ ${args.footer}
196
+ </template>
197
+ </VcDropdown>
198
+ </div>`,
199
+ methods: {
200
+ getItemSlotName(itemId) {
201
+ return `item-${itemId}`;
202
+ },
203
+ },
204
+ computed: {
205
+ allGroupedItems() {
206
+ return this.menuItems.reduce((acc, group) => acc.concat(group.items), []);
207
+ }
208
+ }
209
+ });
210
+
211
+ export const WithGroupedItems = GroupedTemplate.bind({});
212
+
213
+ // Set default values
214
+ WithGroupedItems.args = {
215
+ dataQa: 'VcDropdown',
216
+ maxHeight: 297,
217
+ activator: `<VcButton v-bind='attrs' v-on='on'>Click me</VcButton>`,
218
+ default: `<VcLayout :style="{ minHeight: '400px'}">
219
+ <VcGroupedItems :item-groups='menuItems' show-dividers @change='onChange'>
220
+ <template #group-1-header='groupData'>
221
+ <div class='d-flex align-center'>
222
+ <span>{{groupData.group.label}}</span>
223
+ <VcBadge class='ps-2' badgeText='new' :offsetX='-2' :offsetY='0'></VcBadge>
224
+ </div>
225
+ </template>
226
+
227
+ <template v-for='item in allGroupedItems' #[getItemSlotName(item.id)]='data'>
228
+ <div class='d-flex align-center flex-grow-1 px-4'>
229
+ <VcCheckbox :label='item.label'
230
+ :checked='item.selected'
231
+ :disabled='item.disabled'
232
+ :show-border='false'
233
+ style='padding: 0; margin: 0; flex: 1 1 auto'/>
234
+ </div>
235
+ </template>
236
+ <template v-for='item in allGroupedItems' #item-4>
237
+ <div class='d-flex align-center flex-grow-1 px-4'>
238
+ <span>Slot display override</span>
239
+ <VcBadge class='ps-2' badgeText='new' :offsetX='-2' :offsetY='0'></VcBadge>
240
+ </div>
241
+ </template>
242
+ </VcGroupedItems>
243
+ </VcLayout>`,
244
+ menuItems,
245
+ showAddAnother: true,
246
+ addAnotherLabel: 'Click to add item',
247
+ }
248
+
249
+ export default {
250
+ title: 'containers / menu / VcDropdown', // This will control the story sidebar position
251
+ id: 'VcDropdown', // This will be the permanent link to this component
252
+ component: VcDropdown,
253
+ argTypes: {
254
+ onSelect: {action: 'select', table: {disable: true}},
255
+ onSearchEvent: {action: 'search', table: {disable: true}},
256
+ onChange: {action: 'change', table: {disable: true}},
257
+ },
258
+ parameters: {
259
+ design: {
260
+ type: 'figma',
261
+ url: 'https://www.figma.com/file/xIOY6fBoA1wpy1tHv3i5js/vcita---ui-library?node-id=251%3A908',
262
+ },
263
+ status: {
264
+ type: 'beta', // 'beta' | 'stable' | 'deprecated' | 'releaseCandidate'
265
+ },
266
+ docs: {
267
+ page: VcBaseDocs,
268
+ inlineStories: false,
269
+ iframeHeight: 400,
270
+ },
271
+ },
272
+ };