Skip to content

[6.x] Restore field action menus and handles in the new form system - #19480

Draft
brianjhanson wants to merge 1 commit into
6.xfrom
feature/field-action-menus
Draft

[6.x] Restore field action menus and handles in the new form system#19480
brianjhanson wants to merge 1 commit into
6.xfrom
feature/field-action-menus

Conversation

@brianjhanson

Copy link
Copy Markdown
Contributor

BaseField::formNode() never called ->actions(), so the "⋮" menu every field carried in Craft 5 — Field settings, Copy field handle — was absent from every form the new system renders, along with the inline handle chip admins see with the "Show field handles in edit forms" preference on.

Everything feeding that menu survived the port but had no caller: actionMenuItems(), copyAttributeAction(), showAttribute(), the six native field overrides, and FieldLayoutActionMenuItemsResolving (whose yii2-adapter bridge to DefineFieldActionsEvent was already wired and waiting). The inputHtml() tier was orphaned too, which left copyAttributeAction() with no live call sites at all.

Adds craft:action-menu and craft:copy-attribute Form Nodes, emitted from formNode() into the Field node's existing actions slot. Node UIDs derive from the control path, not the layout element UID: that UID is nullable, and one layout element can emit several Fields (LatLongField).

Item behavior is now declarative. HtmlStack::jsWithVars registers JS on a full page load only, so a menu built that way is inert on exactly the Inertia-rendered screens this targets. Items instead carry BaseAction descriptors that craft-action-item runs, with listeners in resources/js/modules/fields. Matrix's expand/collapse-all and the Matrix and Addresses copy-all items are converted the same way; their listeners scope to the invoking item's own craft-field, preserving the direct-descendant scoping the old jQuery selectors relied on, which the two render paths spell differently.

ElementHtml's three private action-menu rendering methods move to a shared Cp\Components\ActionMenu. Both renderers now consume one canonical item shape, so the HTML and Vue paths can't drift.

Two known gaps: the old handlers hid or disabled items on menu open (expand-all only when something was collapsed, copy greyed out when empty), which isn't reproduced; and "Copy value from site…" is still absent, since it needs a values key on CopyElementValuesController's response, a Vue site picker, and a listener that calls setValue() — the legacy modal resolves its field through .closest('.menu').data('disclosureMenu').

Description

Related issues

`BaseField::formNode()` never called `->actions()`, so the "⋮" menu every
field carried in Craft 5 — Field settings, Copy field handle — was absent from
every form the new system renders, along with the inline handle chip admins see
with the "Show field handles in edit forms" preference on.

Everything feeding that menu survived the port but had no caller:
`actionMenuItems()`, `copyAttributeAction()`, `showAttribute()`, the six native
field overrides, and `FieldLayoutActionMenuItemsResolving` (whose yii2-adapter
bridge to `DefineFieldActionsEvent` was already wired and waiting). The
`inputHtml()` tier was orphaned too, which left `copyAttributeAction()` with no
live call sites at all.

Adds `craft:action-menu` and `craft:copy-attribute` Form Nodes, emitted from
`formNode()` into the Field node's existing `actions` slot. Node UIDs derive
from the control path, not the layout element UID: that UID is nullable, and
one layout element can emit several Fields (`LatLongField`).

Item behavior is now declarative. `HtmlStack::jsWithVars` registers JS on a
full page load only, so a menu built that way is inert on exactly the
Inertia-rendered screens this targets. Items instead carry `BaseAction`
descriptors that `craft-action-item` runs, with listeners in
`resources/js/modules/fields`. Matrix's expand/collapse-all and the Matrix and
Addresses copy-all items are converted the same way; their listeners scope to
the invoking item's own `craft-field`, preserving the direct-descendant
scoping the old jQuery selectors relied on, which the two render paths spell
differently.

`ElementHtml`'s three private action-menu rendering methods move to a shared
`Cp\Components\ActionMenu`. Both renderers now consume one canonical item
shape, so the HTML and Vue paths can't drift.

Two known gaps: the old handlers hid or disabled items on menu open (expand-all
only when something was collapsed, copy greyed out when empty), which isn't
reproduced; and "Copy value from site…" is still absent, since it needs a
`values` key on `CopyElementValuesController`'s response, a Vue site picker,
and a listener that calls `setValue()` — the legacy modal resolves its field
through `.closest('.menu').data('disclosureMenu')`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📚 Storybook previews

@craftcms/uiopen Storybook

No changed components detected in this Storybook.

resources/jsopen Storybook

No changed components detected in this Storybook.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant