@vcita/design-system 1.2.1 → 1.2.3

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 (53) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/config/locales/ds.en.yml +5 -1
  3. package/dist/@vcita/design-system.esm.js +1492 -913
  4. package/dist/@vcita/design-system.min.js +2 -2
  5. package/dist/@vcita/design-system.ssr.js +1290 -811
  6. package/package.json +1 -1
  7. package/src/components/VcAvatar/VcAvatar.stories.js +0 -1
  8. package/src/components/VcButton/VcButton.stories.js +23 -23
  9. package/src/components/VcChip/VcChip.stories.js +3 -2
  10. package/src/components/VcChipList/VcChipList.stories.js +34 -21
  11. package/src/components/VcGalleryItem/VcGalleryItem.spec.js +120 -0
  12. package/src/components/VcGalleryItem/VcGalleryItem.stories.js +94 -0
  13. package/src/components/VcGalleryItem/VcGalleryItem.vue +161 -0
  14. package/src/components/VcGalleryList/VcGalleryList.spec.js +86 -0
  15. package/src/components/VcGalleryList/VcGalleryList.stories.js +63 -0
  16. package/src/components/VcGalleryList/VcGalleryList.vue +102 -0
  17. package/src/components/VcGalleryList/mockData.js +50 -0
  18. package/src/components/VcIcon/VcIcon.stories.js +30 -7
  19. package/src/components/VcIcon/VcIcon.vue +11 -2
  20. package/src/components/VcMiniBanner/VcMiniBanner.spec.js +74 -0
  21. package/src/components/VcMiniBanner/VcMiniBanner.stories.js +75 -0
  22. package/src/components/VcMiniBanner/VcMiniBanner.vue +129 -0
  23. package/src/components/VcSearchPicker/VcSearchPicker.vue +12 -5
  24. package/src/components/VcSideNav/VcSideNav.spec.js +105 -0
  25. package/src/components/VcSideNav/VcSideNav.stories.js +117 -0
  26. package/src/components/VcSideNav/VcSideNav.vue +136 -0
  27. package/src/components/VcTextField/VcTextField.stories.js +60 -101
  28. package/src/components/VcTextField/VcTextField.vue +4 -0
  29. package/src/components/index.js +4 -0
  30. package/src/components/list/VcList/pattern/VcMobilePickerPattern.stories.js +22 -8
  31. package/src/components/list/VcListEntity/VcListEntity.stories.js +14 -19
  32. package/src/components/modal/VcConfirmModal/VcConfirmModal.stories.js +73 -46
  33. package/src/components/modal/VcConfirmModal/VcConfirmModal.vue +12 -2
  34. package/src/components/modal/VcConfirmProminentModal/VcConfirmProminentModal.stories.js +6 -10
  35. package/src/components/modal/VcConfirmProminentModal/VcConfirmProminentModal.vue +5 -0
  36. package/src/components/modal/VcInputModal/VcInputModal.stories.js +47 -56
  37. package/src/components/modal/VcInputModal/VcInputModal.vue +2 -1
  38. package/src/components/modal/VcNoticeModal/VcNoticeModal.stories.js +36 -45
  39. package/src/components/modal/VcNoticeModal/VcNoticeModal.vue +5 -0
  40. package/src/components/modal/elements/VcModalContainer.stories.js +35 -12
  41. package/src/components/modal/elements/VcModalContainer.vue +8 -1
  42. package/src/components/modal/elements/VcModalFooter.stories.js +10 -6
  43. package/src/components/modal/elements/VcModalWrapper.stories.js +13 -6
  44. package/src/stories/assets/app-market/fc.svg +31 -0
  45. package/src/stories/assets/app-market/google.svg +1 -0
  46. package/src/stories/assets/app-market/qb.svg +9 -0
  47. package/src/stories/assets/app-market/stripe.svg +1 -0
  48. package/src/stories/assets/app-market/zapier.svg +1 -0
  49. package/src/stories/assets/pics/gallery-item-1.jpg +0 -0
  50. package/src/stories/assets/pics/gallery-item-2.jpg +0 -0
  51. package/src/stories/assets/pics/gallery-item-3.jpg +0 -0
  52. package/src/stories/assets/pics/gallery-item-4.jpg +0 -0
  53. package/src/stories/assets/pics/gallery-item-5.jpg +0 -0
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.3",
4
4
  "description": "vcita design system",
5
5
  "author": "vcita",
