diff --git a/CHANGELOG.md b/CHANGELOG.md index a3d27877d85..83e1bd0703f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,17 @@ - The global `axios` is now only loaded in the control panel when `craftcms/yii2-adapter` is installed. `Craft.sendActionRequest()` or `actionClient` from `@craftcms/ui` should be used instead. - Removed `Cp.$axios`. - Fixed a bug where legacy embedded element indexes were missing actions, exporters, and reorder controls. ([#19789](https://github.com/craftcms/cms/pull/19789)) +- Added `CraftCms\Cms\Form\Controls\NestedElements` and `CraftCms\Cms\Element\NestedElementManager::formControl()`, allowing plugins to manage custom nested element types as cards or embedded element indexes. ([#19792](https://github.com/craftcms/cms/pull/19792)) +- Unified entry edit pages and nested element slideouts under the generic element editor, with a default `CraftCms\Cms\Http\ViewModels\ElementEditViewModel` for custom element types. ([#19792](https://github.com/craftcms/cms/pull/19792)) +- Added `CraftCms\Cms\Element\Events\ElementEditorPayloadResolving`. ([#19792](https://github.com/craftcms/cms/pull/19792)) +- The user Addresses screen now uses the shared nested element manager, including duplicating, deleting, and the element index view for users with many addresses. ([#19792](https://github.com/craftcms/cms/pull/19792)) +- Removed the `pasteableEntryTypeIds` nested element manager setting. `pasteableData` should be used instead. ([#19792](https://github.com/craftcms/cms/pull/19792)) +- Fixed a bug where Addresses fields’ configured Cards and Index view modes weren’t used in element forms. ([#19792](https://github.com/craftcms/cms/pull/19792)) +- Fixed a bug where nested element cards’ Copy, Duplicate, and Delete actions were always disabled. ([#19792](https://github.com/craftcms/cms/pull/19792)) +- Fixed a bug where nested elements without their own edit page, such as addresses, couldn’t be opened from their cards. ([#19792](https://github.com/craftcms/cms/pull/19792)) +- Fixed a bug where nested element slideouts for element types other than entries always used the legacy editor. ([#19792](https://github.com/craftcms/cms/pull/19792)) +- Fixed a bug where addresses couldn’t be saved from an element editor slideout. ([#19792](https://github.com/craftcms/cms/pull/19792)) +- Fixed a bug where element actions couldn’t find a user’s addresses. ([#19792](https://github.com/craftcms/cms/pull/19792)) - Fixed a bug where users’ breadcrumb chips weren’t getting hyperlinked. - Fixed a bug where `craft:up` could fail on installs that didn’t have a migrations table yet. ([#19796](https://github.com/craftcms/cms/pull/19796)) - Fixed a bug where subsequent embedded index requests lost configuration supplied by non-Matrix nested element managers. ([#19788](https://github.com/craftcms/cms/pull/19788)) diff --git a/docs/forms.md b/docs/forms.md index 2bb31e9932c..cc77c3ea54a 100644 --- a/docs/forms.md +++ b/docs/forms.md @@ -126,6 +126,43 @@ Return zero or one root Node. It may contain children or a composite Control. Th mode. Listen for `FieldLayoutFormResolving` to add, remove, or reorder typed Nodes after compilation; do not mutate rendered HTML or persisted layout data. +### Nested elements + +Elements nested in an owner — Matrix and Addresses fields, a user's addresses, or a plugin's own nested element type — +are managed by a `NestedElementManager`, which builds the shared `NestedElements` Control (`craft:nested-elements`). It +renders the elements as cards or an embedded element index outside the owner's form, and handles creating, editing in +a slideout, reordering, pasting, duplicating, and deleting them, including preparing the owner's draft first: + +```php +use CraftCms\Cms\Form\Contracts\Control; + +public function formControl(FieldContext $context): Control +{ + return $this->manager()->formControl($context->path, $context->element, 'cards', [ + 'canCreate' => true, + 'sortable' => true, + 'maxElements' => $this->maxItems, + ]); +} +``` + +The view mode is `cards`, `cards-grid`, or `index`. The frontend retains the initial index's display settings and +sends them with later requests, including paging and inline saves. Fields and owner elements do not need a +configuration provider. The frontend uses `maxElements` to disable operations when the whole selection will not +fit. The backend resolves the owner and nested element scope on each request and checks the element type's or +field's policies. Authoritative limits belong in those policies and field validation. A posted display setting +cannot bypass them. As in 5.x, duplication can partially succeed if the selection no longer fits when it runs. + +Screens that manage an owner's nested elements outside an element editor render `NestedElements.vue` directly with the +Control's props, passing `savedNestedOwner()` as its `owner` so changes apply to the saved owner and the screen +re-renders afterwards (see `pages/users/Addresses.vue`). + +Nested element types use the shared Inertia element editor automatically. They supply their field layout and +`sidebarForm()`, and can extend `ElementEditViewModel` through `ElementInterface::editViewModelClass()` when they +need additional payload or a different save action. `ElementEditorPayloadResolving` lets listeners modify the +prepared payload for edit screens and autosave responses. With the Yii adapter installed, existing editor HTML events +and `prepareEditScreen()` customizations are rendered around the native forms. + ### FieldLayout component settings Field layout components — tabs and layout elements — describe the form shown in the designer's settings slideout by diff --git a/docs/slideouts.md b/docs/slideouts.md index 31c29bec4a0..5bc6957e253 100644 --- a/docs/slideouts.md +++ b/docs/slideouts.md @@ -240,32 +240,18 @@ open and keeps saving as the user types, so an opener that refreshes on it shoul ### The element editor -The `elements/edit` screen is the exception: it doesn't submit itself. Drafts, autosaving, -provisional drafts, delta submission and tab error indicators all live in `Craft.ElementEditor`, so -the panel hands that screen over to it rather than reimplementing any of it — the same deal -`ElementEditorSlideout` strikes for the jQuery stack. - -`useElementEditor()` builds the editor and gives it the shell's regions: the panel `