Corey Ward
Freelance full-stack dev focused on building awesome Jamstack experiences
Corey is located at Austin, Texas, US
Generate a custom validator function for Portable Text fields using built-in routines
/**
* Validator-generator for Portable Text fields
*
* @param {Object} options
* @param {Boolean} options.required Require a value to be set in this field?
* @param {Boolean} options.noEmptyBlocks Prevent zero-length blocks?
* @param {Boolean} options.validateLinks Ensure links have required attributes?
* @param {Boolean} options.styleRequired Ensure blocks have an associated style?
*/
export const blockValidator = options => {
const { required, ...customValidators } = options
return Rule =>
[
required && Rule.required(),
...Object.entries(customValidators)
.filter(([, value]) => value)
.map(([name]) => Rule.custom(validators[name])),
].filter(Boolean)
}
export default blockValidator({
required: true,
noEmptyBlocks: true,
styleRequired: true,
validateLinks: true,
})
const validators = {
// https://www.sanity.io/docs/validation#validating-children-9e69d5db6f72
noEmptyBlocks: blocks => {
const emptyBlocks = (blocks || []).filter(
block =>
block._type === "block" &&
block.children.every(
span => span._type === "span" && span.text.trim() === ""
)
)
const emptyPaths = emptyBlocks.map(
(block, index) => [{ _key: block._key }] || [index]
)
return emptyPaths.length === 0
? true
: {
message: "Paragraph cannot be empty",
paths: emptyPaths,
}
},
// Links without href attributes
validateLinks: blocks => {
const errorPaths = (blocks || [])
.filter(
block =>
block._type === "block" &&
block.markDefs.some(
def => def._type === "link" && !(def.href && def.href.trim() !== "")
)
)
.map(block => [{ _key: block._key }])
return errorPaths.length === 0
? true
: {
message: "Links must have a url set",
paths: errorPaths,
}
},
// Ensure all blocks have a `style`
styleRequired: blocks => {
const emptyPaths = (blocks || [])
.filter(block => block._type === "block" && !block.style)
.map((block, index) => [{ _key: block._key }] || [index])
return emptyPaths.length === 0
? true
: {
message: "Must have a style selected",
paths: emptyPaths,
}
},
}
This makes it easy to add these common validation patterns to Portable Text fields, as well as provides a structure to create custom validators:
href
Freelance full-stack dev focused on building awesome Jamstack experiences
Drop this into your Studio to let editors know when there's a more recent version of your Studio available, making sure they have the latest fields and validations.
Go to Auto-reload Studio when changes are deployed