maz-ui 5.0.0-beta.29 → 5.0.0-beta.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import{_ as setFieldValidationState,f as hasModeIncludes,i as removeEventFromInteractiveElements,n as findInteractiveElements,o as fieldHasValidation,p as updateFieldState,r as getValidationEvents,s as getContext,t as addEventToInteractiveElements,u as handleFieldBlur}from"../chunks/dom-events.CGvpt5mn.js";import{useFreezeValue}from"./useFreezeValue.js";import{computed,onMounted,onUnmounted}from"vue";import{isEqual}from"@maz-ui/utils/helpers/isEqual";function resolveBindElement(node){return node instanceof HTMLElement?node:node instanceof CharacterData&&node.nextElementSibling instanceof HTMLElement?node.nextElementSibling:null}function useFormField(name,options){let opts={formIdentifier:`main-form-validator`,...options};let{fieldsStates,payload,options:formOptions,internalSchema,errorMessages,isSubmitted}=getContext(opts.formIdentifier,`useFormField`);let finalOpts=opts;let fieldMode=fieldHasValidation(name,internalSchema.value)?options?.mode??formOptions.mode:void 0;finalOpts.mode=fieldMode;let fieldState=computed(()=>fieldsStates.value[name]);if(fieldsStates.value[name]=updateFieldState({name,fieldState:fieldState.value,payload:payload.value,schema:internalSchema.value,options:{...formOptions,...finalOpts}}),finalOpts.defaultValue!==void 0&&!isEqual(payload.value[name],finalOpts.defaultValue)){let initialValue=finalOpts.defaultValue;payload.value[name]=initialValue,fieldsStates.value[name].initialValue=useFreezeValue(initialValue)}fieldMode&&setFieldValidationState({name,fieldState:fieldState.value,payload:payload.value,schema:internalSchema.value,setError:fieldMode===`aggressive`,setErrorIfInvalidAndNotEmpty:fieldMode===`lazy`});function onBlur(){handleFieldBlur({name,fieldState:fieldState.value,payload:payload.value,schema:internalSchema.value,isSubmitted:isSubmitted.value})}let validationEvents=computed(()=>getValidationEvents({hasRef:!!finalOpts.ref?.value,onBlur,fieldState:fieldState.value}));if(finalOpts.ref&&fieldMode&&hasModeIncludes([`eager`,`blur`,`progressive`],fieldMode)){let interactiveElements=[];let handleInteractiveElements=element=>{interactiveElements.length>0&&removeEventFromInteractiveElements({interactiveElements,onBlur}),interactiveElements=findInteractiveElements(element),addEventToInteractiveElements({interactiveElements,onBlur,mode:fieldMode})};onMounted(()=>{let refValue=finalOpts.ref?.value;let elementToBind=resolveBindElement(refValue instanceof HTMLElement?refValue:refValue?.$el);if(elementToBind){handleInteractiveElements(elementToBind);return}console.warn(`[maz-ui](useFormField) No element found for ref in field '${String(name)}'. Make sure the ref is properly bound to an HTMLElement or Vue component (form identifier: ${String(formOptions.identifier)})`)}),onUnmounted(()=>{removeEventFromInteractiveElements({interactiveElements,onBlur})})}return{hasError:computed(()=>fieldState.value.error),errors:computed(()=>fieldState.value.errors),errorMessage:computed(()=>errorMessages.value[name]),isValid:computed(()=>fieldState.value.valid),isDirty:computed(()=>fieldState.value.dirty),isBlurred:computed(()=>fieldState.value.blurred),isValidated:computed(()=>fieldState.value.validated),isValidating:computed(()=>fieldState.value.validating),mode:computed(()=>fieldState.value.mode),value:computed({get:()=>payload.value[name],set:value=>payload.value[name]=value}),validationEvents}}export{useFormField};
1
+ import{_ as setFieldValidationState,f as hasModeIncludes,i as removeEventFromInteractiveElements,n as findInteractiveElements,o as fieldHasValidation,p as updateFieldState,r as getValidationEvents,s as getContext,t as addEventToInteractiveElements,u as handleFieldBlur}from"../chunks/dom-events.CGvpt5mn.js";import{useFreezeValue}from"./useFreezeValue.js";import{computed,onUnmounted,unref,watch}from"vue";import{isClient}from"@maz-ui/utils/helpers/isClient";import{isEqual}from"@maz-ui/utils/helpers/isEqual";function resolveBindElement(node){return node instanceof HTMLElement?node:node instanceof CharacterData&&node.nextElementSibling instanceof HTMLElement?node.nextElementSibling:null}function useFormField(name,options){let opts={formIdentifier:`main-form-validator`,...options};let{fieldsStates,payload,options:formOptions,internalSchema,errorMessages,isSubmitted}=getContext(opts.formIdentifier,`useFormField`);let finalOpts=opts;let fieldMode=fieldHasValidation(name,internalSchema.value)?options?.mode??formOptions.mode:void 0;finalOpts.mode=fieldMode;let fieldState=computed(()=>fieldsStates.value[name]);if(fieldsStates.value[name]=updateFieldState({name,fieldState:fieldState.value,payload:payload.value,schema:internalSchema.value,options:{...formOptions,...finalOpts}}),finalOpts.defaultValue!==void 0&&!isEqual(payload.value[name],finalOpts.defaultValue)){let initialValue=finalOpts.defaultValue;payload.value[name]=initialValue,fieldsStates.value[name].initialValue=useFreezeValue(initialValue)}fieldMode&&setFieldValidationState({name,fieldState:fieldState.value,payload:payload.value,schema:internalSchema.value,setError:fieldMode===`aggressive`,setErrorIfInvalidAndNotEmpty:fieldMode===`lazy`});function onBlur(){handleFieldBlur({name,fieldState:fieldState.value,payload:payload.value,schema:internalSchema.value,isSubmitted:isSubmitted.value})}let validationEvents=computed(()=>getValidationEvents({hasRef:!!unref(finalOpts.ref),onBlur,fieldState:fieldState.value}));if(finalOpts.ref&&fieldMode&&hasModeIncludes([`eager`,`blur`,`progressive`],fieldMode)){let interactiveElements=[];let cleanupInteractiveElements=()=>{interactiveElements.length>0&&(removeEventFromInteractiveElements({interactiveElements,onBlur}),interactiveElements=[])};let handleInteractiveElements=element=>{cleanupInteractiveElements(),interactiveElements=findInteractiveElements(element),addEventToInteractiveElements({interactiveElements,onBlur,mode:fieldMode})};watch(()=>unref(finalOpts.ref),refValue=>{if(!isClient())return;let elementToBind=resolveBindElement(refValue instanceof HTMLElement?refValue:refValue?.$el);elementToBind?handleInteractiveElements(elementToBind):cleanupInteractiveElements()},{immediate:!0,flush:`post`}),onUnmounted(cleanupInteractiveElements)}return{hasError:computed(()=>fieldState.value?.error??!1),errors:computed(()=>fieldState.value?.errors??[]),errorMessage:computed(()=>errorMessages.value[name]),isValid:computed(()=>fieldState.value?.valid??!1),isDirty:computed(()=>fieldState.value?.dirty??!1),isBlurred:computed(()=>fieldState.value?.blurred??!1),isValidated:computed(()=>fieldState.value?.validated??!1),isValidating:computed(()=>fieldState.value?.validating??!1),mode:computed(()=>fieldState.value?.mode),value:computed({get:()=>payload.value[name],set:value=>payload.value[name]=value}),validationEvents}}export{useFormField};
@@ -76,6 +76,7 @@ export interface FieldState<Model extends BaseFormPayload, ModelKey extends Extr
76
76
  }
