Skip to content

Commit

Permalink
Declunkify focal point picker dragging (#28676)
Browse files Browse the repository at this point in the history
* FocalPointPicker: call onDrag instead of onChange while dragging

Also:
- fix focus and keyboard input on media container
- fix onDragStart and onDragEnd to actually fire

* Cover block: use imperative preview of focal point while dragging

* Media & Text block: use imperative focal point preview while dragging

Due to the need to forward a ref through a few components they are
also updated. The HOC withNotices is refactored to a function
component and made accept and return forwardRef components.
ResizableBox is updated to a forwardRef.

* Correct createErrorNotice in withNotices

* Use a more lenient test for forwardRefs in withNotices

* add unit tests for withNotices

* Refine event handling in FocalPointPicker

- interrupt dragging on blur instead of via withFocusOutside
- avoid redundant calls to onDragEnd and onChange
- have mousemove listener start and stop synchronously
- pass focal point value as first argument to onDrag
- some minor stylistic changes

* restore grabbing cursor style in FocalPointPicker

* Update FocalPointPicker usage in core blocks

* add unit tests for FocalPointPicker

* Update docs for FocalPointPicker

* Update changelog for components package
  • Loading branch information
stokesman authored Feb 15, 2021
1 parent df5c8a3 commit c5ae463
Show file tree
Hide file tree
Showing 11 changed files with 490 additions and 226 deletions.
20 changes: 16 additions & 4 deletions packages/block-library/src/cover/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,15 +236,19 @@ function useCoverIsDark( url, dimRatio = 50, overlayColor, elementRef ) {
return isDark;
}

function mediaPosition( { x, y } ) {
return `${ Math.round( x * 100 ) }% ${ Math.round( y * 100 ) }%`;
}

function CoverEdit( {
attributes,
setAttributes,
isSelected,
noticeUI,
noticeOperations,
overlayColor,
setAttributes,
setOverlayColor,
toggleSelection,
noticeOperations,
} ) {
const {
contentPosition,
Expand Down Expand Up @@ -345,9 +349,8 @@ function CoverEdit( {

const mediaStyle = {
objectPosition:
// prettier-ignore
focalPoint && isImgElement
? `${ Math.round( focalPoint.x * 100 ) }% ${ Math.round( focalPoint.y * 100) }%`
? mediaPosition( focalPoint )
: undefined,
};

Expand All @@ -356,6 +359,13 @@ function CoverEdit( {
isVideoBackground ||
( isImageBackground && ( ! hasParallax || isRepeated ) );

const imperativeFocalPointPreview = ( value ) => {
const [ styleOfRef, property ] = isDarkElement.current
? [ isDarkElement.current.style, 'objectPosition' ]
: [ blockProps.ref.current.style, 'backgroundPosition' ];
styleOfRef[ property ] = mediaPosition( value );
};

const controls = (
<>
<BlockControls>
Expand Down Expand Up @@ -406,6 +416,8 @@ function CoverEdit( {
label={ __( 'Focal point picker' ) }
url={ url }
value={ focalPoint }
onDragStart={ imperativeFocalPointPreview }
onDrag={ imperativeFocalPointPreview }
onChange={ ( newFocalPoint ) =>
setAttributes( {
focalPoint: newFocalPoint,
Expand Down
12 changes: 11 additions & 1 deletion packages/block-library/src/media-text/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { map, filter } from 'lodash';
*/
import { __, _x } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import { useState } from '@wordpress/element';
import { useState, useRef } from '@wordpress/element';
import {
BlockControls,
BlockVerticalAlignmentToolbar,
Expand Down Expand Up @@ -146,6 +146,13 @@ function MediaTextEdit( { attributes, isSelected, setAttributes } ) {
[ isSelected, mediaId ]
);

const refMediaContainer = useRef();
const imperativeFocalPointPreview = ( value ) => {
const { style } = refMediaContainer.current.resizable;
const { x, y } = value;
style.backgroundPosition = `${ x * 100 }% ${ y * 100 }%`;
};

const [ temporaryMediaWidth, setTemporaryMediaWidth ] = useState( null );

const onSelectMedia = attributesFromMedia( { attributes, setAttributes } );
Expand Down Expand Up @@ -254,6 +261,8 @@ function MediaTextEdit( { attributes, isSelected, setAttributes } ) {
onChange={ ( value ) =>
setAttributes( { focalPoint: value } )
}
onDragStart={ imperativeFocalPointPreview }
onDrag={ imperativeFocalPointPreview }
/>
) }
{ mediaType === 'image' && (
Expand Down Expand Up @@ -325,6 +334,7 @@ function MediaTextEdit( { attributes, isSelected, setAttributes } ) {
onSelectMedia={ onSelectMedia }
onWidthChange={ onWidthChange }
commitWidthChange={ commitWidthChange }
ref={ refMediaContainer }
{ ...{
focalPoint,
imageFill,
Expand Down
29 changes: 18 additions & 11 deletions packages/block-library/src/media-text/media-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import { __ } from '@wordpress/i18n';
import { useViewportMatch } from '@wordpress/compose';
import { useDispatch } from '@wordpress/data';
import { forwardRef } from '@wordpress/element';

/**
* Internal dependencies
Expand All @@ -40,15 +41,20 @@ export function imageFillStyles( url, focalPoint ) {
: {};
}

function ResizableBoxContainer( { isSelected, isStackedOnMobile, ...props } ) {
const isMobile = useViewportMatch( 'small', '<' );
return (
<ResizableBox
showHandle={ isSelected && ( ! isMobile || ! isStackedOnMobile ) }
{ ...props }
/>
);
}
const ResizableBoxContainer = forwardRef(
( { isSelected, isStackedOnMobile, ...props }, ref ) => {
const isMobile = useViewportMatch( 'small', '<' );
return (
<ResizableBox
ref={ ref }
showHandle={
isSelected && ( ! isMobile || ! isStackedOnMobile )
}
{ ...props }
/>
);
}
);

function ToolbarEditButton( { mediaId, mediaUrl, onSelectMedia } ) {
return (
Expand Down Expand Up @@ -91,7 +97,7 @@ function PlaceholderContainer( {
);
}

function MediaContainer( props ) {
function MediaContainer( props, ref ) {
const {
className,
commitWidthChange,
Expand Down Expand Up @@ -155,6 +161,7 @@ function MediaContainer( props ) {
axis="x"
isSelected={ isSelected }
isStackedOnMobile={ isStackedOnMobile }
ref={ ref }
>
<ToolbarEditButton
onSelectMedia={ onSelectMedia }
Expand All @@ -169,4 +176,4 @@ function MediaContainer( props ) {
return <PlaceholderContainer { ...props } />;
}

export default withNotices( MediaContainer );
export default withNotices( forwardRef( MediaContainer ) );
10 changes: 10 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

## Unreleased

### Breaking Change
- `onChange` prop of `FocalPointPicker` is called at the end of drag operations. Previously, it was called repetitively while dragging.

### New Feature
- Supports ref forwarding in `withNotices` and `ResizableBox`.
- Adds `onDrag` prop of `FocalPointPicker`.

### Bug Fix
- Allows focus of the `FocalPointPicker` draggable area and adjustment with arrow keys. This was added in [#22531](https://github.com/WordPress/gutenberg/pull/22264) but was no longer working.

## 12.0.0 (2020-12-17)

### Enhancements
Expand Down
28 changes: 21 additions & 7 deletions packages/components/src/focal-point-picker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,6 @@ URL of the image or video to be displayed

Autoplays HTML5 video. This only applies to video sources (`url`).

### `dimensions`

- Type: `Object`
- Required: Yes

An object describing the height and width of the image. Requires two parameters: `height`, `width`.

### `value`

- Type: `Object`
Expand All @@ -80,3 +73,24 @@ The focal point. Should be an object containing `x` and `y` params.
- Required: Yes

Callback which is called when the focal point changes.

### `onDrag`

- Type: `Function`
- Required: No

Callback which is called repetitively during drag operations.

### `onDragEnd`

- Type: `Function`
- Required: No

Callback which is called at the end of drag operations.

### `onDragStart`

- Type: `Function`
- Required: No

Callback which is called at the start of drag operations.
Loading

0 comments on commit c5ae463

Please sign in to comment.