Skip to content
This repository was archived by the owner on Jun 27, 2023. It is now read-only.

Commit 0b8b4e4

Browse files
authored
Merge pull request #96 from alvarosaburido/feature/custom-inputs-via-slots-for-next
feat(custom-field): added custom field support via scoped slots
2 parents a39a582 + 9242bf8 commit 0b8b4e4

File tree

8 files changed

+114
-9
lines changed

8 files changed

+114
-9
lines changed

.eslintrc.js

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module.exports = {
1414
ecmaVersion: 2020,
1515
},
1616
rules: {
17+
'vue/valid-v-slot': 'off',
1718
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
1819
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
1920
'@typescript-eslint/no-this-alias': [

dev/typescript/App.vue

+41-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,25 @@
99
@submited="handleSubmit"
1010
@changed="valueChanged"
1111
@error="handleError"
12-
/>
12+
>
13+
<template
14+
v-slot:customField1="{ control, onChange, onFocus, onBlur }"
15+
>
16+
<div class="avocado-field">
17+
<input
18+
v-if="control"
19+
class="form-control"
20+
v-model="control.value"
21+
:type="control.type"
22+
:name="control.name"
23+
@change="onChange"
24+
@focus="onFocus"
25+
@blur="onBlur"
26+
/>
27+
<i>🥑</i>
28+
</div>
29+
</template>
30+
</dynamic-form>
1331
<button
1432
class="btn bg-teal-500 text-white hover:bg-teal-700 mt-4"
1533
submit="true"
@@ -37,6 +55,7 @@ import {
3755
TextAreaInput,
3856
CheckboxInput,
3957
RadioInput,
58+
InputBase,
4059
} from '../../src';
4160
import { email, pattern } from '@/core/utils';
4261
@@ -117,6 +136,11 @@ export default defineComponent({
117136
},
118137
],
119138
}),
139+
new InputBase<string>({
140+
type: 'custom-field',
141+
label: 'Custom Field',
142+
name: 'customField1',
143+
}),
120144
],
121145
});
122146
function handleSubmit(values) {
@@ -140,4 +164,19 @@ export default defineComponent({
140164
},
141165
});
142166
</script>
143-
<style lang="scss"></style>
167+
<style lang="scss">
168+
.avocado-field {
169+
position: relative;
170+
171+
.form-control {
172+
border-color: #aec64c;
173+
background-color: #e2eb5d52;
174+
border-radius: 16px;
175+
}
176+
i {
177+
position: absolute;
178+
top: 5px;
179+
right: 15px;
180+
}
181+
}
182+
</style>

src/components/dynamic-form/DynamicForm.vue

+32-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,24 @@
1111
:key="control.name"
1212
:control="control"
1313
@changed="valueChange"
14-
/>
14+
>
15+
<template v-slot:customField="props">
16+
<div
17+
v-for="slot in deNormalizedScopedSlots"
18+
:key="slot"
19+
class="custom-form-wrapper"
20+
>
21+
<slot
22+
v-if="props.control.name === slot"
23+
:name="slot"
24+
:control="normalizedControls[slot]"
25+
:onChange="props.onChange"
26+
:onFocus="props.onFocus"
27+
:onBlur="props.onBlur"
28+
></slot>
29+
</div>
30+
</template>
31+
</dynamic-input>
1532
</form>
1633
</template>
1734

@@ -46,7 +63,7 @@ export default defineComponent({
4663
name: 'asDynamicForm',
4764
props,
4865
components,
49-
setup(props, { emit }) {
66+
setup(props, { emit, slots }) {
5067
const controls: Ref<FormControl<any>[]> = ref([]);
5168
const formValues = reactive({});
5269
const submited = ref(false);
@@ -124,6 +141,16 @@ export default defineComponent({
124141
emit('changed', formValues);
125142
}
126143
144+
const deNormalizedScopedSlots = computed(() => Object.keys(slots));
145+
146+
const normalizedControls = computed(() => {
147+
let normalizedControls = {};
148+
controls.value.forEach(element => {
149+
normalizedControls[element.name] = element;
150+
});
151+
return normalizedControls;
152+
});
153+
127154
watch(props, () => {
128155
mapControls();
129156
});
@@ -136,6 +163,9 @@ export default defineComponent({
136163
handleSubmit,
137164
isValid,
138165
errors,
166+
deNormalizedScopedSlots,
167+
normalizedControls,
168+
submited,
139169
};
140170
},
141171
});

src/components/dynamic-input/DynamicInput.vue

+28-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import RadioInput from '../radio-input/RadioInput.vue';
1010
1111
import { FormControl } from '../../core/models';
1212
import { isEmpty, entries, values, keys } from '../../core/utils/helpers';
13+
import { useInputEvents } from '../../composables/input-events';
1314
1415
const components = {
1516
TextInput,
@@ -29,7 +30,9 @@ export default defineComponent({
2930
name: 'asDynamicInput',
3031
components,
3132
props,
32-
setup(props, { emit }) {
33+
setup(props, { emit, slots }) {
34+
const { onFocus, onBlur } = useInputEvents(props?.control, emit);
35+
3336
let component;
3437
3538
const getClasses = computed(() => {
@@ -133,6 +136,30 @@ export default defineComponent({
133136
case 'radio':
134137
component = h(RadioInput, attributes.value);
135138
break;
139+
case 'custom-field':
140+
component = h(
141+
'slot',
142+
{
143+
name: 'customField',
144+
},
145+
slots.customField({
146+
control: props.control,
147+
onChange: ($event: any) => {
148+
const newValue = {};
149+
const value = $event.target.value;
150+
151+
if (props.control) {
152+
props.control.dirty = true;
153+
newValue[props.control.name] = value;
154+
validate();
155+
emit('changed', newValue);
156+
}
157+
},
158+
onFocus,
159+
onBlur,
160+
}),
161+
);
162+
break;
136163
default:
137164
break;
138165
}

src/composables/input-events.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import { FormControl } from '@/core/models';
22

3-
export function useInputEvents(control: FormControl<any> | undefined, emit) {
4-
function onChange($event) {
3+
export function useInputEvents(
4+
control: FormControl<any> | undefined,
5+
emit: any,
6+
) {
7+
function onChange($event: any) {
58
if (control) {
69
control.value = $event.target.value;
710
control.dirty = true;
811
}
912
emit('changed', $event.target.value);
1013
}
11-
function onCheck($event) {
14+
function onCheck($event: any) {
1215
if (control) {
1316
control.value = $event.target.checked;
1417
control.dirty = true;

src/styles/themes/default.scss

+4
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,7 @@ $input-error-color: #dc3545 !default;
137137
user-select: none;
138138
font-size: 0.85rem;
139139
}
140+
141+
.custom-form-wrapper {
142+
order: 2;
143+
}

src/useApi.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { DynamicFormsPlugin } from './dynamicForms';
33

44
export const dynamicFormsSymbol: InjectionKey<DynamicFormsPlugin> = Symbol();
55

6-
export function useDynamicForms() {
6+
export function useDynamicForms(): DynamicFormsPlugin {
77
const dynamicForms = inject(dynamicFormsSymbol);
88
if (!dynamicForms) throw new Error('No dynamicForms provided!!!');
99

tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"sourceMap": true,
1414
"noImplicitThis": true,
1515
"noImplicitAny": false,
16+
"strictNullChecks": false,
1617
"allowJs": true,
1718
"baseUrl": ".",
1819
"rootDir": ".",

0 commit comments

Comments
 (0)