-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Description
Hello, team. Thank you for your hard work on this package.
Following the docs, I created a custom widget: videoEmbed
.
But when I try to add it as a field in one of my collections of files, of course it's not an acceptable widget type according to netlify-cms-core
's shipped typings.
To Reproduce
- Create custom widget & register with the CMS
- Create a
config.ts
file which specifies theCmsConfig
object which is passed intoCMS.init(config)
- In the CmsConfig object, add a File Collection with a single file with a single file/page.
- In that file's
fields
, add the custom widget (in my casevideoEmbed
) - Notice the Typescript error (screenshots)
TLDR: Expected Behavior
I would expect a typescript-safe way to specify custom widgets in a typescript config file. Maybe there is?
Is there a "nice" and sanctioned way to add type support for custom widgets in cmsConfig.ts
?
Workaround 1
Add as unknown as CmsField
after each custom widget field like so:
{
label: 'Video',
name: 'videoEmbed',
widget: 'videoEmbed',
} as unknown as CmsField,
This "works" as you can see in the screenshot:
Downside
The more I use custom widgets on more and more pages, the more I have to repeat the use of as unknown as CmsField
. This doesn't feel right.
Of course, I could just create a single const and use that instead but I still don't think this is the right way to go:
const videoEmbedCmsField = {
label: 'Video',
name: 'videoEmbed',
widget: 'videoEmbed',
} as unknown as CmsField;
// ...
{
label: 'Intro',
name: 'intro',
widget: 'markdown',
},
videoEmbedCmsField,
{
label: 'Show Gallery?',
name: 'showGallery',
widget: 'boolean',
},
// ...
Workaround 2
The other approach is to modify the CmsConfig
type aaaaaaall the way until I reach the field: CmsField
type so that I can add { widget: 'videoEmbed' }
as an acceptable widget type.
This feels like the right way to do it could it have some unintended side-effects since I need to adjust the init function to make it happy CMS.init({ config: cmsConfig as CmsConfig });
?
This screenshot shows how I got it to work (with a helper type Modify<T, R> = Omit<T, keyof R> & R
).
This all works and it feels like the right approach. Is it?
Workaround 3
Modify type CmsField
in netlify-cms-core/index.d.ts
to include the new widget type:
export interface CmsFieldVideoEmbed {
widget: 'videoEmbed';
default?: string;
}
export type CmsField = CmsFieldBase &
(
| CmsFieldBoolean
| CmsFieldCode
| CmsFieldColor
| CmsFieldDateTime
| CmsFieldFileOrImage
| CmsFieldList
| CmsFieldMap
| CmsFieldMarkdown
| CmsFieldNumber
| CmsFieldObject
| CmsFieldRelation
| CmsFieldSelect
| CmsFieldHidden
| CmsFieldStringOrText
| CmsFieldMeta
| CmsFieldVideoEmbed // <-- my custom widget type
);
Obviously, this is not the right way to do it but it allows my project to run locally. 🎉
Conclusion
Is there a proper way to do this? Thank you for your time.
Applicable Versions
- netlify-cms-app 2.15.72
- netlify-cms-core 2.55.2
- Git provider: GitHub, BitBucket
- OS: macOS Monterey 12.5
- Browser version Chrome 103
- Node.JS version: v16.10.0
CMS configuration
{
backend: {
name: 'git-gateway',
branch: 'main',
commit_messages: {
create: 'docs: create {{collection}} “{{slug}}”',
update: 'docs: update {{collection}} “{{slug}}”',
delete: 'docs: delete {{collection}} “{{slug}}”',
uploadMedia: 'docs: upload “{{path}}”',
deleteMedia: 'docs: delete “{{path}}”',
openAuthoring: 'docs: {{message}}',
},
},
local_backend: true,
media_folder: '/public/uploads',
public_folder: '/uploads',
collections: [
{
label: 'Pages',
name: 'pages',
files: [
{
label: 'Home',
name: 'home',
file: 'content/home.md',
fields: [
{
label: 'Title',
name: 'title',
widget: 'string',
},
{
label: 'Intro',
name: 'intro',
widget: 'markdown',
},
{
label: 'Show Gallery?',
name: 'showGallery',
widget: 'boolean',
},
{
label: 'Video',
name: 'videoEmbed',
widget: 'videoEmbed', // <-- This is the issue here
},
{
label: 'Features',
name: 'features',
widget: 'list',
fields: [
{ label: 'Title', name: 'title', widget: 'string' },
{
label: 'Content',
name: 'content',
widget: 'markdown',
modes: ['rich_text', 'raw'],
},
],
},
{
label: 'Gallery Images',
name: 'gallery',
widget: 'list',
label_singular: 'Image',
add_to_top: true,
fields: [{ label: 'Image', name: 'image', widget: 'image' }],
},
],
},
],
},
],
}