@vcita/design-system 0.6.15 → 0.6.17-beta.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcita/design-system",
3
- "version": "0.6.15",
3
+ "version": "0.6.17-beta.0",
4
4
  "description": "vcita design system",
5
5
  "author": "vcita",
6
6
  "scripts": {
@@ -18,6 +18,7 @@
18
18
 
19
19
  import VcIcon from '@/components/VcIcon/VcIcon.vue'
20
20
  import VcTextField from "@/components/VcTextField/VcTextField.vue";
21
+
21
22
  const throttle = require("lodash.throttle")
22
23
 
23
24
  export default {
@@ -75,14 +76,16 @@ export default {
75
76
  </script>
76
77
 
77
78
  <style lang="scss" scoped>
78
- .vc-search-bar {
79
+ .vc-search-bar.VcTextInput {
79
80
  padding: var(--size-value0);
80
81
  margin: var(--size-value0);
81
82
 
82
83
  &.border-top-radius {
83
84
  ::v-deep {
84
- .v-input__slot {
85
- border-radius: var(--border-radius) var(--border-radius) var(--size-value0) var(--size-value0);
85
+ .v-input__control {
86
+ .v-input__slot {
87
+ border-radius: var(--border-radius) var(--border-radius) var(--size-value0) var(--size-value0);
88
+ }
86
89
  }
87
90
  }
88
91
  }
@@ -62,8 +62,6 @@ export default {
62
62
  },
63
63
  content: {
64
64
  type: String,
65
- required: true,
66
- validator: prop => prop.length > 0
67
65
  },
68
66
  top: {
69
67
  type: Boolean,
@@ -1,17 +1,17 @@
1
1
  <template>
2
2
  <VcTooltip :content="tooltipContent"
3
- dark
4
3
  :disabled="!tooltipContent || !disabled"
5
- class="VcChecklistItem-wrapper">
4
+ class="VcChecklistItem-wrapper"
5
+ dark>
6
6
  <template>
7
- <VcLayout class="VcChecklistItem" :data-qa="dataQa"
8
- :class="{'disabled': disabled}">
9
- <VcCheckbox :checked="checked"
10
- :avatar="getAvatar"
7
+ <VcLayout :class="{'disabled': disabled}" :data-qa="dataQa"
8
+ class="VcChecklistItem">
9
+ <VcCheckbox :avatar="getAvatar"
10
+ :checked="checked"
11
+ :data-qa="`${dataQa}-checkbox`"
12
+ :disabled="disabled"
11
13
  :label="label"
12
14
  :show-avatar-border="false"
13
- :disabled="disabled"
14
- :data-qa="`${dataQa}-checkbox`"
15
15
  @change="onChange">
16
16
 
17
17
  </VcCheckbox>
@@ -83,6 +83,10 @@ export default {
83
83
  .VcChecklistItem-wrapper {
84
84
  width: 100%;
85
85
 
86
+ &[hide=true] {
87
+ display: none;
88
+ }
89
+
86
90
  .VcChecklistItem {
87
91
  &.disabled {
88
92
  background-color: var(--gray-lighten-3);
@@ -4,6 +4,7 @@ import Vuetify from 'vuetify'
4
4
  import {render} from "@testing-library/vue";
5
5
  import init from "../../../../testing-library.config";
6
6
  import {fireEvent} from "@testing-library/dom";
7
+ import userEvent from "@testing-library/user-event";
7
8
 
8
9
  init();
9
10
 
@@ -14,13 +15,15 @@ const props = {
14
15
  label: 'Peter Parker',
15
16
  avatar: {
16
17
  path: require('@/stories/assets/pics/spider-man.png'),
17
- }
18
+ },
19
+ identifier: 0
18
20
  },
19
21
  {
20
22
  label: 'Tony Stark',
21
23
  avatar: {
22
24
  path: require('@/stories/assets/pics/ironman.png'),
23
- }
25
+ },
26
+ identifier: 1
24
27
  },
25
28
  {
26
29
  label: 'Bruce Banner',
@@ -28,13 +31,15 @@ const props = {
28
31
  path: require('@/stories/assets/pics/hulk.png'),
29
32
  },
30
33
  disabled: true,
31
- tooltipContent: 'Hulk is too STRONG'
34
+ tooltipContent: 'Hulk is too STRONG',
35
+ identifier: 2
32
36
  },
33
37
  {
34
38
  label: 'Clint Barton',
35
39
  avatar: {
36
40
  colorId: 13,
37
41
  },
42
+ identifier: 3
38
43
  },
39
44
  ],
40
45
  }
@@ -123,4 +128,60 @@ describe("VcListbox.vue", () => {
123
128
  expect(emitted().addNew.length).toBe(1);
124
129
  expect(getByText('add new Item')).toBeInTheDocument();
125
130
  });
126
- });
131
+
132
+ it("With search bar", async () => {
133
+ const {container, getByText, getByTestId} = renderWithVuetify(VcListbox, {
134
+ props: {
135
+ ...props,
136
+ addSearch: true,
137
+ }
138
+ })
139
+ const searchBar = getByTestId('vc-list-box-search')
140
+ expect(searchBar).toBeVisible()
141
+
142
+ props.items.forEach((item) => expect(getByText(item.label)).toBeVisible())
143
+
144
+ await userEvent.type(searchBar, 'peter')
145
+
146
+ const checklistItemWrappers = container.getElementsByClassName('VcChecklistItem-wrapper')
147
+
148
+ expect(checklistItemWrappers[0]).not.toHaveAttribute('hide', 'true')
149
+
150
+ for (let i = 1; i < props.items.length; i++) {
151
+ expect(checklistItemWrappers[i]).toHaveAttribute('hide', 'true')
152
+ }
153
+ });
154
+
155
+ it("Empty result from the search bar", async () => {
156
+ const {getByText, getByTestId, queryByText} = renderWithVuetify(VcListbox, {
157
+ props: {
158
+ ...props,
159
+ addSearch: true
160
+ }
161
+ })
162
+
163
+ props.items.forEach((item) => expect(getByText(item.label)).toBeVisible())
164
+
165
+ const searchBar = getByTestId('vc-list-box-search')
166
+ await userEvent.paste(searchBar, 'clark kent')
167
+
168
+ for (let i = 0; i < props.items.length; i++) {
169
+ expect(queryByText(props.items[i].label)).not.toBeInTheDocument()
170
+ }
171
+ });
172
+
173
+ it("Empty result from the search bar with unique empty list massage", async () => {
174
+ const {getByTestId} = renderWithVuetify(VcListbox, {
175
+ props: {
176
+ ...props,
177
+ addSearch: true,
178
+ emptyListMsg: 'No Avengers found'
179
+ }
180
+ })
181
+
182
+ const searchBar = getByTestId('vc-list-box-search')
183
+ await userEvent.paste(searchBar, 'clark kent')
184
+ const emptyCase = getByTestId('vc-list-box-empty')
185
+ expect(emptyCase).toHaveTextContent('No Avengers found')
186
+ });
187
+ });
@@ -9,6 +9,8 @@ const Template = (args, {argTypes}) => ({
9
9
  :title="title"
10
10
  :add-another="addAnother"
11
11
  :add-another-label="addAnotherLabel"
12
+ :add-search="addSearch"
13
+ :empty-list-msg="emptyListMsg"
12
14
  :data-qa="dataQa"
13
15
  @change="onChange"
14
16
  @addNew="onAddNew">
@@ -21,28 +23,33 @@ export const Playground = Template.bind({});
21
23
  // Set default values
22
24
  Playground.args = {
23
25
  title: 'Avengers crew',
26
+ addSearch: false,
24
27
  addAnother: false,
25
28
  addAnotherLabel: 'Add new Avenger',
29
+ emptyListMsg: 'No Avengers found',
26
30
  dataQa: "vc-listbox",
27
31
  items: [
28
32
  {
29
33
  label: 'Peter Parker',
30
34
  avatar: {
31
35
  path: require('@/stories/assets/pics/spider-man.png'),
32
- }
36
+ },
37
+ identifier: 0
33
38
  },
34
39
  {
35
40
  label: 'Tony Stark',
36
41
  avatar: {
37
42
  path: require('@/stories/assets/pics/ironman.png'),
38
43
  },
39
- checked: true
44
+ checked: true,
45
+ identifier: 1
40
46
  },
41
47
  {
42
48
  label: 'Natasha Romanoff',
43
49
  avatar: {
44
50
  path: require('@/stories/assets/pics/black-widow.jpeg'),
45
- }
51
+ },
52
+ identifier: 2
46
53
  },
47
54
  {
48
55
  label: 'Bruce Banner',
@@ -50,13 +57,15 @@ Playground.args = {
50
57
  path: require('@/stories/assets/pics/hulk.png'),
51
58
  },
52
59
  disabled: true,
53
- tooltipContent: 'Hulk is too STRONG'
60
+ tooltipContent: 'Hulk is too STRONG',
61
+ identifier: 3
54
62
  },
55
63
  {
56
64
  label: 'Clint Barton',
57
65
  avatar: {
58
66
  colorId: 13,
59
67
  },
68
+ identifier: 4
60
69
  },
61
70
  ],
62
71
  onChange: action('changed'),
@@ -1,34 +1,48 @@
1
1
  <template>
2
2
  <div>
3
3
  <div v-if="title"
4
- class="vc-list-title"
5
- :data-qa="`${dataQa}-title`">
4
+ :data-qa="`${dataQa}-title`"
5
+ class="vc-list-title">
6
6
  {{ title }}
7
7
  </div>
8
8
 
9
- <v-list class="VcListbox"
10
- :data-qa="dataQa">
9
+ <v-list :class="{'with-search' : addSearch, 'with-add-another' : addAnother}"
10
+ :data-qa="dataQa"
11
+ class="VcListbox">
12
+ <VcSearchBar v-if="addSearch"
13
+ :data-qa="`${dataQa}-search`"
14
+ border-top-radius
15
+ @search="onSearch">
16
+ </VcSearchBar>
11
17
  <div class="vc-overflow">
12
18
  <v-list-item-group
19
+ v-if="listExist"
13
20
  :value="confirmedArray"
14
21
  multiple
15
22
  @change="onSelection">
16
- <VcTooltip v-for="(item, index) in items"
17
- :key="index"
18
- dark
23
+ <VcTooltip v-for="item in filteredItems"
24
+ :key="item.identifier"
19
25
  :content="item.tooltipContent"
26
+ :data-qa="`${dataQa}-${setDataQa(item.label)}-tooltip`"
20
27
  :disabled="!item.tooltipContent || !item.disabled"
21
- :data-qa="`${dataQa}-${setDataQa(item.label)}-tooltip`">
22
- <v-list-item class="vc-list-item"
23
- :tabindex="index"
28
+ dark>
29
+ <v-list-item :disabled="item.disabled"
30
+ :tabindex="`${item.label}-${item.identifier}`"
24
31
  :value="item"
25
- :disabled="item.disabled">
26
- <VcChecklistItem :data-qa="`${dataQa}-${setDataQa(item.label)}`"
27
- v-bind="item">
32
+ class="vc-list-item">
33
+ <VcChecklistItem v-bind="item"
34
+ :data-qa="`${dataQa}-${setDataQa(item.label)}`">
28
35
  </VcChecklistItem>
29
36
  </v-list-item>
30
37
  </VcTooltip>
31
38
  </v-list-item-group>
39
+ <VcLayout v-else
40
+ :data-qa="`${dataQa}-empty`"
41
+ align-center
42
+ class="VcListbox__empty"
43
+ justify-center>
44
+ {{ noItemsMsg }}
45
+ </VcLayout>
32
46
  </div>
33
47
 
34
48
  <div v-if="addAnother"
@@ -49,20 +63,26 @@
49
63
  import VcChecklistItem from "@/components/listBox/VcChecklistItem/VcChecklistItem.vue";
50
64
  import VcIcon from "@/components/VcIcon/VcIcon.vue";
51
65
  import VcTooltip from "@/components/VcTooltip/VcTooltip.vue";
66
+ import VcSearchBar from "@/components/VcSearchBar/VcSearchBar.vue";
67
+ import VcLayout from "@/components/VcLayout/VcLayout.vue";
52
68
 
53
69
  export default {
54
70
  name: "VcListbox",
55
- components: {VcChecklistItem, VcIcon, VcTooltip},
71
+ components: {VcLayout, VcSearchBar, VcChecklistItem, VcIcon, VcTooltip},
56
72
  props: {
57
73
  items: {
58
74
  type: Array,
59
75
  required: true,
60
- validator: items => items.every(item => item.label),
76
+ validator: items => items.every(item => item.label && item.identifier || item.identifier === 0),
61
77
  },
62
78
  addAnother: {
63
79
  type: Boolean,
64
80
  default: false
65
81
  },
82
+ addSearch: {
83
+ type: Boolean,
84
+ default: false
85
+ },
66
86
  addAnotherLabel: {
67
87
  type: String,
68
88
  default: ""
@@ -71,17 +91,38 @@ export default {
71
91
  type: String,
72
92
  default: ''
73
93
  },
94
+ emptyListMsg: {
95
+ type: String
96
+ },
74
97
  dataQa: {
75
98
  type: String,
76
99
  default: 'VcListbox'
77
100
  }
78
101
  },
102
+ data: () => ({
103
+ search: ''
104
+ }
105
+ ),
79
106
  computed: {
80
107
  getAddAnotherLabel() {
81
108
  return this.addAnotherLabel || this.$dst('ds.listbox.add')
82
109
  },
83
110
  confirmedArray() {
84
- return this.items.filter(item => item.checked)
111
+ return this.filteredItems.filter(item => item.checked)
112
+ },
113
+ filteredItems() {
114
+ return this.items.map((item) => (
115
+ {
116
+ ...item,
117
+ hide: !item.label.toLowerCase().includes(this.search),
118
+ })
119
+ )
120
+ },
121
+ listExist() {
122
+ return this.filteredItems.some((item) => !item.hide)
123
+ },
124
+ noItemsMsg() {
125
+ return this.emptyListMsg || this.$dst('ds.listbox.empty_list')
85
126
  }
86
127
  },
87
128
  methods: {
@@ -89,8 +130,11 @@ export default {
89
130
  const newSelections = selections.map((selected) => ({...selected, checked: true}))
90
131
  this.$emit('change', newSelections)
91
132
  },
133
+ onSearch(search) {
134
+ this.search = search
135
+ },
92
136
  setDataQa(label) {
93
- return label.replace(/ /g,'-')
137
+ return label.replace(/ /g, '-')
94
138
  }
95
139
  }
96
140
  };
@@ -115,13 +159,38 @@ export default {
115
159
  border-radius: var(--border-radius);
116
160
  box-shadow: none !important;
117
161
 
162
+ &.with-search {
163
+ border: none;
164
+
165
+ .vc-overflow {
166
+ border-inline: var(--border-frame);
167
+ border-block-end: var(--border-frame);
168
+ border-radius: 0 0 var(--border-radius) var(--border-radius);
169
+ }
170
+
171
+ &.with-add-another {
172
+ .vc-overflow {
173
+ border-inline: var(--border-frame);
174
+ border-block-end: unset;
175
+ border-radius: unset;
176
+ }
177
+
178
+ .last-item {
179
+ border-inline: var(--border-frame);
180
+ border-block-end: var(--border-frame);
181
+ border-radius: 0 0 var(--border-radius) var(--border-radius);
182
+ }
183
+ }
184
+ }
185
+
118
186
  .vc-overflow {
119
187
  overflow: auto;
120
- max-height: 160px;
188
+ height: 160px;
121
189
 
122
190
  .vc-list-item {
123
191
  padding: var(--size-value0);
124
192
  min-height: unset;
193
+
125
194
  &:before {
126
195
  opacity: 0;
127
196
  }
@@ -135,6 +204,7 @@ export default {
135
204
  .last-item {
136
205
  cursor: pointer;
137
206
  min-height: var(--size-value10);
207
+ padding-block: var(--size-value1) var(--size-value2);
138
208
 
139
209
  &:hover {
140
210
  background-color: var(--gray-lighten-3);
@@ -163,5 +233,12 @@ export default {
163
233
  }
164
234
  }
165
235
  }
236
+
237
+ &__empty {
238
+ height: 100%;
239
+ font-weight: var(--font-weight-medium2);
240
+ font-size: var(--font-size-xx-small);
241
+ color: var(--gray-darken-4);
242
+ }
166
243
  }
167
244
  </style>
@@ -135,7 +135,7 @@ export default {
135
135
  @include md-and-up {
136
136
  display: grid;
137
137
  grid-template-columns: minmax(250px,1fr) 3fr;
138
- grid-template-rows: minmax(562px,1fr) 80px;
138
+ grid-template-rows: 1fr 80px;
139
139
  grid-row-gap: 0px;
140
140
  &.wizard-size {
141
141
  &-md {