@@ -7,12 +7,15 @@ import {
77 AlignmentToolbar ,
88 BlockControls ,
99 InspectorControls ,
10+ MediaUpload ,
11+ MediaUploadCheck ,
1012 PanelColorSettings ,
1113 RichText ,
1214 withColors ,
1315} from '@wordpress/editor' ;
1416import {
1517 Button ,
18+ IconButton ,
1619 PanelBody ,
1720 Placeholder ,
1821 RangeControl ,
@@ -24,23 +27,41 @@ import {
2427import classnames from 'classnames' ;
2528import { Component , Fragment } from '@wordpress/element' ;
2629import { compose } from '@wordpress/compose' ;
27- import { debounce } from 'lodash' ;
30+ import { debounce , isObject } from 'lodash' ;
2831import PropTypes from 'prop-types' ;
2932
3033/**
3134 * Internal dependencies
3235 */
3336import ProductControl from '../../components/product-control' ;
37+ import {
38+ getImageSrcFromProduct ,
39+ getImageIdFromProduct ,
40+ } from '../../utils/products' ;
3441
35- // Copied from core/cover, updated for product.
36- function backgroundImageStyles ( { images = [ ] } ) {
37- if ( images . length ) {
38- const url = images [ 0 ] . src ;
42+ /**
43+ * Generate a style object given either a product object or URL to an image.
44+ *
45+ * @param {object|string } url A product object as returned from the API, or an image URL.
46+ * @return {object } A style object with a backgroundImage set (if a valid image is provided).
47+ */
48+ function backgroundImageStyles ( url ) {
49+ // If `url` is an object, it's actually a product.
50+ if ( isObject ( url ) ) {
51+ url = getImageSrcFromProduct ( url ) ;
52+ }
53+ if ( url ) {
3954 return { backgroundImage : `url(${ url } )` } ;
4055 }
4156 return { } ;
4257}
4358
59+ /**
60+ * Convert the selected ratio to the correct background class.
61+ *
62+ * @param {number } ratio Selected opacity from 0 to 100.
63+ * @return {string } The class name, if applicable (not used for ratio 0 or 50).
64+ */
4465function dimRatioToClass ( ratio ) {
4566 return ratio === 0 || ratio === 50 ?
4667 null :
@@ -107,7 +128,7 @@ class FeaturedProduct extends Component {
107128 selected = { attributes . productId || 0 }
108129 onChange = { ( value = [ ] ) => {
109130 const id = value [ 0 ] ? value [ 0 ] . id : 0 ;
110- setAttributes ( { productId : id } ) ;
131+ setAttributes ( { productId : id , mediaId : 0 , mediaSrc : '' } ) ;
111132 } }
112133 />
113134 </ PanelBody >
@@ -173,7 +194,7 @@ class FeaturedProduct extends Component {
173194 selected = { attributes . productId || 0 }
174195 onChange = { ( value = [ ] ) => {
175196 const id = value [ 0 ] ? value [ 0 ] . id : 0 ;
176- setAttributes ( { productId : id } ) ;
197+ setAttributes ( { productId : id , mediaId : 0 , mediaSrc : '' } ) ;
177198 } }
178199 />
179200 < Button isDefault onClick = { onDone } >
@@ -205,8 +226,11 @@ class FeaturedProduct extends Component {
205226 dimRatioToClass ( dimRatio ) ,
206227 contentAlign !== 'center' && `has-${ contentAlign } -content`
207228 ) ;
229+ const mediaId = attributes . mediaId || getImageIdFromProduct ( product ) ;
208230
209- const style = ! ! product ? backgroundImageStyles ( product ) : { } ;
231+ const style = ! ! product ?
232+ backgroundImageStyles ( attributes . mediaSrc || product ) :
233+ { } ;
210234 if ( overlayColor . color ) {
211235 style . backgroundColor = overlayColor . color ;
212236 }
@@ -230,6 +254,25 @@ class FeaturedProduct extends Component {
230254 } ,
231255 ] }
232256 />
257+ < MediaUploadCheck >
258+ < Toolbar >
259+ < MediaUpload
260+ onSelect = { ( media ) => {
261+ setAttributes ( { mediaId : media . id , mediaSrc : media . url } ) ;
262+ } }
263+ allowedTypes = { [ 'image' ] }
264+ value = { mediaId }
265+ render = { ( { open } ) => (
266+ < IconButton
267+ className = "components-toolbar__control"
268+ label = { __ ( 'Edit media' ) }
269+ icon = "format-image"
270+ onClick = { open }
271+ />
272+ ) }
273+ />
274+ </ Toolbar >
275+ </ MediaUploadCheck >
233276 </ BlockControls >
234277 { ! attributes . editMode && this . getInspectorControls ( ) }
235278 { editMode ? (
0 commit comments