Improve custom field documentation
I've been trying to create my own "Select images from media gallery" custom field which basically just replicates this document component block extension, but I feel like I'm basically throwing my head against a wall trying to understand what all the different custom field config options actually do. While I do appreciate that everything is typed, reverse engineering from the types alone is very painful.
Here's some things I think would be very helpful if explained in documentation:
- What is the config object passed into your custom field function? For example:
export function text<ListTypeInfo extends BaseListTypeInfo>({
isIndexed,
...config // <-- this
}
- Explanation of the
graphqlobject exported from@keystone-6/core - Detailed explanation of the
inputandoutputproperties required by thefieldType()function - How does this magical
controllerobject work? How does it hook in to everything else? Maybe some simple diagrams? - Detailed explanation of all the properties in the following types:
-
FieldControllerConfig -
FieldController<FormState, FilterValue>
-
I'm sure there's more that I've missed, but better documentation for custom fields would be a god-send.
Any luck creating your "Select images from media gallery" custom field @elliott-w? I was about to start trying to create such a field...
@cyruskorn Unfortunately not, I'm going to wait for better custom field documentation.
I ended up using a relationship field with displayMode: 'cards'. It's a sub-par content entry experience, but it will make it easier to replace with a custom field in the future since I plan for the custom field to store data in the exact same way as the relationship field does. Not sure if it'll help but here's the code:
// Other fields above...
gallery: relationship({
ref: 'PublicImage',
many: true,
ui: {
displayMode: 'cards',
cardFields: ['image'],
inlineEdit: { fields: ['image'] },
inlineCreate: { fields: ['image'] },
inlineConnect: true,
},
}),
// Other fields below...
And then the PublicImage list:
import { Lists } from '.keystone/types'
import { list } from '@keystone-6/core'
import { image, text, timestamp } from '@keystone-6/core/fields'
import { FileUpload } from 'graphql-upload'
import vars from '../utils/env-vars'
import { requireImage } from '../utils/require-image'
export const lists: Lists = {
PublicImage: list({
fields: {
name: text({
hooks: {
resolveInput: async ({ inputData, resolvedData }) => {
if (!resolvedData.name && inputData.image) {
const upload = (await inputData.image.upload) as FileUpload
return upload.filename
}
return resolvedData.name
},
},
}),
image: image({
storage: vars.IMAGE_STORAGE_PUBLIC,
hooks: {
validateInput: ({ resolvedData, addValidationError, operation }) => {
requireImage(resolvedData.image, operation, addValidationError)
},
},
}),
createdAt: timestamp({
defaultValue: {
kind: 'now',
},
validation: {
isRequired: true,
},
}),
},
}),
}
export default lists