@farm-investimentos/front-mfe-components 15.5.4 → 15.6.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": "@farm-investimentos/front-mfe-components",
3
- "version": "15.5.4",
3
+ "version": "15.6.0",
4
4
  "author": "farm investimentos",
5
5
  "private": false,
6
6
  "main": "./dist/front-mfe-components.common.js",
@@ -7,6 +7,11 @@
7
7
  align-items: center;
8
8
  justify-content: space-between;
9
9
  cursor: pointer;
10
+
11
+ &--custom {
12
+ position: relative;
13
+ cursor: pointer;
14
+ }
10
15
  }
11
16
 
12
17
  &__content-title {
@@ -19,6 +24,12 @@
19
24
  display: flex;
20
25
  align-items: center;
21
26
  justify-content: space-between;
27
+
28
+ &--custom {
29
+ position: absolute;
30
+ right: 0;
31
+ top: 3px;
32
+ }
22
33
  }
23
34
 
24
35
  &__icon {
@@ -37,6 +48,10 @@
37
48
  }
38
49
  }
39
50
 
51
+ .full-width {
52
+ width: 100%;
53
+ }
54
+
40
55
  .fade-enter-active,
41
56
  .fade-leave-active {
42
57
  transition: opacity 0.3s ease-in-out;
@@ -152,20 +152,182 @@ export const Dense = () => ({
152
152
 
153
153
  export const Custom = () => ({
154
154
  template: `
155
- <farm-collapsible custom>
155
+ <farm-collapsible title="" custom open>
156
156
  <template #custom>
157
+ <farm-row justify="space-between" align="center">
158
+ <farm-col md="6">
159
+ <farm-caption>caption</farm-caption>
160
+ </farm-col>
161
+ <farm-col md="6" justify="end"
162
+ align="end">
157
163
  <farm-btn
158
- v-bind="attrs"
159
- v-on="on"
164
+
160
165
  >
161
166
  custom
162
167
  </farm-btn>
168
+ </farm-col>
169
+ </farm-row>
163
170
  </template>
164
171
  collapsible content
165
172
  </farm-collapsible>
166
173
  `,
167
174
  });
168
175
 
176
+ export const CustomHeaderContent = () => ({
177
+ template: `
178
+ <farm-collapsible title="" custom-header>
179
+ <template #header-content>
180
+ <farm-row>
181
+ <farm-col md="12">
182
+ <farm-bodytext color="success">initial text</farm-bodytext>
183
+ </farm-col>
184
+ </farm-row>
185
+
186
+ <farm-row class="pt-4">
187
+ <farm-col class="collapsible-stories-class-with-line">
188
+ <farm-caption variation="semiBold"
189
+ >text here</farm-caption
190
+ >
191
+ 123455
192
+ </farm-col>
193
+ <farm-col class="collapsible-stories-class-with-line">
194
+ <farm-caption variation="semiBold"
195
+ >label here</farm-caption
196
+ >
197
+
198
+ <farm-caption variation="medium" class="my-1">R$ 1000</farm-caption>
199
+ </farm-col>
200
+
201
+ <farm-col class="collapsible-stories-class-with-line">
202
+ <farm-caption variation="semiBold">LABEL HERE</farm-caption>
203
+
204
+ <farm-caption variation="medium" class="my-1">R$ 1000</farm-caption>
205
+ </farm-col>
206
+
207
+ <farm-col>
208
+ <farm-caption variation="semiBold"
209
+ >Label here (text here)</farm-caption
210
+ >
211
+ <farm-caption variation="medium" class="my-1">value here</farm-caption>
212
+ </farm-col>
213
+ </farm-row>
214
+ </template>
215
+
216
+ <farm-bodytext >collapsible content</farm-bodytext>
217
+ </farm-collapsible>
218
+ `,
219
+ });
220
+
221
+ export const customBodyContent = () => ({
222
+ template: `
223
+ <farm-collapsible title="simple title" custom-body>
224
+ <farm-row extraDecrease style="background-color:#f5f5f5;" class="px-4">
225
+ <farm-col class="collapsible-stories-class-with-line">
226
+ <farm-caption variation="semiBold"
227
+ >text here</farm-caption
228
+ >
229
+ 123455
230
+ </farm-col>
231
+ <farm-col class="collapsible-stories-class-with-line">
232
+ <farm-caption variation="semiBold"
233
+ >label here</farm-caption
234
+ >
235
+
236
+ <farm-caption variation="medium" class="my-1">R$ 1000</farm-caption>
237
+ </farm-col>
238
+
239
+ <farm-col class="collapsible-stories-class-with-line">
240
+ <farm-caption variation="semiBold">LABEL HERE</farm-caption>
241
+
242
+ <farm-caption variation="medium" class="my-1">R$ 1000</farm-caption>
243
+ </farm-col>
244
+
245
+ <farm-col>
246
+ <farm-caption variation="semiBold"
247
+ >Label here (text here)</farm-caption
248
+ >
249
+ <farm-caption variation="medium" class="my-1">value here</farm-caption>
250
+ </farm-col>
251
+ </farm-row>
252
+ </farm-collapsible>
253
+ `,
254
+ });
255
+
256
+ export const CustomHeaderAndBodyContent = () => ({
257
+ template: `
258
+ <farm-collapsible title="" custom-header custom-body>
259
+
260
+ <template #header-content>
261
+ <div class="mb-4">
262
+ <farm-row>
263
+ <farm-col md="12">
264
+ <farm-bodytext color="success">initial text</farm-bodytext>
265
+ </farm-col>
266
+ </farm-row>
267
+
268
+ <farm-row class="pt-4">
269
+ <farm-col class="collapsible-stories-class-with-line">
270
+ <farm-caption variation="semiBold"
271
+ >text here</farm-caption
272
+ >
273
+ 123455
274
+ </farm-col>
275
+ <farm-col class="collapsible-stories-class-with-line">
276
+ <farm-caption variation="semiBold"
277
+ >label here</farm-caption
278
+ >
279
+
280
+ <farm-caption variation="medium" class="my-1">R$ 1000</farm-caption>
281
+ </farm-col>
282
+
283
+ <farm-col class="collapsible-stories-class-with-line">
284
+ <farm-caption variation="semiBold">LABEL HERE</farm-caption>
285
+
286
+ <farm-caption variation="medium" class="my-1">R$ 1000</farm-caption>
287
+ </farm-col>
288
+
289
+ <farm-col>
290
+ <farm-caption variation="semiBold"
291
+ >Label here (text here)</farm-caption
292
+ >
293
+ <farm-caption variation="medium" class="my-1">value here</farm-caption>
294
+ </farm-col>
295
+ </farm-row>
296
+ </div>
297
+ </template>
298
+
299
+ <farm-row extraDecrease style="background-color:#f5f5f5;" class="mt-5 px-2">
300
+ <farm-col class="collapsible-stories-class-with-line">
301
+ <farm-caption variation="semiBold"
302
+ >text here</farm-caption
303
+ >
304
+ 123455
305
+ </farm-col>
306
+ <farm-col class="collapsible-stories-class-with-line">
307
+ <farm-caption variation="semiBold"
308
+ >label here</farm-caption
309
+ >
310
+
311
+ <farm-caption variation="medium" class="my-1">R$ 1000</farm-caption>
312
+ </farm-col>
313
+
314
+ <farm-col class="collapsible-stories-class-with-line">
315
+ <farm-caption variation="semiBold">LABEL HERE</farm-caption>
316
+
317
+ <farm-caption variation="medium" class="my-1">R$ 1000</farm-caption>
318
+ </farm-col>
319
+
320
+ <farm-col>
321
+ <farm-caption variation="semiBold"
322
+ >Label here (text here)</farm-caption
323
+ >
324
+ <farm-caption variation="medium" class="my-1">value here</farm-caption>
325
+ </farm-col>
326
+ </farm-row>
327
+ </farm-collapsible>
328
+ `,
329
+ });
330
+
169
331
  Primary.storyName = 'Basic';
170
332
  Title.storyName = 'Title';
171
333
  Icon.storyName = 'Icon';
@@ -1,9 +1,19 @@
1
1
  <template>
2
2
  <farm-card class="collapsible">
3
- <farm-card-content gutter="md">
4
- <div class="collapsible__header" @click="onToggleCollapsible(status)">
5
- <div class="collapsible__content-title">
6
- <div class="collapsible__icon collapsible__icon--main" v-if="icon !== '' && !custom">
3
+ <farm-card-content gutter="md" :class="{ 'pb-0': customBody }">
4
+ <div
5
+ v-if="!customHeader"
6
+ class="collapsible__header"
7
+ @click="onToggleCollapsible(status)"
8
+ >
9
+ <div
10
+ class="collapsible__content-title"
11
+ :class="{ 'full-width': custom, 'pb-4': customBody }"
12
+ >
13
+ <div
14
+ class="collapsible__icon collapsible__icon--main"
15
+ v-if="icon !== '' && !custom"
16
+ >
7
17
  <farm-icon size="md" :color="colorIcon">
8
18
  {{ icon }}
9
19
  </farm-icon>
@@ -40,7 +50,29 @@
40
50
  </div>
41
51
  </div>
42
52
  </div>
43
- <transition name="fade">
53
+
54
+ <div
55
+ v-if="customHeader"
56
+ class="collapsible__header--custom"
57
+ @click="onToggleCollapsible(status)"
58
+ >
59
+ <slot name="header-content"></slot>
60
+ <div class="collapsible__content-right--custom">
61
+ <div class="collapsible__icon collapsible__icon--arrow">
62
+ <farm-icon size="md" color="primary">
63
+ {{ arrowIcon }}
64
+ </farm-icon>
65
+ </div>
66
+ </div>
67
+ </div>
68
+
69
+ <transition v-if="customBody" name="fade">
70
+ <div v-show="status">
71
+ <slot></slot>
72
+ </div>
73
+ </transition>
74
+
75
+ <transition v-else name="fade">
44
76
  <div class="collapsible__body" v-show="status">
45
77
  <slot></slot>
46
78
  </div>
@@ -180,6 +212,14 @@ export default defineComponent({
180
212
  type: Boolean,
181
213
  default: false,
182
214
  },
215
+ customBody: {
216
+ type: Boolean,
217
+ default: false,
218
+ },
219
+ customHeader: {
220
+ type: Boolean,
221
+ default: false,
222
+ },
183
223
  },
184
224
 
185
225
  data() {
@@ -8,62 +8,75 @@
8
8
  display: flex;
9
9
  align-items: center;
10
10
 
11
+ .farm-icon,
12
+ .farm-typography {
13
+ color: var(--farm-neutral-darken);
14
+ }
15
+
11
16
  &--clickable {
12
17
  cursor: pointer;
13
18
  }
14
19
 
15
- > a {
16
- text-decoration: none;
20
+ &--disabled {
21
+ cursor: default;
22
+
23
+ .farm-icon,
24
+ .farm-typography {
25
+ color: var(--farm-stroke-disabled);
26
+ }
17
27
  }
18
28
 
19
- .farm-icon,
20
- .farm-typography {
21
- color: var(--farm-neutral-darken);
29
+ > a {
30
+ text-decoration: none;
22
31
  }
23
32
 
24
33
  &:hover,
25
34
  &:focus {
26
35
  border-radius: 5px;
27
36
 
28
- @each $color in $theme-colors-list {
29
- &#{'.farm-listitem--' + $color + '-base'} {
30
- background-color: rgba(themeColor($color), 0.27);
31
- .farm-icon,
32
- .farm-typography {
33
- color: rgba(themeColor($color), 1);
37
+ &:not(.farm-listitem--disabled) {
38
+ @each $color in $theme-colors-list {
39
+ &#{'.farm-listitem--' + $color + '-base'} {
40
+ background-color: rgba(themeColor($color), 0.27);
41
+ .farm-icon,
42
+ .farm-typography {
43
+ color: rgba(themeColor($color), 1);
44
+ }
34
45
  }
35
- }
36
46
 
37
- &#{'.farm-listitem--' + $color + '-lighten'} {
38
- background-color: rgba(themeColor($color, 'lighten'), 0.27);
39
- .farm-icon,
40
- .farm-typography {
41
- color: rgba(themeColor($color), 1);
47
+ &#{'.farm-listitem--' + $color + '-lighten'} {
48
+ background-color: rgba(themeColor($color, 'lighten'), 0.27);
49
+ .farm-icon,
50
+ .farm-typography {
51
+ color: rgba(themeColor($color), 1);
52
+ }
42
53
  }
43
- }
44
54
 
45
- &#{'.farm-listitem--' + $color + '-darken'} {
46
- background-color: rgba(themeColor($color, 'darken'), 0.27);
47
- .farm-icon,
48
- .farm-typography {
49
- color: rgba(themeColor($color), 1);
55
+ &#{'.farm-listitem--' + $color + '-darken'} {
56
+ background-color: rgba(themeColor($color, 'darken'), 0.27);
57
+ .farm-icon,
58
+ .farm-typography {
59
+ color: rgba(themeColor($color), 1);
60
+ }
50
61
  }
51
62
  }
52
63
  }
53
64
  }
54
65
 
55
66
  &:active {
56
- @each $color in $theme-colors-list {
57
- &#{'.farm-listitem--' + $color + '-base'} {
58
- background-color: rgba(themeColor($color), 0.8);
59
- }
67
+ &:not(.farm-listitem--disabled) {
68
+ @each $color in $theme-colors-list {
69
+ &#{'.farm-listitem--' + $color + '-base'} {
70
+ background-color: rgba(themeColor($color), 0.8);
71
+ }
60
72
 
61
- &#{'.farm-listitem--' + $color + '-lighten'} {
62
- background-color: rgba(themeColor($color, 'lighten'), 0.8);
63
- }
73
+ &#{'.farm-listitem--' + $color + '-lighten'} {
74
+ background-color: rgba(themeColor($color, 'lighten'), 0.8);
75
+ }
64
76
 
65
- &#{'.farm-listitem--' + $color + '-darken'} {
66
- background-color: rgba(themeColor($color, 'darken'), 0.8);
77
+ &#{'.farm-listitem--' + $color + '-darken'} {
78
+ background-color: rgba(themeColor($color, 'darken'), 0.8);
79
+ }
67
80
  }
68
81
  }
69
82
  }
@@ -28,19 +28,19 @@
28
28
  margin-right: 8px;
29
29
  }
