Repository navigation
Add adapters for the remaining registered controls - #260
Merged
Merged
Conversation
* seven: Update README with the Plone Aurora Seven querystringWidget (#8017) [Seven] Add `renderEmptyState` to `Table` component (#8308) Recurrence widget (#7200)
Co-authored-by: Steve Piercy <web@stevepiercy.com>
* origin/main: (190 commits) Make control panels saveable (#220) Public UI: render a single .content-area root (#230) (#234) Remove tsconfig test/spec/story excludes that never matched any file (#222) Add PloneClient.extend() and clientEndpoints utility for custom endpoints (#221) Store the default block width of every top-level block (#190) Releasing @plone/aurora 1.0.0-alpha.19 Release @plone/cmsui 1.0.0-alpha.12 Release @plone/agave 1.0.0-alpha.9 Release @plone/theming 1.0.0-alpha.9 Release @plone/layout 1.0.0-alpha.14 Release @plone/blocks 1.0.0-alpha.18 Release @plone/plate 1.0.0-alpha.25 Release @plone/registry 4.0.0-alpha.5 Release @plone/quanta 1.0.0-alpha.2 Content CSS Phase 11: theming guide for blocks and cleanup (#219) Rename the Plone blocks' classnames to the content contract (#218) Share the block spacing between the Public UI and the editor (#217) Content CSS Phase 8: structural blocks and content root to styles/content.css (#216) Remove the Plate media nodes from Aurora's presets (#215) Move the table styles to styles/content.css (#214) ... # Conflicts: # packages/cmsui/components/BooleanWidget/BooleanWidget.stories.tsx # packages/cmsui/components/BooleanWidget/BooleanWidget.test.tsx # packages/cmsui/components/BooleanWidget/BooleanWidget.tsx # packages/cmsui/news/+boolean-widget-adapter.bugfix
Address the review: add a diagram that follows one field from its schema to its control and back, a comparison with HTML form controls and database columns, worked adapter examples for a boolean and a date widget, and a glossary. Apply the suggested wording and title changes. Add the missing cmsui and docs news fragments.
The content form, the control panels and the block settings each copied the same fieldset loop and spread the raw field schema into the widget props. They now render through SchemaFieldsets, and the field component builds the widget props from the field schema in one place (buildWidgetProps): - label and description from the schema, readOnly from readonly - defaultValue is the schema default, not the current value - invalid and one errorMessage instead of the raw error list - no forced placeholder - schema keys the form understands (type, title, factory...) are no longer passed as props; other keys stay widget options, and the raw schema is available as schema The field component is now field.SchemaField; field.Quanta stays as a deprecated alias. ObjectBrowserWidget now starts from the field value and uses the label as its title, since it relied on defaultValue being the current value. Refs #243
createFormStore keeps one form's values, and the touched, dirty and error state of its fields, in a Jotai store of its own. The values are the single source of truth: fields and any code that has the form read and write them by path, and each field only subscribes to its own path. Errors are derived from validators and server errors, and only show once a field is touched or the form submitted. The React bindings (useFormStore, FormProvider, useFormContext, useSchemaField, useFieldValue, useSetFieldValue, useFormState) live in form/react.tsx. useFormStore recreates the store when the form's key changes. Also adds Path / PathValue, to replace TanStack Form's DeepKeys / DeepValue, and getByPath / setByPath. Refs #244
…hema-field-renderer * origin/widgetsDefinitions: Scope widget lookups to their category (#249) Subscribe only to the form fields that are read (#248) Give each form its own store and remount it per item (#247) Wait for hydration in sharing acceptance tests (#250) # Conflicts: # packages/cmsui/components/RecurrenceWidget/RecurrenceWidget.tsx # packages/cmsui/routes/controlpanel.tsx
The content form, the control panels and the block settings now keep their values in a store from @plone/helpers (useFormStore, FormProvider) instead of TanStack Form plus a Jotai atom kept in sync with it. The store's values are the single source of truth; there is no sync left. - SchemaField reads its value and state with useSchemaField. - ContentForm and the control panels submit the store's values. - Block settings write each change, side effects included, back to the Plate node in one call, and start over when the node changes outside the form. - BlocksEditor reads and writes the blocks through useFormContext. - Plate's title binding finds the form with useOptionalFormContext, so the formAtom registry utility is gone, and so are routes/atoms and useAppForm. Removing the per-form Jotai Provider also puts the settings sidebar toggle and the sidebar on the same store again. The recurrence modal still uses TanStack Form internally; it moves next. Refs #244
…migration * origin/feat/form-store: Fix the indentation of the jotai/vanilla optimizeDeps entry
The recurrence modal's own form now uses a form store from @plone/helpers. It is not provided as the current form, so the fields in the modal still read the event's start and end from the content form. The field components take plain onChange(value) setters instead of TanStack updaters. With that, nothing uses @tanstack/react-form anymore, and cmsui drops the dependency. Also fixes the modal crashing the edit form for events that end on days 1 to 9 of a month: the default "until" date was built without padding the day (2026-10-5), which is not a valid ISO date. Adds the first acceptance test for the recurrence widget. Refs #244
…ecurrence-form-store * origin/feat/form-migration: Fix the indentation of the jotai/vanilla optimizeDeps entry
Required fields must not be empty, and the validators registered as validator utilities run on the fields they match, by fieldType, widget, format, behaviorName + fieldName, or blockType + fieldName. This keeps Volto's validator architecture, so add-ons plug in validators the same way, with i18next's t instead of formatMessage. The validators of a form are resolved once, from its schema, when the form store is created. - Ports the Volto validators (lengths, patterns, email, URL, numbers, list sizes, unique items, event date range). - An invalid save shows the errors on their fields, switches the content form to the Content tab and focuses the first invalid field. - The add, edit and control panel actions return plone.restapi's validation errors to the form, which shows them on their fields. - The default widget and the date and time widget become adapters (TextWidget, DateTimeWidget) that show the required and invalid state. Refs #244
* origin/main: Fix the recurrence modal crash for events ending on days 1 to 9 (#255)
…hema-field-renderer * origin/widgetsDefinitions: Fix the recurrence modal crash for events ending on days 1 to 9 (#255)
… feat/form-store * origin/feat/schema-field-renderer: Fix the recurrence modal crash for events ending on days 1 to 9 (#255)
…migration * origin/feat/form-store: Fix the recurrence modal crash for events ending on days 1 to 9 (#255)
…ecurrence-form-store * origin/feat/form-migration: Fix the recurrence modal crash for events ending on days 1 to 9 (#255)
… feat/schema-validation * origin/feat/recurrence-form-store: Fix the recurrence modal crash for events ending on days 1 to 9 (#255)
…hema-field-renderer * origin/widgetsDefinitions: Explain where controls and widgets live in the widgets guide
… feat/form-store * origin/feat/schema-field-renderer: Explain where controls and widgets live in the widgets guide
…migration * origin/feat/form-store: Explain where controls and widgets live in the widgets guide
…ecurrence-form-store * origin/feat/form-migration: Explain where controls and widgets live in the widgets guide
… feat/schema-validation * origin/feat/recurrence-form-store: Explain where controls and widgets live in the widgets guide
Covers the same ground as Volto's validation docs, for Plone Aurora: the default validators, registering validators by format (for blocks and, through frontendOptions, for content types), by field type, widget, behavior and field name, or block type and field name, how validators match a field, overriding them, the validator signature, translating messages, and invariants. The conceptual guide's validation section now links to it. Also updates the block schema side effects how-to, whose example still showed the block settings form before it moved to the form store.
Volto types its validators with a required formatMessage, so a validator utility type without it would no longer accept them. The arguments now carry both: t and fieldName for Plone Aurora, and formatMessage for validators written for Volto. Plone Aurora passes a formatMessage built on t, so Volto-style validators, which translate message descriptors, also run in its forms. A compatibility test registers validators typed exactly as Volto types them, so the type check fails if the shared type breaks them again.
The textarea, date, align, size and width widgets now follow the widget contract, as cmsui adapters around Quanta controls: - TextareaWidget, registered for the textarea widget (the summary of a page used to render as a single-line text field). - DateWidget, around the Quanta DatePicker, which reads and writes ISO date strings. It replaces the @plone/components DateField, which worked with DateValue objects. - AlignWidget, SizeWidget and WidthWidget around the Quanta pickers. They forward their widget options (actions, actionsInfoMap) from the block schema, and select the schema default without a stored value. Quanta's AlignWidget, SizeWidget and WidthWidget are controls, so they are renamed AlignPicker, SizePicker and WidthPicker, keeping the old names as deprecated aliases. Adds a Forms and widgets section to the upgrade guide, covering the changes of the whole form refactoring for add-ons. Refs #243
This was referenced Oct 9, 2026
Adds versionchanged, versionremoved, versionadded and deprecated admonitions for 1.0.0-alpha.20 to the Forms and widgets section, as the other upgrade sections have.
Member
Author
|
LGTM |
An error occurred while trying to automatically change base from
feat/schema-validation
to
feat/recurrence-form-store
October 10, 2026 22:38
* origin/main: 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) # Conflicts: # packages/cmsui/config/widgets.ts
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
sneridagh
added this pull request to stack #270
October 10, 2026 22:48
pnicolli
approved these changes
Oct 11, 2026
sneridagh
added a commit
that referenced
this pull request
Oct 11, 2026
…skip-content * commit '131c5e236cf8c17189e2ec94de4acbb040a1c0f6': Add the missing core widgets (#263) Type-check registered widgets and test them against the contract (#262) Give widgets a context instead of the route (#261) Add adapters for the remaining registered controls (#260) 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) # Conflicts: # packages/cmsui/routes/objectBrowserWidget.tsx
sneridagh
added a commit
that referenced
this pull request
Oct 11, 2026
…source-prefix * feat/resource-routes-skip-content: Drop the object browser breadcrumbs news fragment Add the missing core widgets (#263) Type-check registered widgets and test them against the contract (#262) Give widgets a context instead of the route (#261) Add adapters for the remaining registered controls (#260) 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)
sneridagh
added a commit
that referenced
this pull request
Oct 11, 2026
…drasekhar-eab6cd * commit '5729a626fba8358d111bc30925f0294b99346841': Use a single @ for the Contents view resource routes (#268) Let resource routes skip the root content middleware (#265) Update React Aria Components to 1.22 (#273) Add the missing core widgets (#263) Type-check registered widgets and test them against the contract (#262) Give widgets a context instead of the route (#261) Add adapters for the remaining registered controls (#260) 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) # Conflicts: # apps/aurora/app/middleware.server.ts
sneridagh
added a commit
that referenced
this pull request
Oct 11, 2026
* 'main' of github.com:plone/aurora: Use a single @ for the Contents view resource routes (#268) Let resource routes skip the root content middleware (#265) Update React Aria Components to 1.22 (#273) Add the missing core widgets (#263) Type-check registered widgets and test them against the contract (#262) Give widgets a context instead of the route (#261) Add adapters for the remaining registered controls (#260) 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) Fix the recurrence modal crash for events ending on days 1 to 9 (#255) Scope widget lookups to their category (#249) Subscribe only to the form fields that are read (#248) Give each form its own store and remount it per item (#247) Wait for hydration in sharing acceptance tests (#250) # Conflicts: # apps/aurora/app/middleware.server.ts
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.
The rest of #243 step 4. Stacked on #256, which added
TextWidgetandDateTimeWidget.Adapters
Every control registered as a widget is now a cmsui adapter that follows the widget contract (
FormWidgetProps) and shows the required and invalid state:textareaTextareaWidgetTextAreaFielddateDateWidgetDatePicker(ISOYYYY-MM-DDstrings)@plone/componentsDateField, which takes and emitsDateValueobjectsalign,size,widthAlignWidget,SizeWidget,WidthWidgetAlignPicker,SizePicker,WidthPickerThe three picker adapters share one contract → radio group mapping. They forward their widget options from the block schema (
actions,actionsInfoMap), and select the schemadefaultwhen there's no stored value.Quanta's pickers are renamed
Following the packaging rule (#243 rule 5, and the guide's "Where controls and widgets live"): Quanta's
AlignWidget,SizeWidgetandWidthWidgetare controls (React Aria radio groups), so they're renamedAlignPicker,SizePicker,WidthPicker, after Quanta's existingDatePicker. Their props types are exported. The old names stay as deprecated aliases, so this isn't breaking. Quanta's README and AGENTS.md, the conventions reference and the components README are updated.Upgrade guide
The form refactoring had no upgrade notes yet. This PR adds a "Forms and widgets" section to the upgrade guide, covering the whole stack's changes for add-ons:
useAppForm,field.Quanta, theformAtomutility androutes/atoms, with a before/after for reading form values (Move the forms onto the helpers form store #253, Move the recurrence modal off TanStack Form #254);t(Validate schema-driven forms #256);Tests
PickerWidgets/adapters.test.tsx):actionsfrom the schema, and show errors;<textarea>with its value, required and invalid state;optimizeDepsaudit are clean. No references to the old names or Storybook IDs remain.