Experimental Image Cropper: Ensure focus is on canvas when dragging#77591
Conversation
|
Size Change: +14 B (0%) Total Size: 7.76 MB 📦 View Changed
ℹ️ View Unchanged
|
| ownerDoc?.activeElement instanceof HTMLElement && | ||
| ownerDoc.activeElement !== el |
There was a problem hiding this comment.
Yeah, good call. This works well. I'm also thinking that when the keyboard is panning the dim layer could also lighten like it does when mouse dragging.
2026-04-23.19.41.10.mp4
Here's how I tested:
diff
diff --git a/packages/media-editor/src/image-editor/core/interaction-controller.ts b/packages/media-editor/src/image-editor/core/interaction-controller.ts
index 343a21a0883..3ed18d990e4 100644
--- a/packages/media-editor/src/image-editor/core/interaction-controller.ts
+++ b/packages/media-editor/src/image-editor/core/interaction-controller.ts
@@ -167,6 +167,12 @@ export class InteractionController {
/** Whether a wheel gesture is currently active. */
private wheelGestureActive = false;
+ /** Timer for keyboard pan gesture debounce. */
+ private keyboardGestureTimer: ReturnType< typeof setTimeout > | undefined;
+
+ /** Whether a keyboard pan gesture is currently active. */
+ private keyboardGestureActive = false;
+
/** Current requestAnimationFrame ID. */
private rafId = 0;
@@ -778,6 +784,25 @@ export class InteractionController {
handleKeyDown( e: KeyboardEvent ): void {
const currentState = this.options.getState();
+ if (
+ e.key === 'ArrowUp' ||
+ e.key === 'ArrowDown' ||
+ e.key === 'ArrowLeft' ||
+ e.key === 'ArrowRight'
+ ) {
+ if ( ! this.keyboardGestureActive ) {
+ this.keyboardGestureActive = true;
+ this.setStatus( { isDragging: true } );
+ this.options.onGestureStart?.();
+ }
+ clearTimeout( this.keyboardGestureTimer );
+ this.keyboardGestureTimer = setTimeout( () => {
+ this.keyboardGestureActive = false;
+ this.setStatus( { isDragging: false } );
+ this.options.onGestureEnd?.();
+ }, DOUBLE_TAP_TIME );
+ }
+
switch ( e.key ) {
case 'ArrowUp': {
e.preventDefault();
@@ -903,6 +928,7 @@ export class InteractionController {
cancelAnimationFrame( this.rafId );
clearTimeout( this.zoomTimer );
clearTimeout( this.wheelGestureTimer );
+ clearTimeout( this.keyboardGestureTimer );
this.touchCleanup?.();
this.touchCleanup = null;
this.pointerCleanup?.();
On a side note, I activated showGrid locally. Do you think we should show the grid by default?
There was a problem hiding this comment.
Yeah, good call. This works well. I'm also thinking that when the keyboard is panning the dim layer could also lighten like it does when mouse dragging.
On second thought, this is just an interesting nice to have. I think the keyboard functionality we have here is way more valuable than screen bling. I'm just wondering if it's worth thinking about how to indicate visually when the image is focussed and therefore pannable. Or if it's worth it at all.
There was a problem hiding this comment.
I'm just wondering if it's worth thinking about how to indicate visually when the image is focussed and therefore pannable. Or if it's worth it at all.
I do think it's valuable to think about for sure! My main goal at the moment was to try to look at it in little pieces. I'm not too sure about the focused state of the canvas itself, but when it comes to the drag handles, I could see having a focus style on them when dragging with the mouse, so it's clear what's focused, and we could do a similar thing of allowing keyboard controls at that stage, too.
Do you think we should show the grid by default?
My preference would be to not show the grid as it interferes with looking at the image itself. Something for us to play with could be either a) for the grid to show only while dragging, rotating, moving the crop etc, and then have it fade out, or b) have a toggle in the sidebar to control display. But I reckon let's look at the grid separately (good thinking, though!)
For now, I'll fix up the tests in this PR and see how we go. Then in a follow-up, I'd like to look at focusing the drag handles, and play around with visually indicating what's focused. What do you reckon?
There was a problem hiding this comment.
For a follow-up, just jotting down what Google Photos does for the drag handles. If you tab to them it's got a nice big focus styles to make it clear what you've got selected:
(It also uses circles instead of squares, not sure if we have a preference there)
In any case, happy to play around with it!
There was a problem hiding this comment.
For now, I'll fix up the tests in this PR and see how we go.
Sounds good to me. All these ideas are good. We can test them out later.
|
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. |
|
Alrighty, fixed up the tests now, so 🤞 it'll pass |
|
Flaky tests detected in ffb8357. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/24864597522
|
|
Thanks Ramon! I'll merge this in, and will hack around with the drag handles and focus states in a follow-up 👍 |
…77591) * Experimental Image Cropper: Ensure focus is on canvas when dragging * Add a test and ensure focus has been mocked to get things passing Co-authored-by: andrewserong <andrewserong@git.wordpress.org> Co-authored-by: ramonjd <ramonopoly@git.wordpress.org> Co-authored-by: simison <87168+simison@users.noreply.github.com>




Part of:
What?
Update the experimental image cropper so that focus is on the canvas when clicking to interact.
Why?
I noticed that if I click to move the crop area, if I then go to make adjustments via the keyboard, nothing happened. So my hunch is that if we move focus there, it'll feel a little more intuitive moving from mouse to keyboard.
It's just a small change, but thought I'd try it out. If it proves okay, we might do a similar thing with the drag handles themselves. But I've kept this PR small in case it's not really viable.
How?
Testing Instructions
Enable the MediaEditorModal experiment, and go to make a crop. Set the crop area, and drag the middle area of the crop. Then use keyboard arrows, and it should work.
Screenshots or screencast
Before
2026-04-23.17.14.27.mp4
After
2026-04-23.17.26.48.mp4
Use of AI Tools
Claude Code