@wordpress/block-editor 14.2.1-next.1f6eadc42.0 → 14.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/background-image-control/index.js +566 -0
  3. package/build/components/background-image-control/index.js.map +1 -0
  4. package/build/components/block-card/index.js +5 -2
  5. package/build/components/block-card/index.js.map +1 -1
  6. package/build/components/block-list/use-block-props/use-zoom-out-mode-exit.js +4 -2
  7. package/build/components/block-list/use-block-props/use-zoom-out-mode-exit.js.map +1 -1
  8. package/build/components/global-styles/background-panel.js +20 -545
  9. package/build/components/global-styles/background-panel.js.map +1 -1
  10. package/build/components/global-styles/dimensions-panel.js +3 -0
  11. package/build/components/global-styles/dimensions-panel.js.map +1 -1
  12. package/build/components/iframe/index.js +1 -0
  13. package/build/components/iframe/index.js.map +1 -1
  14. package/build/components/image-editor/use-save-image.js +6 -0
  15. package/build/components/image-editor/use-save-image.js.map +1 -1
  16. package/build/components/image-editor/use-transform-image.js +1 -0
  17. package/build/components/image-editor/use-transform-image.js.map +1 -1
  18. package/build/components/inserter/block-patterns-explorer/pattern-explorer-sidebar.js +2 -4
  19. package/build/components/inserter/block-patterns-explorer/pattern-explorer-sidebar.js.map +1 -1
  20. package/build/components/inserter/block-patterns-tab/index.js +2 -4
  21. package/build/components/inserter/block-patterns-tab/index.js.map +1 -1
  22. package/build/components/inserter/media-tab/media-preview.js +4 -8
  23. package/build/components/inserter/media-tab/media-preview.js.map +1 -1
  24. package/build/components/inserter/media-tab/media-tab.js +2 -4
  25. package/build/components/inserter/media-tab/media-tab.js.map +1 -1
  26. package/build/components/inserter/quick-inserter.js +2 -4
  27. package/build/components/inserter/quick-inserter.js.map +1 -1
  28. package/build/components/inserter-listbox/item.js +2 -4
  29. package/build/components/inserter-listbox/item.js.map +1 -1
  30. package/build/components/link-control/index.js +14 -14
  31. package/build/components/link-control/index.js.map +1 -1
  32. package/build/components/link-control/search-input.js +4 -2
  33. package/build/components/link-control/search-input.js.map +1 -1
  34. package/build/components/rich-text/index.js +10 -4
  35. package/build/components/rich-text/index.js.map +1 -1
  36. package/build/components/spacing-sizes-control/utils.js +16 -4
  37. package/build/components/spacing-sizes-control/utils.js.map +1 -1
  38. package/build/components/url-input/index.js +7 -6
  39. package/build/components/url-input/index.js.map +1 -1
  40. package/build/hooks/block-bindings.js +64 -53
  41. package/build/hooks/block-bindings.js.map +1 -1
  42. package/build/hooks/block-hooks.js +1 -8
  43. package/build/hooks/block-hooks.js.map +1 -1
  44. package/build/store/private-selectors.js +10 -0
  45. package/build/store/private-selectors.js.map +1 -1
  46. package/build-module/components/background-image-control/index.js +556 -0
  47. package/build-module/components/background-image-control/index.js.map +1 -0
  48. package/build-module/components/block-card/index.js +6 -3
  49. package/build-module/components/block-card/index.js.map +1 -1
  50. package/build-module/components/block-list/use-block-props/use-zoom-out-mode-exit.js +4 -2
  51. package/build-module/components/block-list/use-block-props/use-zoom-out-mode-exit.js.map +1 -1
  52. package/build-module/components/global-styles/background-panel.js +22 -546
  53. package/build-module/components/global-styles/background-panel.js.map +1 -1
  54. package/build-module/components/global-styles/dimensions-panel.js +3 -0
  55. package/build-module/components/global-styles/dimensions-panel.js.map +1 -1
  56. package/build-module/components/iframe/index.js +1 -0
  57. package/build-module/components/iframe/index.js.map +1 -1
  58. package/build-module/components/image-editor/use-save-image.js +6 -0
  59. package/build-module/components/image-editor/use-save-image.js.map +1 -1
  60. package/build-module/components/image-editor/use-transform-image.js +1 -0
  61. package/build-module/components/image-editor/use-transform-image.js.map +1 -1
  62. package/build-module/components/inserter/block-patterns-explorer/pattern-explorer-sidebar.js +2 -4
  63. package/build-module/components/inserter/block-patterns-explorer/pattern-explorer-sidebar.js.map +1 -1
  64. package/build-module/components/inserter/block-patterns-tab/index.js +2 -4
  65. package/build-module/components/inserter/block-patterns-tab/index.js.map +1 -1
  66. package/build-module/components/inserter/media-tab/media-preview.js +4 -8
  67. package/build-module/components/inserter/media-tab/media-preview.js.map +1 -1
  68. package/build-module/components/inserter/media-tab/media-tab.js +2 -4
  69. package/build-module/components/inserter/media-tab/media-tab.js.map +1 -1
  70. package/build-module/components/inserter/quick-inserter.js +2 -4
  71. package/build-module/components/inserter/quick-inserter.js.map +1 -1
  72. package/build-module/components/inserter-listbox/item.js +2 -4
  73. package/build-module/components/inserter-listbox/item.js.map +1 -1
  74. package/build-module/components/link-control/index.js +15 -15
  75. package/build-module/components/link-control/index.js.map +1 -1
  76. package/build-module/components/link-control/search-input.js +4 -2
  77. package/build-module/components/link-control/search-input.js.map +1 -1
  78. package/build-module/components/rich-text/index.js +10 -4
  79. package/build-module/components/rich-text/index.js.map +1 -1
  80. package/build-module/components/spacing-sizes-control/utils.js +16 -4
  81. package/build-module/components/spacing-sizes-control/utils.js.map +1 -1
  82. package/build-module/components/url-input/index.js +8 -7
  83. package/build-module/components/url-input/index.js.map +1 -1
  84. package/build-module/hooks/block-bindings.js +64 -53
  85. package/build-module/hooks/block-bindings.js.map +1 -1
  86. package/build-module/hooks/block-hooks.js +3 -10
  87. package/build-module/hooks/block-hooks.js.map +1 -1
  88. package/build-module/store/private-selectors.js +10 -0
  89. package/build-module/store/private-selectors.js.map +1 -1
  90. package/build-style/style-rtl.css +152 -276
  91. package/build-style/style.css +152 -276
  92. package/package.json +32 -32
  93. package/src/components/background-image-control/index.js +741 -0
  94. package/src/components/background-image-control/style.scss +170 -0
  95. package/src/components/background-image-control/test/index.js +47 -0
  96. package/src/components/block-card/index.js +12 -3
  97. package/src/components/block-list/use-block-props/use-zoom-out-mode-exit.js +2 -5
  98. package/src/components/global-styles/background-panel.js +19 -730
  99. package/src/components/global-styles/dimensions-panel.js +3 -0
  100. package/src/components/global-styles/style.scss +0 -168
  101. package/src/components/global-styles/test/background-panel.js +1 -47
  102. package/src/components/image-editor/use-save-image.js +7 -0
  103. package/src/components/inserter/block-patterns-explorer/pattern-explorer-sidebar.js +1 -2
  104. package/src/components/inserter/block-patterns-tab/index.js +1 -2
  105. package/src/components/inserter/media-tab/media-preview.js +2 -4
  106. package/src/components/inserter/media-tab/media-tab.js +1 -2
  107. package/src/components/inserter/quick-inserter.js +1 -2
  108. package/src/components/inserter/style.scss +0 -1
  109. package/src/components/inserter-listbox/item.js +1 -5
  110. package/src/components/link-control/index.js +19 -14
  111. package/src/components/link-control/search-input.js +2 -0
  112. package/src/components/link-control/style.scss +0 -22
  113. package/src/components/list-view/style.scss +1 -1
  114. package/src/components/rich-text/index.js +20 -5
  115. package/src/components/spacing-sizes-control/test/utils.js +18 -25
  116. package/src/components/spacing-sizes-control/utils.js +22 -5
  117. package/src/components/url-input/index.js +5 -4
  118. package/src/components/url-input/style.scss +3 -26
  119. package/src/hooks/block-bindings.js +63 -49
  120. package/src/hooks/block-hooks.js +3 -14
  121. package/src/hooks/block-hooks.scss +0 -9
  122. package/src/store/private-selectors.js +9 -0
  123. package/src/style.scss +1 -0
  124. package/src/utils/test/transform-styles.js +1 -1
