Skip to content

Commit

Permalink
Cover: Video - Add position controls (#22531)
Browse files Browse the repository at this point in the history
* Add initial support for video in FocalPointPicker

* Add FocalPointPicker stories + update README.

* Improve FocalPointPicker and add Grid

* Update docs manifest

* Add click + keyboard arrow movements to update position

* Show grid on drag. Improve click/drag interaction.

* Apply Cover background position on save.js

* Refactor FocalPointPicker class component. Adjust styles.

* Refactor FocalPointPicker Media and add tests

* Refactor FocalPointPicker updateValue parsing.

Improve grid CSS rendering.

* Refactor percentage value updates from FocalPointPicker and sub components

* Add side label alignment for InputControl. Update controls in FocalPointPicker

* Add shift + drag to jump by 10. Improve stability of calculations on load

* Update fixture for Cover

* Fix file path for media import in test

* Update Flex component from master

* Add .ogv for video file

* Format style files

* Fix FocalPointPicker to handle reset value cases (e.g. UNDO)

* Improve rendering styles of FocalPointPicker media and picker

* Fix import path for roundClamp

* Ensure Cover save does not generated empty styles if there are no video bg positions

* Remove unused focal-point-picker style

* Adjusted super call in FocalPointPicker constructor

* Adjust useRevealAnimation hook with useUpdateEffect for debouncing

* Simplifiy showFocalPointPicker logic in cover/edit

* Fix position rounding for cover/save.js
  • Loading branch information
Q authored Jul 15, 2020
1 parent 11a0cd5 commit ff313a7
Show file tree
Hide file tree
Showing 20 changed files with 979 additions and 331 deletions.
51 changes: 27 additions & 24 deletions packages/block-library/src/cover/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,9 @@ function CoverEdit( {
isDarkElement
);

const isImageBackground = IMAGE_BACKGROUND_TYPE === backgroundType;
const isVideoBackground = VIDEO_BACKGROUND_TYPE === backgroundType;

const [ temporaryMinHeight, setTemporaryMinHeight ] = useState( null );
const { removeAllNotices, createErrorNotice } = noticeOperations;

Expand All @@ -280,9 +283,7 @@ function CoverEdit( {
: minHeight;

const style = {
...( backgroundType === IMAGE_BACKGROUND_TYPE
? backgroundImageStyles( url )
: {} ),
...( isImageBackground ? backgroundImageStyles( url ) : {} ),
backgroundColor: overlayColor.color,
minHeight: temporaryMinHeight || minHeightWithUnit || undefined,
};
Expand All @@ -291,13 +292,18 @@ function CoverEdit( {
style.background = gradientValue;
}

let positionValue;

if ( focalPoint ) {
style.backgroundPosition = `${ focalPoint.x * 100 }% ${
focalPoint.y * 100
}%`;
positionValue = `${ focalPoint.x * 100 }% ${ focalPoint.y * 100 }%`;
if ( isImageBackground ) {
style.backgroundPosition = positionValue;
}
}

const hasBackground = !! ( url || overlayColor.color || gradientValue );
const showFocalPointPicker =
isVideoBackground || ( isImageBackground && ! hasParallax );

const controls = (
<>
Expand Down Expand Up @@ -327,28 +333,24 @@ function CoverEdit( {
<InspectorControls>
{ !! url && (
<PanelBody title={ __( 'Media settings' ) }>
{ IMAGE_BACKGROUND_TYPE === backgroundType && (
{ isImageBackground && (
<ToggleControl
label={ __( 'Fixed background' ) }
checked={ hasParallax }
onChange={ toggleParallax }
/>
) }
{ IMAGE_BACKGROUND_TYPE === backgroundType &&
! hasParallax && (
<FocalPointPicker
label={ __( 'Focal point picker' ) }
url={ url }
value={ focalPoint }
onChange={ ( newFocalPoint ) =>
setAttributes( {
focalPoint: newFocalPoint,
} )
}
/>
) }
{ VIDEO_BACKGROUND_TYPE === backgroundType && (
<video autoPlay muted loop src={ url } />
{ showFocalPointPicker && (
<FocalPointPicker
label={ __( 'Focal point picker' ) }
url={ url }
value={ focalPoint }
onChange={ ( newFocalPoint ) =>
setAttributes( {
focalPoint: newFocalPoint,
} )
}
/>
) }
<PanelRow>
<Button
Expand Down Expand Up @@ -498,7 +500,7 @@ function CoverEdit( {
} }
showHandle={ isSelected }
/>
{ IMAGE_BACKGROUND_TYPE === backgroundType && (
{ isImageBackground && (
// Used only to programmatically check if the image is dark or not
<img
ref={ isDarkElement }
Expand All @@ -520,14 +522,15 @@ function CoverEdit( {
style={ { background: gradientValue } }
/>
) }
{ VIDEO_BACKGROUND_TYPE === backgroundType && (
{ isVideoBackground && (
<video
ref={ isDarkElement }
className="wp-block-cover__video-background"
autoPlay
muted
loop
src={ url }
style={ { objectPosition: positionValue } }
/>
) }
<InnerBlocks
Expand Down
35 changes: 25 additions & 10 deletions packages/block-library/src/cover/save.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,23 +48,37 @@ export default function save( { attributes } ) {
? `${ minHeightProp }${ minHeightUnit }`
: minHeightProp;

const style =
backgroundType === IMAGE_BACKGROUND_TYPE
? backgroundImageStyles( url )
: {};
const isImageBackground = IMAGE_BACKGROUND_TYPE === backgroundType;
const isVideoBackground = VIDEO_BACKGROUND_TYPE === backgroundType;

const style = isImageBackground ? backgroundImageStyles( url ) : {};
const videoStyle = {};

if ( ! overlayColorClass ) {
style.backgroundColor = customOverlayColor;
}
if ( focalPoint && ! hasParallax ) {
style.backgroundPosition = `${ Math.round(
focalPoint.x * 100
) }% ${ Math.round( focalPoint.y * 100 ) }%`;
}

if ( customGradient && ! url ) {
style.background = customGradient;
}
style.minHeight = minHeight || undefined;

let positionValue;

if ( focalPoint ) {
positionValue = `${ Math.round( focalPoint.x * 100 ) }% ${ Math.round(
focalPoint.y * 100
) }%`;

if ( isImageBackground && ! hasParallax ) {
style.backgroundPosition = positionValue;
}

if ( isVideoBackground ) {
videoStyle.objectPosition = positionValue;
}
}

const classes = classnames(
dimRatioToClass( dimRatio ),
overlayColorClass,
Expand Down Expand Up @@ -96,14 +110,15 @@ export default function save( { attributes } ) {
}
/>
) }
{ VIDEO_BACKGROUND_TYPE === backgroundType && url && (
{ isVideoBackground && url && (
<video
className="wp-block-cover__video-background"
autoPlay
muted
loop
playsInline
src={ url }
style={ videoStyle }
/>
) }
<div className="wp-block-cover__inner-container">
Expand Down
82 changes: 48 additions & 34 deletions packages/components/src/focal-point-picker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,60 +9,74 @@ Corresponding CSS: `background-position: 50% 10%;`

```jsx
import { FocalPointPicker } from '@wordpress/components';
import { useState } from '@wordpress/element';

const MyFocalPointPicker = withState( {
focalPoint: {
const Example = () => {
const [ focalPoint, setFocalPoint ] = useState( {
x: 0.5,
y: 0.5
},
} )( ( { focalPoint, setState } ) => {
y: 0.5,
} );

const url = '/path/to/image';
const dimensions = {
width: 400,
height: 100
height: 100,
};
return (
<FocalPointPicker
url={ url }
dimensions={ dimensions }
value={ focalPoint }
onChange={ ( focalPoint ) => setState( { focalPoint } ) }
/>
)
} );

/* Example function to render the CSS styles based on Focal Point Picker value */
const renderImageContainerWithFocalPoint = ( url, focalPoint ) => {

/* Example function to render the CSS styles based on Focal Point Picker value */
const style = {
backgroundImage: `url(${ url })` ,
backgroundPosition: `${ focalPoint.x * 100 }% ${ focalPoint.y * 100 }%`
}
return <div style={ style } />;
backgroundImage: `url(${ url })`,
backgroundPosition: `${ focalPoint.x * 100 }% ${ focalPoint.y * 100 }%`,
};

return (
<>
<FocalPointPicker
url={ url }
dimensions={ dimensions }
value={ focalPoint }
onChange={ ( focalPoint ) => setFocalPoint( { focalPoint } ) }
/>
<div style={ style } />
</>
);
};
```

## Props

### `url`

- Type: `Text`
- Required: Yes
- Description: URL of the image to be displayed
- Type: `Text`
- Required: Yes

URL of the image or video to be displayed

### `autoPlay`

- Type: `Boolean`
- Required: No
- Default: `true`

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

### `dimensions`

- Type: `Object`
- Required: Yes
- Description: An object describing the height and width of the image. Requires two paramaters: `height`, `width`.
- Type: `Object`
- Required: Yes

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

### `value`

- Type: `Object`
- Required: Yes
- Description: The focal point. Should be an object containing `x` and `y` params.
- Type: `Object`
- Required: Yes

The focal point. Should be an object containing `x` and `y` params.

### `onChange`

- Type: `Function`
- Required: Yes
- Description: Callback which is called when the focal point changes.
- Type: `Function`
- Required: Yes

Callback which is called when the focal point changes.
70 changes: 70 additions & 0 deletions packages/components/src/focal-point-picker/controls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* External dependencies
*/
import { noop } from 'lodash';

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import {
UnitControl as BaseUnitControl,
ControlWrapper,
} from './styles/focal-point-picker-style';
import { fractionToPercentage } from './utils';

const TEXTCONTROL_MIN = 0;
const TEXTCONTROL_MAX = 100;

export default function FocalPointPickerControls( {
onChange = noop,
percentages = {
x: 0.5,
y: 0.5,
},
} ) {
const valueX = fractionToPercentage( percentages.x );
const valueY = fractionToPercentage( percentages.y );

const handleOnXChange = ( next ) => {
onChange( { ...percentages, x: parseInt( next ) / 100 } );
};
const handleOnYChange = ( next ) => {
onChange( { ...percentages, y: parseInt( next ) / 100 } );
};

return (
<ControlWrapper className="focal-point-picker__controls">
<UnitControl
label={ __( 'Left' ) }
value={ valueX }
onChange={ handleOnXChange }
dragDirection="e"
/>
<UnitControl
label={ __( 'Top' ) }
value={ valueY }
onChange={ handleOnYChange }
dragDirection="s"
/>
</ControlWrapper>
);
}

function UnitControl( props ) {
return (
<BaseUnitControl
className="focal-point-picker__controls-position-unit-control"
labelPosition="side"
max={ TEXTCONTROL_MAX }
min={ TEXTCONTROL_MIN }
unit="%"
units={ [ { value: '%', label: '%' } ] }
{ ...props }
/>
);
}
Loading

0 comments on commit ff313a7

Please sign in to comment.