close
Skip to content

Image editor: formalize cropper contract#77668

Merged
ramonjd merged 6 commits into
WordPress:trunkfrom
ramonjd:update/image-editor-contract-api
Apr 28, 2026
Merged

Image editor: formalize cropper contract#77668
ramonjd merged 6 commits into
WordPress:trunkfrom
ramonjd:update/image-editor-contract-api

Conversation

@ramonjd
Copy link
Copy Markdown
Member

@ramonjd ramonjd commented Apr 25, 2026

What?

Part of:

This is part of a series of PRs to make the image editor extensible and predictable:

  • Makes the cropper's supported API explicit instead of accidentally exposing internals through wildcard exports.
  • Removes reducer dispatch from the public controller, so consumers use stable methods like setZoom, setCropRect, and applyOperation.
  • Keeps reducer actions private by omitting CropperAction from the public barrels, giving us room to change internals without breaking future extensions.
  • Updates internal cropper interactions to call named controller actions instead of reaching back into reducer dispatch.
  • Updates docs and recipes so the described contract matches the implementation.
  • Sets up the foundation for an extensible image editor surface: custom tools, stencils, selections, and provider-backed AI operations.

Why?

This makes the cropper safer to extend because consumers and internal React wiring both rely on named controller methods and curated exports rather than reducer internals.

How?

  • The public image editor barrel exports only the intended contract.
  • CropperAction remains with the core type declarations, but is intentionally not exported through the public API.
  • useCropperState() exposes a named setZoomAtPoint() controller method for atomic focal-point zoom updates.
  • <Cropper> passes the controller's named methods into the interaction layer instead of resolving a private dispatch bridge.
  • The README, architecture notes, roadmap, and recipes describe named controller methods instead of reducer dispatch as the supported extension boundary.

Testing Instructions

There should be no regressions. CI should pass.

Test using npm run storybook:dev or via https://playground.wordpress.net/?gutenberg-pr=77668 (enable media editor modal experiment)

Validated with:

  • npm run test:unit -- packages/media-editor/src/image-editor/react/hooks/test/use-cropper-state.ts packages/media-editor/src/image-editor/core/test/interaction-controller.ts
  • npm run lint:js -- packages/media-editor/src/image-editor/core/types.ts packages/media-editor/src/image-editor/core/state.ts packages/media-editor/src/image-editor/core/interaction-controller.ts packages/media-editor/src/image-editor/core/test/interaction-controller.ts packages/media-editor/src/image-editor/react/hooks/use-cropper-state.ts packages/media-editor/src/image-editor/react/hooks/use-interaction.ts packages/media-editor/src/image-editor/react/hooks/test/use-cropper-state.ts packages/media-editor/src/image-editor/react/components/cropper.tsx
  • git diff --check

@ramonjd ramonjd self-assigned this Apr 25, 2026
@ramonjd ramonjd added [Feature] Media Anything that impacts the experience of managing media [Type] Experimental Experimental feature or API. labels Apr 25, 2026
@ramonjd ramonjd requested review from andrewserong and Copilot April 25, 2026 03:17
@ramonjd ramonjd marked this pull request as ready for review April 25, 2026 03:17
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 25, 2026

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: ramonjd <ramonopoly@git.wordpress.org>
Co-authored-by: andrewserong <andrewserong@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR formalizes the image editor/cropper public contract by removing accidental public exposure of reducer internals and establishing a stable controller-driven API boundary for consumers and tests.

Changes:

  • Moves CropperAction into a new internal core/actions.ts module and removes it from core/types.ts.
  • Removes raw reducer dispatch from the useCropperState() controller; internal React code now accesses dispatch via a private WeakMap bridge.
  • Replaces wildcard exports with an explicit image-editor barrel export list, and updates docs/tests accordingly.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/media-editor/src/image-editor/react/hooks/use-interaction.ts Updates CropperAction import to the new internal actions module.
packages/media-editor/src/image-editor/react/hooks/use-cropper-state.ts Removes public __dispatch, adds WeakMap dispatch bridge, returns controller without reducer internals.
packages/media-editor/src/image-editor/react/hooks/test/use-cropper-state.ts Updates tests to use public controller methods and asserts __dispatch is not exposed.
packages/media-editor/src/image-editor/react/components/cropper.tsx Switches internal wiring to resolve dispatch via getCropperControllerDispatch().
packages/media-editor/src/image-editor/index.ts Replaces wildcard exports with an explicit, curated public contract.
packages/media-editor/src/image-editor/docs/roadmap.md Updates roadmap to reflect the new “no raw dispatch” controller boundary.
packages/media-editor/src/image-editor/core/types.ts Removes CropperAction from public types.
packages/media-editor/src/image-editor/core/test/interaction-controller.ts Updates tests to import CropperAction from the internal actions module.
packages/media-editor/src/image-editor/core/state.ts Updates CropperAction import source to core/actions.
packages/media-editor/src/image-editor/core/interaction-controller.ts Updates CropperAction import source to core/actions.
packages/media-editor/src/image-editor/core/actions.ts Introduces internal reducer action union in a dedicated module.
packages/media-editor/src/image-editor/README.md Updates docs to describe the supported controller contract and removes __dispatch guidance.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/media-editor/src/image-editor/react/hooks/use-cropper-state.ts Outdated
@ramonjd ramonjd mentioned this pull request Apr 25, 2026
55 tasks
/** Returns the current cropper state. Called on every interaction. */
getState: () => CropperState;
/** Dispatches a cropper action. */
dispatch: ( action: CropperAction ) => void;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completely remove reducer-based actions from the public API

export * from './react/hooks';
export * from './react/components';
/**
* Public image editor contract.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The public contract in packages/media-editor/src/image-editor/index.ts exports the controller, cropper components, state/types, and helper functions only. It does not export:

  • CropperAction
  • CropperInteractionActions
  • InteractionController
  • reducer dispatch
  • any actions object

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/media-editor/src/image-editor/core/actions.ts Outdated
Comment thread packages/media-editor/src/image-editor/core/actions.ts Outdated
Copy link
Copy Markdown
Contributor

@andrewserong andrewserong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking great, nice improvements here! Smoke-tested that things are working as on trunk, and this tidies things up nicely 👍

@ramonjd ramonjd force-pushed the update/image-editor-contract-api branch from 29f5a5b to 89551b8 Compare April 28, 2026 02:12
@ramonjd ramonjd enabled auto-merge (squash) April 28, 2026 02:12
@ramonjd ramonjd merged commit 0f87afb into WordPress:trunk Apr 28, 2026
39 checks passed
@github-actions github-actions Bot added this to the Gutenberg 23.1 milestone Apr 28, 2026
t-hamano pushed a commit that referenced this pull request Apr 29, 2026
Co-authored-by: ramonjd <ramonopoly@git.wordpress.org>
Co-authored-by: andrewserong <andrewserong@git.wordpress.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Media Anything that impacts the experience of managing media [Type] Experimental Experimental feature or API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants