@inkline/inkline
Version:
Inkline is the intuitive UI Components library that gives you a developer-friendly foundation for building high-quality, accessible, and customizable Vue.js 3 Design Systems.
129 lines (128 loc) • 4.18 kB
JavaScript
import { clone, getValueByPath, setValueByPath, setValuesAlongPath } from "@grozav/utils";
import { computed, inject, ref, unref, watch } from "vue";
import { FormKey, FormGroupKey } from "@inkline/inkline/constants";
import { setSchemaStateRecursively, validateSchema } from "@inkline/inkline/validation";
import { useInkline } from "@inkline/inkline/composables/useInkline";
export function useValidation(options) {
const inkline = useInkline();
const form = inject(FormKey, null);
const formGroup = inject(FormGroupKey, null);
const schema = form ? computed(
() => form.schema && options.validate?.value && getValueByPath(form.schema.value, options.name.value)
) : ref(options.schema?.value || null);
if (!form && options.schema?.value) {
watch(
() => options.schema?.value,
(value) => {
schema.value = value;
}
);
}
function shouldValidate(schema2, eventName) {
if (!options.validate?.value) {
return;
}
const events = schema2.validateOn ? [].concat(schema2.validateOn) : inkline?.options?.validateOn;
return events.includes(eventName);
}
async function setValue(name, value) {
if (!options.validate?.value) {
return;
}
let resolvedSchema = clone(schema.value);
const targetSchema = getValueByPath(resolvedSchema, name);
if (!targetSchema) {
throw new Error(
'Schema to be validated not found. Did you forget to match the schema key to the input "name" prop?'
);
}
resolvedSchema = setValueByPath(resolvedSchema, `${name}.value`, value);
resolvedSchema = setValuesAlongPath(resolvedSchema, name, {
pristine: false,
dirty: true
});
if (shouldValidate(targetSchema, "input")) {
resolvedSchema = await validateSchema(resolvedSchema);
}
schema.value = resolvedSchema;
options.onUpdate?.(resolvedSchema);
}
async function setTouched(name, event) {
if (!options.validate?.value) {
return;
}
let resolvedSchema = clone(schema.value);
const targetSchema = getValueByPath(resolvedSchema, name);
if (!targetSchema) {
throw new Error(
'Schema to be validated not found. Did you forget to match the schema key to the input "name" prop?'
);
}
resolvedSchema = setValuesAlongPath(resolvedSchema, name, {
untouched: false,
touched: true
});
if (shouldValidate(targetSchema, event.type)) {
resolvedSchema = await validateSchema(resolvedSchema);
}
schema.value = resolvedSchema;
options.onUpdate?.(resolvedSchema);
}
async function onSubmit(event) {
if (!options.validate?.value) {
return;
}
let resolvedSchema = await validateSchema(schema.value);
resolvedSchema = setSchemaStateRecursively(resolvedSchema, {
untouched: false,
touched: true
});
if (resolvedSchema.valid) {
options.onSubmit?.(event);
}
schema.value = resolvedSchema;
options.onUpdate?.(resolvedSchema);
}
async function onInput(nameRef, value) {
const name = unref(nameRef);
if (!options.validate?.value || !name) {
return;
}
if (formGroup) {
formGroup.onInput(name, value);
} else if (form) {
form.onInput(name, value);
} else if (options.schema?.value) {
await setValue(name, value);
}
}
function onBlur(nameRef, event) {
const name = unref(nameRef);
if (!options.validate?.value || !name) {
return;
}
if (formGroup) {
formGroup.onBlur(name, event);
} else if (form) {
form.onBlur(name, event);
} else if (options.schema?.value) {
setTouched(name, event);
}
}
return { schema, onSubmit, onInput, onBlur };
}
export function useFormValidationError(options) {
const hasError = computed(() => {
if (typeof options.error.value === "boolean") {
return options.error.value;
} else if (options.schema.value && options.error.value) {
let visible = true;
[].concat(options.error.value).forEach((status) => {
visible = visible && options.schema.value[status];
});
return visible;
}
return false;
});
return { hasError };
}