@@ -1,71 +1,22 @@
1
- /**
2
- * External dependencies
3
- */
4
- import clsx from 'clsx';
5
-
6
1
  /**
7
2
  * WordPress dependencies
8
3
  */
9
4
  import {
10
5
  __experimentalToolsPanel as ToolsPanel,
11
6
  __experimentalToolsPanelItem as ToolsPanelItem,
12
- ToggleControl,
13
- __experimentalToggleGroupControl as ToggleGroupControl,
14
- __experimentalToggleGroupControlOption as ToggleGroupControlOption,
15
- __experimentalUnitControl as UnitControl,
16
- __experimentalVStack as VStack,
17
- DropZone,
18
- FlexItem,
19
- FocalPointPicker,
20
- MenuItem,
21
- VisuallyHidden,
22
- __experimentalItemGroup as ItemGroup,
23
- __experimentalHStack as HStack,
24
- __experimentalTruncate as Truncate,
25
- Dropdown,
26
- Placeholder,
27
- Spinner,
28
- __experimentalDropdownContentWrapper as DropdownContentWrapper,
29
7
  } from '@wordpress/components';
30
- import { __, _x, sprintf } from '@wordpress/i18n';
31
- import { store as noticesStore } from '@wordpress/notices';
32
- import { getFilename } from '@wordpress/url';
33
- import {
34
- useCallback,
35
- Platform,
36
- useRef,
37
- useState,
38
- useEffect,
39
- useMemo,
40
- } from '@wordpress/element';
41
- import { useDispatch, useSelect } from '@wordpress/data';
42
- import { focus } from '@wordpress/dom';
43
- import { isBlobURL } from '@wordpress/blob';
44
-
8
+ import { useCallback, Platform } from '@wordpress/element';
45
9
  /**
46
10
  * Internal dependencies
47
11
  */
