Skip to content

[6.x] Inertia User addresses - #19324

Merged
brandonkelly merged 23 commits into
6.xfrom
feature/inertia-addresses
Jul 29, 2026
Merged

[6.x] Inertia User addresses#19324
brandonkelly merged 23 commits into
6.xfrom
feature/inertia-addresses

Conversation

@brianjhanson

@brianjhanson brianjhanson commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Ports the My Account → Addresses page to a full Inertia page, and builds out the pieces needed to render nested element cards from data instead of server HTML.

  • Added NestedElementManager::getCardsData()/getIndexData(), and card-part renderers on ElementHtml (elementCardLabelHtml(), elementCardActionsHtml(), elementCardThumbHtml(), elementCardThumbAlignment()), which the Vue page feeds into craft-card slots.
  • Card action menus are rendered server-side. On the data path the menu items carry self-contained server-driven actions: Delete posts to nested-elements/delete, Duplicate to elements/duplicate, and Edit is a craft:edit-element event action handled by the slideout module (with ctrl-click opening the full edit page). On manager-hosted HTML the items keep behavior-less data-*-action markers so the hosting manager can wire its own draft-aware handling.
  • craft-button gained first-class action support (with a matching Button::action() setter on the PHP component), and action parsing now accepts raw JSON strings, since Vue's in-DOM compiler assigns attribute values as string properties on upgraded custom elements.
  • The Vue page renders the card grid, a craft-empty empty state, and an "Add address" button matching the Craft 5 flow (elements/create → editor slideout). Card mutations refresh via Inertia partial reloads driven by action:change-state and craft:element-saved events.
  • Craft.NestedElementManager was ported from the legacy jQuery bundle to a modern TypeScript module (resources/js/modules/nested-element-manager/); it still powers Matrix and nested-element fields on element edit pages.
  • Supporting changes: @craftcms/ui element-creator utilities and a Craft.ui compatibility shim, a fleshed-out craft-empty component, PHPStan literal type support in the TypeScript transpiler, strict-mode defaults for legacy element template variables, and an elevatedFields option for useSettingsSave.

brianjhanson and others added 13 commits July 24, 2026 11:23
Moves the legacy jQuery NestedElementManager into
resources/js/modules/nested-element-manager/ following the shared module
pattern: a logic class on @craftcms/garnish Base (modern Select/DragSort
for card selection and drag-sorting, documented jQuery seams for the
Craft.ui buttons, disclosure/expandable menus, element index, editor
slideouts, and Craft.cp), a <craft-nested-element-manager>
ControllerElement that boots from an element-type attribute and a JSON
settings attribute, a WeakMap instance registry, and an index shim that
assigns window.Craft.NestedElementManager (the constructor still accepts
the legacy three-argument signature for plugin boots).

NestedElementManager::createView() now emits the custom element around
its rendered markup instead of an HtmlStack JS boot, so the manager
self-boots and re-boots across Inertia fragment swaps. destroy() now
actually tears down listeners and the Select/DragSort instances.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Refines the empty-state styling (quiet fill, radius, grid-gap content
layout), registers the CraftEmpty export from the package root, and adds
Storybook stories covering the label/icon args and the graphic, content,
and default (action) slots.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
AddressesController::index() now renders users/Addresses for both
myaccount/addresses and users/{id}/addresses. The address card grid (or
the >50-address element index) stays server-rendered, captured as an
HtmlFragment by the new UserAddressesViewModel and injected by the Vue
page, so the nested element manager keeps working unchanged inside the
Inertia shell.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
createButton/createSubmitButton/createPasteButton in @craftcms/ui build
craft-button elements from the legacy Craft.ui config surface (plus the
modern variant/appearance/size/loading options), with the label in a
slotted span.label to preserve the legacy .find('.label') contract. New
code imports these directly.

The new resources/js/modules/ui shim patches the legacy Craft.ui methods
to delegate to the creators — returning jQuery, and bridging the legacy
style classes (disabled/loading/submit/secondary/small/big) onto the
component properties via a class-attribute observer — whether Craft.ui
is assigned before or after the shim loads. Matrix's paste button is the
first direct-import migration.

Also gives the ui package's `utilities` vitest project the same
tsconfigPaths resolution as the other projects, so utility tests can
import components.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The move/duplicate/copy/delete items the nested element manager used to
inject into each card's disclosure menu client-side now come down
server-rendered: ElementHtml::nestedCardActionItems() appends
behavior-less items marked data-move-forward-action /
data-move-backward-action / data-duplicate-action / data-delete-action
to the card action menu, each gated on the current user's permissions.

The signal (`showNestedActions`) is decided server-side in both render
paths: NestedElementManager::getCardsHtml() sets it for its own renders,
and app/render-elements derives it from the criterion's ownerId matching
the element's actual owner — client-supplied configs can request nothing.

Client-side, the manager only wires behavior: the marked items map to
the existing bulk-aware move/duplicate/delete flows, the element's own
server-wired Copy item is intercepted in capture phase for bulk mode,
and the clipboard-dependent Paste item is injected via
Craft.addActionsToChip. Position/limit/clipboard gating re-syncs on
every state change, replacing the legacy menu-open toggling, and the
now-dead client-side menu construction (#initElementActionMenu and the
.action-btn lookup) is removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sugar over passwordConfirmation: pages can name the form fields that
require an elevated session when dirty (or '*' for any change) instead
of hand-writing the initial-value comparison predicate. The Permissions
page is the first adopter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Re-enables the legacy stylesheet in CpAsset — slideout chrome and other
legacy surfaces still depend on it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown

📚 Storybook previews

@craftcms/uiopen Storybook

Changed components:

resources/jsopen Storybook

No changed components detected in this Storybook.

@brianjhanson
brianjhanson marked this pull request as ready for review July 28, 2026 14:32
brianjhanson and others added 9 commits July 28, 2026 09:37
Cards-data menu items now carry self-contained duplicate/delete HTTP
actions, the addresses page restores its empty state and refreshes via
partial reloads on action success, and AGENTS.md notes the VueUse
utilities.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
[ci skip]
@brandonkelly
brandonkelly merged commit e7fe053 into 6.x Jul 29, 2026
@brandonkelly
brandonkelly deleted the feature/inertia-addresses branch July 29, 2026 20:38
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.

2 participants