Skip to content

Commit

Permalink
Add component to disable validation updates (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
Alduino authored Nov 5, 2023
1 parent 8d6c8f2 commit 406614f
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 22 deletions.
5 changes: 5 additions & 0 deletions .changeset/plenty-chefs-allow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@radiantguild/form-contexts": minor
---

Added a `<NoValidationUpdates>` component that disables any validation update calls in its children. See `useValidationUpdate`’s docs for more info.
76 changes: 58 additions & 18 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/contexts/NoValidationUpdateContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import {createContext} from "react";

export const NoValidationUpdateContext = createContext<boolean>(false);
6 changes: 4 additions & 2 deletions src/hooks/useInputValidity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {useContext, useEffect} from "react";
import {FormContext} from "~/contexts/FormContext";
import {NoValidationUpdateContext} from "~/contexts/NoValidationUpdateContext";

/**
* Notifies the wrapping form about the validity of this input
Expand All @@ -9,11 +10,12 @@ import {FormContext} from "~/contexts/FormContext";
*/
export default function useInputValidity(isValid: boolean) {
const context = useContext(FormContext);
const disabled = useContext(NoValidationUpdateContext);

useEffect(() => {
if (!context || isValid) return;
if (!context || isValid || disabled) return;

context.addInvalid();
return () => context.removeInvalid();
}, [context, isValid]);
}, [context, disabled, isValid]);
}
11 changes: 9 additions & 2 deletions src/hooks/useValidationUpdate.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import {ValidateResult} from "@radiantguild/yoogi";
import {useContext, useEffect} from "react";
import {ValidationSetterContext} from "~/contexts/ValidationSetterContext";
import {NoValidationUpdateContext} from "~/contexts/NoValidationUpdateContext";

/**
* Sets the validation result of this input so that `useValidation` can read it
* Sets the validation result of this input so that `useValidation` can read it.
*
* If a composite form field includes sub-fields with `useValidationUpdate` (or `useInputState`),
* the composite form field should wrap those elements in `<NoValidationUpdates>` to prevent clashing updates.
*
* @see ValidationProvider
* @see useValidation
* @see NoValidationUpdates
*/
export default function useValidationUpdate(result: ValidateResult | null): void {
const setValidateResult = useContext(ValidationSetterContext);
const disabled = useContext(NoValidationUpdateContext);

useEffect(() => {
if (disabled) return;
setValidateResult?.update(result);
}, [setValidateResult, result]);
}, [disabled, setValidateResult, result]);
}

2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ export {InlineGroup} from "~/providers/InlineGroup";
export type {InlineGroupProps} from "~/providers/InlineGroup";
export {ValidationProvider} from "~/providers/ValidationProvider";
export type {ValidationProviderProps} from "~/providers/ValidationProvider";
export {NoValidationUpdates} from "~/providers/NoValidationUpdates";
export type {NoValidationUpdatesProps} from "~/providers/NoValidationUpdates";
19 changes: 19 additions & 0 deletions src/providers/NoValidationUpdates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {createElement, ReactNode} from "react";
import {NoValidationUpdateContext} from "~/contexts/NoValidationUpdateContext";

export interface NoValidationUpdatesProps {
children: ReactNode;
}

/**
* Nullifies any `useValidationUpdate` calls by child nodes
*
* @see useValidationUpdate
*/
export function NoValidationUpdates({children}: NoValidationUpdatesProps) {
return createElement(
NoValidationUpdateContext.Provider,
{value: true},
children
)
}

0 comments on commit 406614f

Please sign in to comment.