Duotone Picker: Stop the duotone bar offering to move its control points - #81850
Duotone Picker: Stop the duotone bar offering to move its control points#81850ramonjd wants to merge 4 commits into
Conversation
The bar announced that arrow keys and dragging change the gradient position, and that the button removes a control point. A duotone is two colors with no positions, so a move was discarded, and removal needs more than two control points, so it was never available either. CustomGradientBar gains a disablePositioning prop, set by CustomDuotoneBar, which guards the arrow key and drag handlers and swaps the description for one that matches what the control can do.
|
Warning: Type of PR label mismatch To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.
Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task. |
There was a problem hiding this comment.
Pull request overview
Prevents duotone controls from advertising or performing unsupported stop positioning.
Changes:
- Adds
disablePositioningtoCustomGradientBar. - Disables duotone dragging and position updates.
- Adds accessibility and keyboard tests.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
packages/components/CHANGELOG.md |
Documents the fix. |
packages/components/src/custom-gradient-picker/types.ts |
Defines the new prop. |
packages/components/src/custom-gradient-picker/gradient-bar/index.tsx |
Forwards positioning state. |
packages/components/src/custom-gradient-picker/gradient-bar/control-points.tsx |
Adjusts handlers and description. |
packages/components/src/duotone-picker/custom-duotone-bar.tsx |
Disables positioning for duotones. |
packages/components/src/duotone-picker/test/custom-duotone-bar.tsx |
Tests description and arrow keys. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Size Change: +98 B (0%) Total Size: 7.74 MB 📦 View Changed
|
| return ( | ||
| <CustomGradientBar | ||
| disableInserter | ||
| disablePositioning |
There was a problem hiding this comment.
CustomDuotoneBar sets the flag internally, so no public change (and not opt-out). This is okay presumably since you can't perform the position action for duotones anyway.
The early return skipped the stopPropagation calls that live inside the arrow key branches, so left and right bubbled out of the control and could move focus to another editor area. Measured against trunk: two arrow presses reached an ancestor listener where trunk let none through. The keys are now consumed before returning. Other keys are untouched and still bubble.
| isOpen, | ||
| position, | ||
| color, | ||
| disablePositioning, |
There was a problem hiding this comment.
Is this the right prop name?
| aria-label={ sprintf( | ||
| // translators: 1: gradient position e.g: 70. 2: gradient color code e.g: rgb(52,121,151). | ||
| __( | ||
| 'Gradient control point at position %1$d%% with color code %2$s.' |
There was a problem hiding this comment.
Mentioned in the PR desc.
I left thearia-label unchanged as it states a fact rather than promising an action.
The smallest version could be to flip the string to something like:
'Duotone control point with color code %s.'
?
| onToggle(); | ||
| } } | ||
| onMouseDown={ () => { | ||
| if ( disablePositioning ) { |
There was a problem hiding this comment.
No touch/point change handling to miss AFAIK so we can return early here.
| } | ||
| } } | ||
| onKeyDown={ ( event ) => { | ||
| if ( disablePositioning ) { |
There was a problem hiding this comment.
I think this could be optional, but a nice to have.
Trunk swallowed the arrow keys (below), but "handles" them for position changes, which we don't need for duotone.
…click path Nothing asserted that arrow keys move a control point on the gradient bar, so the claim that disablePositioning is opt-in had no test behind it. Adds that, plus its negative counterpart. Also covers clicking a duotone control point, since disabling positioning must not disable the one action the point still has.
|
Flaky tests detected in a7c3418. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/32333633400 Should save the changes in
|
There was a problem hiding this comment.
Should we add a regression test for disabled mouse dragging? In its simplest form, something like
it( 'does not move a control point when dragged', () => {
const onChange = jest.fn();
render( <CustomDuotoneBar value={ VALUE } onChange={ onChange } /> );
const [ firstPoint ] = screen.getAllByRole( 'button', {
name: /Gradient control point/,
} );
fireEvent.mouseDown( firstPoint );
fireEvent.mouseMove( window, { clientX: 50 } );
fireEvent.mouseUp( window );
expect( onChange ).not.toHaveBeenCalled();
} );For completeness, even a positive CustomGradientBar case that mocks the markers container’s getBoundingClientRect(), performs the same window-level events, and confirms onChange receives a moved position
What?
Stops the duotone bar telling users they can move its control points.
Closes #81799.
Why?
Each control point is described as:
Both halves are wrong for a duotone:
CustomDuotoneBarpasses the stops throughgetColorsFromColorStops(), which keeps only the colors. A duotone is two colors with no positions, so a move is discarded.controlPoints.length > 2, and a duotone has exactly two.Screen reader users get the whole sentence, so they are the ones told to perform operations that do nothing.
How?
CustomGradientBargainsdisablePositioning, set byCustomDuotoneBar. It guards the arrow key and drag handlers, and swaps the description for:Opt-in, so the gradient bar is unchanged.
Two notes on scope:
CustomDuotoneBaris the only consumer that disables anything, and it is also the only place removal is unavailable, so a second axis would be untested.aria-labelstill reads "Gradient control point at position 0%…". It states a fact rather than promising an action, so it is left alone.Testing Instructions
The duotone bar
Add an Image block, open the duotone control in the toolbar, pick a duotone. The bar appears below the swatches.
Screen reader
With VoiceOver or NVDA, focus a control point.
Without a screen reader, inspect the control point and follow
aria-describedby.Gradient bar, unchanged
Site Editor → Styles → Colors → Edit palette → Gradient. Add a gradient, click its swatch.