Skip to content

Commit 6d7a301

Browse files
fixing buttons field after updates to useform
1 parent 5f46aa4 commit 6d7a301

File tree

3 files changed

+256
-241
lines changed

3 files changed

+256
-241
lines changed

src/plugin/components/fields/VSFButtonField/VSFButtonField.vue

Lines changed: 129 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,92 @@
11
<template>
2-
<Field
3-
v-slot="props"
4-
v-model="modelValue"
5-
:name="field.name"
6-
type="text"
7-
:validate-on-blur="fieldValidateOn === 'blur'"
8-
:validate-on-change="fieldValidateOn === 'change'"
9-
:validate-on-input="fieldValidateOn === 'input'"
10-
:validate-on-model-update="fieldValidateOn != null"
11-
>
12-
<div :class="{
13-
...buttonFieldContainerClass,
14-
'v-input--error': props.errorMessage ? props.errorMessage?.length > 0 : false,
15-
}">
16-
<v-label>
17-
<FieldLabel
18-
:label="field.label"
19-
:required="fieldRequired"
20-
/>
21-
</v-label>
22-
23-
<v-item-group
24-
:id="field?.id"
25-
v-model="modelValue"
26-
class="mt-2"
27-
:class="itemGroupClass"
28-
:data-cy="`vsf-field-group-${field.name}`"
29-
:style="itemGroupStyle"
2+
<div :class="buttonFieldContainerClass">
3+
<v-label>
4+
<FieldLabel
5+
:label="field.label"
6+
:required="fieldRequired"
7+
/>
8+
</v-label>
9+
10+
<v-item-group
11+
:id="field?.id"
12+
v-model="modelValue"
13+
class="mt-2"
14+
:class="itemGroupClass"
15+
:data-cy="`vsf-field-group-${field.name}`"
16+
:style="itemGroupStyle"
17+
>
18+
<v-item
19+
v-for="option, key in field?.options"
20+
:key="option.value"
3021
>
31-
<v-item
32-
v-for="option, key in field?.options"
33-
:key="option.value"
34-
>
35-
<template #default>
36-
<v-btn
37-
v-bind="boundSettings"
38-
:id="getId(option, key)"
39-
:active="isActive(option.value)"
40-
:appendIcon="getIcon(option, 'appendIcon')"
41-
class="text-none"
42-
:class="{
43-
[`${option?.class}`]: true,
44-
...buttonClass,
45-
[`${field.selectedClass}`]: isActive(option.value) && field.selectedClass != null,
46-
}"
47-
:color="option?.color || field?.color || settings?.color"
48-
:data-cy="`vsf-field-${field.name}`"
49-
:density="fieldDensity"
50-
:height="getHeight(option)"
51-
:icon="getIcon(option, 'icon')"
52-
:maxHeight="getMaxHeight(option)"
53-
:maxWidth="getMaxWidth(option)"
54-
:minHeight="getMinHeight(option)"
55-
:minWidth="getMinWidth(option)"
56-
:prependIcon="getIcon(option, 'prependIcon')"
57-
:value="option.value"
58-
:variant="getVariant(option.value)"
59-
:width="getWidth(option)"
60-
@click.prevent="onActions(props.validate, 'click', option.value); props.handleInput(modelValue)"
61-
@keydown.space.prevent="onActions(props.validate, 'click', option.value); props.handleInput(modelValue)"
62-
@mousedown="onFocus(option.value)"
63-
@mouseleave="onFocus(null)"
64-
@mouseup="onFocus(null)"
22+
<template #default>
23+
<v-btn
24+
v-bind="boundSettings"
25+
:id="getId(option, key)"
26+
:active="isActive(option.value)"
27+
:appendIcon="getIcon(option, 'appendIcon')"
28+
class="text-none"
29+
:class="{ ...buttonClass, ...buttonClassAdditional(option) }"
30+
:color="option?.color || field?.color || settings?.color"
31+
:data-cy="`vsf-field-${field.name}`"
32+
:density="fieldDensity"
33+
:height="getHeight(option)"
34+
:icon="getIcon(option, 'icon')"
35+
:maxHeight="getMaxHeight(option)"
36+
:maxWidth="getMaxWidth(option)"
37+
:minHeight="getMinHeight(option)"
38+
:minWidth="getMinWidth(option)"
39+
:prependIcon="getIcon(option, 'prependIcon')"
40+
:value="option.value"
41+
:variant="getVariant(option.value)"
42+
:width="getWidth(option)"
43+
@click.prevent="onActions('click', option.value)"
44+
@keydown.space.prevent="onActions('click', option.value)"
45+
@mousedown="onFocus(option.value)"
46+
@mouseleave="onFocus(null)"
47+
@mouseup="onFocus(null)"
48+
>
49+
<template
50+
v-if="getIcon(option, 'icon') == null"
51+
#default
6552
>
66-
<template
67-
v-if="getIcon(option, 'icon') == null"
68-
#default
69-
>
70-
<span
71-
class="vsf-button-field__btn-label"
72-
:class="getLabelClass(option)"
73-
v-html="option.label"
74-
></span>
75-
</template>
76-
</v-btn>
77-
</template>
78-
</v-item>
79-
</v-item-group>
80-
81-
<div
82-
v-if="hasDetails"
83-
class="v-input__details"
53+
<span
54+
class="vsf-button-field__btn-label"
55+
:class="getLabelClass(option)"
56+
v-html="option.label"
57+
></span>
58+
</template>
59+
</v-btn>
60+
</template>
61+
</v-item>
62+
</v-item-group>
63+
64+
<div
65+
v-if="hasDetails"
66+
class="v-input__details"
67+
>
68+
<VMessages
69+
:active="activeMessages(errorMessage)"
70+
:color="errorMessage ? 'error' : undefined"
71+
data-cy="vsf-field-messages"
72+
:messages="fieldMessages(errorMessage)"
8473
>
85-
<VMessages
86-
:active="activeMessages(props.errorMessage)"
87-
:color="props.errorMessage ? 'error' : undefined"
88-
data-cy="vsf-field-messages"
89-
:messages="fieldMessages(props.errorMessage)"
90-
>
91-
</VMessages>
92-
</div>
74+
</VMessages>
9375
</div>
76+
</div>
9477

