Skip to content

Commit 2260b57

Browse files
committed
feat(CFormCheck, CFormInput, CFormRange, CFormSelect, CFormSwitch, CFormTextarea): add new properties to generate labels, helper texts, and validation messages'
1 parent 118eea4 commit 2260b57

File tree

8 files changed

+474
-122
lines changed

8 files changed

+474
-122
lines changed

packages/coreui-vue/src/components/form/CFormCheck.ts

Lines changed: 82 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import { defineComponent, h } from 'vue'
22
import { shape } from 'vue-types'
33

4-
import { Color, Shape } from '../props'
4+
import { CFormControlValidation } from './CFormControlValidation'
55
import { CFormLabel } from './CFormLabel'
66

7+
import { Color, Shape } from '../props'
8+
79
const CFormCheck = defineComponent({
810
name: 'CFormCheck',
911
inheritAttrs: false,
1012
props: {
13+
...CFormControlValidation.props,
1114
/**
1215
* Create button-like checkboxes and radio buttons.
1316
*/
@@ -75,6 +78,17 @@ const CFormCheck = defineComponent({
7578
type: Boolean,
7679
required: false,
7780
},
81+
/**
82+
* Sets hit area to the full area of the component.
83+
*/
84+
hitArea: {
85+
type: String,
86+
required: false,
87+
validator: (value: string): boolean => {
88+
// The value must match one of these strings
89+
return ['full'].includes(value)
90+
},
91+
},
7892
/**
7993
* The element represents a caption for a component.
8094
*/
@@ -126,39 +140,57 @@ const CFormCheck = defineComponent({
126140
emit('update:modelValue', target.checked)
127141
}
128142

129-
const formControl = () => {
130-
return h('input', {
131-
...attrs,
132-
checked: props.modelValue,
133-
class: [
134-
props.button ? 'btn-check' : 'form-check-input',
143+
const className = [
144+
'form-check',
145+
{
146+
'form-check-inline': props.inline,
147+
'is-invalid': props.invalid,
148+
'is-valid': props.valid,
149+
},
150+
attrs.class,
151+
]
152+
153+
const inputClassName = props.button
154+
? 'btn-check'
155+
: [
156+
'form-check-input',
135157
{
136158
'is-invalid': props.invalid,
137159
'is-valid': props.valid,
160+
'me-2': props.hitArea,
138161
},
139-
],
162+
]
163+
164+
const labelClassName = props.button
165+
? [
166+
'btn',
167+
props.button.variant
168+
? `btn-${props.button.variant}-${props.button.color}`
169+
: `btn-${props.button.color}`,
170+
{
171+
[`btn-${props.button.size}`]: props.button.size,
172+
},
173+
`${props.button.shape}`,
174+
]
175+
: 'form-check-label'
176+
177+
const formControl = () => {
178+
return h('input', {
179+
...attrs,
180+
...(props.modelValue && { checked: props.modelValue }),
181+
class: inputClassName,
140182
id: props.id,
141183
indeterminate: props.indeterminate,
142184
onChange: (event: InputEvent) => handleChange(event),
143185
type: props.type,
144186
})
145187
}
188+
146189
const formLabel = () => {
147190
return h(
148191
CFormLabel,
149192
{
150-
customClassName: props.button
151-
? [
152-
'btn',
153-
props.button.variant
154-
? `btn-${props.button.variant}-${props.button.color}`
155-
: `btn-${props.button.color}`,
156-
{
157-
[`btn-${props.button.size}`]: props.button.size,
158-
},
159-
`${props.button.shape}`,
160-
]
161-
: 'form-check-label',
193+
customClassName: labelClassName,
162194
...(props.id && { for: props.id }),
163195
},
164196
{
@@ -167,25 +199,41 @@ const CFormCheck = defineComponent({
167199
)
168200
}
169201

202+
const formValidation = () => {
203+
return h(CFormControlValidation, {
204+
describedby: attrs['aria-describedby'] as string,
205+
feedback: props.feedback,
206+
feedbackInvalid: props.feedbackInvalid,
207+
feedbackValid: props.feedbackValid,
208+
invalid: props.invalid,
209+
tooltipFeedback: props.tooltipFeedback,
210+
valid: props.valid,
211+
})
212+
}
213+
170214
return () =>
171215
props.button
172-
? [formControl(), (slots.label || props.label) && formLabel()]
216+
? [formControl(), (slots.label || props.label) && formLabel(), formValidation()]
173217
: props.label
174-
? h(
175-
'div',
176-
{
177-
class: [
178-
'form-check',
218+
? props.hitArea
219+
? [
220+
h(
221+
CFormLabel,
179222
{
180-
'form-check-inline': props.inline,
181-
'is-invalid': props.invalid,
182-
'is-valid': props.valid,
223+
customClassName: className,
224+
...(props.id && { for: props.id }),
183225
},
184-
attrs.class,
185-
],
186-
},
187-
[formControl(), props.label && formLabel()],
188-
)
226+
[formControl(), props.label],
227+
),
228+
formValidation(),
229+
]
230+
: h(
231+
'div',
232+
{
233+
class: className,
234+
},
235+
[formControl(), props.label && formLabel(), formValidation()],
236+
)
189237
: formControl()
190238
},
191239
})
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { defineComponent, h } from 'vue'
2+
import { CFormFeedback } from './CFormFeedback'
3+
4+
const CFormControlValidation = defineComponent({
5+
name: 'CFormControlValidation',
6+
inheritAttrs: false,
7+
props: {
8+
/**
9+
* @ignore
10+
*/
11+
describedby: {
12+
type: String,
13+
},
14+
/**
15+
* Provide valuable, actionable feedback.
16+
*
17+
* @since 4.2.0
18+
*/
19+
feedback: {
20+
type: String,
21+
},
22+
/**
23+
* Provide valuable, actionable feedback.
24+
*
25+
* @since 4.2.0
26+
*/
27+
feedbackInvalid: {
28+
type: String,
29+
},
30+
/**
31+
* Provide valuable, actionable invalid feedback when using standard HTML form validation which applied two CSS pseudo-classes, `:invalid` and `:valid`.
32+
*
33+
* @since 4.2.0
34+
*/
35+
feedbackValid: {
36+
type: String,
37+
},
38+
/**
39+
* Set component validation state to invalid.
40+
*/
41+
invalid: Boolean,
42+
/**
43+
* Display validation feedback in a styled tooltip.
44+
*
45+
* @since 4.2.0
46+
*/
47+
tooltipFeedback: Boolean,
48+
/**
49+
* Set component validation state to valid.
50+
*/
51+
valid: Boolean,
52+
},
53+
setup(props, { slots }) {
54+
return () => [
55+
props.feedback &&
56+
(props.valid || props.invalid) &&
57+
h(
58+
CFormFeedback,
59+
{
60+
...(props.invalid && { id: props.describedby }),
61+
invalid: props.invalid,
62+
tooltip: props.tooltipFeedback,
63+
valid: props.valid,
64+
},
65+
{
66+
default: () => (slots.feedback && slots.feedback()) || props.feedback,
67+
},
68+
),
69+
(props.feedbackInvalid || slots.feedbackInvalid) &&
70+
h(
71+
CFormFeedback,
72+
{
73+
id: props.describedby,
74+
invalid: true,
75+
tooltip: props.tooltipFeedback,
76+
},
77+
{
78+
default: () =>
79+
(slots.feedbackInvalid && slots.feedbackInvalid()) || props.feedbackInvalid,
80+
},
81+
),
82+
(props.feedbackValid || slots.feedbackValid) &&
83+
h(
84+
CFormFeedback,
85+
{
86+
tooltip: props.tooltipFeedback,
87+
valid: true,
88+
},
89+
{
90+
default: () => (slots.feedbackValid && slots.feedbackValid()) || props.feedbackValid,
91+
},
92+
),
93+
]
94+
},
95+
})
96+
97+
export { CFormControlValidation }
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { defineComponent, h } from 'vue'
2+
import { CFormControlValidation } from './CFormControlValidation'
3+
import { CFormFloating } from './CFormFloating'
4+
import { CFormLabel } from './CFormLabel'
5+
import { CFormText } from './CFormText'
6+
7+
const CFormControlWrapper = defineComponent({
8+
name: 'CFormControlWrapper',
9+
inheritAttrs: false,
10+
props: {
11+
...CFormControlValidation.props,
12+
/**
13+
* Provide valuable, actionable valid feedback when using standard HTML form validation which applied two CSS pseudo-classes, `:invalid` and `:valid`.
14+
*
15+
* @since 4.2.0
16+
*/
17+
floatingLabel: {
18+
type: String,
19+
},
20+
/**
21+
* @ignore
22+
*/
23+
id: {
24+
type: String,
25+
},
26+
/**
27+
* Add a caption for a component.
28+
*
29+
* @since 4.2.0
30+
*/
31+
label: {
32+
type: String,
33+
},
34+
/**
35+
* Add helper text to the component.
36+
*
37+
* @since 4.2.0
38+
*/
39+
text: {
40+
type: String,
41+
},
42+
},
43+
setup(props, { slots }) {
44+
return () =>
45+
props.floatingLabel
46+
? h(CFormFloating, [
47+
slots.default && slots.default(),
48+
h(
49+
CFormLabel,
50+
{
51+
for: props.id,
52+
},
53+
{
54+
default: () => (slots.label && slots.label()) || props.label || props.floatingLabel,
55+
},
56+
),
57+
])
58+
: [
59+
(props.label || slots.label) &&
60+
h(
61+
CFormLabel,
62+
{
63+
for: props.id,
64+
},
65+
{
66+
default: () => (slots.label && slots.label()) || props.label,
67+
},
68+
),
69+
slots.default && slots.default(),
70+
(props.text || slots.text) &&
71+
h(
72+
CFormText,
73+
{
74+
id: props.describedby,
75+
},
76+
{
77+
default: () => (slots.text && slots.text()) || props.text,
78+
},
79+
),
80+
h(
81+
CFormControlValidation,
82+
{
83+
describedby: props.describedby,
84+
feedback: props.feedback,
85+
feedbackInvalid: props.feedbackInvalid,
86+
feedbackValid: props.feedbackValid,
87+
floatingLabel: props.floatingLabel,
88+
invalid: props.invalid,
89+
tooltipFeedback: props.tooltipFeedback,
90+
valid: props.valid,
91+
},
92+
{
93+
...(slots.feedback && { feedback: () => slots.feedback && slots.feedback() }),
94+
...(slots.feedbackInvalid && {
95+
feedbackInvalid: () => slots.feedbackInvalid && slots.feedbackInvalid(),
96+
}),
97+
...(slots.feedbackValid && {
98+
feedbackValid: () => slots.feedbackInvalid && slots.feedbackInvalid(),
99+
}),
100+
},
101+
),
102+
]
103+
},
104+
})
105+
106+
export { CFormControlWrapper }

0 commit comments

Comments
 (0)