Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added slot typings for components closes #3534 #3537

Merged
merged 1 commit into from Oct 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 16 additions & 4 deletions packages/vee-validate/src/ErrorMessage.ts
@@ -1,8 +1,12 @@
import { inject, h, defineComponent, computed, resolveDynamicComponent } from 'vue';
import { inject, h, defineComponent, computed, resolveDynamicComponent, VNode } from 'vue';
import { FormContextKey } from './symbols';
import { normalizeChildren } from './utils';

export const ErrorMessage = defineComponent({
interface ErrorMessageSlotProps {
message: string | undefined;
}

const ErrorMessageImpl = defineComponent({
name: 'ErrorMessage',
props: {
as: {
Expand All @@ -20,7 +24,7 @@ export const ErrorMessage = defineComponent({
return form?.errors.value[props.name];
});

function slotProps() {
function slotProps(): ErrorMessageSlotProps {
return {
message: message.value,
};
Expand All @@ -33,7 +37,7 @@ export const ErrorMessage = defineComponent({
}

const tag = (props.as ? resolveDynamicComponent(props.as) : props.as) as string;
const children = normalizeChildren(tag, ctx, slotProps);
const children = normalizeChildren(tag, ctx, slotProps as any);

const attrs = {
role: 'alert',
Expand All @@ -56,3 +60,11 @@ export const ErrorMessage = defineComponent({
};
},
});

export const ErrorMessage = ErrorMessageImpl as typeof ErrorMessageImpl & {
new (): {
$slots: {
default: (arg: ErrorMessageSlotProps) => VNode[];
};
};
};
65 changes: 56 additions & 9 deletions packages/vee-validate/src/Field.ts
@@ -1,9 +1,21 @@
import { h, defineComponent, toRef, SetupContext, resolveDynamicComponent, computed, watch, PropType } from 'vue';
import {
h,
defineComponent,
toRef,
SetupContext,
resolveDynamicComponent,
computed,
watch,
PropType,
VNode,
} from 'vue';
import { getConfig } from './config';
import { RuleExpression, useField } from './useField';
import { normalizeChildren, hasCheckedAttr, shouldHaveValueBinding, isPropPresent, normalizeEventValue } from './utils';
import { toNumber } from '../../shared';
import { IS_ABSENT } from './symbols';
import { FieldMeta } from './types';
import { FieldContext } from '.';

interface ValidationTriggersProps {
validateOnMount: boolean;
Expand All @@ -13,7 +25,30 @@ interface ValidationTriggersProps {
validateOnModelUpdate: boolean;
}

export const Field = defineComponent({
interface FieldBindingObject<TValue = unknown> {
name: string;
onBlur: (e: Event) => unknown;
onInput: (e: Event) => unknown;
onChange: (e: Event) => unknown;
'onUpdate:modelValue'?: ((e: TValue) => unknown) | undefined;
value?: unknown;
checked?: boolean;
}

interface FieldSlotProps<TValue = unknown>
extends Pick<
FieldContext,
'validate' | 'resetField' | 'handleChange' | 'handleReset' | 'handleBlur' | 'setTouched' | 'setErrors'
> {
field: FieldBindingObject<TValue>;
value: TValue;
meta: FieldMeta<TValue>;
errors: string[];
errorMessage: string | undefined;
handleInput: FieldContext['handleChange'];
}

const FieldImpl = defineComponent({
name: 'Field',
inheritAttrs: false,
props: {
Expand Down Expand Up @@ -135,19 +170,23 @@ export const Field = defineComponent({
const fieldProps = computed(() => {
const { validateOnInput, validateOnChange, validateOnBlur, validateOnModelUpdate } =
resolveValidationTriggers(props);
const baseOnBlur = [handleBlur, ctx.attrs.onBlur, validateOnBlur ? validateField : undefined].filter(Boolean);
const baseOnInput = [(e: unknown) => onChangeHandler(e, validateOnInput), ctx.attrs.onInput].filter(Boolean);
const baseOnChange = [(e: unknown) => onChangeHandler(e, validateOnChange), ctx.attrs.onChange].filter(Boolean);
const baseOnBlur: any = [handleBlur, ctx.attrs.onBlur, validateOnBlur ? validateField : undefined].filter(
Boolean
);
const baseOnInput: any = [(e: unknown) => onChangeHandler(e, validateOnInput), ctx.attrs.onInput].filter(Boolean);
const baseOnChange: any = [(e: unknown) => onChangeHandler(e, validateOnChange), ctx.attrs.onChange].filter(
Boolean
);

const attrs: Record<string, any> = {
const attrs: FieldBindingObject<unknown> = {
name: props.name,
onBlur: baseOnBlur,
onInput: baseOnInput,
onChange: baseOnChange,
};

if (validateOnModelUpdate) {
attrs['onUpdate:modelValue'] = [onChangeHandler];
attrs['onUpdate:modelValue'] = [onChangeHandler] as any;
}

if (hasCheckedAttr(ctx.attrs.type) && checked) {
Expand Down Expand Up @@ -177,7 +216,7 @@ export const Field = defineComponent({
}
});

function slotProps() {
function slotProps(): FieldSlotProps {
return {
field: fieldProps.value,
value: value.value,
Expand Down Expand Up @@ -205,7 +244,7 @@ export const Field = defineComponent({

return () => {
const tag = resolveDynamicComponent(resolveTag(props, ctx)) as string;
const children = normalizeChildren(tag, ctx, slotProps);
const children = normalizeChildren(tag, ctx, slotProps as any);

if (tag) {
return h(
Expand Down Expand Up @@ -261,3 +300,11 @@ function resolveInitialValue(props: Record<string, unknown>, ctx: SetupContext<a

return isPropPresent(props, 'modelValue') ? props.modelValue : undefined;
}

export const Field = FieldImpl as typeof FieldImpl & {
new (): {
$slots: {
default: (arg: FieldSlotProps<unknown>) => VNode[];
};
};
};
13 changes: 11 additions & 2 deletions packages/vee-validate/src/FieldArray.ts
@@ -1,8 +1,9 @@
import { defineComponent, toRef } from 'vue';
import { defineComponent, toRef, UnwrapRef, VNode } from 'vue';
import { FieldArrayContext } from './types';
import { useFieldArray } from './useFieldArray';
import { normalizeChildren } from './utils';

export const FieldArray = defineComponent({
const FieldArrayImpl = defineComponent({
name: 'FieldArray',
inheritAttrs: false,
props: {
Expand Down Expand Up @@ -44,3 +45,11 @@ export const FieldArray = defineComponent({
};
},
});

export const FieldArray = FieldArrayImpl as typeof FieldArrayImpl & {
new (): {
$slots: {
default: (arg: UnwrapRef<FieldArrayContext>) => VNode[];
};
};
};
41 changes: 37 additions & 4 deletions packages/vee-validate/src/Form.ts
@@ -1,9 +1,34 @@
import { h, defineComponent, toRef, resolveDynamicComponent, PropType } from 'vue';
import { h, defineComponent, toRef, resolveDynamicComponent, PropType, VNode, UnwrapRef } from 'vue';
import { useForm } from './useForm';
import { SubmissionHandler, InvalidSubmissionHandler } from './types';
import { isEvent, normalizeChildren } from './utils';
import { FormContext } from '.';

export const Form = defineComponent({
type FormSlotProps = UnwrapRef<
Pick<
FormContext,
| 'meta'
| 'errors'
| 'values'
| 'isSubmitting'
| 'submitCount'
| 'validate'
| 'validateField'
| 'handleReset'
| 'submitForm'
| 'setErrors'
| 'setFieldError'
| 'setFieldValue'
| 'setValues'
| 'setFieldTouched'
| 'setTouched'
| 'resetForm'
>
> & {
handleSubmit: (evt: Event | SubmissionHandler, onSubmit?: SubmissionHandler) => Promise<unknown>;
};

const FormImpl = defineComponent({
name: 'Form',
inheritAttrs: false,
props: {
Expand Down Expand Up @@ -89,7 +114,7 @@ export const Form = defineComponent({
return handleSubmit(onSuccess as SubmissionHandler<Record<string, unknown>>, props.onInvalidSubmit)(evt as Event);
}

function slotProps() {
function slotProps(): FormSlotProps {
return {
meta: meta.value,
errors: errors.value,
Expand Down Expand Up @@ -127,7 +152,7 @@ export const Form = defineComponent({
return function renderForm() {
// avoid resolving the form component as itself
const tag = props.as === 'form' ? props.as : (resolveDynamicComponent(props.as) as string);
const children = normalizeChildren(tag, ctx, slotProps);
const children = normalizeChildren(tag, ctx, slotProps as any);

if (!props.as) {
return children;
Expand Down Expand Up @@ -155,3 +180,11 @@ export const Form = defineComponent({
};
},
});

export const Form = FormImpl as typeof FormImpl & {
new (): {
$slots: {
default: (arg: FormSlotProps) => VNode[];
};
};
};