Skip to content

Commit 930c122

Browse files
committed
feat: add CForm components
1 parent 26a012e commit 930c122

File tree

11 files changed

+1156
-0
lines changed

11 files changed

+1156
-0
lines changed

src/components/Forms/CForm.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { mergeData } from 'vue-functional-data-merge'
2+
3+
export default {
4+
name: 'CForm',
5+
functional: true,
6+
props: {
7+
// id: String,
8+
inline: Boolean,
9+
// novalidate: Boolean,
10+
validated: Boolean,
11+
},
12+
render(h, { props, data, children }) {
13+
return h(
14+
'form',
15+
mergeData(data, {
16+
class: {
17+
'form-inline': props.inline,
18+
'was-validated': props.validated
19+
},
20+
// attrs: {
21+
// id: props.id,
22+
// novalidate: props.novalidate
23+
// }
24+
}),
25+
children
26+
)
27+
}
28+
}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
<template>
2+
<CFormGroup v-bind="{validFeedback, invalidFeedback, tooltipFeedback,
3+
description, class: computedClasses}">
4+
<input slot="input"
5+
v-bind="$attrs"
6+
:id="safeId"
7+
:type="type"
8+
:class="inputClasses"
9+
:value="value"
10+
:checked="state"
11+
@change="onChange($event)"
12+
/>
13+
14+
15+
<template slot="labelAfterInput">
16+
<slot name="labelAfterInput">
17+
<label v-if="label" :for="safeId" :class="labelClasses">{{label}}</label>
18+
</slot>
19+
</template>
20+
21+
22+
<template v-for="slot in ['label', 'prepend', 'append', 'validFeedback', 'invalidFeedback','description']"
23+
:slot="slot"
24+
>
25+
<slot :name="slot">
26+
</slot>
27+
</template>
28+
</CFormGroup>
29+
</template>
30+
31+
<script>
32+
import safeId from '../../mixins/safeId'
33+
import { validationComputedProps } from './formMixins'
34+
import { formCheckboxProps as props } from './formProps'
35+
import CFormGroup from './CFormGroup'
36+
export default {
37+
name: 'CFormCheckbox',
38+
inheritAttrs: false,
39+
components: { CFormGroup },
40+
mixins: [safeId, validationComputedProps],
41+
model: {
42+
prop: 'checked',
43+
event: 'change'
44+
},
45+
props,
46+
// {
47+
// label: String,
48+
// id: String,
49+
// wasValidated: Boolean,
50+
// type: {
51+
// type: String,
52+
// default: 'checkbox'
53+
// },
54+
// checked: [Boolean, String, Number],
55+
// value: {
56+
// type: [String, Number, Boolean],
57+
// default: null
58+
// },
59+
// trueValue: {
60+
// type: [String, Number, Boolean],
61+
// default: undefined
62+
// },
63+
// falseValue: {
64+
// type: [String, Number, Boolean],
65+
// default: undefined
66+
// },
67+
// validFeedback: String,
68+
// invalidFeedback: String,
69+
// tooltipFeedback: Boolean,
70+
// description: String,
71+
// isValid: {
72+
// type: Boolean,
73+
// default: null
74+
// },
75+
// addLabelClasses: String,
76+
// custom: [Boolean, String],
77+
// inline: Boolean
78+
// },
79+
data () {
80+
return {
81+
state: null
82+
}
83+
},
84+
created () {
85+
this.state = this.getCheckState()
86+
},
87+
watch: {
88+
checked (val, oldVal) {
89+
if(val !== oldVal)
90+
this.state = this.getCheckState()
91+
}
92+
},
93+
computed: {
94+
customType () {
95+
return typeof this.custom === 'string' ? this.custom : this.type
96+
},
97+
computedClasses () {
98+
return [
99+
this.custom ? `custom-control custom-${this.customType}`: 'form-check',
100+
this.inline ? `${this.custom ? 'custom-control' : 'form-check'}-inline` : '',
101+
{
102+
'was-validated': this.wasValidated
103+
}
104+
]
105+
},
106+
labelClasses () {
107+
return [this.addLabelClasses, this.custom ? 'custom-control-label': 'form-check-label']
108+
},
109+
inputClasses () {
110+
return [
111+
this.custom ? 'custom-control-input' : 'form-check-input',
112+
this.validationClass,
113+
]
114+
},
115+
116+
// validationComputedProps mixin
117+
// computedIsValid () {
118+
// if (typeof this.isValid === 'function')
119+
// return this.isValid(this.state)
120+
// return this.isValid
121+
// },
122+
// validationClass () {
123+
// if (this.computedIsValid === null)
124+
// return
125+
// return this.computedIsValid ? 'is-valid' : 'is-invalid'
126+
// }
127+
},
128+
methods: {
129+
getCheckState () {
130+
if (this.type === 'radio')
131+
return this.checked === this.value
132+
else
133+
return typeof this.checked === 'boolean' ? this.checked :
134+
this.checked === this.trueValue ? true : false
135+
},
136+
onChange (e) {
137+
this.state = e.target.checked
138+
this.$emit('change', this.getValue(e), e)
139+
},
140+
getValue (e) {
141+
if(this.type === 'radio')
142+
return this.value
143+
else if(e.target.checked)
144+
return this.trueValue !== undefined ? this.trueValue : true
145+
else
146+
return this.falseValue !== undefined ? this.falseValue : false
147+
},
148+
},
149+
}
150+
</script>