95-
<input
96-
data-cy="vsf-button-field-input"
97-
:name="field.name"
98-
type="hidden"
99-
:value="modelValue"
100-
/>
101-
</Field>
78+
<input
79+
v-model="value"
80+
data-cy="vsf-button-field-input"
81+
:name="field.name"
82+
type="hidden"
83+
@change="handleChange"
84+
/>
10285
</template>
10386

10487

10588
<script lang="ts" setup>
106-
import { Field } from 'vee-validate';
89+
import { useField } from 'vee-validate';
10790
import { VMessages } from 'vuetify/components';
10891
import type { Option, VSFButtonFieldProps } from './index';
10992
import type { FieldLabelProps } from '../../shared/FieldLabel.vue';
@@ -125,42 +108,62 @@ const fieldRequired = computed<FieldLabelProps['required']>(() => {
125108
const fieldValidateOn = computed(() => field?.validateOn ?? settings.value?.validateOn);
126109
const originalValue = modelValue.value;
127110
111+
112+
const { errorMessage, handleChange, setValue, validate, value } = useField(
113+
field.name,
114+
undefined,
115+
{
116+
initialValue: field?.multiple ? [] : null,
117+
validateOnBlur: fieldValidateOn.value === 'blur',
118+
validateOnChange: fieldValidateOn.value === 'change',
119+
validateOnInput: fieldValidateOn.value === 'input',
120+
validateOnModelUpdate: fieldValidateOn.value != null,
121+
},
122+
);
123+
124+
128125
onUnmounted(() => {
129126
if (!settings.value?.keepValuesOnUnmount) {
130127
modelValue.value = originalValue;
128+
setValue(originalValue);
131129
}
132130
});
133131
134132
135-
if (modelValue?.value == null) {
136-
modelValue.value = field?.multiple ? [] : null;
137-
}
138-
139133
const currentValue = ref(modelValue.value);
140134
141135
// ------------------------- Validate On Actions //
142-
async function onActions(validate: FieldValidateResult, action: ValidateAction, value?: string | number): Promise<void> {
143-
if (currentValue.value === value && (fieldValidateOn.value === 'change' || fieldValidateOn.value === 'input')) {
136+
async function onActions(action: ValidateAction, val?: string | number): Promise<void> {
137+
if (currentValue.value === val && (fieldValidateOn.value === 'change' || fieldValidateOn.value === 'input')) {
144138
return;
145139
}
146140
147-
if (!field?.disabled && value) {
141+
if (!field?.disabled && value.value) {
142+
let updatedValue: string | string[];
143+
148144
if (field?.multiple) {
149-
const localModelValue = modelValue.value == null ? [] : modelValue.value as string[];
145+
const localModelValue = Array.isArray(value.value) ? value.value.slice() : [];
146+
const valStr = String(val);
150147
151-
if (localModelValue != null && localModelValue.includes(String(value))) {
152-
const index = localModelValue.indexOf(String(value));
153-
localModelValue.splice(index, 1);
148+
if (localModelValue.includes(valStr)) {
149+
localModelValue.splice(localModelValue.indexOf(valStr), 1);
154150
}
155151
else {
156-
localModelValue.push(String(value));
152+
localModelValue.push(valStr);
157153
}
158154
159-
modelValue.value = localModelValue;
155+
updatedValue = localModelValue;
160156
}
161157
else {
162-
modelValue.value = value;
158+
updatedValue = val as string;
163159
}
160+
161+
setValue(updatedValue);
162+
modelValue.value = updatedValue;
163+
}
164+
else {
165+
setValue(val);
166+
modelValue.value = val;
164167
}
165168
166169
await useOnActions({
@@ -170,7 +173,7 @@ async function onActions(validate: FieldValidateResult, action: ValidateAction,
170173
settingsValidateOn: settings.value?.validateOn,
171174
validate,
172175
}).then(() => {
173-
currentValue.value = modelValue.value;
176+
currentValue.value = value.value;
174177
})
175178
.catch((error: Error) => {
176179
console.error(error);
@@ -310,11 +313,11 @@ function getHeight(option: Option): string | number | undefined {
310313
}
311314
312315
const isActive = (val: string | number): boolean | undefined => {
313-
if (!modelValue.value) {
316+
if (!value.value) {
314317
return undefined;
315318
}
316319
317-
return modelValue.value === val || (modelValue.value as string[]).includes(val as string);
320+
return value.value === val || (value.value as string[]).includes(val as string);
318321
};
319322
320323
// ------------------------- Variants //
@@ -330,8 +333,8 @@ function getVariant(val: string | number): VSFButtonFieldProps['field']['variant
330333
331334
332335
// -------------------------------------------------- Active Messages //
333-
function activeMessages(errorMessage: string | string[]): boolean {
334-
if (errorMessage ? errorMessage.length > 0 : false) {
336+
function activeMessages(errorMsg: string | string[]): boolean {
337+
if (errorMsg ? errorMsg.length > 0 : false) {
335338
return true;
336339
}
337340
@@ -346,9 +349,9 @@ function activeMessages(errorMessage: string | string[]): boolean {
346349
return false;
347350
}
348351
349-
function fieldMessages(errorMessage?: string | string[]): string | string[] {
350-
if (errorMessage ? errorMessage.length > 0 : false) {
351-
return errorMessage as string[];
352+
function fieldMessages(errorMsg?: string | string[]): string | string[] {
353+
if (errorMsg ? errorMsg.length > 0 : false) {
354+
return errorMsg as string[];
352355
}
353356
354357
if (field.hint && (field.persistentHint || isFocused.value)) {
@@ -403,6 +406,7 @@ const buttonFieldContainerClass = computed(() => {
403406
return {
404407
'd-flex': field?.align,
405408
'flex-column': field?.align,
409+
'v-input--error': errorMessage ? errorMessage?.length > 0 : false,
406410
'vsf-button-field__container': true,
407411
[`align-${field?.align}`]: field?.align,
408412
};
@@ -420,6 +424,13 @@ const buttonClass = computed(() => {
420424
return {};
421425
});
422426
427+
const buttonClassAdditional = (option) => {
428+
return {
429+
[`${option?.class}`]: true,
430+
[`${field.selectedClass}`]: isActive(option.value) && field.selectedClass != null,
431+
};
432+
};
433+
423434
const getLabelClass = (option: Option): object => {
424435
const isActiveOption = isActive(option.value);
425436
const optionVariant = getVariant(option.value);

0 commit comments

Comments
 (0)