@@ -32,10 +32,11 @@ import { getAttributeName } from '~stackable/util'
3232/**
3333 * WordPress dependencies
3434 */
35- import { useSelect } from '@wordpress/data'
35+ import { useSelect , select } from '@wordpress/data'
3636import { _x , __ } from '@wordpress/i18n'
3737import { applyFilters } from '@wordpress/hooks'
3838import { useMemo } from '@wordpress/element'
39+ import { useBlockEditContext } from '@wordpress/block-editor'
3940
4041// Note: image drop shadows do not accept negative spread.
4142const IMAGE_SHADOWS = [
@@ -60,6 +61,7 @@ const Controls = props => {
6061 imageHeightUnit : attributes . imageHeightUnit ,
6162 imageWidth : attributes . imageWidth ,
6263 imageHeight : attributes . imageHeight ,
64+ imageWidthAttribute : attributes . imageWidthAttribute ,
6365 imageHeightTablet : attributes [ getAttributeName ( 'imageHeight' , 'tablet' ) ] ,
6466 imageHeightMobile : attributes [ getAttributeName ( 'imageHeight' , 'mobile' ) ] ,
6567 imageHasLightbox : attributes . imageHasLightbox ,
@@ -78,6 +80,24 @@ const Controls = props => {
7880 const setAttributes = useBlockSetAttributesContext ( )
7981 const deviceType = useDeviceType ( )
8082
83+ // Get the width of the image block, this is needed for resizing the image
84+ // when replacing, and for resetting the width.
85+ const { getEditorDom } = useSelect ( 'stackable/editor-dom' )
86+ const { clientId } = useBlockEditContext ( )
87+ const editorDom = getEditorDom ?. ( ) || undefined
88+ const isImageBlock = useMemo ( ( ) => {
89+ return select ( 'core/block-editor' ) . getBlockName ( clientId ) === 'stackable/image'
90+ } , [ clientId ] )
91+ const imageBlockWidth = useMemo ( ( ) => {
92+ if ( editorDom ) {
93+ if ( isImageBlock ) {
94+ const blockEl = editorDom . querySelector ( `[data-block="${ clientId } "]` )
95+ return blockEl ?. clientWidth || undefined
96+ }
97+ }
98+ return undefined
99+ } , [ editorDom , isImageBlock , clientId ] )
100+
81101 // Get the image size urls.
82102 const { imageData } = useSelect ( select => {
83103 const image = select ( 'core' ) . getMedia ( attributes . imageId )
@@ -117,6 +137,8 @@ const Controls = props => {
117137 imageUrl : '' ,
118138 imageWidthAttribute : '' ,
119139 imageHeightAttribute : '' ,
140+ imageWidthUnit : '' ,
141+ imageHeightUnit : '' ,
120142 } ) }
121143 onChange = { image => {
122144 // Get the URL of the currently selected image size.
@@ -131,14 +153,34 @@ const Controls = props => {
131153 height = image . sizes ?. [ currentSelectedSize ] ?. height || height || ''
132154 width = image . sizes ?. [ currentSelectedSize ] ?. width || width || ''
133155 }
134- setAttributes ( {
156+
157+ const newAttributes = {
135158 imageId : image . id ,
136159 imageUrl : url ,
137160 imageWidthAttribute : width ,
138161 imageHeightAttribute : height ,
139162 imageExternalUrl : '' ,
140163 ...( attributes . imageAlt ? { } : { imageAlt : image . alt || '' } ) , // Only set the alt if it's empty.
141- } )
164+ }
165+
166+ // If the image being selected is smaller than the
167+ // current width of the image block, don't use 100%
168+ // because the image will look blurry, instead use the
169+ // actual width.
170+ if ( isImageBlock && imageBlockWidth && ! props . hasManuallyChangedDimensions ) {
171+ // When the image gets reset, we need to also reset
172+ // the width unit to '%' so that when we add another
173+ // image, the image would not be small
174+ newAttributes . imageWidth = ''
175+ newAttributes . imageWidthUnit = '%'
176+ // We need the width of the image block to compare
177+ if ( width < imageBlockWidth ) {
178+ newAttributes . imageWidth = width
179+ newAttributes . imageWidthUnit = 'px'
180+ }
181+ }
182+
183+ setAttributes ( newAttributes )
142184 } }
143185 />
144186 ) }
@@ -200,8 +242,90 @@ const Controls = props => {
200242 step = { props . widthStep }
201243 initialPosition = { 100 }
202244 allowReset = { true }
203- placeholder = "250" // TODO: This should be referenced somewher instead of just a static number
245+ // placeholder="250" // TODO: This should be referenced somewher instead of just a static number
246+ placeholder = "auto"
247+ // Add a default value here so that the reset button will not appear.
248+ default = { ( ( ) => {
249+ // We follow the logic in the override reset.
250+ if ( isImageBlock && deviceType === 'Desktop' ) {
251+ if ( attributes . imageWidthUnit === 'px' ) {
252+ if ( imageBlockWidth && attributes . imageWidthAttribute < imageBlockWidth ) {
253+ return attributes . imageWidthAttribute
254+ }
255+ }
256+ }
257+ return ''
258+ } ) ( ) }
259+ onChangeUnit = { ( unit , attributeName , oldUnit ) => {
260+ // When the unit is changed, we need to adjust the width
261+ // so that the image does not get distorted.
262+ if ( isImageBlock && deviceType === 'Desktop' ) {
263+ // Switching from % to px
264+ if ( oldUnit === '%' && unit === 'px' ) {
265+ // If image is too small, use the original image width
266+ if ( imageBlockWidth && attributes . imageWidthAttribute < imageBlockWidth ) {
267+ return setAttributes ( {
268+ imageWidth : attributes . imageWidthAttribute ,
269+ [ attributeName ] : unit ,
270+ } )
271+ }
272+ // If the width is larger than the block width, reset to 100% / width of block
273+ if ( attributes . imageWidth === '' ) {
274+ return setAttributes ( {
275+ imageWidth : imageBlockWidth ,
276+ [ attributeName ] : unit ,
277+ } )
278+ }
279+ // Switching from px to %
280+ } else if ( oldUnit === 'px' && unit === '%' ) {
281+ // If the image is larger than the block width, reset to 100%
282+ if ( imageBlockWidth && attributes . imageWidthAttribute > imageBlockWidth ) {
283+ return setAttributes ( {
284+ imageWidth : '' ,
285+ [ attributeName ] : unit ,
286+ } )
287+ }
288+ // If image goes past 100$, reset to 100%
289+ if ( attributes . imageWidth > 100 ) {
290+ return setAttributes ( {
291+ imageWidth : '' ,
292+ [ attributeName ] : unit ,
293+ } )
294+ }
295+ }
296+ }
297+ // Normal saving behavior.
298+ setAttributes ( { [ attributeName ] : unit } )
299+ } }
204300 responsive = "all"
301+ onOverrideReset = { ( ) => {
302+ // When resetting and in desktop, adjust the width so that we get the right "reset" value. Logic:
303+ // - If the width is in px and the width attribute is set, use the original image with
304+ // ...unless the image width is larger than the block width, then reset to 100%
305+ // - If the width is in %, and the image is smaller than the block, reset to the 'px' width
306+ // ...or just reset to 100%
307+ if ( isImageBlock && deviceType === 'Desktop' ) {
308+ let newWidthAttribute = ''
309+ if ( attributes . imageWidthUnit === 'px' ) {
310+ if ( attributes . imageWidthAttribute ) {
311+ newWidthAttribute = attributes . imageWidthAttribute
312+ }
313+ if ( imageBlockWidth && attributes . imageWidthAttribute > imageBlockWidth ) {
314+ newWidthAttribute = ''
315+ // We need to do a 'set attribute' here.
316+ setAttributes ( { imageWidthUnit : '%' } )
317+ }
318+ } else if ( attributes . imageWidthUnit === '%' ) {
319+ if ( imageBlockWidth && attributes . imageWidthAttribute < imageBlockWidth ) {
320+ newWidthAttribute = attributes . imageWidthAttribute
321+ // We need to do a 'set attribute' here.
322+ setAttributes ( { imageWidthUnit : 'px' } )
323+ }
324+ }
325+ // Returning a value here overrides the reset into the new value
326+ return newWidthAttribute
327+ }
328+ } }
205329 helpTooltip = { {
206330 //TODO: Add a working video
207331 title : __ ( 'Image width' , i18n ) ,
0 commit comments