@vuehookform/core 0.4.3 → 0.4.5

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.
package/README.md CHANGED
@@ -42,12 +42,12 @@ const onSubmit = (data) => {
42
42
  <template>
43
43
  <form @submit="handleSubmit(onSubmit)">
44
44
  <input v-bind="register('email')" type="email" />
45
- <span v-if="formState.errors.email">{{ formState.errors.email }}</span>
45
+ <span v-if="formState.value.errors.email">{{ formState.value.errors.email }}</span>
46
46
 
47
47
  <input v-bind="register('password')" type="password" />
48
- <span v-if="formState.errors.password">{{ formState.errors.password }}</span>
48
+ <span v-if="formState.value.errors.password">{{ formState.value.errors.password }}</span>
49
49
 
50
- <button type="submit" :disabled="formState.isSubmitting">Submit</button>
50
+ <button type="submit" :disabled="formState.value.isSubmitting">Submit</button>
51
51
  </form>
52
52
  </template>
53
53
  ```
@@ -160,11 +160,15 @@ const emailError = computed(() => formState.value.errors.email)
160
160
 
161
161
  <!-- ✅ Option 3: Use useController for reusable components -->
162
162
  <script setup>
163
+ import { useForm, useController, type Control } from '@vuehookform/core'
164
+
165
+ // control comes from useForm (pass it as a prop to child components)
166
+ const { control } = useForm({ schema })
163
167
  const { fieldState } = useController({ name: 'email', control })
164
168
  // fieldState is a ComputedRef that updates automatically
165
169
  </script>
166
170
  <template>
167
- <span v-if="fieldState.error">{{ fieldState.error }}</span>
171
+ <span v-if="fieldState.value.error">{{ fieldState.value.error }}</span>
168
172
  </template>
169
173
  ```
170
174
 
package/dist/index.d.ts CHANGED
@@ -20,5 +20,5 @@ export { useWatch, type UseWatchOptions } from './useWatch';
20
20
  export { useController, type UseControllerOptions, type UseControllerReturn, type ControllerFieldProps, } from './useController';
21
21
  export { useFormState, type UseFormStateOptions, type FormStateKey } from './useFormState';
22
22
  export { isFieldError } from './types';
23
- export type { UseFormOptions, UseFormReturn, RegisterOptions, RegisterReturn, FormState, FieldState, FieldErrors, FieldError, FieldErrorValue, ErrorOption, SetErrorsOptions, FieldArray, FieldArrayItem, FieldArrayOptions, FieldArrayRules, FieldArrayFocusOptions, InferSchema, FormValues, FormPath, Path, PathValue, ArrayElement, ArrayPath, FieldPath, ValidationMode, SetFocusOptions, ResetOptions, ResetFieldOptions, AsyncDefaultValues, TriggerOptions, SetValueOptions, UnregisterOptions, CriteriaMode, } from './types';
24
- export { get, set, unset, generateId, clearPathCache } from './utils/paths';
23
+ export type { UseFormOptions, UseFormReturn, UseFormReturn as Control, RegisterOptions, RegisterReturn, FormState, FieldState, FieldErrors, FieldError, FieldErrorValue, ErrorOption, SetErrorsOptions, FieldArray, FieldArrayItem, FieldArrayOptions, FieldArrayRules, FieldArrayFocusOptions, InferSchema, FormValues, FormPath, Path, PathValue, ArrayElement, ArrayPath, FieldPath, ValidationMode, SetFocusOptions, ResetOptions, ResetFieldOptions, AsyncDefaultValues, TriggerOptions, SetValueOptions, UnregisterOptions, CriteriaMode, } from './types';
24
+ export { get, set, unset, clearPathCache } from './utils/paths';
@@ -5,11 +5,11 @@ import { ValidationMode } from '../types';
5
5
  *
6
6
  * @param mode - The form's validation mode
7
7
  * @param isTouched - Whether the field has been touched
8
+ * @param hasSubmitted - Whether the form has been submitted at least once (for reValidateMode)
8
9
  * @param reValidateMode - The form's reValidateMode (used after first submit)
9
- * @param hasSubmitted - Whether the form has been submitted at least once (optional, for reValidateMode)
10
10
  * @returns true if validation should be triggered
11
11
  */
12
- export declare function shouldValidateOnChange(mode: ValidationMode, isTouched: boolean, reValidateMode?: ValidationMode, hasSubmitted?: boolean): boolean;
12
+ export declare function shouldValidateOnChange(mode: ValidationMode, isTouched: boolean, hasSubmitted?: boolean, reValidateMode?: ValidationMode): boolean;
13
13
  /**
14
14
  * Determines if validation should occur on blur event.
15
15
  * Used by useController and register for consistent mode handling.
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Get cached path segments or parse and cache them.
3
+ * Uses simple LRU eviction (delete oldest when full).
4
+ *
5
+ * Exported for use by other utilities that need path parsing
6
+ * with caching benefits (devWarnings, schemaExtract).
7
+ */
8
+ export declare function getPathSegments(path: string): string[];
1
9
  /**
2
10
  * Clear the path segment cache.
3
11
  * Call this between SSR requests to prevent memory accumulation,
@@ -28,7 +28,7 @@ function get(obj, path) {
28
28
  return result;
29
29
  }
30
30
  function set(obj, path, value) {
31
- if (!path) return;
31
+ if (!path || obj === null || obj === void 0) return;
32
32
  const keys = getPathSegments(path).slice();
33
33
  const UNSAFE_KEYS = [
34
34
  "__proto__",
@@ -60,7 +60,7 @@ function set(obj, path, value) {
60
60
  current[lastKey] = value;
61
61
  }
62
62
  function unset(obj, path) {
63
- if (!path) return;
63
+ if (!path || obj === null || obj === void 0) return;
64
64
  const keys = getPathSegments(path).slice();
65
65
  const lastKey = keys.pop();
66
66
  let current = obj;
@@ -118,7 +118,7 @@ function validatePathSyntax(path) {
118
118
  return null;
119
119
  }
120
120
  function traverseSchemaPath(schema, path) {
121
- const segments = path.split(".");
121
+ const segments = getPathSegments(path);
122
122
  let currentSchema = schema;
123
123
  for (let i = 0; i < segments.length; i++) {
124
124
  const segment = segments[i];
@@ -449,7 +449,7 @@ function hasRootEffects(schema) {
449
449
  return hasChecks(schema);
450
450
  }
451
451
  function extractSubSchema(schema, path) {
452
- const segments = path.split(".");
452
+ const segments = getPathSegments(path);
453
453
  let currentSchema = schema;
454
454
  let hasEffects = false;
455
455
  for (const segment of segments) {
@@ -800,7 +800,7 @@ var VALID_MODES = [
800
800
  function validateMode(mode, paramName) {
801
801
  if (__DEV__ && !VALID_MODES.includes(mode)) warnOnce(`Invalid ${paramName}: "${mode}". Expected one of: ${VALID_MODES.join(", ")}`, `invalid-mode-${mode}`);
802
802
  }
803
- function shouldValidateOnChange(mode, isTouched, reValidateMode, hasSubmitted) {
803
+ function shouldValidateOnChange(mode, isTouched, hasSubmitted, reValidateMode) {
804
804
  if (__DEV__) {
805
805
  validateMode(mode, "validation mode");
806
806
  if (reValidateMode) validateMode(reValidateMode, "reValidateMode");
@@ -863,7 +863,7 @@ function createFieldRegistration(ctx, validate) {
863
863
  set(ctx.formData, name, value);
864
864
  updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, value);
865
865
  const fieldOpts = ctx.fieldOptions.get(name);
866
- if (shouldValidateOnChange(ctx.options.mode ?? "onSubmit", ctx.touchedFields.value[name] === true, ctx.options.reValidateMode, ctx.submitCount.value > 0)) {
866
+ if (shouldValidateOnChange(ctx.options.mode ?? "onSubmit", ctx.touchedFields.value[name] === true, ctx.submitCount.value > 0, ctx.options.reValidateMode)) {
867
867
  const validationDebounceMs = ctx.options.validationDebounce || 0;
868
868
  if (validationDebounceMs > 0) {
869
869
  const existingTimer = ctx.schemaValidationTimers.get(name);
@@ -1088,7 +1088,7 @@ function createFieldArrayManager(ctx, validate, setFocus) {
1088
1088
  const validateIfNeeded = () => {
1089
1089
  const isTouched = ctx.touchedFields.value[name] === true;
1090
1090
  const hasSubmitted = ctx.submitCount.value > 0;
1091
- if (shouldValidateOnChange(ctx.options.mode ?? "onSubmit", isTouched, ctx.options.reValidateMode, hasSubmitted)) validate(name);
1091
+ if (shouldValidateOnChange(ctx.options.mode ?? "onSubmit", isTouched, hasSubmitted, ctx.options.reValidateMode)) validate(name);
1092
1092
  };
1093
1093
  const ensureSync = () => {
1094
1094
  const currentValues = get(ctx.formData, name) || [];
@@ -1790,7 +1790,7 @@ function useController(options) {
1790
1790
  const hasSubmitted = form.formState.value.submitCount > 0;
1791
1791
  const mode = form.options.mode ?? "onSubmit";
1792
1792
  const reValidateMode = form.options.reValidateMode;
1793
- const shouldValidate = shouldValidateOnChange(mode, isTouched, reValidateMode, hasSubmitted);
1793
+ const shouldValidate = shouldValidateOnChange(mode, isTouched, hasSubmitted, reValidateMode);
1794
1794
  form.setValue(name, newValue, { shouldValidate });
1795
1795
  };
1796
1796
  const onBlur = () => {
@@ -1844,7 +1844,6 @@ function isFieldError(error) {
1844
1844
  }
1845
1845
  exports.FormContextKey = FormContextKey;
1846
1846
  exports.clearPathCache = clearPathCache;
1847
- exports.generateId = generateId;
1848
1847
  exports.get = get;
1849
1848
  exports.isFieldError = isFieldError;
1850
1849
  exports.provideForm = provideForm;
@@ -27,7 +27,7 @@ function get(obj, path) {
27
27
  return result;
28
28
  }
29
29
  function set(obj, path, value) {
30
- if (!path) return;
30
+ if (!path || obj === null || obj === void 0) return;
31
31
  const keys = getPathSegments(path).slice();
32
32
  const UNSAFE_KEYS = [
33
33
  "__proto__",
@@ -59,7 +59,7 @@ function set(obj, path, value) {
59
59
  current[lastKey] = value;
60
60
  }
61
61
  function unset(obj, path) {
62
- if (!path) return;
62
+ if (!path || obj === null || obj === void 0) return;
63
63
  const keys = getPathSegments(path).slice();
64
64
  const lastKey = keys.pop();
65
65
  let current = obj;
@@ -116,7 +116,7 @@ function validatePathSyntax(path) {
116
116
  return null;
117
117
  }
118
118
  function traverseSchemaPath(schema, path) {
119
- const segments = path.split(".");
119
+ const segments = getPathSegments(path);
120
120
  let currentSchema = schema;
121
121
  for (let i = 0; i < segments.length; i++) {
122
122
  const segment = segments[i];
@@ -447,7 +447,7 @@ function hasRootEffects(schema) {
447
447
  return hasChecks(schema);
448
448
  }
449
449
  function extractSubSchema(schema, path) {
450
- const segments = path.split(".");
450
+ const segments = getPathSegments(path);
451
451
  let currentSchema = schema;
452
452
  let hasEffects = false;
453
453
  for (const segment of segments) {
@@ -798,7 +798,7 @@ var VALID_MODES = [
798
798
  function validateMode(mode, paramName) {
799
799
  if (__DEV__ && !VALID_MODES.includes(mode)) warnOnce(`Invalid ${paramName}: "${mode}". Expected one of: ${VALID_MODES.join(", ")}`, `invalid-mode-${mode}`);
800
800
  }
801
- function shouldValidateOnChange(mode, isTouched, reValidateMode, hasSubmitted) {
801
+ function shouldValidateOnChange(mode, isTouched, hasSubmitted, reValidateMode) {
802
802
  if (__DEV__) {
803
803
  validateMode(mode, "validation mode");
804
804
  if (reValidateMode) validateMode(reValidateMode, "reValidateMode");
@@ -861,7 +861,7 @@ function createFieldRegistration(ctx, validate) {
861
861
  set(ctx.formData, name, value);
862
862
  updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, value);
863
863
  const fieldOpts = ctx.fieldOptions.get(name);
864
- if (shouldValidateOnChange(ctx.options.mode ?? "onSubmit", ctx.touchedFields.value[name] === true, ctx.options.reValidateMode, ctx.submitCount.value > 0)) {
864
+ if (shouldValidateOnChange(ctx.options.mode ?? "onSubmit", ctx.touchedFields.value[name] === true, ctx.submitCount.value > 0, ctx.options.reValidateMode)) {
865
865
  const validationDebounceMs = ctx.options.validationDebounce || 0;
866
866
  if (validationDebounceMs > 0) {
867
867
  const existingTimer = ctx.schemaValidationTimers.get(name);
@@ -1086,7 +1086,7 @@ function createFieldArrayManager(ctx, validate, setFocus) {
1086
1086
  const validateIfNeeded = () => {
1087
1087
  const isTouched = ctx.touchedFields.value[name] === true;
1088
1088
  const hasSubmitted = ctx.submitCount.value > 0;
1089
- if (shouldValidateOnChange(ctx.options.mode ?? "onSubmit", isTouched, ctx.options.reValidateMode, hasSubmitted)) validate(name);
1089
+ if (shouldValidateOnChange(ctx.options.mode ?? "onSubmit", isTouched, hasSubmitted, ctx.options.reValidateMode)) validate(name);
1090
1090
  };
1091
1091
  const ensureSync = () => {
1092
1092
  const currentValues = get(ctx.formData, name) || [];
@@ -1788,7 +1788,7 @@ function useController(options) {
1788
1788
  const hasSubmitted = form.formState.value.submitCount > 0;
1789
1789
  const mode = form.options.mode ?? "onSubmit";
1790
1790
  const reValidateMode = form.options.reValidateMode;
1791
- const shouldValidate = shouldValidateOnChange(mode, isTouched, reValidateMode, hasSubmitted);
1791
+ const shouldValidate = shouldValidateOnChange(mode, isTouched, hasSubmitted, reValidateMode);
1792
1792
  form.setValue(name, newValue, { shouldValidate });
1793
1793
  };
1794
1794
  const onBlur = () => {
@@ -1840,4 +1840,4 @@ function useFormState(options = {}) {
1840
1840
  function isFieldError(error) {
1841
1841
  return typeof error === "object" && error !== null && "type" in error && "message" in error && typeof error.type === "string" && typeof error.message === "string";
1842
1842
  }
1843
- export { FormContextKey, clearPathCache, generateId, get, isFieldError, provideForm, set, unset, useController, useForm, useFormContext, useFormState, useWatch };
1843
+ export { FormContextKey, clearPathCache, get, isFieldError, provideForm, set, unset, useController, useForm, useFormContext, useFormState, useWatch };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vuehookform/core",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "TypeScript-first form library for Vue 3, inspired by React Hook Form. Form-level state management with Zod validation.",
5
5
  "type": "module",
6
6
  "workspaces": [