6
6
  "scripts": {
@@ -230,7 +230,6 @@ export default {
230
230
  id: 'VcAvatar', // This will be the link to this component
231
231
  component: VcAvatarCmp,
232
232
  description: 'some desctext',
233
- id: 'VcAvatarCmp',
234
233
  argTypes: {
235
234
  size: {
236
235
  options: ['x-sm', 'sm', 'md', 'lg'],
@@ -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 {
@@ -0,0 +1,120 @@
1
+ import '@testing-library/jest-dom'
2
+ import VcGalleryItem from './VcGalleryItem.vue';
3
+ import Vuetify from 'vuetify'
4
+ import { render } from '@testing-library/vue';
5
+ import init from '../../../testing-library.config';
6
+ import { fireEvent } from "@testing-library/dom";
7
+
8
+ init();
9
+
10
+ const baseProps = {
11
+ uid: '1a',
12
+ label: 'Correct item label',
13
+ isMobile: false,
14
+ isCreate: false,
15
+ };
16
+
17
+ describe('VcGalleryItem.vue', () => {
18
+
19
+ const renderWithVuetify = (options, callback) => {
20
+ const root = document.createElement('div')
21
+ root.setAttribute('data-app', 'true')
22
+
23
+ return render(
24
+ VcGalleryItem,
25
+ {
26
+ container: document.body.appendChild(root),
27
+ vuetify: new Vuetify(),
28
+ ...options,
29
+ mocks: {$dst: value => value},
30
+ },
31
+ callback,
32
+ )
33
+ }
34
+
35
+ it('Mounts', () => {
36
+ const {container} = renderWithVuetify({
37
+ props: baseProps
38
+ })
39
+ expect(container).toHaveAttribute('data-app', 'true')
40
+ });
41
+
42
+ it('Displays slot content', async () => {
43
+ const labelSlotContent = 'label slot content';
44
+ const buttonSlotContent = 'slot-button';
45
+ const {queryByText, getByTestId} = renderWithVuetify({
46
+ props: baseProps,
47
+ slots: {
48
+ actions: `<div>${buttonSlotContent}</div>`,
49
+ label: `<div>${labelSlotContent}</div>`,
50
+ },
51
+ })
52
+ expect(queryByText(labelSlotContent)).toBeInTheDocument();
53
+ const VcGalleryItem = getByTestId('VcGalleryItem');
54
+ await fireEvent.mouseEnter(VcGalleryItem);
55
+ expect(queryByText(buttonSlotContent)).toBeInTheDocument();
56
+ });
57
+
58
+ it('Button events emission', async () => {
59
+ const {getByTestId, emitted} = renderWithVuetify({
60
+ props: baseProps
61
+ })
62
+ const VcGalleryItem = getByTestId('VcGalleryItem');
63
+ await fireEvent.mouseEnter(VcGalleryItem);
64
+ const selectBtn = getByTestId('VcGalleryItem-select-btn')
65
+ const previewBtn = getByTestId('VcGalleryItem-preview-btn')
66
+ await fireEvent.click(selectBtn)
67
+ await fireEvent.click(previewBtn)
68
+ expect(emitted().onSelect.length).toBe(1)
69
+ expect(emitted().onPreview.length).toBe(1)
70
+ });
71
+
72
+ it('Mobile events emission', async () => {
73
+ const {getByTestId, emitted, updateProps} = renderWithVuetify({
74
+ props: Object.assign(baseProps, { isMobile: true })
75
+ })
76
+ const thumbnail = getByTestId('VcGalleryItem-thumbnail');
77
+ await fireEvent.click(thumbnail);
78
+ expect(emitted().onExpend.length).toBe(1);
79
+ await updateProps({ isMobile: false })
80
+ await fireEvent.click(thumbnail);
81
+ expect(emitted().onExpend.length).toBe(1);
82
+ });
83
+
84
+ it('Displays correct label', async () => {
85
+ const {queryByText, updateProps} = renderWithVuetify({
86
+ props: baseProps
87
+ })
88
+ expect(queryByText(baseProps.label)).toBeInTheDocument();
89
+ expect(queryByText(baseProps.label.repeat(2))).toBeNull();
90
+ await updateProps({label: baseProps.label.repeat(2)})
91
+ expect(queryByText(baseProps.label.repeat(2))).toBeInTheDocument();
92
+ });
93
+
94
+
95
+ it('Toggle isCreate modifier class', async () => {
96
+ const {getByTestId, updateProps} = renderWithVuetify({
97
+ props: baseProps
98
+ })
99
+ const VcGalleryItem = getByTestId('VcGalleryItem');
100
+ expect(VcGalleryItem).not.toHaveClass('vc-gallery-item--is-create');
101
+ await fireEvent.mouseEnter(VcGalleryItem);
102
+ await updateProps({ isCreate: true })
103
+ expect(VcGalleryItem).toHaveClass('vc-gallery-item--is-create');
104
+ });
105
+
106
+ it('Fires onCreate event', async () => {
107
+ const {getByTestId, updateProps, emitted} = renderWithVuetify({
108
+ props: Object.assign(baseProps, { isCreate: true })
109
+ })
110
+ const VcGalleryItem = getByTestId('VcGalleryItem');
111
+ const thumbnail = getByTestId('VcGalleryItem-thumbnail');
112
+ await fireEvent.mouseEnter(VcGalleryItem);
113
+ await fireEvent.click(thumbnail)
114
+ expect(emitted().onCreate.length).toBe(1)
115
+ await updateProps({ isCreate: false })
116
+ await fireEvent.click(thumbnail)
117
+ expect(emitted().onCreate.length).toBe(1)
118
+ });
119
+
120
+ });
@@ -0,0 +1,94 @@
1
+ import VcGalleryItemCmp from './VcGalleryItem';
2
+ import VcButton from '../VcButton/VcButton';
3
+ import VcIcon from '../VcIcon/VcIcon';
4
+
5
+ const baseProps = {
6
+ isMobile: false,
7
+ uid: '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bef',
8
+ isCreate: false,
9
+ dataQa: 'VcGalleryItem',
10
+ }
11
+
12
+ const Template = (args, {argTypes}) => ({
13
+ components: { VcGalleryItem: VcGalleryItemCmp, VcButton, VcIcon },
14
+ props: Object.keys(argTypes),
15
+ template: `<div>
16
+ <div class="description" :style="{margin: '20px 0'}">
17
+ <h4 :style="{margin: '8px 0'}">
18
+ This component functions as a list/grid item and is meant to show inner content.
19
+ </h4>
20
+ <h4 :style="{fontWeight: 400}">
21
+ It keeps a specific ratio while it's text is flushed beneath.<br />
22
+ It presents control-buttons layer on hover, and a simplified click-action on mobile.<br />
23
+ It's slots api label and actions modularity.<br />
24
+ When 'isCreate' is passed as true, it functions as a 'new-item' button. <br />
25
+ </h4>
26
+ </div>
27
+ <VcGalleryItem :isMobile="isMobile"
28
+ :uid="uid"
29
+ :src="src"
30
+ :label="label"
31
+ :dataQa="dataQa"
32
+ :isCreate="isCreate"
33
+ @onSelect="onSelect"
34
+ @onPreview="onPreview"
35
+ @onExpend="onExpend"
36
+ @onCreate="onCreate"
37
+ >
38
+ <template #actions v-if="actionsSlotContent">
39
+ ${args.actionsSlotContent}
40
+ </template>
41
+ <template #label v-if="labelSlotContent">
42
+ ${args.labelSlotContent}
43
+ </template>
44
+ </VcGalleryItem>
45
+ </div>
46
+ `,
47
+ })
48
+
49
+ export const Playground = Template.bind({});
50
+ Playground.args = {
51
+ ...baseProps,
52
+ src: require('@/stories/assets/pics/gallery-item-1.jpg'),
53
+ label: 'Thank’s for your application',
54
+ }
55
+
56
+
57
+ export const LabelSlotContent = Template.bind({});
58
+ LabelSlotContent.args = {
59
+ ...baseProps,
60
+ src: require('@/stories/assets/pics/gallery-item-2.jpg'),
61
+ labelSlotContent: `<span :style="{color: 'green'}">Slot content label</span>`
62
+ }
63
+
64
+
65
+ export const ActionsSlotContent = Template.bind({});
66
+ ActionsSlotContent.args = {
67
+ ...baseProps,
68
+ src: require('@/stories/assets/pics/gallery-item-3.jpg'),
69
+ label: 'Thank’s for your application',
70
+ actionsSlotContent: `<VcButton @click="$emit('onSelect')" flavor="primary" label="Yes" class="buttons__select">
71
+ <template #prepend><VcIcon :style="{ marginRight: '12px' }">$check_circle</VcIcon></template>
72
+ </VcButton>`
73
+ }
74
+
75
+ export const CreateItem = Template.bind({});
76
+ CreateItem.args = {
77
+ ...baseProps,
78
+ isCreate: true,
79
+ }
80
+
81
+ export default {
82
+ title: 'Content display / VcGalleryItem',
83
+ id: 'VcGalleryItem',
84
+ component: VcGalleryItemCmp,
85
+ parameters: {
86
+ design: {
87
+ type: 'figma',
88
+ url: 'https://www.figma.com/file/7FONyMxCo0nkhyz013Xmai/Campaign-editor?node-id=1504%3A205665',
89
+ },
90
+ status: {
91
+ type: 'stable', // 'beta' | 'stable' | 'deprecated' | 'releaseCandidate'
92
+ },
93
+ },
94
+ };
@@ -0,0 +1,161 @@
1
+ <template>
2
+ <div class="vc-gallery-item" :data-qa="dataQa"
3
+ :class="{'vc-gallery-item--is-create': isCreate}">
4
+ <div class="vc-gallery-item__thumbnail"
5
+ :data-qa="`${dataQa}-thumbnail`"
6
+ @click="isCreate ? $emit('onCreate') : isMobile && $emit('onExpend', { uid })">
7
+ <div class="vc-gallery-item__image" :style="{ backgroundImage: `url(${src})` }" v-if="!isCreate" role="image" />
8
+ <div class="buttons flex-column align-center justify-center" v-if="!isMobile || isCreate" >
9
+ <slot name="actions">
10
+ <VcButton @click="$emit('onSelect', { uid })"
11
+ pill
12
+ :label="$dst('ds.gallery_item.select')"
13
+ :data-qa="`${dataQa}-select-btn`"
14
+ v-if="!isCreate"
15
+ class="buttons__select" />
16
+ <VcButton @click="$emit('onPreview', { uid })"
17
+ flavor="secondary"
18
+ pill
19
+ :label="$dst('ds.gallery_item.preview')"
20
+ :data-qa="`${dataQa}-preview-btn`"
21
+ v-if="!isCreate"
22
+ class="buttons__preview" />
23
+ <div class="create__wrap" v-else>
24
+ <VcButton class="create__button" icon plain :data-qa="`${dataQa}-create-button`">
25
+ <template #prepend>
26
+ <VcIcon size="32" :color="$vuetify.theme.defaults.light.secondary.base">$plus</VcIcon>
27
+ </template>
28
+ </VcButton>
29
+ </div>
30
+ </slot>
31
+ </div>
32
+ </div>
33
+ <h3 class="vc-gallery-item__label" :data-qa="`${dataQa}-label`">
34
+ <slot name="label">
35
+ {{ !isCreate ? label : $dst('ds.gallery_item.create') }}
36
+ </slot>
37
+ </h3>
38
+ </div>
39
+ </template>
40
+
41
+ <script>
42
+ import VcButton from "@/components/VcButton/VcButton.vue";
43
+ import VcIcon from "@/components/VcIcon/VcIcon.vue";
44
+ export default {
45
+ name: "VcGalleryItem",
46
+ components: {
47
+ VcButton,
48
+ VcIcon
49
+ },
50
+ props: {
51
+ dataQa: {
52
+ type: String,
53
+ default: 'VcGalleryItem'
54
+ },
55
+ isMobile: {
56
+ type: Boolean,
57
+ required: true
58
+ },
59
+ uid: {
60
+ type: String,
61
+ required: true
62
+ },
63
+ src: {
64
+ type: String,
65
+ default: ''
66
+ },
67
+ label: {
68
+ type: String,
69
+ default: ''
70
+ },
71
+ isCreate: {
72
+ type: Boolean,
73
+ required: false
74
+ },
75
+ },
76
+ }
77
+ </script>
78
+
79
+ <style lang="scss" scoped>
80
+ @import "../../scss/mixins.scss";
81
+
82
+ .vc-gallery-item {
83
+ max-width: 252px;
84
+ margin-bottom: var(--size-value4);
85
+
86
+ @include sm-and-up {
87
+ min-width: 200px;
88
+ }
89
+
90
+ .VcButton.secondary__text {
91
+ background-color: var(--v-secondary-lighten2);
92
+ color: var(--v-secondary-base)!important;
93
+ }
94
+
95
+ &__thumbnail {
96
+ position: relative;
97
+ height: 0;
98
+ padding-bottom: 136%;
99
+ border-radius: var(--border-radius);
100
+ box-shadow: var(--shadow-4);
101
+ margin-bottom: var(--size-value3);
102
+ overflow: hidden;
103
+
104
+ .vc-gallery-item--is-create & {
105
+ background: var(--v-secondary-lighten3);
106
+ border: 1px dashed var(--v-secondary-base);
107
+ }
108
+ }
109
+
110
+ &__image {
111
+ padding-bottom: inherit;
112
+ width: 100%;
113
+ height: 100%;
114
+ background-size: cover;
115
+ background-repeat: no-repeat;
116
+ background-position: top center;
117
+
118
+ .vc-gallery-item__thumbnail:hover & {
119
+ filter: blur(5px);
120
+ transition: filter 0.3s ease-out;
121
+ }
122
+ }
123
+
124
+ &__label {
125
+ font-weight: var(--font-weight-medium2);
126
+ font-size: var(--font-size-small);
127
+ line-height: 1.5;
128
+ text-align: center;
129
+ color: var(--gray-darken-5);
130
+
131
+ .vc-gallery-item--is-create & {
132
+ color: var(--v-secondary-base);
133
+ }
134
+ }
135
+ }
136
+
137
+ .buttons {
138
+ position: absolute;
139
+ width: 100%;
140
+ height: 100%;
141
+ left: 0;
142
+ top: 0;
143
+ background-color: rgba(0, 0, 0, 0.7);
144
+ display: none;
145
+
146
+ .vc-gallery-item--is-create & {
147
+ display: flex;
148
+ background-color: var(--neutral-lighten-3);
149
+ cursor: pointer;
150
+ }
151
+
152
+ .vc-gallery-item__thumbnail:hover & {
153
+ display: flex;
154
+ }
155
+
156
+ &__select {
157
+ margin-bottom: var(--size-value4);
158
+ }
159
+
160
+ }
161
+ </style>
@@ -0,0 +1,86 @@
1
+ import '@testing-library/jest-dom'
2
+ import VcGalleryList from './VcGalleryList.vue';
3
+ import Vuetify from 'vuetify'
4
+ import { render } from '@testing-library/vue';
5
+ import init from '../../../testing-library.config';
6
+ import { fireEvent } from "@testing-library/dom";
7
+ import { items } from './mockData';
8
+
9
+ init();
10
+
11
+ const baseProps = {
12
+ isMobile: false,
13
+ showCreate: true,
14
+ items,
15
+ title: 'Nice list'
16
+ };
17
+
18
+ describe('VcGalleryList.vue', () => {
19
+
20
+ const renderWithVuetify = (options, callback) => {
21
+ const root = document.createElement('div')
22
+ root.setAttribute('data-app', 'true')
23
+
24
+ return render(
25
+ VcGalleryList,
26
+ {
27
+ container: document.body.appendChild(root),
28
+ vuetify: new Vuetify(),
29
+ ...options,
30
+ mocks: { $dst: value => value },
31
+ },
32
+ callback,
33
+ )
34
+ }
35
+
36
+ it('Mounts', () => {
37
+ const {container} = renderWithVuetify({
38
+ props: baseProps
39
+ })
40
+ expect(container).toHaveAttribute('data-app', 'true')
41
+ });
42
+
43
+ it('Renders correct title', async () => {
44
+ const { queryByText, updateProps } = renderWithVuetify({
45
+ props: baseProps
46
+ });
47
+ expect(queryByText(baseProps.title.repeat(2))).not.toBeInTheDocument();
48
+ expect(queryByText(baseProps.title)).toBeInTheDocument();
49
+ await updateProps({ title: baseProps.title.repeat(2) })
50
+ expect(queryByText(baseProps.title.repeat(2))).toBeInTheDocument();
51
+ });
52
+
53
+ it('Toggles title rendering', async () => {
54
+ const { queryByTestId, updateProps } = renderWithVuetify({
55
+ props: baseProps
56
+ });
57
+ const title = queryByTestId('VcGalleryList-title')
58
+ expect(title).toBeTruthy();
59
+ await updateProps({ title: '' })
60
+ const currentTitle = queryByTestId('VcGalleryList-title')
61
+ expect(currentTitle).toBeFalsy();
62
+ });
63
+
64
+ it('Toggles "create" button display', async () => {
65
+ const { queryByTestId, updateProps } = renderWithVuetify({
66
+ props: baseProps
67
+ });
68
+ const createBtn = queryByTestId('create-thumbnail')
69
+ expect(createBtn).toBeTruthy();
70
+ await updateProps({ showCreate: false })
71
+ const currentCreateBtn = queryByTestId('create-thumbnail')
72
+ expect(currentCreateBtn).toBeFalsy();
73
+ });
74
+
75
+ it('Events emission', async () => {
76
+ const { queryByTestId, emitted } = renderWithVuetify({
77
+ props: baseProps
78
+ });
79
+ const createBtn = queryByTestId('create-thumbnail')
80
+ expect(createBtn).toBeTruthy();
81
+ expect(emitted().onCreate).toBeFalsy()
82
+ await fireEvent.click(createBtn)
83
+ expect(emitted().onCreate.length).toBe(1)
84
+ });
85
+
86
+ });