1
1
<template >
2
2
<div >
3
- <FieldLabel
4
- :label =" field.label"
5
- :required =" fieldRequired"
6
- />
7
-
8
- <div class =" vsf-fancy-radio__container" >
9
- <div class =" v-input__control vsf-fancy-radio__control" >
10
- <template
11
- v-for =" option in field ?.options "
12
- :key =" option .value "
3
+ <div
4
+ :id =" field?.groupId"
5
+ class =" vsf-fancy-radio__container"
6
+ >
7
+ <Field
8
+ v-slot =" { errorMessage, validate }"
9
+ v-model =" modelValue"
10
+ :name =" field.name"
11
+ type =" radio"
12
+ :validate-on-model-update =" true"
13
+ >
14
+ <v-radio-group
15
+ v-model =" modelValue"
16
+ class =" vsf-fancy-radio__control"
17
+ :direction =" field?.direction"
18
+ :error =" hasErrors"
19
+ :error-messages =" errorMessage || field?.errorMessages"
20
+ :hideDetails =" field?.hideDetails || settings?.hideDetails"
21
+ :hint =" field?.hint"
22
+ :inline =" field?.inline"
23
+ :max-errors =" field?.maxErrors"
24
+ :max-width =" field?.maxWidth"
25
+ :messages =" field?.messages"
26
+ :min-width =" field?.minWidth"
27
+ :multiple =" field?.multiple"
28
+ :persistentHint =" field?.persistentHint"
29
+ :theme =" field?.theme"
13
30
>
31
+ <template #label >
32
+ <FieldLabel
33
+ :label =" field.label"
34
+ :required =" fieldRequired"
35
+ />
36
+ </template >
37
+
14
38
<div
39
+ v-for =" option in field?.options"
40
+ :key =" option.value"
15
41
class =" vsf-fancy-radio__field v-field"
16
42
:class =" {
17
43
...fieldClasses,
18
- [`vsf-fancy-radio__field-- variant-${fieldVariant}-focused`]: isFocused === option.value,
44
+ [`vsf-fancy-radio__field-variant-${fieldVariant}-focused`]: isFocused === option.value,
19
45
}"
20
46
:style =" fieldStyle"
21
47
>
22
- <Field
23
- v-slot = " { errors, errorMessage, validate } "
48
+ <input
49
+ :id = " option?.id "
24
50
v-model =" modelValue"
51
+ class =" vsf-fancy-radio__input"
52
+ :class =" {
53
+ 'vsf-fancy-radio__input_checked': modelValue === option.value || (Array.isArray(modelValue) ? modelValue.includes(option.value) : false),
54
+ 'vsf-fancy-radio__input_error': hasErrors || errorMessage || field?.errorMessages,
55
+ }"
56
+ :disabled =" (field.disabled as boolean)"
25
57
:name =" field.name"
26
58
type =" radio"
27
- :validate-on-model-update =" true"
28
- >
29
- <input
30
- :id =" `vsf-radio-${field.name}-${option.value}`"
31
- v-model =" modelValue"
32
- class =" vsf-fancy-radio__input"
33
- :class =" {
34
- 'vsf-fancy-radio__input_checked': modelValue === option.value,
35
- 'vsf-fancy-radio__input_error': errors.length > 0,
36
- }"
37
- :error =" errorMessage ? errorMessage?.length > 0 : false"
38
- :error-messages =" errorMessage"
39
- :name =" field.name"
40
- type =" radio"
41
- :value =" option.value"
42
- @blur =" onActions(validate, 'blur')"
43
- @change =" onActions(validate, 'change')"
44
- @click =" onActions(validate, 'click')"
45
- @input =" onActions(validate, 'input')"
46
- />
47
- </Field >
59
+ :value =" option.value"
60
+ :width =" field?.width"
61
+ @blur =" onActions(validate, 'blur')"
62
+ @change =" onActions(validate, 'change')"
63
+ @input =" onActions(validate, 'input')"
64
+ />
48
65
49
66
<label
50
67
:class =" {
51
68
...labelClasses,
52
- [`vsf-fancy-radio__label-- variant-${fieldVariant}-focused`]: isFocused === option.value,
69
+ [`vsf-fancy-radio__label-variant-${fieldVariant}-focused`]: isFocused === option.value,
53
70
}"
54
71
:for =" `vsf-radio-${field.name}-${option.value}`"
55
72
:style =" labelStyle"
73
+ @click =" onActions(validate, 'click', option.value)"
56
74
@mousedown =" onFocus(option.value)"
57
75
@mouseleave =" onFocus(null)"
58
76
@mouseup =" onFocus(null)"
69
87
></div >
70
88
</label >
71
89
</div >
72
- </template >
73
- </div >
90
+ </v-radio-group >
91
+ </Field >
74
92
</div >
93
+
75
94
</div >
76
95
</template >
77
96
@@ -96,8 +115,29 @@ const fieldRequired = computed(() => {
96
115
});
97
116
98
117
118
+ if (modelValue ?.value == null ) {
119
+ modelValue .value = field ?.multiple ? [] : null ;
120
+ }
121
+
99
122
// ------------------------- Validate On Actions //
100
- async function onActions(validate : FieldValidateResult , action : ValidateAction ): Promise <void > {
123
+ async function onActions(validate : FieldValidateResult , action : ValidateAction , value ? : unknown ): Promise <void > {
124
+ // TODO: Check the other validate on states //
125
+
126
+ if (! field ?.disabled && value ) {
127
+ if (field ?.multiple ) {
128
+ if (modelValue .value .includes (value )) {
129
+ const index = modelValue .value .indexOf (value );
130
+ modelValue .value .splice (index , 1 );
131
+ }
132
+ else {
133
+ modelValue .value .push (value );
134
+ }
135
+ }
136
+ else {
137
+ modelValue .value = value ;
138
+ }
139
+ }
140
+
101
141
useOnActions ({
102
142
action ,
103
143
emit ,
@@ -108,6 +148,15 @@ async function onActions(validate: FieldValidateResult, action: ValidateAction):
108
148
}
109
149
110
150
151
+ const hasErrors = computed (() => {
152
+ let err = field ?.error ;
153
+
154
+ err = field ?.errorMessages ? field .errorMessages .length > 0 : err ;
155
+
156
+ return err ;
157
+ });
158
+
159
+
111
160
// -------------------------------------------------- Properties //
112
161
const densityHeight = {
113
162
comfortable: ' 48px' ,
@@ -138,7 +187,10 @@ const fieldHeight = computed(() => {
138
187
const fieldStyle = computed <CSSProperties >(() => {
139
188
const styles = {
140
189
' height' : fieldHeight .value ,
190
+ ' max-width' : field ?.maxWidth ?? ' 100%' ,
141
191
' min-height' : fieldHeight .value ,
192
+ ' min-width' : field .minWidth ?? ' fit-content' ,
193
+ ' width' : field ?.width ?? ' 100px' ,
142
194
};
143
195
144
196
return styles ;
@@ -147,13 +199,16 @@ const fieldStyle = computed<CSSProperties>(() => {
147
199
const labelStyle = computed <CSSProperties >(() => {
148
200
const styles = {
149
201
' min-width' : ' 100px' ,
150
- ' width' : field ?.width ?? ' 100px' ,
202
+ ' width' : field ?.minWidth ?? field ?. maxWidth ?? field ?. width ?? ' 100px' ,
151
203
};
152
204
153
205
return styles ;
154
206
});
155
207
156
208
209
+ const gap = ref (field .gap ?? ' 10px' );
210
+
211
+
157
212
// -------------------------------------------------- Classes //
158
213
const fieldOverlayClasses = computed (() => {
159
214
return {
@@ -182,8 +237,10 @@ const fieldTextClasses = computed(() => {
182
237
183
238
const fieldClasses = computed (() => {
184
239
return {
240
+ ' vsf-fancy-radio__field-disabled' : field ?.disabled ,
241
+ ' vsf-fancy-radio__field-flat' : field ?.flat ,
185
242
[` v-field--variant-${fieldVariant .value } ` ]: true ,
186
- [` vsf-fancy-radio__field-- variant-${fieldVariant .value } ` ]: true ,
243
+ [` vsf-fancy-radio__field-variant-${fieldVariant .value } ` ]: true ,
187
244
};
188
245
});
189
246
@@ -192,8 +249,7 @@ const labelClasses = computed(() => {
192
249
' pa-1' : field ?.density === ' compact' ,
193
250
' pa-4' : field ?.density !== ' compact' ,
194
251
' vsf-fancy-radio__label' : true ,
195
- [` vsf-fancy-radio__label--variant-${fieldVariant .value } ` ]: true ,
196
- // [`vsf-fancy-radio__label-variant-${variant}_${isFocused.value}`]: true,
252
+ [` vsf-fancy-radio__label-variant-${fieldVariant .value } ` ]: true ,
197
253
};
198
254
});
199
255
@@ -210,6 +266,7 @@ function onFocus(value: any) {
210
266
:root {
211
267
--vsf-field-border-radius : 4px ;
212
268
--vsf-field-border-opacity : 0.04 ;
269
+ --vsf-field-disabled-opacity : 0.25 ;
213
270
}
214
271
</style >
215
272
@@ -218,7 +275,6 @@ function onFocus(value: any) {
218
275
& __container {
219
276
align-items : center ;
220
277
display : flex ;
221
- gap : 10px ;
222
278
height : fit-content ;
223
279
justify-content : center ;
224
280
position : relative ;
@@ -227,16 +283,76 @@ function onFocus(value: any) {
227
283
& __control {
228
284
gap : 10px ;
229
285
min-height : fit-content !important ;
286
+ min-width : fit-content !important ;
287
+
288
+ :deep (.v-input__control ) {
289
+ align-items : center ;
290
+ display : flex ;
291
+ justify-content : center ;
292
+
293
+ .v-selection-control-group {
294
+ flex-direction : row !important ;
295
+ gap : v-bind (gap ) !important ;
296
+ justify-content : center !important ;
297
+ padding-inline-start : 0 !important ;
298
+ }
299
+
300
+ .v-label {
301
+ margin-inline-start : 0 !important ;
302
+ }
303
+ }
304
+
305
+ :deep (.v-input__details ) {
306
+ .v- messages {
307
+ align-items : center ;
308
+ display : flex ;
309
+ flex-direction : column ;
310
+ justify-content : center ;
311
+ }
312
+ }
313
+
314
+ & .v-input--vertical {
315
+ display : flex ;
316
+ flex-direction : column ;
317
+
318
+ :deep (.v-input__control ) {
319
+ .v- selection- control- group {
320
+ flex-direction : column !important ;
321
+ }
322
+ }
323
+ }
230
324
}
231
325
232
326
// -------------------------------------------------- Field //
233
327
& __field {
234
328
border-radius : var (--vsf-field-border-radius );
329
+ display : block !important ;
330
+ flex-grow : unset ;
235
331
grid-area : unset ;
236
332
min-height : fit-content !important ;
237
333
334
+ & -disabled {
335
+ .vsf-fancy-radio__overlay {
336
+ opacity : var (--vsf-field-disabled-opacity ) !important ;
337
+ }
338
+
339
+ .vsf-fancy-radio__label {
340
+ cursor : default !important ;
341
+
342
+ & :hover {
343
+ .vsf-fancy-radio__overlay {
344
+ opacity : var (--vsf-field-disabled-opacity ) !important ;
345
+ }
346
+ }
347
+ }
348
+ }
349
+
350
+ & -flat {
351
+ --vsf-field-border-radius : 0 ;
352
+ }
353
+
238
354
// ? -------------------------------------------------- Variants //
239
- & -- variant {
355
+ & -variant {
240
356
241
357
// ? ------------------------- Filled //
242
358
& -filled {
@@ -334,7 +450,7 @@ function onFocus(value: any) {
334
450
}
335
451
336
452
// ? -------------------------------------------------- Variants //
337
- & -- variant {
453
+ & -variant {
338
454
// ? ------------------------- Filled //
339
455
& -filled {
340
456
border-radius : var (--vsf-field-border-radius ) var (--vsf-field-border-radius ) 0 0 ;
0 commit comments