Repository navigation
Conversation
The widget registry typed its slots as React.ComponentType<any>, so any component could be registered, whatever props it took. @plone/types now has a WidgetPropsMap that an app augments with the props its widgets take; the registry types its widget slots with it, and with any props when nothing is declared, so Volto and its add-ons are unaffected. @plone/cmsui declares FormWidgetProps, so in Plone Aurora registering a widget that doesn't take the contract's props is a type error. The check found one: ObjectBrowserWidget read a widgetOptions shape the contract didn't describe. WidgetOptions gains pattern_options, and the widget is typed with the contract. describeWidgetContract (@plone/cmsui/testing/widgetContract) tests a widget's behavior against the contract: label, description, required, validation error only when invalid, no value, unknown widget options, and onChange(value). Every core widget runs it; the raw Quanta TextField, the old default widget, fails the required and invalid checks. The picker adapters are typed as string widgets, since a picker never emits null. Refs #243
…yped-widget-registry * origin/feat/widget-context: Read the object browser breadcrumbs from the middleware
This was referenced Oct 9, 2026
Member
Author
|
LGTM |
This was referenced Oct 9, 2026
…yped-widget-registry * origin/feat/widget-context: Restore files the pre-commit hook reformatted Validate schema-driven forms (#256) Move the recurrence modal off TanStack Form (#254) Move the forms onto the helpers form store (#253) Add a Jotai-native form layer to helpers (#252) Render every schema form through one field renderer (#251) Document and type the form widget contract (#97) Match utility dependencies exactly in the registry (#259)
…yped-widget-registry * origin/feat/widget-context: Add the components changelog entry for the picker rename
sneridagh
added this pull request to stack #270
October 10, 2026 22:48
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#243 step 6. Stacked on #261. Refs #243 (step 7, the missing widgets, still remains).
Typed widget registry, opt-in per app
The widget registry typed its slots as
React.ComponentType<any>, so any component could be registered, whatever props it took. Simply typing them withFormWidgetPropswould break Volto add-ons in TypeScript that register Volto-style widgets (id,onChange(id, value)), since@plone/typesand@plone/registryare shared with Volto. So the contract is declared by the app:@plone/typesadds an emptyWidgetPropsMapandRegisteredWidgetProps. The editing slots (default,id,widget,vocabulary,factory,choices,type) are typed with it, and withanyprops when nothing is declared. Display widgets (views) are unchanged.@plone/cmsuideclaresFormWidgetPropsin it (next to its existing@plone/typesaugmentation). In Aurora, registering a widget that doesn't take the contract's props is a type error, inregisterWidget, inregisterDefaultWidget, and in directconfig.widgetsassignments.@plone/typeswithout cmsui (checked with a scratch file), andwidgets.types.test.tsxchecks the Aurora side with@ts-expect-error.The check found one real mismatch:
ObjectBrowserWidgetexpectedwidgetOptions.pattern_options, which the contract'sWidgetOptionsdidn't describe.WidgetOptionsgainspattern_options(plone.restapi sends it for relation fields), and the widget is now typed with the contract. It passes its options explicitly instead of spreading all props into the browser's config. All other registered widgets already conformed.Contract test helper
describeWidgetContract(name, Widget, options)(@plone/cmsui/testing/widgetContract) tests a widget's behavior against the contract:requiredoraria-required);aria-invalidordata-invalid, and doesn't show it when valid;nullandundefinedvalues;onChange(value).skiptakes a reason per check, so a known gap shows up as a skipped test rather than going unnoticed.config/widgets.contract.test.tsx): text, textarea, boolean, date, date-time, align, size, width. 64 tests, no skips.TextField(the old default widget), it fails "marks a required field" and "shows its validation error".stringwidgets, since a picker never emitsnull.Docs
versionchanged/versionaddedstep for add-ons whose widgets don't follow the contract.Tests
optimizeDepsaudit are clean.