Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Media & Text Block: Add image fill option #14445

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
/**
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the deprecated part to its own file to declutter index.js.

* 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 [
{
frontdevde marked this conversation as resolved.
Show resolved Hide resolved
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: {
frontdevde marked this conversation as resolved.
Show resolved Hide resolved
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 ) : {};
frontdevde marked this conversation as resolved.
Show resolved Hide resolved

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 } />
frontdevde marked this conversation as resolved.
Show resolved Hide resolved
</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