API Overhaul: registerWidget
Current Behavior
Registering a widget is currently pretty manual - you have to pass in each component separately, as well as a string for the name:
import CMS from 'netlify-cms'
import { WidgetControl, WidgetPreview } from 'random-widget'
CMS.registerWidget('random', WidgetControl, WidgetPreview)
We're now seeing a need for widgets to provide more than just components:
- https://github.com/netlify/netlify-cms/issues/1074 - Widgets should provide a standalone configuration validation function
- https://github.com/netlify/netlify-cms/issues/1407 - Widgets should provide a standalone function that produces a dynamic default value
With the current API, we would need to add one or more parameters to registerWidget for these new features, causing registration of multiple widgets to become excessively verbose.
Proposal
Require widgets to provide an object as the default export. As new widget features are added, the object can simply be appended, requiring no change for the projects using them. It would perhaps be shaped like this:
const widget = {
name: 'random',
control: WidgetControl,
preview: WidgetPreview,
validateConfig: config => {...},
default: () => {...},
}
export default widget
Representing widgets as objects allows a single signature to provide as much control as necessary:
import CMS from 'netlify-cms'
import randomWidget from 'random-widget'
// Use the defaults, should work for most cases
CMS.registerWidget(randomWidget)
// Or with an overridden property
CMS.registerWidget({ ...randomWidget, name: 'custom-name' })
// Or total control
import { RandomControl, validateConfig } from 'random-widget'
import CustomPreview from 'CustomPreview'
CMS.registerWidget({
name: 'custom-name',
control: RandomControl,
preview: CustomPreview,
validateConfig,
default: 'custom default value',
})
Finally, we should probably continue support the current signature, but deprecate at 2.0 and remove at 3.0.
Thoughts?
@erquhart I like this approach. Allows for extensible widgets without breaking prior widgets in the future also.
Came back to this with fresh eyes while considering #2037. We've talked about the concept of events and also dynamic defaults as mentioned in the OP. We can combine these two concepts for widgets.
Example
fields:
- name: publish_date
widget: datetime
update_on: ['publish_initial']
required: false
- name: last_modified_at
widget: datetime
visible: false
update_on: ['publish']
Quick breakdown of what these keys would mean:
update_on: list of events to automatically update the value. A widget would need to opt in to supporting this by providing a function outside of the React component. I imagine the function would receive the event name, the entry object, and maybe some other things.
visible: the field doesn't appear in the editor at all, and so would only be populated via update_on.
We could also provide an allow_edit property so a field can be made read only, if that really feels necessary. Not certain it is.
Default widget properties
An ID widget would work with the above API additions, but it's immediately clear that maybe a widget should be able to set its own defaults. Or would that be too confusing?
We're talking this:
- name: id
widget: id
update_on: ['create']
visible: false
Versus this:
- { name: id, widget: id }
Because that's how this widget would be used almost every time.
External functions
It should again be noted that this takes us further into the requirement that a widget consist of more than just a couple of components. For example, a publish event can be triggered from the editorial workflow, where no widget components are loaded at all, so we'd need those event driven functions to be standalone.
Thoughts on all of the above? Better than dynamic defaults? Worse?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
So we quietly did this months ago - still undocumented and technically experimental, but if you want to use it anyway, all of the widgets in the repo use it. Leaving this open until:
- [ ] finalization/documentation
- [ ] split other issues raised in the comments to standalone issues (like events-via-config concept)
@erquhart , did the 'allow_edit' feature make the cut?
Would a widget set to visible: false still be able to have a preview output? I haven't experimented with this yet to see.