48
- import { useToolsPanelDropdownMenuProps, getResolvedValue } from './utils';
12
+ import BackgroundImageControl from '../background-image-control';
13
+ import { useToolsPanelDropdownMenuProps } from './utils';
49
14
  import { setImmutably } from '../../utils/object';
50
- import MediaReplaceFlow from '../media-replace-flow';
51
- import { store as blockEditorStore } from '../../store';
52
-
53
- import {
54
- globalStylesDataKey,
55
- globalStylesLinksDataKey,
56
- } from '../../store/private-keys';
15
+ import { __ } from '@wordpress/i18n';
57
16
 
58
- const IMAGE_BACKGROUND_TYPE = 'image';
59
17
  const DEFAULT_CONTROLS = {
60
18
  backgroundImage: true,
61
19
  };
62
- const BACKGROUND_POPOVER_PROPS = {
63
- placement: 'left-start',
64
- offset: 36,
65
- shift: true,
66
- className: 'block-editor-global-styles-background-panel__popover',
67
- };
68
- const noop = () => {};
69
20
 
70
21
  /**
71
22
  * Checks site settings to see if the background panel may be used.
@@ -110,567 +61,6 @@ export function hasBackgroundImageValue( style ) {
110
61
  );
111
62
  }
112
63
 
113
- /**
114
- * Get the help text for the background size control.
115
- *
116
- * @param {string} value backgroundSize value.
117
- * @return {string} Translated help text.
118
- */
119
- function backgroundSizeHelpText( value ) {
120
- if ( value === 'cover' || value === undefined ) {
121
- return __( 'Image covers the space evenly.' );
122
- }
123
- if ( value === 'contain' ) {
124
- return __( 'Image is contained without distortion.' );
125
- }
126
- return __( 'Image has a fixed width.' );
127
- }
128
-
129
- /**
130
- * Converts decimal x and y coords from FocalPointPicker to percentage-based values
131
- * to use as backgroundPosition value.
132
- *
133
- * @param {{x?:number, y?:number}} value FocalPointPicker coords.
134
- * @return {string} backgroundPosition value.
135
- */
136
- export const coordsToBackgroundPosition = ( value ) => {
137
- if ( ! value || ( isNaN( value.x ) && isNaN( value.y ) ) ) {
138
- return undefined;
139
- }
140
-
141
- const x = isNaN( value.x ) ? 0.5 : value.x;
142
- const y = isNaN( value.y ) ? 0.5 : value.y;
143
-
144
- return `${ x * 100 }% ${ y * 100 }%`;
145
- };
146
-
147
- /**
148
- * Converts backgroundPosition value to x and y coords for FocalPointPicker.
149
- *
150
- * @param {string} value backgroundPosition value.
151
- * @return {{x?:number, y?:number}} FocalPointPicker coords.
152
- */
153
- export const backgroundPositionToCoords = ( value ) => {
154
- if ( ! value ) {
155
- return { x: undefined, y: undefined };
156
- }
157
-
158
- let [ x, y ] = value.split( ' ' ).map( ( v ) => parseFloat( v ) / 100 );
159
- x = isNaN( x ) ? undefined : x;
160
- y = isNaN( y ) ? x : y;
161
-
162
- return { x, y };
163
- };
164
-
165
- function InspectorImagePreviewItem( {
166
- as = 'span',
167
- imgUrl,
168
- toggleProps = {},
169
- filename,
170
- label,
171
- className,
172
- onToggleCallback = noop,
173
- } ) {
174
- useEffect( () => {
175
- if ( typeof toggleProps?.isOpen !== 'undefined' ) {
176
- onToggleCallback( toggleProps?.isOpen );
177
- }
178
- }, [ toggleProps?.isOpen, onToggleCallback ] );
179
- return (
180
- <ItemGroup as={ as } className={ className } { ...toggleProps }>
181
- <HStack
182
- justify="flex-start"
183
- as="span"
184
- className="block-editor-global-styles-background-panel__inspector-preview-inner"
185
- >
186
- { imgUrl && (
187
- <span
188
- className="block-editor-global-styles-background-panel__inspector-image-indicator-wrapper"
189
- aria-hidden
190
- >
191
- <span
192
- className="block-editor-global-styles-background-panel__inspector-image-indicator"
193
- style={ {
194
- backgroundImage: `url(${ imgUrl })`,
195
- } }
196
- />
197
- </span>
198
- ) }
199
- <FlexItem as="span" style={ imgUrl ? {} : { flexGrow: 1 } }>
200
- <Truncate
201
- numberOfLines={ 1 }
202
- className="block-editor-global-styles-background-panel__inspector-media-replace-title"
203
- >
204
- { label }
205
- </Truncate>
206
- <VisuallyHidden as="span">
207
- { imgUrl
208
- ? sprintf(
209
- /* translators: %s: file name */
210
- __( 'Background image: %s' ),
211
- filename || label
212
- )
213
- : __( 'No background image selected' ) }
214
- </VisuallyHidden>
215
- </FlexItem>
216
- </HStack>
217
- </ItemGroup>
218
- );
219
- }
220
-
221
- function BackgroundControlsPanel( {
222
- label,
223
- filename,
224
- url: imgUrl,
225
- children,
226
- onToggle: onToggleCallback = noop,
227
- hasImageValue,
228
- } ) {
229
- if ( ! hasImageValue ) {
230
- return;
231
- }
232
-
233
- const imgLabel =
234
- label || getFilename( imgUrl ) || __( 'Add background image' );
235
-
236
- return (
237
- <Dropdown
238
- popoverProps={ BACKGROUND_POPOVER_PROPS }
239
- renderToggle={ ( { onToggle, isOpen } ) => {
240
- const toggleProps = {
241
- onClick: onToggle,
242
- className:
243
- 'block-editor-global-styles-background-panel__dropdown-toggle',
244
- 'aria-expanded': isOpen,
245
- 'aria-label': __(
246
- 'Background size, position and repeat options.'
247
- ),
248
- isOpen,
249
- };
250
- return (
251
- <InspectorImagePreviewItem
252
- imgUrl={ imgUrl }
253
- filename={ filename }
254
- label={ imgLabel }
255
- toggleProps={ toggleProps }
256
- as="button"
257
- onToggleCallback={ onToggleCallback }
258
- />
259
- );
260
- } }
261
- renderContent={ () => (
262
- <DropdownContentWrapper
263
- className="block-editor-global-styles-background-panel__dropdown-content-wrapper"
264
- paddingSize="medium"
265
- >
266
- { children }
267
- </DropdownContentWrapper>
268
- ) }
269
- />
270
- );
271
- }
272
-
273
- function LoadingSpinner() {
274
- return (
275
- <Placeholder className="block-editor-global-styles-background-panel__loading">
276
- <Spinner />
277
- </Placeholder>
278
- );
279
- }
280
-
281
- function BackgroundImageControls( {
282
- onChange,
283
- style,
284
- inheritedValue,
285
- onRemoveImage = noop,
286
- onResetImage = noop,
287
- displayInPanel,
288
- defaultValues,
289
- } ) {
290
- const [ isUploading, setIsUploading ] = useState( false );
291
- const { getSettings } = useSelect( blockEditorStore );
292
-
293
- const { id, title, url } = style?.background?.backgroundImage || {
294
- ...inheritedValue?.background?.backgroundImage,
295
- };
296
- const replaceContainerRef = useRef();
297
- const { createErrorNotice } = useDispatch( noticesStore );
298
- const onUploadError = ( message ) => {
299
- createErrorNotice( message, { type: 'snackbar' } );
300
- setIsUploading( false );
301
- };
302
-
303
- const resetBackgroundImage = () =>
304
- onChange(
305
- setImmutably(
306
- style,
307
- [ 'background', 'backgroundImage' ],
308
- undefined
309
- )
310
- );
311
-
312
- const onSelectMedia = ( media ) => {
313
- if ( ! media || ! media.url ) {
314
- resetBackgroundImage();
315
- setIsUploading( false );
316
- return;
317
- }
318
-
319
- if ( isBlobURL( media.url ) ) {
320
- setIsUploading( true );
321
- return;
322
- }
323
-
324
- // For media selections originated from a file upload.
325
- if (
326
- ( media.media_type &&
327
- media.media_type !== IMAGE_BACKGROUND_TYPE ) ||
328
- ( ! media.media_type &&
329
- media.type &&
330
- media.type !== IMAGE_BACKGROUND_TYPE )
331
- ) {
332
- onUploadError(
333
- __( 'Only images can be used as a background image.' )
334
- );
335
- return;
336
- }
337
-
338
- const sizeValue =
339
- style?.background?.backgroundSize || defaultValues?.backgroundSize;
340
- const positionValue = style?.background?.backgroundPosition;
341
- onChange(
342
- setImmutably( style, [ 'background' ], {
343
- ...style?.background,
344
- backgroundImage: {
345
- url: media.url,
346
- id: media.id,
347
- source: 'file',
348
- title: media.title || undefined,
349
- },
350
- backgroundPosition:
351
- /*
352
- * A background image uploaded and set in the editor receives a default background position of '50% 0',
353
- * when the background image size is the equivalent of "Tile".
354
- * This is to increase the chance that the image's focus point is visible.
355
- * This is in-editor only to assist with the user experience.
356
- */
357
- ! positionValue && ( 'auto' === sizeValue || ! sizeValue )
358
- ? '50% 0'
359
- : positionValue,
360
- backgroundSize: sizeValue,
361
- } )
362
- );
363
- setIsUploading( false );
364
- };
365
-
366
- // Drag and drop callback, restricting image to one.
367
- const onFilesDrop = ( filesList ) => {
368
- if ( filesList?.length > 1 ) {
369
- onUploadError(
370
- __( 'Only one image can be used as a background image.' )
371
- );
372
- return;
373
- }
374
- getSettings().mediaUpload( {
375
- allowedTypes: [ IMAGE_BACKGROUND_TYPE ],
376
- filesList,
377
- onFileChange( [ image ] ) {
378
- onSelectMedia( image );
379
- },
380
- onError: onUploadError,
381
- } );
382
- };
383
-
384
- const hasValue = hasBackgroundImageValue( style );
385
-
386
- const closeAndFocus = () => {
387
- const [ toggleButton ] = focus.tabbable.find(
388
- replaceContainerRef.current
389
- );
390
- // Focus the toggle button and close the dropdown menu.
391
- // This ensures similar behaviour as to selecting an image, where the dropdown is
392
- // closed and focus is redirected to the dropdown toggle button.
393
- toggleButton?.focus();
394
- toggleButton?.click();
395
- };
396
-
397
- const onRemove = () =>
398
- onChange(
399
- setImmutably( style, [ 'background' ], {
400
- backgroundImage: 'none',
401
- } )
402
- );
403
- const canRemove = ! hasValue && hasBackgroundImageValue( inheritedValue );
404
- const imgLabel =
405
- title || getFilename( url ) || __( 'Add background image' );
406
-
407
- return (
408
- <div
409
- ref={ replaceContainerRef }
410
- className="block-editor-global-styles-background-panel__image-tools-panel-item"
411
- >
412
- { isUploading && <LoadingSpinner /> }
413
- <MediaReplaceFlow
414
- mediaId={ id }
415
- mediaURL={ url }
416
- allowedTypes={ [ IMAGE_BACKGROUND_TYPE ] }
417
- accept="image/*"
418
- onSelect={ onSelectMedia }
419
- popoverProps={ {
420
- className: clsx( {
421
- 'block-editor-global-styles-background-panel__media-replace-popover':
422
- displayInPanel,
423
- } ),
424
- } }
425
- name={
426
- <InspectorImagePreviewItem
427
- className="block-editor-global-styles-background-panel__image-preview"
428
- imgUrl={ url }
429
- filename={ title }
430
- label={ imgLabel }
431
- />
432
- }
433
- variant="secondary"
434
- onError={ onUploadError }
435
- onReset={ () => {
436
- closeAndFocus();
437
- onResetImage();
438
- } }
439
- >
440
- { canRemove && (
441
- <MenuItem
442
- onClick={ () => {
443
- closeAndFocus();
444
- onRemove();
445
- onRemoveImage();
446
- } }
447
- >
448
- { __( 'Remove' ) }
449
- </MenuItem>
450
- ) }
451
- </MediaReplaceFlow>
452
- <DropZone
453
- onFilesDrop={ onFilesDrop }
454
- label={ __( 'Drop to upload' ) }
455
- />
456
- </div>
457
- );
458
- }
459
-
460
- function BackgroundSizeControls( {
461
- onChange,
462
- style,
463
- inheritedValue,
464
- defaultValues,
465
- } ) {
466
- const sizeValue =
467
- style?.background?.backgroundSize ||
468
- inheritedValue?.background?.backgroundSize;
469
- const repeatValue =
470
- style?.background?.backgroundRepeat ||
471
- inheritedValue?.background?.backgroundRepeat;
472
- const imageValue =
473
- style?.background?.backgroundImage?.url ||
474
- inheritedValue?.background?.backgroundImage?.url;
475
- const isUploadedImage = style?.background?.backgroundImage?.id;
476
- const positionValue =
477
- style?.background?.backgroundPosition ||
478
- inheritedValue?.background?.backgroundPosition;
479
- const attachmentValue =
480
- style?.background?.backgroundAttachment ||
481
- inheritedValue?.background?.backgroundAttachment;
482
-
483
- /*
484
- * Set default values for uploaded images.
485
- * The default values are passed by the consumer.
486
- * Block-level controls may have different defaults to root-level controls.
487
- * A falsy value is treated by default as `auto` (Tile).
488
- */
489
- let currentValueForToggle =
490
- ! sizeValue && isUploadedImage
491
- ? defaultValues?.backgroundSize
492
- : sizeValue || 'auto';
493
- /*
494
- * The incoming value could be a value + unit, e.g. '20px'.
495
- * In this case set the value to 'tile'.
496
- */
497
- currentValueForToggle = ! [ 'cover', 'contain', 'auto' ].includes(
498
- currentValueForToggle
499
- )
500
- ? 'auto'
501
- : currentValueForToggle;
502
- /*
503
- * If the current value is `cover` and the repeat value is `undefined`, then
504
- * the toggle should be unchecked as the default state. Otherwise, the toggle
505
- * should reflect the current repeat value.
506
- */
507
- const repeatCheckedValue = ! (
508
- repeatValue === 'no-repeat' ||
509
- ( currentValueForToggle === 'cover' && repeatValue === undefined )
510
- );
511
-
512
- const updateBackgroundSize = ( next ) => {
513
- // When switching to 'contain' toggle the repeat off.
514
- let nextRepeat = repeatValue;
515
- let nextPosition = positionValue;
516
-
517
- if ( next === 'contain' ) {
518
- nextRepeat = 'no-repeat';
519
- nextPosition = undefined;
520
- }
521
-
522
- if ( next === 'cover' ) {
523
- nextRepeat = undefined;
524
- nextPosition = undefined;
525
- }
526
-
527
- if (
528
- ( currentValueForToggle === 'cover' ||
529
- currentValueForToggle === 'contain' ) &&
530
- next === 'auto'
531
- ) {
532
- nextRepeat = undefined;
533
- /*
534
- * A background image uploaded and set in the editor (an image with a record id),
535
- * receives a default background position of '50% 0',
536
- * when the toggle switches to "Tile". This is to increase the chance that
537
- * the image's focus point is visible.
538
- * This is in-editor only to assist with the user experience.
539
- */
540
- if ( !! style?.background?.backgroundImage?.id ) {
541
- nextPosition = '50% 0';
542
- }
543
- }
544
-
545
- /*
546
- * Next will be null when the input is cleared,
547
- * in which case the value should be 'auto'.
548
- */
549
- if ( ! next && currentValueForToggle === 'auto' ) {
550
- next = 'auto';
551
- }
552
-
553
- onChange(
554
- setImmutably( style, [ 'background' ], {
555
- ...style?.background,
556
- backgroundPosition: nextPosition,
557
- backgroundRepeat: nextRepeat,
558
- backgroundSize: next,
559
- } )
560
- );
561
- };
562
-
563
- const updateBackgroundPosition = ( next ) => {
564
- onChange(
565
- setImmutably(
566
- style,
567
- [ 'background', 'backgroundPosition' ],
568
- coordsToBackgroundPosition( next )
569
- )
570
- );
571
- };
572
-
573
- const toggleIsRepeated = () =>
574
- onChange(
575
- setImmutably(
576
- style,
577
- [ 'background', 'backgroundRepeat' ],
578
- repeatCheckedValue === true ? 'no-repeat' : 'repeat'
579
- )
580
- );
581
-
582
- const toggleScrollWithPage = () =>
583
- onChange(
584
- setImmutably(
585
- style,
586
- [ 'background', 'backgroundAttachment' ],
587
- attachmentValue === 'fixed' ? 'scroll' : 'fixed'
588
- )
589
- );
590
-
591
- // Set a default background position for non-site-wide, uploaded images with a size of 'contain'.
592
- const backgroundPositionValue =
593
- ! positionValue && isUploadedImage && 'contain' === sizeValue
594
- ? defaultValues?.backgroundPosition
595
- : positionValue;
596
-
597
- return (
598
- <VStack spacing={ 3 } className="single-column">
599
- <FocalPointPicker
600
- __nextHasNoMarginBottom
601
- label={ __( 'Focal point' ) }
602
- url={ imageValue }
603
- value={ backgroundPositionToCoords( backgroundPositionValue ) }
604
- onChange={ updateBackgroundPosition }
605
- />
606
- <ToggleControl
607
- __nextHasNoMarginBottom
608
- label={ __( 'Fixed background' ) }
609
- checked={ attachmentValue === 'fixed' }
610
- onChange={ toggleScrollWithPage }
611
- />
612
- <ToggleGroupControl
613
- __nextHasNoMarginBottom
614
- size="__unstable-large"
615
- label={ __( 'Size' ) }
616
- value={ currentValueForToggle }
617
- onChange={ updateBackgroundSize }
618
- isBlock
619
- help={ backgroundSizeHelpText(
620
- sizeValue || defaultValues?.backgroundSize
621
- ) }
622
- >
623
- <ToggleGroupControlOption
624
- key="cover"
625
- value="cover"
626
- label={ _x(
627
- 'Cover',
628
- 'Size option for background image control'
629
- ) }
630
- />
631
- <ToggleGroupControlOption
632
- key="contain"
633
- value="contain"
634
- label={ _x(
635
- 'Contain',
636
- 'Size option for background image control'
637
- ) }
638
- />
639
- <ToggleGroupControlOption
640
- key="tile"
641
- value="auto"
642
- label={ _x(
643
- 'Tile',
644
- 'Size option for background image control'
645
- ) }
646
- />
647
- </ToggleGroupControl>
648
- <HStack justify="flex-start" spacing={ 2 } as="span">
649
- <UnitControl
650
- aria-label={ __( 'Background image width' ) }
651
- onChange={ updateBackgroundSize }
652
- value={ sizeValue }
653
- size="__unstable-large"
654
- __unstableInputWidth="100px"
655
- min={ 0 }
656
- placeholder={ __( 'Auto' ) }
657
- disabled={
658
- currentValueForToggle !== 'auto' ||
659
- currentValueForToggle === undefined
660
- }
661
- />
662
- <ToggleControl
663
- __nextHasNoMarginBottom
664
- label={ __( 'Repeat' ) }
665
- checked={ repeatCheckedValue }
666
- onChange={ toggleIsRepeated }
667
- disabled={ currentValueForToggle === 'cover' }
668
- />
669
- </HStack>
670
- </VStack>
671
- );
672
- }
673
-
674
64
  function BackgroundToolsPanel( {
675
65
  resetAllFilter,
676
66
  onChange,
@@ -697,54 +87,20 @@ function BackgroundToolsPanel( {
697
87
  );
698
88
  }
699
89
 
700
- export default function BackgroundPanel( {
90
+ export default function BackgroundImagePanel( {
701
91
  as: Wrapper = BackgroundToolsPanel,
702
92
  value,
703
93
  onChange,
704
- inheritedValue = value,
94
+ inheritedValue,
705
95
  settings,
706
96
  panelId,
707
97
  defaultControls = DEFAULT_CONTROLS,
708
98
  defaultValues = {},
709
99
  headerLabel = __( 'Background image' ),
710
100
  } ) {
711
- /*
712
- * Resolve any inherited "ref" pointers.
713
- * Should the block editor need resolved, inherited values
714
- * across all controls, this could be abstracted into a hook,
715
- * e.g., useResolveGlobalStyle
716
- */
717
- const { globalStyles, _links } = useSelect( ( select ) => {
718
- const { getSettings } = select( blockEditorStore );
719
- const _settings = getSettings();
720
- return {
721
- globalStyles: _settings[ globalStylesDataKey ],
722
- _links: _settings[ globalStylesLinksDataKey ],
723
- };
724
- }, [] );
725
- const resolvedInheritedValue = useMemo( () => {
726
- const resolvedValues = {
727
- background: {},
728
- };
729
-
730
- if ( ! inheritedValue?.background ) {
731
- return inheritedValue;
732
- }
733
-
734
- Object.entries( inheritedValue?.background ).forEach(
735
- ( [ key, backgroundValue ] ) => {
736
- resolvedValues.background[ key ] = getResolvedValue(
737
- backgroundValue,
738
- {
739
- styles: globalStyles,
740
- _links,
741
- }
742
- );
743
- }
744
- );
745
- return resolvedValues;
746
- }, [ globalStyles, _links, inheritedValue ] );
747
-
101
+ const showBackgroundImageControl = useHasBackgroundPanel( settings );
102
+ const resetBackground = () =>
103
+ onChange( setImmutably( value, [ 'background' ], {} ) );
748
104
  const resetAllFilter = useCallback( ( previousValue ) => {
749
105
  return {
750
106
  ...previousValue,
@@ -752,29 +108,6 @@ export default function BackgroundPanel( {
752
108
  };
753
109
  }, [] );
754
110
 
755
- const resetBackground = () =>
756
- onChange( setImmutably( value, [ 'background' ], {} ) );
757
-
758
- const { title, url } = value?.background?.backgroundImage || {
759
- ...resolvedInheritedValue?.background?.backgroundImage,
760
- };
761
- const hasImageValue =
762
- hasBackgroundImageValue( value ) ||
763
- hasBackgroundImageValue( resolvedInheritedValue );
764
-
765
- const imageValue =
766
- value?.background?.backgroundImage ||
767
- inheritedValue?.background?.backgroundImage;
768
-
769
- const shouldShowBackgroundImageControls =
770
- hasImageValue &&
771
- 'none' !== imageValue &&
772
- ( settings?.background?.backgroundSize ||
773
- settings?.background?.backgroundPosition ||
774
- settings?.background?.backgroundRepeat );
775
-
776
- const [ isDropDownOpen, setIsDropDownOpen ] = useState( false );
777
-
778
111
  return (
779
112
  <Wrapper
780
113
  resetAllFilter={ resetAllFilter }
@@ -783,14 +116,7 @@ export default function BackgroundPanel( {
783
116
  panelId={ panelId }
784
117
  headerLabel={ headerLabel }
785
118
  >
786
- <div
787
- className={ clsx(
788
- 'block-editor-global-styles-background-panel__inspector-media-replace-container',
789
- {
790
- 'is-open': isDropDownOpen,
791
- }
792
- ) }
793
- >
119
+ { showBackgroundImageControl && (
794
120
  <ToolsPanelItem
795
121
  hasValue={ () => !! value?.background }
796
122
  label={ __( 'Image' ) }
@@ -798,53 +124,16 @@ export default function BackgroundPanel( {
798
124
  isShownByDefault={ defaultControls.backgroundImage }
799
125
  panelId={ panelId }
800
126
  >
801
- { shouldShowBackgroundImageControls ? (
802
- <BackgroundControlsPanel
803
- label={ title }
804
- filename={ title }
805
- url={ url }
806
- onToggle={ setIsDropDownOpen }
807
- hasImageValue={ hasImageValue }
808
- >
809
- <VStack spacing={ 3 } className="single-column">
810
- <BackgroundImageControls
811
- onChange={ onChange }
812
- style={ value }
813
- inheritedValue={ resolvedInheritedValue }
814
- displayInPanel
815
- onResetImage={ () => {
816
- setIsDropDownOpen( false );
817
- resetBackground();
818
- } }
819
- onRemoveImage={ () =>
820
- setIsDropDownOpen( false )
821
- }
822
- defaultValues={ defaultValues }
823
- />
824
- <BackgroundSizeControls
825
- onChange={ onChange }
826
- panelId={ panelId }
827
- style={ value }
828
- defaultValues={ defaultValues }
829
- inheritedValue={ resolvedInheritedValue }
830
- />
831
- </VStack>
832
- </BackgroundControlsPanel>
833
- ) : (
834
- <BackgroundImageControls
835
- onChange={ onChange }
836
- style={ value }
837
- inheritedValue={ resolvedInheritedValue }
838
- defaultValues={ defaultValues }
839
- onResetImage={ () => {
840
- setIsDropDownOpen( false );
841
- resetBackground();
842
- } }
843
- onRemoveImage={ () => setIsDropDownOpen( false ) }
844
- />
845
- ) }
127
+ <BackgroundImageControl
128
+ value={ value }
129
+ onChange={ onChange }
130
+ settings={ settings }
131
+ inheritedValue={ inheritedValue }
132
+ defaultControls={ defaultControls }
133
+ defaultValues={ defaultValues }
134
+ />
846
135
  </ToolsPanelItem>
847
- </div>
136
+ ) }
848
137
  </Wrapper>
849
138
  );
850
139
  }