Skip to content

Commit

Permalink
Media & Text Block: Add image fill option (#14445)
Browse files Browse the repository at this point in the history
* Add image fill option to Media & Text block

* Update label copy

* Move imageFillStyles inline

* Use identical semantic structure for both image and imageFill

* Reset attributes on onSelectMedia

* Ensure attributes are reset properly

* Remove default for imageFill to prevent tests failing

* Add fixtures for image fill tests with/without focal point selected

*  Visually hide the image but make it accessible to assistive technologies

* Remove unnecessary deprecation

* Update changelog

* Change default background-position to 50%/50% and update fixtures

* Updated the transforms snapshot.
  • Loading branch information
frontdevde authored Apr 3, 2019
1 parent 1443f45 commit b3961d0
Show file tree
Hide file tree
Showing 17 changed files with 372 additions and 52 deletions.
1 change: 1 addition & 0 deletions packages/block-library/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Add `wide` and `full` alignments to Categories block ([#14533](https://github.com/WordPress/gutenberg/pull/14533)).
- Add all alignment options to RSS block ([#14533](https://github.com/WordPress/gutenberg/pull/14533)).
- Add all alignment options to Search block ([#14533](https://github.com/WordPress/gutenberg/pull/14533)).
- Add image fill option and focal point picker to Media & Text block ([#14445](https://github.com/WordPress/gutenberg/pull/14445)).
- Updated the edit flow of the `image` block, updated the edit icon and unified the image editing in only one UI based on `MediaPlaceholder`

### Bug Fixes
Expand Down
107 changes: 107 additions & 0 deletions packages/block-library/src/media-text/deprecated.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/**
* External dependencies
*/
import classnames from 'classnames';
import { noop } from 'lodash';

/**
* WordPress dependencies
*/
import {
InnerBlocks,
getColorClassName,
} from '@wordpress/block-editor';

/**
* Internal dependencies
*/
import { DEFAULT_MEDIA_WIDTH } from './index';

export default [
{
attributes: {
align: {
type: 'string',
default: 'wide',
},
backgroundColor: {
type: 'string',
},
customBackgroundColor: {
type: 'string',
},
mediaAlt: {
type: 'string',
source: 'attribute',
selector: 'figure img',
attribute: 'alt',
default: '',
},
mediaPosition: {
type: 'string',
default: 'left',
},
mediaId: {
type: 'number',
},
mediaUrl: {
type: 'string',
source: 'attribute',
selector: 'figure video,figure img',
attribute: 'src',
},
mediaType: {
type: 'string',
},
mediaWidth: {
type: 'number',
default: 50,
},
isStackedOnMobile: {
type: 'boolean',
default: false,
},
},
save( { attributes } ) {
const {
backgroundColor,
customBackgroundColor,
isStackedOnMobile,
mediaAlt,
mediaPosition,
mediaType,
mediaUrl,
mediaWidth,
} = attributes;
const mediaTypeRenders = {
image: () => <img src={ mediaUrl } alt={ mediaAlt } />,
video: () => <video controls src={ mediaUrl } />,
};
const backgroundClass = getColorClassName( 'background-color', backgroundColor );
const className = classnames( {
'has-media-on-the-right': 'right' === mediaPosition,
[ backgroundClass ]: backgroundClass,
'is-stacked-on-mobile': isStackedOnMobile,
} );

let gridTemplateColumns;
if ( mediaWidth !== DEFAULT_MEDIA_WIDTH ) {
gridTemplateColumns = 'right' === mediaPosition ? `auto ${ mediaWidth }%` : `${ mediaWidth }% auto`;
}
const style = {
backgroundColor: backgroundClass ? undefined : customBackgroundColor,
gridTemplateColumns,
};
return (
<div className={ className } style={ style }>
<figure className="wp-block-media-text__media" >
{ ( mediaTypeRenders[ mediaType ] || noop )() }
</figure>
<div className="wp-block-media-text__content">
<InnerBlocks.Content />
</div>
</div>
);
},
},
];
24 changes: 22 additions & 2 deletions packages/block-library/src/media-text/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
ToggleControl,
Toolbar,
ExternalLink,
FocalPointPicker,
} from '@wordpress/components';
/**
* Internal dependencies
Expand Down Expand Up @@ -77,6 +78,8 @@ class MediaTextEdit extends Component {
mediaId: media.id,
mediaType,
mediaUrl: src || media.url,
imageFill: undefined,
focalPoint: undefined,
} );
}

Expand All @@ -99,15 +102,15 @@ class MediaTextEdit extends Component {

renderMediaArea() {
const { attributes } = this.props;
const { mediaAlt, mediaId, mediaPosition, mediaType, mediaUrl, mediaWidth } = attributes;
const { mediaAlt, mediaId, mediaPosition, mediaType, mediaUrl, mediaWidth, imageFill, focalPoint } = attributes;

return (
<MediaContainer
className="block-library-media-text__media-container"
onSelectMedia={ this.onSelectMedia }
onWidthChange={ this.onWidthChange }
commitWidthChange={ this.commitWidthChange }
{ ...{ mediaAlt, mediaId, mediaType, mediaUrl, mediaPosition, mediaWidth } }
{ ...{ mediaAlt, mediaId, mediaType, mediaUrl, mediaPosition, mediaWidth, imageFill, focalPoint } }
/>
);
}
Expand All @@ -128,6 +131,9 @@ class MediaTextEdit extends Component {
mediaType,
mediaWidth,
verticalAlignment,
mediaUrl,
imageFill,
focalPoint,
} = attributes;
const temporaryMediaWidth = this.state.mediaWidth;
const classNames = classnames( className, {
Expand All @@ -136,6 +142,7 @@ class MediaTextEdit extends Component {
[ backgroundColor.class ]: backgroundColor.class,
'is-stacked-on-mobile': isStackedOnMobile,
[ `is-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment,
'is-image-fill': imageFill,
} );
const widthString = `${ temporaryMediaWidth || mediaWidth }%`;
const style = {
Expand Down Expand Up @@ -173,6 +180,19 @@ class MediaTextEdit extends Component {
isStackedOnMobile: ! isStackedOnMobile,
} ) }
/>
{ mediaType === 'image' && ( <ToggleControl
label={ __( 'Crop image to fill entire column' ) }
checked={ imageFill }
onChange={ () => setAttributes( {
imageFill: ! imageFill,
} ) }
/> ) }
{ imageFill && ( <FocalPointPicker
label={ __( 'Focal Point Picker' ) }
url={ mediaUrl }
value={ focalPoint }
onChange={ ( value ) => setAttributes( { focalPoint: value } ) }
/> ) }
{ mediaType === 'image' && ( <TextareaControl
label={ __( 'Alt Text (Alternative Text)' ) }
value={ mediaAlt }
Expand Down
5 changes: 5 additions & 0 deletions packages/block-library/src/media-text/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
width: 100% !important;
}

.wp-block-media-text.is-image-fill .editor-media-container__resizer {
// The resizer sets an inline height but for the image fill we set it to full height.
height: 100% !important;
}

.wp-block-media-text .block-editor-inner-blocks {
word-break: break-word;
grid-area: media-text-content;
Expand Down
63 changes: 15 additions & 48 deletions packages/block-library/src/media-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ import { __ } from '@wordpress/i18n';
*/
import edit from './edit';
import icon from './icon';
import deprecated from './deprecated';
import { imageFillStyles } from './media-container';

const DEFAULT_MEDIA_WIDTH = 50;
export const DEFAULT_MEDIA_WIDTH = 50;

export const name = 'core/media-text';

Expand Down Expand Up @@ -69,6 +71,12 @@ const blockAttributes = {
verticalAlignment: {
type: 'string',
},
imageFill: {
type: 'boolean',
},
focalPoint: {
type: 'object',
},
};

export const settings = {
Expand Down Expand Up @@ -160,6 +168,8 @@ export const settings = {
mediaWidth,
mediaId,
verticalAlignment,
imageFill,
focalPoint,
} = attributes;
const mediaTypeRenders = {
image: () => <img src={ mediaUrl } alt={ mediaAlt } className={ ( mediaId && mediaType === 'image' ) ? `wp-image-${ mediaId }` : null } />,
Expand All @@ -171,7 +181,9 @@ export const settings = {
[ backgroundClass ]: backgroundClass,
'is-stacked-on-mobile': isStackedOnMobile,
[ `is-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment,
'is-image-fill': imageFill,
} );
const backgroundStyles = imageFill ? imageFillStyles( mediaUrl, focalPoint ) : {};

let gridTemplateColumns;
if ( mediaWidth !== DEFAULT_MEDIA_WIDTH ) {
Expand All @@ -183,7 +195,7 @@ export const settings = {
};
return (
<div className={ className } style={ style }>
<figure className="wp-block-media-text__media" >
<figure className="wp-block-media-text__media" style={ backgroundStyles }>
{ ( mediaTypeRenders[ mediaType ] || noop )() }
</figure>
<div className="wp-block-media-text__content">
Expand All @@ -193,50 +205,5 @@ export const settings = {
);
},

deprecated: [
{
attributes: blockAttributes,
save( { attributes } ) {
const {
backgroundColor,
customBackgroundColor,
isStackedOnMobile,
mediaAlt,
mediaPosition,
mediaType,
mediaUrl,
mediaWidth,
} = attributes;
const mediaTypeRenders = {
image: () => <img src={ mediaUrl } alt={ mediaAlt } />,
video: () => <video controls src={ mediaUrl } />,
};
const backgroundClass = getColorClassName( 'background-color', backgroundColor );
const className = classnames( {
'has-media-on-the-right': 'right' === mediaPosition,
[ backgroundClass ]: backgroundClass,
'is-stacked-on-mobile': isStackedOnMobile,
} );

let gridTemplateColumns;
if ( mediaWidth !== DEFAULT_MEDIA_WIDTH ) {
gridTemplateColumns = 'right' === mediaPosition ? `auto ${ mediaWidth }%` : `${ mediaWidth }% auto`;
}
const style = {
backgroundColor: backgroundClass ? undefined : customBackgroundColor,
gridTemplateColumns,
};
return (
<div className={ className } style={ style }>
<figure className="wp-block-media-text__media" >
{ ( mediaTypeRenders[ mediaType ] || noop )() }
</figure>
<div className="wp-block-media-text__content">
<InnerBlocks.Content />
</div>
</div>
);
},
},
],
deprecated,
};
14 changes: 12 additions & 2 deletions packages/block-library/src/media-text/media-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ import icon from './media-container-icon';
*/
const ALLOWED_MEDIA_TYPES = [ 'image', 'video' ];

export function imageFillStyles( url, focalPoint ) {
return url ?
{
backgroundImage: `url(${ url })`,
backgroundPosition: focalPoint ? `${ focalPoint.x * 100 }% ${ focalPoint.y * 100 }%` : `50% 50%`,
} :
{};
}

class MediaContainer extends Component {
renderToolbarEditButton() {
const { mediaId, onSelectMedia } = this.props;
Expand All @@ -46,11 +55,12 @@ class MediaContainer extends Component {
}

renderImage() {
const { mediaAlt, mediaUrl, className } = this.props;
const { mediaAlt, mediaUrl, className, imageFill, focalPoint } = this.props;
const backgroundStyles = imageFill ? imageFillStyles( mediaUrl, focalPoint ) : {};
return (
<Fragment>
{ this.renderToolbarEditButton() }
<figure className={ className }>
<figure className={ className } style={ backgroundStyles }>
<img src={ mediaUrl } alt={ mediaAlt } />
</figure>
</Fragment>
Expand Down
18 changes: 18 additions & 0 deletions packages/block-library/src/media-text/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@
vertical-align: middle;
}

.wp-block-media-text.is-image-fill figure {
height: 100%;
min-height: 250px;
background-size: cover;
}

.wp-block-media-text.is-image-fill figure > img {
// The image is visually hidden but accessible to assistive technologies.
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}

/*
* Here we here not able to use a mobile first CSS approach.
* Custom widths are set using inline styles, and on mobile,
Expand Down
12 changes: 12 additions & 0 deletions packages/e2e-tests/fixtures/block-transforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ export const EXPECTED_TRANSFORMS = {
'Image',
],
},
'core__media-text__image-fill-no-focal-point-selected': {
originalBlock: 'Media & Text',
availableTransforms: [
'Image',
],
},
'core__media-text__image-fill-with-focal-point-selected': {
originalBlock: 'Media & Text',
availableTransforms: [
'Image',
],
},
'core__media-text__is-stacked-on-mobile': {
originalBlock: 'Media & Text',
availableTransforms: [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- wp:media-text {"mediaType":"image","imageFill":true} -->
<div class="wp-block-media-text alignwide is-image-fill">
<figure class="wp-block-media-text__media"
style="background-image:url(data:image/jpeg;base64,/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=);background-position:50% 50%">
<img src="data:image/jpeg;base64,/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k="
alt="My alt text" /></figure>
<div class="wp-block-media-text__content">
<!-- wp:paragraph {"placeholder":"Content…","fontSize":"large"} -->
<p class="has-large-font-size">My Content</p>
<!-- /wp:paragraph -->
</div>
</div>
<!-- /wp:media-text -->
Loading

0 comments on commit b3961d0

Please sign in to comment.