Releases: brophdawg11/remix-validity-state
v0.11.1
What's Changed
- Fix
serverFormInfo.valid
computation on the server by @brophdawg11 in #59
Full Changelog: v0.11.0...v0.11.1
v0.11.0
The values in serverFormInfo.submittedValues
should now be type-safe based on your formDefinition
, however it does seem to require the usage of TS satisfies
to get the proper inference. For example:
interface FormSchema {
inputs: {
firstName: InputDefinition;
};
}
let formDefinition = {
inputs: {
firstName: {
validationAttrs: {
required: true,
},
},
},
} satisfies FormSchema; // 👈 Important! Requires TS 4.9+
export const action = async ({ request }: ActionArgs) => {
const formData = await request.formData();
const serverFormInfo = await validateServerFormData(formData, formDefinition);
if (!serverFormInfo.valid) { return json({ serverFormInfo }); }
serverFormInfo.submittedValues.firstName
// ^? string 👈
...
};
Note: This will hopefully get better in the future but for now you should only trust these types if serverFormInfo.valid === true
since if it's invalid we can't guarantee what got submitted.
In simple cases you probably won't notice much of a change here, since normal <input type="text">
inputs will always submit a string
value even if not required. Where this gets interesting is in more complex situations where you may submit multiple values or not submit a value at all.
Multiple Controls
Sometimes you want to accept multiple values with the same name. To tell RVS about this you can now add a multiple
boolean prop to your formDefinition
to indicate that you will render multiple controls with the same name, and this will change the type to string[]
since we'll get the values via formData.getAll()
:
let formDefinition = {
inputs: {
hobby: {
multiple: true, // 👈
},
},
} satisfies FormSchema;
export const action = async ({ request }: ActionArgs) => {
const formData = await request.formData();
const serverFormInfo = await validateServerFormData(formData, formDefinition);
if (!serverFormInfo.valid) { return json({ serverFormInfo }); }
serverFormInfo.submittedValues.hobby
// ^? string[] 👈
Multiple Values
Checkboxes accept multiple by default so they don't require a multiple
field in the formDefinition
and will have a type of string[] | null
by default or string[] if you also include required: true
let formDefinition = {
inputs: {
hobby: {
validationAttrs: {
type: "checkbox",
}
},
favoriteHobby: {
validationAttrs: {
type: "checkbox",
required: true,
}
},
},
} satisfies FormSchema;
export const action = async ({ request }: ActionArgs) => {
const formData = await request.formData();
const serverFormInfo = await validateServerFormData(formData, formDefinition);
if (!serverFormInfo.valid) { return json({ serverFormInfo }); }
serverFormInfo.submittedValues.hobby
// ^? string[] | null 👈
serverFormInfo.submittedValues.favoriteHobby
// ^? string[] 👈
Other controls, such as <select>
and <input type="email">
can accept a multiple
HTML attribute which lets a single control submit multiple values, so in those cases you include that in your validationAttrs
:
let formDefinition = {
inputs: {
hobby: {
element: "select",
validationAttrs: {
required: true,
multiple: true, // 👈
}
},
emails: {
validationAttrs: {
type: "email",
required: true,
multiple: true, // 👈
}
},
},
} satisfies FormSchema;
export const action = async ({ request }: ActionArgs) => {
const formData = await request.formData();
const serverFormInfo = await validateServerFormData(formData, formDefinition);
if (!serverFormInfo.valid) { return json({ serverFormInfo }); }
serverFormInfo.submittedValues.hobby
// ^? string[] 👈
serverFormInfo.submittedValues.email
// ^? string[] 👈
Minor Changes
- feat: make
ServerFormInfo
'ssubmittedValues
type-safe by @MichaelDeBoey in #46
Patch Changes
- chore: update dependencies by @MichaelDeBoey in #49
- Allow string type for date input min/max attrs by @brophdawg11 in #57
New Contributors
- @nickmccurdy made their first contribution in #47
Full Changelog: v0.10.0...v0.11.0
v0.10.1
v0.10.0
serverFormInfo.submittedValues
now that we've added value
to InputInfo
since you'd be able to get those values from serverFormInfo.inputs
. So consider submittedValues
deprecated and start using inputs[name].value
.
What's Changed
- make
serverFormInfo
optional in<FormProvider>
by @CSFlorin in #42 - Expose
info.value
andref
fromuseValidatedInput()
by @brophdawg11 in #43 - Add support for server-side
type=email
/type=url
intrinsic validation by @brophdawg11 in #44
New Contributors
- @CSFlorin made their first contribution in #42
Full Changelog: v0.9.1...v0.10.0
v0.9.1
👀 What's Changed
- Stabilize error message during subsequent async validations by @brophdawg11 in #36
Full Changelog: v0.9.0...v0.9.1
v0.9.0
👀 What's Changed
- Support server-only validations by @brophdawg11 in #33
Full Changelog: v0.8.0...v0.9.0
v0.8.0
👀 What's Changed
- Add support for other controls (textarea, select, radio, checkbox) by @brophdawg11 in #31. Please see the
README
for example usage.
⚠️ Breaking Changes
<Field>
renamed to<Input>
for consistency with<TextArea>
/<Select>
Full Changelog: v0.7.0...v0.8.0
v0.7.0
⚠️ Breaking Changes
v0.7.0
has a few breaking changes from v0.6.0
. Please red through the below PRs for additional context, but the general changes include:
Changed formValidations
to formDefinition
Your now define your form validations in a more comprehensive and explicit object. Previously you maintained formValidations and errorMessages separately, and placed custom validations alongside built-oin validation attributes. Now we have made a single structure that has locations for all of this:
// New Structure
let formDefinition: FormSchema = {
inputs: {
firstName: {
// ✅ Built-in HTML validations
validationAttrs: {
required: true,
pattern: "^[a-zA-Z]+$",
},
},
emailAddress: {
validationAttrs: {
type: "email",
required: true,
},
// ✅ Custom validations
customValidations: {
async uniqueEmail(value) {
await new Promise((r) => setTimeout(r, 1000));
return value !== "john@doe.com" && value !== "jane@doe.com";
},
},
// ✅ Field-specific error messages
errorMessages: {
uniqueEmail(attrValue, name, value) {
return `The email address "${value}" is already in use!`;
},
},
},
},
// ✅ Form-level error messages
errorMessages: { ... },
};
Changed FormContextProvider
to FormProvider
We no longer pass the context object, and instead pass formDefinition
and serverFormInfo
independently:
// New
<FormProvider formDefinition={formDefinition} serverFormInfo={actionData?.serverFormInfo}>
👀 What's Changed
- Slim build and remove UMD bundle by @brophdawg11 in #23
- Change structure for form definition by @brophdawg11 in #26
- Initial support for multiple inputs by @brophdawg11 in #28
- docs: update
action
s to useActionArgs
by @MichaelDeBoey in #27 - Dynamic Attrs by @brophdawg11 in #29
- chore: cleanup
BuiltInValidationAttrs
by @MichaelDeBoey in #30
🎉 New Contributors
- @MichaelDeBoey made their first contribution in #27
Full Changelog: v0.6.0...v0.7.0
v0.6.0
👀 What's Changed
- Support
formData
in server validation by @kentcdodds (#16) - Allow user to pass input refs to
useValidatedInput
by @chaance (#19) useFormContext
renamed touseOptionalFormContext
by @brophdawg11 (#22)
🎉 New Contributors
- @kentcdodds made their first contribution in #16
- @chaance made their first contribution in #19
Full Changelog: v0.5.0...v0.6.0