Skip to content

Commit

Permalink
Merge pull request #247 from XiNiHa/feat/validateon-per-field
Browse files Browse the repository at this point in the history
Make (re)validateOn overridable per field
  • Loading branch information
fabian-hiller authored Sep 6, 2024
2 parents 438d13c + ef934ee commit 222293a
Show file tree
Hide file tree
Showing 38 changed files with 221 additions and 22 deletions.
1 change: 1 addition & 0 deletions packages/preact/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ All notable changes to the library will be documented in this file.
## vX.X.X (Month DD, YYYY)

- Add support for async validation with Zod (issue #233)
- Add `validateOn` and `revalidateOn` option to `Field` and `FieldArray` component (pull request #247)

## v0.9.1 (June 27, 2024)

Expand Down
3 changes: 3 additions & 0 deletions packages/preact/src/components/Field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type {
ResponseData,
TransformField,
ValidateField,
ValidationMode,
} from '../types';
import {
getElementInput,
Expand Down Expand Up @@ -71,6 +72,8 @@ export type FieldProps<
validate?: Maybe<
MaybeArray<ValidateField<FieldPathValue<TFieldValues, TFieldName>>>
>;
validateOn?: Maybe<ValidationMode>;
revalidateOn?: Maybe<ValidationMode>;
transform?: Maybe<
MaybeArray<TransformField<FieldPathValue<TFieldValues, TFieldName>>>
>;
Expand Down
3 changes: 3 additions & 0 deletions packages/preact/src/components/FieldArray.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {
MaybeArray,
ResponseData,
ValidateFieldArray,
ValidationMode,
} from '../types';
import { initializeFieldArrayStore } from '../utils';

Expand Down Expand Up @@ -43,6 +44,8 @@ export type FieldArrayProps<
store: FieldArrayStore<TFieldValues, TFieldArrayName>
) => ComponentChild;
validate?: Maybe<MaybeArray<ValidateFieldArray<number[]>>>;
validateOn?: Maybe<ValidationMode>;
revalidateOn?: Maybe<ValidationMode>;
keepActive?: Maybe<boolean>;
keepState?: Maybe<boolean>;
};
Expand Down
11 changes: 10 additions & 1 deletion packages/preact/src/hooks/useLifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type {
TransformField,
ValidateField,
ValidateFieldArray,
ValidationMode,
} from '../types';
import { getUniqueId, updateFormState } from '../utils';

Expand All @@ -33,6 +34,8 @@ type LifecycleProps<
| MaybeArray<ValidateField<FieldPathValue<TFieldValues, TFieldName>>>
| MaybeArray<ValidateFieldArray<number[]>>
>;
validateOn?: Maybe<ValidationMode>;
revalidateOn?: Maybe<ValidationMode>;
transform?: Maybe<
MaybeArray<TransformField<FieldPathValue<TFieldValues, TFieldName>>>
>;
Expand All @@ -56,6 +59,8 @@ export function useLifecycle({
name,
store,
validate,
validateOn,
revalidateOn,
transform,
keepActive = false,
keepState = true,
Expand All @@ -68,6 +73,10 @@ export function useLifecycle({
: [validate]
: [];

// Set validation mode overrides
store.validateOn = validateOn;
store.revalidateOn = revalidateOn;

// Add transformation functions
if ('transform' in store) {
store.transform = transform
Expand All @@ -76,7 +85,7 @@ export function useLifecycle({
: [transform]
: [];
}
}, [store, transform, validate]);
}, [store, transform, validate, validateOn, revalidateOn]);

useEffect(() => {
// Create unique consumer ID
Expand Down
3 changes: 3 additions & 0 deletions packages/preact/src/types/field.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Signal } from '@preact/signals';
import type { FieldPath, FieldPathValue } from './path';
import type { MaybeValue, MaybePromise, Maybe } from './utils';
import type { ValidationMode } from './form';

/**
* Value type of the field value.
Expand Down Expand Up @@ -89,6 +90,8 @@ export type InternalFieldStore<

// Other
validate: ValidateField<FieldPathValue<TFieldValues, TFieldName>>[];
validateOn: Maybe<ValidationMode>;
revalidateOn: Maybe<ValidationMode>;
transform: TransformField<FieldPathValue<TFieldValues, TFieldName>>[];
consumers: Set<number>;
};
Expand Down
5 changes: 4 additions & 1 deletion packages/preact/src/types/fieldArray.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Signal } from '@preact/signals';
import type { MaybePromise } from './utils';
import type { Maybe, MaybePromise } from './utils';
import type { ValidationMode } from './form';

/**
* Function type to validate a field array.
Expand Down Expand Up @@ -28,6 +29,8 @@ export type InternalFieldArrayStore = {

// Other
validate: ValidateFieldArray<number[]>[];
validateOn: Maybe<ValidationMode>;
revalidateOn: Maybe<ValidationMode>;
consumers: Set<number>;
};

Expand Down
2 changes: 2 additions & 0 deletions packages/preact/src/utils/initializeFieldArrayStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ export function initializeFieldArrayStore<

// Other
validate: [],
validateOn: undefined,
revalidateOn: undefined,
consumers: new Set(),
};

Expand Down
2 changes: 2 additions & 0 deletions packages/preact/src/utils/initializeFieldStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ export function initializeFieldStore(

// Other
validate: [],
validateOn: undefined,
revalidateOn: undefined,
transform: [],
consumers: new Set(),
};
Expand Down
9 changes: 6 additions & 3 deletions packages/preact/src/utils/validateIfRequired.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,18 @@ export function validateIfRequired<
name: TFieldName | TFieldArrayName,
{ on: modes, shouldFocus = false }: ValidateOptions
): void {
const validateOn = fieldOrFieldArray.validateOn ?? form.internal.validateOn;
const revalidateOn =
fieldOrFieldArray.revalidateOn ?? form.internal.revalidateOn;
if (
(modes as string[]).includes(
(
form.internal.validateOn === 'submit'
validateOn === 'submit'
? form.submitted.peek()
: fieldOrFieldArray.error.peek()
)
? form.internal.revalidateOn
: form.internal.validateOn
? revalidateOn
: validateOn
)
) {
validate(form, name, { shouldFocus });
Expand Down
1 change: 1 addition & 0 deletions packages/qwik/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ All notable changes to the library will be documented in this file.
## vX.X.X (Month DD, YYYY)

- Add support for async validation with Zod (issue #233)
- Add `validateOn` and `revalidateOn` option to `Field` and `FieldArray` component (pull request #247)

## v0.26.1 (June 27, 2024)

Expand Down
3 changes: 3 additions & 0 deletions packages/qwik/src/components/Field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type {
ResponseData,
TransformField,
ValidateField,
ValidationMode,
} from '../types';
import { Lifecycle } from './Lifecycle';

Expand Down Expand Up @@ -54,6 +55,8 @@ export type FieldProps<
validate?: Maybe<
MaybeArray<QRL<ValidateField<FieldPathValue<TFieldValues, TFieldName>>>>
>;
validateOn?: Maybe<ValidationMode>;
revalidateOn?: Maybe<ValidationMode>;
transform?: Maybe<
MaybeArray<QRL<TransformField<FieldPathValue<TFieldValues, TFieldName>>>>
>;
Expand Down
3 changes: 3 additions & 0 deletions packages/qwik/src/components/FieldArray.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
MaybeArray,
ResponseData,
ValidateFieldArray,
ValidationMode,
} from '../types';
import { Lifecycle } from './Lifecycle';

Expand All @@ -26,6 +27,8 @@ export type FieldArrayProps<
store: FieldArrayStore<TFieldValues, TFieldArrayName>
) => JSXOutput;
validate?: Maybe<MaybeArray<QRL<ValidateFieldArray<number[]>>>>;
validateOn?: Maybe<ValidationMode>;
revalidateOn?: Maybe<ValidationMode>;
keepActive?: Maybe<boolean>;
keepState?: Maybe<boolean>;
};
Expand Down
9 changes: 9 additions & 0 deletions packages/qwik/src/components/Lifecycle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type {
TransformField,
ValidateField,
ValidateFieldArray,
ValidationMode,
} from '../types';
import { getUniqueId, updateFormState } from '../utils';

Expand All @@ -43,6 +44,8 @@ type LifecycleProps<
| MaybeArray<QRL<ValidateField<FieldPathValue<TFieldValues, TFieldName>>>>
| MaybeArray<QRL<ValidateFieldArray<number[]>>>
>;
validateOn?: Maybe<ValidationMode>;
revalidateOn?: Maybe<ValidationMode>;
transform?: Maybe<
MaybeArray<QRL<TransformField<FieldPathValue<TFieldValues, TFieldName>>>>
>;
Expand Down Expand Up @@ -77,6 +80,8 @@ export function Lifecycle(
of: form,
store,
validate,
validateOn,
revalidateOn,
transform,
keepActive = false,
keepState = true,
Expand All @@ -96,6 +101,10 @@ export function Lifecycle(
: [validate]
: [];

// Set validation mode overrides
store.internal.validateOn = validateOn;
store.internal.revalidateOn = revalidateOn;

// Add transformation functions
if ('value' in store) {
store.internal.transform = transform
Expand Down
3 changes: 3 additions & 0 deletions packages/qwik/src/types/field.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { NoSerialize, QRL } from '@builder.io/qwik';
import type { FieldPath, FieldPathValue } from './path';
import type { Maybe, MaybePromise, MaybeValue } from './utils';
import type { ValidationMode } from './form';

/**
* Value type of the field value.
Expand Down Expand Up @@ -87,6 +88,8 @@ export type InternalFieldStore<
initialValue: Maybe<FieldPathValue<TFieldValues, TFieldName>>;
startValue: Maybe<FieldPathValue<TFieldValues, TFieldName>>;
validate: QRL<ValidateField<FieldPathValue<TFieldValues, TFieldName>>>[];
validateOn: Maybe<ValidationMode>;
revalidateOn: Maybe<ValidationMode>;
transform: QRL<TransformField<FieldPathValue<TFieldValues, TFieldName>>>[];
elements: FieldElement[];
consumers: number[];
Expand Down
5 changes: 4 additions & 1 deletion packages/qwik/src/types/fieldArray.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { QRL } from '@builder.io/qwik';
import type { FieldValues } from './field';
import type { FieldArrayPath } from './path';
import type { MaybePromise } from './utils';
import type { Maybe, MaybePromise } from './utils';
import type { ValidationMode } from './form';

/**
* Function type to validate a field array.
Expand All @@ -22,6 +23,8 @@ export type InternalFieldArrayStore = {
initialItems: number[];
startItems: number[];
validate: QRL<ValidateFieldArray<number[]>>[];
validateOn: Maybe<ValidationMode>;
revalidateOn: Maybe<ValidationMode>;
consumers: number[];
};

Expand Down
2 changes: 2 additions & 0 deletions packages/qwik/src/utils/getInitialFieldArrayStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export function getInitialFieldArrayStore<
initialItems: [...initialItems],
startItems: [...initialItems],
validate: [],
validateOn: undefined,
revalidateOn: undefined,
consumers: [],
},
name,
Expand Down
2 changes: 2 additions & 0 deletions packages/qwik/src/utils/getInitialFieldStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export function getInitialFieldStore<
initialValue,
startValue: initialValue,
validate: [],
validateOn: undefined,
revalidateOn: undefined,
transform: [],
elements: [],
consumers: [],
Expand Down
14 changes: 7 additions & 7 deletions packages/qwik/src/utils/validateIfRequired.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ export function validateIfRequired<
name: TFieldName | TFieldArrayName,
{ on: modes, shouldFocus = false }: ValidateOptions
): void {
const validateOn =
fieldOrFieldArray.internal.validateOn ?? form.internal.validateOn;
const revalidateOn =
fieldOrFieldArray.internal.revalidateOn ?? form.internal.revalidateOn;
if (
(modes as string[]).includes(
(
form.internal.validateOn === 'submit'
? form.submitted
: fieldOrFieldArray.error
)
? form.internal.revalidateOn
: form.internal.validateOn
(validateOn === 'submit' ? form.submitted : fieldOrFieldArray.error)
? revalidateOn
: validateOn
)
) {
validate(form, name, { shouldFocus });
Expand Down
1 change: 1 addition & 0 deletions packages/react/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ All notable changes to the library will be documented in this file.
## vX.X.X (Month DD, YYYY)

- Add support for async validation with Zod (issue #233)
- Add `validateOn` and `revalidateOn` option to `Field` and `FieldArray` component (pull request #247)

## v0.8.1 (June 27, 2024)

Expand Down
3 changes: 3 additions & 0 deletions packages/react/src/components/Field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type {
ResponseData,
TransformField,
ValidateField,
ValidationMode,
} from '../types';
import {
getElementInput,
Expand Down Expand Up @@ -74,6 +75,8 @@ export type FieldProps<
validate?: Maybe<
MaybeArray<ValidateField<FieldPathValue<TFieldValues, TFieldName>>>
>;
validateOn?: Maybe<ValidationMode>;
revalidateOn?: Maybe<ValidationMode>;
transform?: Maybe<
MaybeArray<TransformField<FieldPathValue<TFieldValues, TFieldName>>>
>;
Expand Down
3 changes: 3 additions & 0 deletions packages/react/src/components/FieldArray.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
MaybeArray,
ResponseData,
ValidateFieldArray,
ValidationMode,
} from '../types';
import { initializeFieldArrayStore } from '../utils';

Expand Down Expand Up @@ -41,6 +42,8 @@ export type FieldArrayProps<
store: FieldArrayStore<TFieldValues, TFieldArrayName>
) => ReactNode;
validate?: Maybe<MaybeArray<ValidateFieldArray<number[]>>>;
validateOn?: Maybe<ValidationMode>;
revalidateOn?: Maybe<ValidationMode>;
keepActive?: Maybe<boolean>;
keepState?: Maybe<boolean>;
};
Expand Down
Loading

0 comments on commit 222293a

Please sign in to comment.