src/components/Forms/CFormFile.vue

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
<template>
2+
<CFormGroup v-bind="{validFeedback, invalidFeedback,
3+
tooltipFeedback, description,
4+
wrapperClasses, class: computedClasses}"
5+
>
6+
<template slot="label">
7+
<slot name="label">
8+
<label v-if="label" :for="safeId" :class="labelClasses">{{label}}</label>
9+
</slot>
10+
</template>
11+
12+
13+
<template slot="input">
14+
<input v-bind="$attrs"
15+
:id="safeId"
16+
:class="inputClasses"
17+
type="file"
18+
@change="onChange($event)"
19+
/>
20+
<label v-if="custom" :for="safeId" class="custom-file-label">
21+
{{typeof custom === 'string' ? custom : multiple ? 'Choose files...' : 'Choose file...'}}
22+
</label>
23+
</template>
24+
25+
26+
<template v-for="slot in ['labelAfterInput','validFeedback',
27+
'invalidFeedback','description']"
28+
:slot="slot"
29+
>
30+
<slot :name="slot"></slot>
31+
</template>
32+
</CFormGroup>
33+
</template>
34+
35+
<script>
36+
import * as allFormMixins from './formMixins'
37+
const mixins = Object.values(allFormMixins)
38+
import { formFileProps as props } from './formProps'
39+
import CFormGroup from './CFormGroup'
40+
export default {
41+
name: 'CFormFile',
42+
inheritAttrs: false,
43+
components: { CFormGroup },
44+
mixins,
45+
props,
46+
// {
47+
// // Html props: disabled, required, accept
48+
// label: String,
49+
// id: String,
50+
// wasValidated: Boolean,
51+
// size: {
52+
// type: String,
53+
// validator: str => ['','sm','lg'].includes(str)
54+
// },
55+
// horizontal: [Boolean, Object],
56+
// validFeedback: String,
57+
// invalidFeedback: String,
58+
// tooltipFeedback: Boolean,
59+
// description: String,
60+
// isValid: {
61+
// type: Boolean,
62+
// default: null
63+
// },
64+
// multiple: Boolean,
65+
// custom: [Boolean, String],
66+
// addInputClasses: String,
67+
// addLabelClasses: String,
68+
// addWrapperClasses: String,
69+
// },
70+
data () {
71+
return {
72+
state: null,
73+
}
74+
},
75+
computed: {
76+
// classesComputedProps mixin
77+
haveCustomSize () {
78+
return ['','sm','lg'].includes(this.size) &&
79+
Boolean(this.size) && !Boolean(this.custom)
80+
},
81+
// haveCustomSize () {
82+
// return ['','sm','lg'].includes(this.size) && Boolean(this.size)
83+
// },
84+
computedClasses () {
85+
return [
86+
this.isHorizontal ? 'form-row':
87+
this.custom ? 'custom-file' : 'form-group position-relative',
88+
{
89+
'was-validated': this.wasValidated
90+
}
91+
]
92+
},
93+
// computedClasses () {
94+
// return [
95+
// this.isHorizontal ? 'form-row': 'form-group',
96+
// {
97+
// 'was-validated': this.wasValidated
98+
// }
99+
// ]
100+
// },
101+
// labelClasses () {
102+
// return [ this.addLabelClasses, {
103+
// 'col-form-label': this.isHorizontal,
104+
// [this.horizontal.label || 'col-2']: this.isHorizontal,
105+
// [`col-form-label-${this.size}`]: this.haveCustomSize,
106+
// }]
107+
// },
108+
// customSizeClass () {
109+
// return this.haveCustomSize ? `form-control-${this.size}` : null
110+
// },
111+
inputClass () {
112+
return this.custom ? 'custom-file-input' : 'form-control-file'
113+
},
114+
// inputClasses () {
115+
// return [
116+
// this.inputClass || 'form-control',
117+
// this.stateClass,
118+
// this.addInputClasses,
119+
// this.customSizeClass
120+
// ]
121+
// },
122+
123+
124+
// validationComputedProps mixin
125+
// computedIsValid () {
126+
// if (typeof this.isValid === 'function')
127+
// return this.isValid(this.state)
128+
// return this.isValid
129+
// },
130+
// validationClass () {
131+
// if (this.computedIsValid === null)
132+
// return
133+
// return this.computedIsValid ? 'is-valid' : 'is-invalid'
134+
// }
135+
136+
//wrapperComputedProps mixin
137+
// isHorizontal () {
138+
// return Boolean(this.horizontal)
139+
// },
140+
// haveInputGroup () {
141+
// return Boolean(this.tooltipFeedback || this.append ||
142+
// this.prepend || this.$slots.append || this.$slots.prepend)
143+
// },
144+
haveInputGroup () {
145+
return false
146+
}
147+
// haveWrapper () {
148+
// return this.haveInputGroup || Boolean(this.addWrapperClasses || this.isHorizontal)
149+
// },
150+
// wrapperClasses () {
151+
// if(this.haveWrapper)
152+
// return [ this.addWrapperClasses, {
153+
// [this.horizontal.input || 'col-10'] : this.isHorizontal,
154+
// 'input-group' : this.haveInputGroup
155+
// }]
156+
// }
157+
},
158+
methods: {
159+
onChange (e) {
160+
this.state = e.target.files
161+
this.$emit('change', e.target.files, e)
162+
}
163+
}
164+
}
165+
</script>

0 commit comments

Comments
 (0)