30
30
 
31
- :deep(.farm-listitem:hover .farm-typography) {
31
+ :deep(.farm-listitem:not(.farm-listitem--disabled):hover .farm-typography) {
32
32
  color: var(--farm-primary-base);
33
33
  }
34
34
 
35
- :deep(.farm-listitem:focus .farm-typography) {
35
+ :deep(.farm-listitem:not(.farm-listitem--disabled):focus .farm-typography) {
36
36
  color: var(--farm-primary-base);
37
37
  }
38
38
 
39
- :deep(.farm-listitem:hover .farm-checkbox .farm-icon) {
39
+ :deep(.farm-listitem:not(.farm-listitem--disabled):hover .farm-checkbox .farm-icon) {
40
40
  color: var(--farm-primary-lighten);
41
41
  }
42
42
 
43
- :deep(.farm-listitem:focus .farm-checkbox .farm-icon) {
43
+ :deep(.farm-listitem:not(.farm-listitem--disabled):focus .farm-checkbox .farm-icon) {
44
44
  color: var(--farm-primary-lighten);
45
45
  }
46
46
 
@@ -10,7 +10,8 @@ export default {
10
10
  description: {
11
11
  component: `Select<br />
12
12
  selector: <em>farm-select</em><br />
13
- <span style="color: var(--farm-primary-base);">ready for use</span>
13
+ <span style="color: var(--farm-primary-base);">ready for use</span><br />
14
+ <a href="https://github.com/Farm-Investimentos/front-mfe-components/blob/develop/src/components/Select/Select.vue" target="_blank">Github</a>
14
15
  `,
15
16
  },
16
17
  },
@@ -129,6 +130,42 @@ export const Disabled = () => ({
129
130
  </div>`,
130
131
  });
131
132
 
133
+ export const DisabledKeys = () => ({
134
+ data() {
135
+ return {
136
+ v: null,
137
+ items: [
138
+ { value: 1, text: ' value 1', disabled: true },
139
+ { value: 2, text: ' value 2', disabled: true },
140
+ { value: 3, text: ' value 3' },
141
+ ],
142
+ };
143
+ },
144
+ methods: {
145
+ allowAllOptions() {
146
+ this.items = [
147
+ { value: 1, text: ' value 1' },
148
+ { value: 2, text: ' value 2' },
149
+ { value: 3, text: ' value 3' },
150
+ ];
151
+ },
152
+ reset() {
153
+ this.items = [
154
+ { value: 1, text: ' value 1', disabled: true },
155
+ { value: 2, text: ' value 2', disabled: true },
156
+ { value: 3, text: ' value 3' },
157
+ ];
158
+ },
159
+ },
160
+ template: `<div style="width: 480px">
161
+ <farm-select v-model="v" :items="items" />
162
+ v-model: {{ v }}
163
+ <br><br>
164
+ <farm-btn @click="allowAllOptions">Habilitar todos itens</farm-btn>
165
+ <farm-btn @click="reset">Resetar</farm-btn>
166
+ </div>`,
167
+ });
168
+
132
169
  export const Validate = () => ({
133
170
  data() {
134
171
  return {
@@ -13,16 +13,24 @@
13
13
  v-if="!readonly && !disabled"
14
14
  :id="customId"
15
15
  >
16
- <farm-contextmenu bottom v-model="isVisible" :stay-open="multiple" ref="contextmenu">
16
+ <farm-contextmenu
17
+ bottom
18
+ v-model="isVisible"
19
+ :stay-open="multiple || clickedDisabledItem"
20
+ ref="contextmenu"
21
+ >
17
22
  <farm-list v-if="!readonly" ref="listRef" @keydown="onKeyDown">
18
23
  <farm-listitem
19
- tabindex="0"
20
24
  v-for="(item, index) in items"
25
+ tabindex="0"
21
26
  clickable
22
- hoverColorVariation="lighten"
23
- hover-color="primary"
27
+ hover-color-variation="lighten"
28
+ :hover-color="item.disabled ? 'neutral' : 'primary'"
24
29
  :key="'contextmenu_item_' + index"
25
- :class="{ 'farm-listitem--selected': item[itemValue] === innerValue }"
30
+ :class="{
31
+ 'farm-listitem--selected': item[itemValue] === innerValue,
32
+ 'farm-listitem--disabled': item.disabled,
33
+ }"
26
34
  @click="selectItem(item)"
27
35
  >
28
36
  <farm-checkbox
@@ -30,6 +38,7 @@
30
38
  v-model="checked"
31
39
  value="1"
32
40
  size="sm"
41
+ :disabled="item.disabled"
33
42
  v-if="isChecked(item)"
34
43
  />
35
44
  <farm-checkbox
@@ -37,6 +46,7 @@
37
46
  v-model="checked"
38
47
  value="2"
39
48
  size="sm"
49
+ :disabled="item.disabled"
40
50
  v-else-if="multiple"
41
51
  />
42
52
  <farm-caption bold tag="span">{{ item[itemText] }}</farm-caption>
@@ -242,6 +252,7 @@ export default defineComponent({
242
252
  keys,
243
253
  } = buildData(props);
244
254
 
255
+ const clickedDisabledItem = ref(false);
245
256
  const listRef = ref();
246
257
 
247
258
  const contextmenu = ref(null);
@@ -339,7 +350,20 @@ export default defineComponent({
339
350
  };
340
351
 
341
352
  const selectItem = item => {
342
- inputField.value.focus();
353
+ if (inputField.value) {
354
+ inputField.value.focus();
355
+ }
356
+
357
+ if (item.disabled) {
358
+ clickedDisabledItem.value = true;
359
+
360
+ // "Schedule" execution to next loop, so the contextMenu won't close immediately if a disabled item is clicked
361
+ setTimeout(() => {
362
+ clickedDisabledItem.value = false;
363
+ });
364
+ return;
365
+ }
366
+
343
367
  if (multiple.value) {
344
368
  const alreadyAdded = multipleValues.value.findIndex(
345
369
  val => val === item[itemValue.value]
@@ -457,6 +481,7 @@ export default defineComponent({
457
481
  customId,
458
482
  showErrorText,
459
483
  contextmenu,
484
+ clickedDisabledItem,
460
485
  validate,
461
486
  reset,
462
487
  selectItem,
@@ -1,6 +1,11 @@
1
1
  import { shallowMount } from '@vue/test-utils';
2
2
  import Select from '../Select';
3
3
 
4
+ /* jest.spyOn(global, 'setTimeout').mockImplementation(fn => {
5
+ fn();
6
+ return setTimeout(() => 1, 0);
7
+ }); */
8
+
4
9
  describe('Select component', () => {
5
10
  let wrapper;
6
11
  let component;
@@ -124,6 +129,66 @@ describe('Select component', () => {
124
129
  expect(component.selectedText).toBe('value 0 (+2 outros)');
125
130
  });
126
131
  });
132
+ describe('disabled items', () => {
133
+ it('should not select a disabled item', async () => {
134
+ const items = [
135
+ { value: 0, text: 'value 0', disabled: true },
136
+ { value: 1, text: 'value 1' },
137
+ { value: 2, text: 'value 2' },
138
+ { value: 3, text: 'value 3' },
139
+ ];
140
+
141
+ await wrapper.setProps({
142
+ items,
143
+ value: 1,
144
+ });
145
+
146
+ expect(component.innerValue).toBe(1);
147
+ expect(component.selectedText).toBe('value 1');
148
+ component.selectItem(items[2]);
149
+ setTimeout(() => {
150
+ expect(component.innerValue).toBe(2);
151
+ expect(component.selectedText).toBe('value 2');
152
+ }, 150);
153
+ component.selectItem(items[0]);
154
+ setTimeout(() => {
155
+ expect(component.innerValue).toBe(2);
156
+ expect(component.selectedText).toBe('value 2');
157
+ }, 150);
158
+ component.selectItem(items[3]);
159
+ setTimeout(() => {
160
+ expect(component.innerValue).toBe(3);
161
+ expect(component.selectedText).toBe('value 3');
162
+ }, 150);
163
+ });
164
+ it('should not select a disabled item if is multiple', async () => {
165
+ const items = [
166
+ { value: 0, text: 'value 0' },
167
+ { value: 1, text: 'value 1', disabled: true },
168
+ { value: 2, text: 'value 2' },
169
+ { value: 3, text: 'value 3', disabled: true },
170
+ ];
171
+
172
+ await wrapper.setProps({
173
+ multiple: true,
174
+ items,
175
+ value: [0],
176
+ });
177
+
178
+ expect(component.innerValue).toEqual([0]);
179
+ expect(component.selectedText).toBe('value 0');
180
+ component.selectItem(items[2]);
181
+ setTimeout(() => {
182
+ expect(component.innerValue).toEqual([0, 2]);
183
+ expect(component.selectedText).toBe('value 0 (+1 outro)');
184
+ }, 150);
185
+ component.selectItem(items[1]);
186
+ setTimeout(() => {
187
+ expect(component.innerValue).toEqual([0, 2]);
188
+ expect(component.selectedText).toBe('value 0 (+1 outro)');
189
+ }, 150);
190
+ });
191
+ });
127
192
 
128
193
  describe('onKeyDown', () => {
129
194
  it('should open the ContextMenu and click on current element', () => {
@@ -11,9 +11,8 @@ tr.v-data-table__empty-wrapper {
11
11
  }
12
12
  }
13
13
 
14
-
15
14
  .mf-Containers.mf-Containers-authenticated {
16
- >.mf-Container>div.v-application {
15
+ > .mf-Container > div.v-application {
17
16
  padding-bottom: 2.625rem;
18
17
  }
19
18
  }
@@ -37,8 +36,6 @@ body.body--has-footer {
37
36
  .v-icon.v-icon {
38
37
  font-size: 22px;
39
38
  color: var(--farm-neutral-farken);
40
- ;
41
-
42
39
  &.mdi-checkbox-marked,
43
40
  &.mdi-minus-box {
44
41
  color: var(--farm-primary-base);
@@ -48,4 +45,18 @@ body.body--has-footer {
48
45
  .v-input--selection-controls__ripple {
49
46
  display: none;
50
47
  }
51
- }
48
+ }
49
+
50
+ .collapsible-stories-class-with-line {
51
+ position: relative;
52
+ padding-right: 20px;
53
+ &:after {
54
+ content: '';
55
+ position: absolute;
56
+ height: 80%;
57
+ width: 1px;
58
+ border-right: 1px solid var(--farm-stroke-base);
59
+ right: 10px;
60
+ top: 5%;
61
+ }
62
+ }