@farm-investimentos/front-mfe-components 15.6.0 → 15.6.1
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/dist/front-mfe-components.common.js +90 -88
- package/dist/front-mfe-components.common.js.map +1 -1
- package/dist/front-mfe-components.umd.js +90 -88
- package/dist/front-mfe-components.umd.js.map +1 -1
- package/dist/front-mfe-components.umd.min.js +1 -1
- package/dist/front-mfe-components.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Form/Form.stories.js +79 -0
- package/src/components/Form/Form.vue +14 -10
- package/src/components/Form/__tests__/Form.spec.js +63 -1
- package/src/components/Form/__tests__/helpers.js +106 -0
package/package.json
CHANGED
|
@@ -20,10 +20,16 @@ const styles = {
|
|
|
20
20
|
vForm: {
|
|
21
21
|
maxWidth: '480px',
|
|
22
22
|
},
|
|
23
|
+
dynamicField: {
|
|
24
|
+
display: 'flex',
|
|
25
|
+
},
|
|
23
26
|
footer: {
|
|
24
27
|
display: 'flex',
|
|
25
28
|
justifyContent: 'end',
|
|
26
29
|
},
|
|
30
|
+
footerMargin: {
|
|
31
|
+
marginTop: '16px',
|
|
32
|
+
},
|
|
27
33
|
};
|
|
28
34
|
|
|
29
35
|
export const Primary = () => ({
|
|
@@ -141,6 +147,79 @@ export const Secondary = () => ({
|
|
|
141
147
|
`,
|
|
142
148
|
});
|
|
143
149
|
|
|
150
|
+
export const WithDynamicFields = () => ({
|
|
151
|
+
data() {
|
|
152
|
+
return {
|
|
153
|
+
form: {
|
|
154
|
+
document: null,
|
|
155
|
+
name: null,
|
|
156
|
+
checkbox: null,
|
|
157
|
+
birthDate: '',
|
|
158
|
+
selectId: null,
|
|
159
|
+
rangeDate: [],
|
|
160
|
+
dynamics: [],
|
|
161
|
+
},
|
|
162
|
+
validForm: true,
|
|
163
|
+
rules: {
|
|
164
|
+
required: value => !!value || 'Campo obrigatório',
|
|
165
|
+
checked: value => !!value || 'Deve estar marcado',
|
|
166
|
+
},
|
|
167
|
+
items: [
|
|
168
|
+
{ value: null, text: '' },
|
|
169
|
+
{ value: 1, text: 'label 1' },
|
|
170
|
+
{ value: 2, text: 'label 2' },
|
|
171
|
+
],
|
|
172
|
+
styles,
|
|
173
|
+
};
|
|
174
|
+
},
|
|
175
|
+
methods: {
|
|
176
|
+
addDynamic() {
|
|
177
|
+
const dynamic = {
|
|
178
|
+
name2: '',
|
|
179
|
+
selectId2: null,
|
|
180
|
+
};
|
|
181
|
+
this.form.dynamics.push({ ...dynamic });
|
|
182
|
+
this.$refs.form.restart();
|
|
183
|
+
},
|
|
184
|
+
removeDynamic(index) {
|
|
185
|
+
this.form.dynamics.splice(index, 1);
|
|
186
|
+
this.$refs.form.restart();
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
template: `
|
|
190
|
+
<div>
|
|
191
|
+
<farm-btn @click="addDynamic">Add field</farm-btn>
|
|
192
|
+
|
|
193
|
+
<farm-form v-model="validForm" :style="[styles.vForm]" ref="form">
|
|
194
|
+
<farm-label :required="true">Nome</farm-label>
|
|
195
|
+
<farm-textfield-v2 v-model="form.name" :rules="[rules.required]" />
|
|
196
|
+
|
|
197
|
+
<farm-label :required="true">Select</farm-label>
|
|
198
|
+
<farm-select :rules="[rules.required]" :items="items" v-model="form.selectId"/>
|
|
199
|
+
|
|
200
|
+
<div :style="[styles.dynamicField]" v-for="(dynamic, index) in form.dynamics">
|
|
201
|
+
<div>
|
|
202
|
+
<farm-label :key="index + 'label'" :required="true">Dynamic</farm-label>
|
|
203
|
+
<farm-textfield-v2 :key="index" v-model="dynamic.name2" :rules="[rules.required]" />
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
<farm-icon @click="removeDynamic(index)">delete</farm-icon>
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
Is valid form: {{ validForm }}
|
|
210
|
+
|
|
211
|
+
<farm-line />
|
|
212
|
+
|
|
213
|
+
<footer class="footer" :style="[styles.footer, styles.footerMargin]">
|
|
214
|
+
<farm-btn outlined @click="$refs.form.restart()" class="mr-3">Restart</farm-btn>
|
|
215
|
+
<farm-btn outlined @click="$refs.form.restartValidation()" class="mr-3">Restart Validation</farm-btn>
|
|
216
|
+
<farm-btn outlined @click="$refs.form.reset()" class="mr-3">Reset</farm-btn>
|
|
217
|
+
<farm-btn :disabled="!validForm">Salvar</farm-btn>
|
|
218
|
+
</footer>
|
|
219
|
+
</farm-form>
|
|
220
|
+
</div>`,
|
|
221
|
+
});
|
|
222
|
+
|
|
144
223
|
export const InitInvalid = () => ({
|
|
145
224
|
data() {
|
|
146
225
|
return {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<form class="farm-form"><slot></slot></form>
|
|
3
3
|
</template>
|
|
4
4
|
<script lang="ts">
|
|
5
|
-
import { onMounted,
|
|
5
|
+
import { onMounted, ref, getCurrentInstance, defineComponent } from 'vue';
|
|
6
6
|
|
|
7
7
|
type ErrorsBag = Record<number, boolean>;
|
|
8
8
|
|
|
@@ -14,13 +14,13 @@ export default defineComponent({
|
|
|
14
14
|
inheritAttrs: true,
|
|
15
15
|
setup(props, { emit }) {
|
|
16
16
|
const innerValue = ref(props.value);
|
|
17
|
-
let errorsBag =
|
|
17
|
+
let errorsBag = ref({} as ErrorsBag);
|
|
18
18
|
let validationFields = [];
|
|
19
19
|
const instance = getCurrentInstance().proxy;
|
|
20
20
|
|
|
21
21
|
const dispatchError = () => {
|
|
22
|
-
const keys = Object.keys(errorsBag);
|
|
23
|
-
const errorsIds = keys.filter(key => !errorsBag[key]);
|
|
22
|
+
const keys = Object.keys(errorsBag.value);
|
|
23
|
+
const errorsIds = keys.filter(key => !errorsBag.value[key]);
|
|
24
24
|
emit('input', errorsIds.length === 0);
|
|
25
25
|
};
|
|
26
26
|
|
|
@@ -28,7 +28,7 @@ export default defineComponent({
|
|
|
28
28
|
field.$watch(
|
|
29
29
|
'hasError',
|
|
30
30
|
() => {
|
|
31
|
-
errorsBag[field._uid] = field.valid;
|
|
31
|
+
errorsBag.value[field._uid] = field.valid;
|
|
32
32
|
dispatchError();
|
|
33
33
|
},
|
|
34
34
|
{ immediate: true }
|
|
@@ -67,7 +67,7 @@ export default defineComponent({
|
|
|
67
67
|
|
|
68
68
|
const restartValidation = () => {
|
|
69
69
|
validationFields = [];
|
|
70
|
-
errorsBag = {};
|
|
70
|
+
errorsBag.value = {};
|
|
71
71
|
recursiveFormField(instance);
|
|
72
72
|
validationFields.forEach(field => {
|
|
73
73
|
watchInput(field);
|
|
@@ -78,10 +78,14 @@ export default defineComponent({
|
|
|
78
78
|
|
|
79
79
|
const restart = () => {
|
|
80
80
|
validationFields = [];
|
|
81
|
-
errorsBag = {};
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
errorsBag.value = {};
|
|
82
|
+
|
|
83
|
+
instance.$nextTick(() => {
|
|
84
|
+
recursiveFormField(instance);
|
|
85
|
+
|
|
86
|
+
validationFields.forEach(field => {
|
|
87
|
+
watchInput(field);
|
|
88
|
+
});
|
|
85
89
|
});
|
|
86
90
|
};
|
|
87
91
|
|
|
@@ -1,14 +1,76 @@
|
|
|
1
1
|
import { shallowMount } from '@vue/test-utils';
|
|
2
2
|
import Form from '../Form';
|
|
3
|
+
import { formWithChildrenFactory, getDeepErrorsBag } from './helpers';
|
|
3
4
|
|
|
4
5
|
describe('Form component', () => {
|
|
5
|
-
let wrapper;
|
|
6
|
+
let wrapper, component;
|
|
6
7
|
|
|
7
8
|
beforeEach(() => {
|
|
8
9
|
wrapper = shallowMount(Form);
|
|
10
|
+
component = wrapper.vm;
|
|
9
11
|
});
|
|
10
12
|
|
|
11
13
|
test('Created hook', () => {
|
|
12
14
|
expect(wrapper).toBeDefined();
|
|
13
15
|
});
|
|
16
|
+
|
|
17
|
+
describe('errors bag', () => {
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
const helper = formWithChildrenFactory(Form);
|
|
20
|
+
|
|
21
|
+
wrapper = helper.wrapper;
|
|
22
|
+
component = helper.component;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should have errors bag after mount form', () => {
|
|
26
|
+
const { errorsBag, errorsBagLength } = getDeepErrorsBag(component);
|
|
27
|
+
|
|
28
|
+
expect(component.errorsBag).toStrictEqual(errorsBag.value);
|
|
29
|
+
expect(Object.keys(component.errorsBag).length).toBe(errorsBagLength);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should update errors bag after change validatable items', async () => {
|
|
33
|
+
const { errorsBag, errorsBagLength } = getDeepErrorsBag(component);
|
|
34
|
+
|
|
35
|
+
expect(component.errorsBag).toStrictEqual(errorsBag.value);
|
|
36
|
+
expect(Object.keys(component.errorsBag).length).toBe(errorsBagLength);
|
|
37
|
+
|
|
38
|
+
await component.addDynamic();
|
|
39
|
+
await component.restart();
|
|
40
|
+
|
|
41
|
+
const { errorsBag: plusOneErrorsBag, errorsBagLength: plusOneErrorsBagLength } =
|
|
42
|
+
getDeepErrorsBag(component);
|
|
43
|
+
|
|
44
|
+
expect(Object.keys(component.errorsBag).length).toBe(plusOneErrorsBagLength);
|
|
45
|
+
expect(component.errorsBag).toStrictEqual(plusOneErrorsBag.value);
|
|
46
|
+
|
|
47
|
+
await component.removeDynamic(1);
|
|
48
|
+
await component.restart();
|
|
49
|
+
|
|
50
|
+
const { errorsBag: minusOneErrorsBag, errorsBagLength: minusOneErrorsBagLength } =
|
|
51
|
+
getDeepErrorsBag(component);
|
|
52
|
+
|
|
53
|
+
expect(Object.keys(component.errorsBag).length).toBe(minusOneErrorsBagLength);
|
|
54
|
+
expect(component.errorsBag).toStrictEqual(minusOneErrorsBag.value);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('isValidForm', () => {
|
|
59
|
+
let isValidForm;
|
|
60
|
+
|
|
61
|
+
beforeEach(() => {
|
|
62
|
+
const helper = formWithChildrenFactory(Form);
|
|
63
|
+
|
|
64
|
+
wrapper = helper.wrapper;
|
|
65
|
+
component = helper.component;
|
|
66
|
+
isValidForm = helper.isValidForm;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should be invalid until all validatable fields are valid', () => {
|
|
70
|
+
const { errorsBag } = getDeepErrorsBag(component);
|
|
71
|
+
|
|
72
|
+
expect(isValidForm.value).toBeFalsy();
|
|
73
|
+
expect(Object.values(errorsBag.value)).toEqual([false, false, false]);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
14
76
|
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { ref } from 'vue';
|
|
3
|
+
|
|
4
|
+
export const errorsBag = ref({});
|
|
5
|
+
|
|
6
|
+
export function getDeepErrorsBag($node) {
|
|
7
|
+
const getDeep = $node => {
|
|
8
|
+
$node.$children.forEach($leaf => {
|
|
9
|
+
if ($leaf.validate) {
|
|
10
|
+
errorsBag.value[$leaf._uid] = $leaf.valid;
|
|
11
|
+
} else if ($leaf.$children.length > 1) {
|
|
12
|
+
getDeep($leaf);
|
|
13
|
+
} else if ($leaf.$children[0] && $leaf.$children[0].validate) {
|
|
14
|
+
errorsBag.value[$leaf.$children[0]._uid] = $leaf.$children[0].valid;
|
|
15
|
+
} else if ($leaf.validatable) {
|
|
16
|
+
errorsBag.value[$leaf._uid] = $leaf.valid;
|
|
17
|
+
} else {
|
|
18
|
+
getDeep($leaf);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
getDeep($node);
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
errorsBag,
|
|
27
|
+
errorsBagLength: errorsBag.value ? Object.keys(errorsBag.value).length : 0,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function resetErrorsBag() {
|
|
32
|
+
errorsBag.value = {};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function mountSlot() {
|
|
36
|
+
const normalComponent = {
|
|
37
|
+
props: {
|
|
38
|
+
form: {
|
|
39
|
+
type: Object,
|
|
40
|
+
required: true,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
template: `
|
|
44
|
+
<div>
|
|
45
|
+
<farm-textfield-v2 :rules=[rules.required] />
|
|
46
|
+
<farm-textfield-v2 :rules=[rules.required] />
|
|
47
|
+
<farm-textfield-v2 :rules=[rules.required] />
|
|
48
|
+
|
|
49
|
+
section id="dynamics">
|
|
50
|
+
<farm-textfield-v2 v-for="(dynamic, index) in form?.dynamics" :key="index" :name="'dynamic-' + index" />
|
|
51
|
+
</section>
|
|
52
|
+
</div>
|
|
53
|
+
`,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
normalComponent,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function formWithChildrenFactory(formComponent) {
|
|
62
|
+
resetErrorsBag();
|
|
63
|
+
|
|
64
|
+
const { normalComponent } = mountSlot();
|
|
65
|
+
|
|
66
|
+
const form = ref({
|
|
67
|
+
dynamics: [],
|
|
68
|
+
});
|
|
69
|
+
const isValidForm = ref(false);
|
|
70
|
+
|
|
71
|
+
const wrapper = mount(formComponent, {
|
|
72
|
+
propsData: {
|
|
73
|
+
value: isValidForm,
|
|
74
|
+
},
|
|
75
|
+
slots: {
|
|
76
|
+
default: '<normal-component :form="form" />',
|
|
77
|
+
},
|
|
78
|
+
mocks: {
|
|
79
|
+
form,
|
|
80
|
+
rules: {
|
|
81
|
+
required: value => !!value || 'Campo obrigatório',
|
|
82
|
+
},
|
|
83
|
+
addDynamic() {
|
|
84
|
+
form.value.dynamics.push({
|
|
85
|
+
name: '',
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return form.value.dynamics;
|
|
89
|
+
},
|
|
90
|
+
removeDynamic(index) {
|
|
91
|
+
form.value.dynamics.splice(index, 1);
|
|
92
|
+
|
|
93
|
+
return form.value.dynamics;
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
stubs: {
|
|
97
|
+
'normal-component': normalComponent,
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
isValidForm,
|
|
103
|
+
wrapper,
|
|
104
|
+
component: wrapper.vm,
|
|
105
|
+
};
|
|
106
|
+
}
|