@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.
- package/CHANGELOG.md +11 -0
- package/config/locales/ds.en.yml +5 -1
- package/dist/@vcita/design-system.esm.js +1492 -913
- package/dist/@vcita/design-system.min.js +2 -2
- package/dist/@vcita/design-system.ssr.js +1290 -811
- package/package.json +1 -1
- package/src/components/VcAvatar/VcAvatar.stories.js +0 -1
- 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/VcGalleryItem/VcGalleryItem.spec.js +120 -0
- package/src/components/VcGalleryItem/VcGalleryItem.stories.js +94 -0
- package/src/components/VcGalleryItem/VcGalleryItem.vue +161 -0
- package/src/components/VcGalleryList/VcGalleryList.spec.js +86 -0
- package/src/components/VcGalleryList/VcGalleryList.stories.js +63 -0
- package/src/components/VcGalleryList/VcGalleryList.vue +102 -0
- package/src/components/VcGalleryList/mockData.js +50 -0
- package/src/components/VcIcon/VcIcon.stories.js +30 -7
- package/src/components/VcIcon/VcIcon.vue +11 -2
- package/src/components/VcMiniBanner/VcMiniBanner.spec.js +74 -0
- package/src/components/VcMiniBanner/VcMiniBanner.stories.js +75 -0
- package/src/components/VcMiniBanner/VcMiniBanner.vue +129 -0
- package/src/components/VcSearchPicker/VcSearchPicker.vue +12 -5
- 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 +4 -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/src/stories/assets/app-market/fc.svg +31 -0
- package/src/stories/assets/app-market/google.svg +1 -0
- package/src/stories/assets/app-market/qb.svg +9 -0
- package/src/stories/assets/app-market/stripe.svg +1 -0
- package/src/stories/assets/app-market/zapier.svg +1 -0
- package/src/stories/assets/pics/gallery-item-1.jpg +0 -0
- package/src/stories/assets/pics/gallery-item-2.jpg +0 -0
- package/src/stories/assets/pics/gallery-item-3.jpg +0 -0
- package/src/stories/assets/pics/gallery-item-4.jpg +0 -0
- package/src/stories/assets/pics/gallery-item-5.jpg +0 -0
package/package.json
CHANGED
|
@@ -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 {
|
|
@@ -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
|
+
});
|