1
1
<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"
30
21
>
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
65
52
>
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)"
84
73
>
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 >
93
75
</div >
76
+ </div >
94
77
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
+ / >
102
85
</template >
103
86
104
87
105
88
<script lang="ts" setup>
106
- import { Field } from ' vee-validate' ;
89
+ import { useField } from ' vee-validate' ;
107
90
import { VMessages } from ' vuetify/components' ;
108
91
import type { Option , VSFButtonFieldProps } from ' ./index' ;
109
92
import type { FieldLabelProps } from ' ../../shared/FieldLabel.vue' ;
@@ -125,42 +108,62 @@ const fieldRequired = computed<FieldLabelProps['required']>(() => {
125
108
const fieldValidateOn = computed (() => field ?.validateOn ?? settings .value ?.validateOn );
126
109
const originalValue = modelValue .value ;
127
110
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
+
128
125
onUnmounted (() => {
129
126
if (! settings .value ?.keepValuesOnUnmount ) {
130
127
modelValue .value = originalValue ;
128
+ setValue (originalValue );
131
129
}
132
130
});
133
131
134
132
135
- if (modelValue ?.value == null ) {
136
- modelValue .value = field ?.multiple ? [] : null ;
137
- }
138
-
139
133
const currentValue = ref (modelValue .value );
140
134
141
135
// ------------------------- 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' )) {
144
138
return ;
145
139
}
146
140
147
- if (! field ?.disabled && value ) {
141
+ if (! field ?.disabled && value .value ) {
142
+ let updatedValue: string | string [];
143
+
148
144
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 );
150
147
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 );
154
150
}
155
151
else {
156
- localModelValue .push (String ( value ) );
152
+ localModelValue .push (valStr );
157
153
}
158
154
159
- modelValue . value = localModelValue ;
155
+ updatedValue = localModelValue ;
160
156
}
161
157
else {
162
- modelValue . value = value ;
158
+ updatedValue = val as string ;
163
159
}
160
+
161
+ setValue (updatedValue );
162
+ modelValue .value = updatedValue ;
163
+ }
164
+ else {
165
+ setValue (val );
166
+ modelValue .value = val ;
164
167
}
165
168
166
169
await useOnActions ({
@@ -170,7 +173,7 @@ async function onActions(validate: FieldValidateResult, action: ValidateAction,
170
173
settingsValidateOn: settings .value ?.validateOn ,
171
174
validate ,
172
175
}).then (() => {
173
- currentValue .value = modelValue .value ;
176
+ currentValue .value = value .value ;
174
177
})
175
178
.catch ((error : Error ) => {
176
179
console .error (error );
@@ -310,11 +313,11 @@ function getHeight(option: Option): string | number | undefined {
310
313
}
311
314
312
315
const isActive = (val : string | number ): boolean | undefined => {
313
- if (! modelValue .value ) {
316
+ if (! value .value ) {
314
317
return undefined ;
315
318
}
316
319
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 );
318
321
};
319
322
320
323
// ------------------------- Variants //
@@ -330,8 +333,8 @@ function getVariant(val: string | number): VSFButtonFieldProps['field']['variant
330
333
331
334
332
335
// -------------------------------------------------- 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 ) {
335
338
return true ;
336
339
}
337
340
@@ -346,9 +349,9 @@ function activeMessages(errorMessage: string | string[]): boolean {
346
349
return false ;
347
350
}
348
351
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 [];
352
355
}
353
356
354
357
if (field .hint && (field .persistentHint || isFocused .value )) {
@@ -403,6 +406,7 @@ const buttonFieldContainerClass = computed(() => {
403
406
return {
404
407
' d-flex' : field ?.align ,
405
408
' flex-column' : field ?.align ,
409
+ ' v-input--error' : errorMessage ? errorMessage ?.length > 0 : false ,
406
410
' vsf-button-field__container' : true ,
407
411
[` align-${field ?.align } ` ]: field ?.align ,
408
412
};
@@ -420,6 +424,13 @@ const buttonClass = computed(() => {
420
424
return {};
421
425
});
422
426
427
+ const buttonClassAdditional = (option ) => {
428
+ return {
429
+ [` ${option ?.class } ` ]: true ,
430
+ [` ${field .selectedClass } ` ]: isActive (option .value ) && field .selectedClass != null ,
431
+ };
432
+ };
433
+
423
434
const getLabelClass = (option : Option ): object => {
424
435
const isActiveOption = isActive (option .value );
425
436
const optionVariant = getVariant (option .value );
0 commit comments