Image editor: formalize cropper contract#77668
Conversation
|
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 If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
There was a problem hiding this comment.
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
CropperActioninto a new internalcore/actions.tsmodule and removes it fromcore/types.ts. - Removes raw reducer
dispatchfrom theuseCropperState()controller; internal React code now accesses dispatch via a private WeakMap bridge. - Replaces wildcard exports with an explicit
image-editorbarrel 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.
| /** Returns the current cropper state. Called on every interaction. */ | ||
| getState: () => CropperState; | ||
| /** Dispatches a cropper action. */ | ||
| dispatch: ( action: CropperAction ) => void; |
There was a problem hiding this comment.
Completely remove reducer-based actions from the public API
| export * from './react/hooks'; | ||
| export * from './react/components'; | ||
| /** | ||
| * Public image editor contract. |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
andrewserong
left a comment
There was a problem hiding this comment.
Looking great, nice improvements here! Smoke-tested that things are working as on trunk, and this tidies things up nicely 👍
…-state.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
29f5a5b to
89551b8
Compare
Co-authored-by: ramonjd <ramonopoly@git.wordpress.org> Co-authored-by: andrewserong <andrewserong@git.wordpress.org>

What?
Part of:
This is part of a series of PRs to make the image editor extensible and predictable:
setZoom,setCropRect, andapplyOperation.CropperActionfrom the public barrels, giving us room to change internals without breaking future extensions.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?
CropperActionremains with the core type declarations, but is intentionally not exported through the public API.useCropperState()exposes a namedsetZoomAtPoint()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.Testing Instructions
There should be no regressions. CI should pass.
Test using
npm run storybook:devor 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.tsnpm 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.tsxgit diff --check