77
77
  export type FieldsStates<Model extends BaseFormPayload, ModelKey extends ExtractModelKey<FormSchema<Model>>> = Record<ModelKey, FieldState<Model, ModelKey, Model[ModelKey]>>;
78
78
  export type BaseFormPayload = Record<string, any>;
79
+ export type FormFieldRef = Ref | TemplateRef | HTMLElement;
79
80
  export interface FormFieldOptions<Model extends BaseFormPayload, ModelKey extends ExtractModelKey<FormSchema<Model>>, FieldType> {
80
81
  /**
81
82
  * Default value of the field
@@ -90,8 +91,10 @@ export interface FormFieldOptions<Model extends BaseFormPayload, ModelKey extend
90
91
  /**
91
92
  * Reference to the component or HTML element to associate and trigger validation events
92
93
  * Necessary for 'eager', 'progressive' and 'blur' validation modes
94
+ * Accepts a reactive `Ref`/`TemplateRef` (recommended, supports conditional rendering with `v-if`)
95
+ * or a raw `HTMLElement`
93
96
  */
94
- ref?: Ref | TemplateRef;
97
+ ref?: FormFieldRef;
95
98
  /**
96
99
  * Identifier for the form
97
100
  * Useful when you have multiple forms on the same component
@@ -1,7 +1,6 @@
1
1
  import { DeepPartial } from '@maz-ui/utils/ts-helpers/DeepPartial';
2
2
  import { MaybeRefOrGetter, Ref } from 'vue';
3
3
  import { BaseFormPayload, ExtractModelKey, FieldsStates, FormSchema, FormValidatorOptions, InferOutputSchemaFormValidator, InferSchemaFormValidator, ValidationIssues } from './useFormValidator/types';
4
- import { scrollToError } from './useFormValidator/dom-events';
5
4
  export declare function useFormValidator<TSchema extends MaybeRefOrGetter<FormSchema<BaseFormPayload>>>({ schema, defaultValues, model, options }: {
6
5
  schema: TSchema;
7
6
  defaultValues?: MaybeRefOrGetter<DeepPartial<InferSchemaFormValidator<TSchema>> | undefined | null>;
@@ -18,7 +17,7 @@ export declare function useFormValidator<TSchema extends MaybeRefOrGetter<FormSc
18
17
  model: Ref<InferSchemaFormValidator<TSchema>, InferSchemaFormValidator<TSchema>>;
19
18
  fieldsStates: Ref<FieldsStates<InferSchemaFormValidator<TSchema>, ExtractModelKey<FormSchema<InferSchemaFormValidator<TSchema>>>>, FieldsStates<InferSchemaFormValidator<TSchema>, ExtractModelKey<FormSchema<InferSchemaFormValidator<TSchema>>>>>;
20
19
  validateForm: (setErrors?: boolean) => Promise<void[]>;
21
- scrollToError: typeof scrollToError;
20
+ scrollToError: (selector?: string) => void;
22
21
  resetForm: () => void;
23
22
  handleSubmit: <Func extends (model: InferOutputSchemaFormValidator<TSchema>) => Promise<Awaited<ReturnType<Func>>> | ReturnType<Func>>(successCallback: Func, enableScrollOrSelector?: FormValidatorOptions["scrollToError"], options?: {
24
23
  onError?: (payload: {
@@ -1 +1 @@
1
- import{a as scrollToError,c as getFieldsStates,d as handleFieldInput,f as hasModeIncludes,g as getFieldsErrors,h as getErrorMessages,l as getInstance,m as updateFieldsStates,v as validateForm,y as CONFIG}from"../chunks/dom-events.CGvpt5mn.js";import{computed,nextTick,provide,ref,toValue,watch}from"vue";function createValidationProcessor(fieldsToValidate,fieldsStates,payload,internalSchema,isSubmitted){return()=>{fieldsToValidate.forEach(name=>{let fieldState=fieldsStates.value[name];handleFieldInput({name,fieldState,payload:payload.value,schema:internalSchema.value,isSubmitted:isSubmitted.value,forceValidation:!0})})}}function useFormValidator({schema,defaultValues,model,options}){let instance=getInstance(`useFormValidator`);let opts={mode:CONFIG.mode,scrollToError:CONFIG.scrollToErrorSelector,debouncedFields:null,throttledFields:null,identifier:`main-form-validator`,resetOnSuccess:!0,...options};let internalDefaultValues=ref(toValue(defaultValues));let payload=ref({...internalDefaultValues.value,...model?.value});let internalSchema=ref(toValue(schema));let fieldsStates=ref(getFieldsStates({schema:internalSchema.value,payload:payload.value,options:opts}));let isSubmitting=ref(!1);let isSubmitted=ref(!1);let isValid=computed(()=>{for(let key in fieldsStates.value)if(!fieldsStates.value[key].valid)return!1;return!0});let isDirty=computed(()=>{for(let key in fieldsStates.value)if(fieldsStates.value[key].dirty)return!0;return!1});let errors=computed(()=>getFieldsErrors(fieldsStates.value));let errorMessages=computed(()=>getErrorMessages(errors.value,fieldsStates.value));model&&(watch(payload,newPayload=>{model.value={...internalDefaultValues.value,...newPayload}},{deep:!0}),watch(model,newModel=>{newModel&&Object.assign(payload.value,newModel)},{deep:!0})),watch(internalDefaultValues,newDefaultValues=>{payload.value={...newDefaultValues,...payload.value}},{deep:!0}),watch(internalSchema,schema=>{updateFieldsStates({schema,fieldsStates:fieldsStates.value,payload:payload.value,options:opts}),internalValidateForm()},{deep:!0}),internalValidateForm();function internalValidateForm(setErrors=opts.mode===`aggressive`){return validateForm({fieldsStates:fieldsStates.value,payload:payload.value,schema:internalSchema.value,setErrors})}let payloadWatchStop=null;function setupOptimizedWatch(){payloadWatchStop&&payloadWatchStop(),payloadWatchStop=watch(computed(()=>{let snapshot={};for(let key of Object.keys(internalSchema.value))snapshot[key]=payload.value[key];return snapshot}),(newSnapshot,oldSnapshot)=>{let fieldsToValidate=Object.keys(internalSchema.value).filter(name=>{let fieldState=fieldsStates.value[name];return fieldState&&newSnapshot[name]!==oldSnapshot?.[name]&&hasModeIncludes([`aggressive`,`lazy`,`progressive`],fieldState.mode)});if(fieldsToValidate.length>0){let processValidations=createValidationProcessor(fieldsToValidate,fieldsStates,payload,internalSchema,isSubmitted);typeof requestIdleCallback<`u`?requestIdleCallback(processValidations,{timeout:100}):nextTick(processValidations)}},{deep:!0})}function resetForm(){payloadWatchStop&&payloadWatchStop(),isSubmitting.value=!1,isSubmitted.value=!1,payload.value={...internalDefaultValues.value},fieldsStates.value=getFieldsStates({schema:internalSchema.value,payload:payload.value,options:opts}),internalValidateForm(!1),setupOptimizedWatch()}function handleSubmit(successCallback,enableScrollOrSelector,options){let finalOptions={resetOnSuccess:options?.resetOnSuccess??opts.resetOnSuccess};return async event=>{if(event?.preventDefault(),!isSubmitting.value){isSubmitted.value=!0,isSubmitting.value=!0;try{await internalValidateForm(!0);let scrollToErrorParam=typeof enableScrollOrSelector==`string`?enableScrollOrSelector:opts.scrollToError;let response;return isValid.value?(response=await successCallback(payload.value),(finalOptions.resetOnSuccess||options?.resetOnSuccess)&&resetForm()):typeof scrollToErrorParam!=`boolean`&&(options?.onError?.({model:payload.value,errorMessages:errorMessages.value,errors:errors.value}),scrollToError(scrollToErrorParam)),isSubmitting.value=!1,response}finally{isSubmitting.value=!1}}}}let context={fieldsStates,payload,options:opts,internalSchema,errorMessages,isSubmitted};return instance.formContexts??=new Map,instance.formContexts.set(opts.identifier,context),provide(opts.identifier,context),setupOptimizedWatch(),{identifier:opts.identifier,isDirty,isSubmitting,isSubmitted,isValid,errors,hasError:computed(()=>Object.values(errorMessages.value).some(Boolean)),model:payload,fieldsStates,validateForm:internalValidateForm,scrollToError,resetForm,handleSubmit,errorMessages}}export{useFormValidator};
1
+ import{a as scrollToError,c as getFieldsStates,d as handleFieldInput,f as hasModeIncludes,g as getFieldsErrors,h as getErrorMessages,l as getInstance,m as updateFieldsStates,v as validateForm,y as CONFIG}from"../chunks/dom-events.CGvpt5mn.js";import{computed,nextTick,provide,ref,toValue,watch}from"vue";function createValidationProcessor(fieldsToValidate,fieldsStates,payload,internalSchema,isSubmitted){return()=>{fieldsToValidate.forEach(name=>{let fieldState=fieldsStates.value[name];handleFieldInput({name,fieldState,payload:payload.value,schema:internalSchema.value,isSubmitted:isSubmitted.value,forceValidation:fieldState.mode!==`eager`})})}}function useFormValidator({schema,defaultValues,model,options}){let instance=getInstance(`useFormValidator`);let opts={mode:CONFIG.mode,scrollToError:CONFIG.scrollToErrorSelector,debouncedFields:null,throttledFields:null,identifier:`main-form-validator`,resetOnSuccess:!0,...options};let internalDefaultValues=ref(toValue(defaultValues));let payload=ref({...internalDefaultValues.value,...model?.value});let internalSchema=ref(toValue(schema));let fieldsStates=ref(getFieldsStates({schema:internalSchema.value,payload:payload.value,options:opts}));let isSubmitting=ref(!1);let isSubmitted=ref(!1);let isValid=computed(()=>{for(let key in fieldsStates.value)if(!fieldsStates.value[key].valid)return!1;return!0});let isDirty=computed(()=>{for(let key in fieldsStates.value)if(fieldsStates.value[key].dirty)return!0;return!1});let errors=computed(()=>getFieldsErrors(fieldsStates.value));let errorMessages=computed(()=>getErrorMessages(errors.value,fieldsStates.value));model&&(watch(payload,newPayload=>{model.value={...internalDefaultValues.value,...newPayload}},{deep:!0}),watch(model,newModel=>{newModel&&Object.assign(payload.value,newModel)},{deep:!0})),watch(internalDefaultValues,newDefaultValues=>{payload.value={...newDefaultValues,...payload.value}},{deep:!0}),watch(internalSchema,schema=>{updateFieldsStates({schema,fieldsStates:fieldsStates.value,payload:payload.value,options:opts}),internalValidateForm()},{deep:!0}),internalValidateForm();function internalValidateForm(setErrors=opts.mode===`aggressive`){return validateForm({fieldsStates:fieldsStates.value,payload:payload.value,schema:internalSchema.value,setErrors})}let payloadWatchStop=null;function setupOptimizedWatch(){payloadWatchStop&&payloadWatchStop(),payloadWatchStop=watch(computed(()=>{let snapshot={};for(let key of Object.keys(internalSchema.value))snapshot[key]=payload.value[key];return snapshot}),(newSnapshot,oldSnapshot)=>{let fieldsToValidate=Object.keys(internalSchema.value).filter(name=>{let fieldState=fieldsStates.value[name];return fieldState&&newSnapshot[name]!==oldSnapshot?.[name]&&hasModeIncludes([`aggressive`,`lazy`,`progressive`,`eager`],fieldState.mode)});if(fieldsToValidate.length>0){let processValidations=createValidationProcessor(fieldsToValidate,fieldsStates,payload,internalSchema,isSubmitted);typeof requestIdleCallback<`u`?requestIdleCallback(processValidations,{timeout:100}):nextTick(processValidations)}},{deep:!0})}function resetForm(){payloadWatchStop&&payloadWatchStop(),isSubmitting.value=!1,isSubmitted.value=!1,payload.value={...internalDefaultValues.value},fieldsStates.value=getFieldsStates({schema:internalSchema.value,payload:payload.value,options:opts}),internalValidateForm(!1),setupOptimizedWatch()}function handleSubmit(successCallback,enableScrollOrSelector,options){let finalOptions={resetOnSuccess:options?.resetOnSuccess??opts.resetOnSuccess};return async event=>{if(event?.preventDefault(),!isSubmitting.value){isSubmitted.value=!0,isSubmitting.value=!0;try{await internalValidateForm(!0);let scrollToErrorParam=typeof enableScrollOrSelector==`string`?enableScrollOrSelector:opts.scrollToError;let response;return isValid.value?(response=await successCallback(payload.value),finalOptions.resetOnSuccess&&resetForm()):typeof scrollToErrorParam!=`boolean`&&(options?.onError?.({model:payload.value,errorMessages:errorMessages.value,errors:errors.value}),scrollToError(scrollToErrorParam)),response}finally{isSubmitting.value=!1}}}}let context={fieldsStates,payload,options:opts,internalSchema,errorMessages,isSubmitted};return instance.formContexts??=new Map,instance.formContexts.set(opts.identifier,context),provide(opts.identifier,context),setupOptimizedWatch(),{identifier:opts.identifier,isDirty,isSubmitting,isSubmitted,isValid,errors,hasError:computed(()=>Object.values(errorMessages.value).some(Boolean)),model:payload,fieldsStates,validateForm:internalValidateForm,scrollToError:selector=>scrollToError(selector??(typeof opts.scrollToError==`string`?opts.scrollToError:void 0)),resetForm,handleSubmit,errorMessages}}export{useFormValidator};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "maz-ui",
3
3
  "type": "module",
4
- "version": "5.0.0-beta.29",
4
+ "version": "5.0.0-beta.30",
5
5
  "description": "A standalone components library for Vue.Js 3 & Nuxt.Js 3",
6
6
  "author": "Louis Mazel <me@loicmazuel.com>",
7
7
  "license": "MIT",
@@ -185,11 +185,11 @@
185
185
  "dayjs": "^1.11.20",
186
186
  "libphonenumber-js": "^1.13.6",
187
187
  "valibot": "^1.4.0",
188
- "@maz-ui/cli": "5.0.0-beta.28",
189
- "@maz-ui/utils": "5.0.0-beta.28",
190
188
  "@maz-ui/icons": "5.0.0-beta.25",
189
+ "@maz-ui/cli": "5.0.0-beta.28",
191
190
  "@maz-ui/translations": "5.0.0-beta.28",
192
- "@maz-ui/themes": "5.0.0-beta.28"
191
+ "@maz-ui/themes": "5.0.0-beta.28",
192
+ "@maz-ui/utils": "5.0.0-beta.28"
193
193
  },
194
194
  "devDependencies": {
195
195
  "@tailwindcss/cli": "^4.3.0",