Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add instantValidation prop for TextArea #2355

Merged
merged 8 commits into from
Nov 13, 2024
5 changes: 5 additions & 0 deletions .changeset/chatty-moles-brush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@khanacademy/wonder-blocks-form": minor
---

Adds `instantValidation` prop for TextArea
93 changes: 93 additions & 0 deletions __docs__/wonder-blocks-form/text-area.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,99 @@ ErrorFromPropAndValidation.parameters = {
},
};

/**
* The `instantValidation` prop controls when validation is triggered. Validation
* is triggered if the `validate` or `required` props are set.
*
* It is preferred to set `instantValidation` to `false` so that the user isn't
* shown an error until they are done with a field. Note: if `instantValidation`
* is not explicitly set, it defaults to `true` since this is the current
* behaviour of existing usage. Validation on blur needs to be opted in.
*
* Validation is triggered:
* - On mount if the `value` prop is not empty
* - If `instantValidation` is `true`, validation occurs `onChange` (default)
* - If `instantValidation` is `false`, validation occurs `onBlur`
*
* When `required` is set to `true`:
* - If `instantValidation` is `true`, the required error message is shown after
* a value is cleared
* - If `instantValidation` is `false`, the required error message is shown
* whenever the user tabs away from the required field
*/
export const InstantValidation: StoryComponentType = {
args: {
validate(value: string) {
const emailRegex = /^[^@\s]+@[^@\s.]+\.[^@.\s]+$/;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this make sense for a test utility so it could be reused?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! I'll have another PR up soon related to shared validation logic for TextField and TextArea so I will update the stories to use a test utility there!

if (!emailRegex.test(value)) {
return "Please enter a valid email";
}
},
},
render: (args) => {
return (
<View style={{gap: spacing.small_12}}>
<LabelSmall htmlFor="instant-validation-true-not-required">
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will replace with LabeledField after. I'll be merging/releasing the form field updates separately from LabeledField (LabeledField changes are in feature/labeled-field right now, and I'll update it with these form field changes after!)

Validation on mount if there is a value
</LabelSmall>
<ControlledTextArea
{...args}
id="instant-validation-true-not-required"
value="invalid"
/>
<LabelSmall htmlFor="instant-validation-true-not-required">
Error shown immediately (instantValidation: true, required:
false)
</LabelSmall>
<ControlledTextArea
{...args}
id="instant-validation-true-not-required"
instantValidation={true}
/>
<LabelSmall htmlFor="instant-validation-false-not-required">
Error shown onBlur (instantValidation: false, required:
false)
</LabelSmall>
<ControlledTextArea
{...args}
id="instant-validation-false-not-required"
instantValidation={false}
/>

<LabelSmall htmlFor="instant-validation-true-required">
Error shown immediately after clearing the value
(instantValidation: true, required: true)
</LabelSmall>
<ControlledTextArea
{...args}
validate={undefined}
value="T"
id="instant-validation-true-required"
instantValidation={true}
required="Required"
/>
<LabelSmall htmlFor="instant-validation-false-required">
Error shown on blur if it is empty (instantValidation:
false, required: true)
</LabelSmall>
<ControlledTextArea
{...args}
validate={undefined}
id="instant-validation-false-required"
instantValidation={false}
required="Required"
/>
</View>
);
},
parameters: {
chromatic: {
// Disabling because this doesn't test anything visual.
disableSnapshot: true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooh, I didn't know you could do that! Nice.

},
},
};

/**
* A required field will have error styling if the field is left blank. To
* observe this, type something into the field, backspace all the way,
Expand Down
Loading