From 79e56b64a13646c38542518ef97297fdb401b688 Mon Sep 17 00:00:00 2001 From: James Koster Date: Wed, 2 Aug 2023 09:40:26 +0100 Subject: [PATCH 01/22] Update document title buttons radius (#53221) --- .../components/header-edit-mode/document-actions/style.scss | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss b/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss index d3116b4576490..25b2c7b6eaabb 100644 --- a/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss +++ b/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss @@ -1,7 +1,6 @@ .edit-site-document-actions { display: flex; align-items: center; - gap: $grid-unit; height: $button-size; justify-content: space-between; // Flex items will, by default, refuse to shrink below a minimum @@ -10,7 +9,7 @@ // See https://dev.w3.org/csswg/css-flexbox/#min-size-auto min-width: 0; background: $gray-100; - border-radius: 4px; + border-radius: $grid-unit-05; width: min(100%, 450px); // Make the document title shorter in top-toolbar mode, as it has to be covered. @@ -19,6 +18,8 @@ } .components-button { + border-radius: $grid-unit-05; + &:hover { color: var(--wp-block-synced-color); background: $gray-200; From 0524c65feeb3a8225753f6c38916aa5476b63608 Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Thu, 3 Aug 2023 11:43:51 +0900 Subject: [PATCH 02/22] Fix: Sync status overlaps for some languages in Patterns post type page (#53243) --- packages/editor/src/components/post-sync-status/style.scss | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/editor/src/components/post-sync-status/style.scss b/packages/editor/src/components/post-sync-status/style.scss index 7f81a327443ee..90a75c86bf466 100644 --- a/packages/editor/src/components/post-sync-status/style.scss +++ b/packages/editor/src/components/post-sync-status/style.scss @@ -2,15 +2,18 @@ width: 100%; position: relative; justify-content: flex-start; + align-items: flex-start; > span { display: block; width: 45%; flex-shrink: 0; + padding: $grid-unit-15 * 0.5 0; + word-break: break-word; } > div { // Match padding on tertiary buttons for alignment. - padding-left: $grid-unit-15; + padding: $grid-unit-15 * 0.5 0 $grid-unit-15 * 0.5 $grid-unit-15; } } From 3a9178a0f07063b20d7a1e4344c6e29e8b5fd0ae Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Thu, 3 Aug 2023 10:06:59 -0600 Subject: [PATCH 03/22] Image block: Fix stretched images constrained by max-width (#53274) * Fix dragging to resize from stretching image in the frontend * Add image block v7 deprecation * Update deprecation comment * Prevent image losing its aspect ratio at smaller window dimensions * Revert "Prevent image losing its aspect ratio at smaller window dimensions" This reverts commit 8ac9f8c4469d5e6cdfd5aa06bc0c89a37771f7c5. --------- Co-authored-by: scruffian --- packages/block-library/src/image/block.json | 4 +- .../block-library/src/image/deprecated.js | 209 +++++++++++++++++- packages/block-library/src/image/image.js | 52 +++-- packages/block-library/src/image/save.js | 2 - ...ed-v2-add-is-resized-class.serialized.html | 2 +- ...cated-v3-add-align-wrapper.serialized.html | 2 +- ...ed-v4-remove-align-wrapper.serialized.html | 2 +- ...-v6-add-style-width-height.serialized.html | 2 +- ...ted-v7-string-width-height-attributes.html | 3 + ...ted-v7-string-width-height-attributes.json | 15 ++ ...string-width-height-attributes.parsed.json | 15 ++ ...ng-width-height-attributes.serialized.html | 3 + 12 files changed, 278 insertions(+), 33 deletions(-) create mode 100644 test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.html create mode 100644 test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.json create mode 100644 test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.parsed.json create mode 100644 test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.serialized.html diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index 7c8b2c2715c99..fad94a62e5a75 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -64,10 +64,10 @@ "__experimentalRole": "content" }, "width": { - "type": "number" + "type": "string" }, "height": { - "type": "number" + "type": "string" }, "aspectRatio": { "type": "string" diff --git a/packages/block-library/src/image/deprecated.js b/packages/block-library/src/image/deprecated.js index edbabd7fb2d83..d159009b17373 100644 --- a/packages/block-library/src/image/deprecated.js +++ b/packages/block-library/src/image/deprecated.js @@ -740,4 +740,211 @@ const v6 = { }, }; -export default [ v6, v5, v4, v3, v2, v1 ]; +/** + * Deprecation for converting to string width and height block attributes and + * removing the width and height img element attributes which are not needed + * as they get added by the TODO hook. + * + * @see https://github.com/WordPress/gutenberg/pull/53274 + */ +const v7 = { + attributes: { + align: { + type: 'string', + }, + url: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'src', + __experimentalRole: 'content', + }, + alt: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'alt', + default: '', + __experimentalRole: 'content', + }, + caption: { + type: 'string', + source: 'html', + selector: 'figcaption', + __experimentalRole: 'content', + }, + title: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'title', + __experimentalRole: 'content', + }, + href: { + type: 'string', + source: 'attribute', + selector: 'figure > a', + attribute: 'href', + __experimentalRole: 'content', + }, + rel: { + type: 'string', + source: 'attribute', + selector: 'figure > a', + attribute: 'rel', + }, + linkClass: { + type: 'string', + source: 'attribute', + selector: 'figure > a', + attribute: 'class', + }, + id: { + type: 'number', + __experimentalRole: 'content', + }, + width: { + type: 'number', + }, + height: { + type: 'number', + }, + aspectRatio: { + type: 'string', + }, + scale: { + type: 'string', + }, + sizeSlug: { + type: 'string', + }, + linkDestination: { + type: 'string', + }, + linkTarget: { + type: 'string', + source: 'attribute', + selector: 'figure > a', + attribute: 'target', + }, + }, + supports: { + anchor: true, + behaviors: { + lightbox: true, + }, + color: { + text: false, + background: false, + }, + filter: { + duotone: true, + }, + __experimentalBorder: { + color: true, + radius: true, + width: true, + __experimentalSkipSerialization: true, + __experimentalDefaultControls: { + color: true, + radius: true, + width: true, + }, + }, + }, + migrate( { width, height, ...attributes } ) { + return { + ...attributes, + width: `${ width }px`, + height: `${ height }px`, + }; + }, + save( { attributes } ) { + const { + url, + alt, + caption, + align, + href, + rel, + linkClass, + width, + height, + aspectRatio, + scale, + id, + linkTarget, + sizeSlug, + title, + } = attributes; + + const newRel = ! rel ? undefined : rel; + const borderProps = getBorderClassesAndStyles( attributes ); + + const classes = classnames( { + [ `align${ align }` ]: align, + [ `size-${ sizeSlug }` ]: sizeSlug, + 'is-resized': width || height, + 'has-custom-border': + !! borderProps.className || + ( borderProps.style && + Object.keys( borderProps.style ).length > 0 ), + } ); + + const imageClasses = classnames( borderProps.className, { + [ `wp-image-${ id }` ]: !! id, + } ); + + const image = ( + { + ); + + const figure = ( + <> + { href ? ( + + { image } + + ) : ( + image + ) } + { ! RichText.isEmpty( caption ) && ( + + ) } + + ); + + return ( +
+ { figure } +
+ ); + }, +}; + +export default [ v7, v6, v5, v4, v3, v2, v1 ]; diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index 5fe5c93f4199b..a880c20ed59ab 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -114,6 +114,11 @@ export default function Image( { linkTarget, sizeSlug, } = attributes; + + // The only supported unit is px, so we can parseInt to strip the px here. + const numericWidth = width ? parseInt( width, 10 ) : undefined; + const numericHeight = height ? parseInt( height, 10 ) : undefined; + const imageRef = useRef(); const prevCaption = usePrevious( caption ); const [ showCaption, setShowCaption ] = useState( !! caption ); @@ -473,23 +478,14 @@ export default function Image( { ) } { // Rebuilding the object forces setting `undefined` // for values that are removed since setAttributes // doesn't do anything with keys that aren't set. setAttributes( { - width: - newValue.width && - parseInt( newValue.width, 10 ), - height: - newValue.height && - parseInt( newValue.height, 10 ), + width: newValue.width, + height: newValue.height, scale: newValue.scale, aspectRatio: newValue.aspectRatio, } ); @@ -587,8 +583,8 @@ export default function Image( { { img }; } else { + const numericRatio = aspectRatio && evalAspectRatio( aspectRatio ); + const customRatio = numericWidth / numericHeight; const ratio = - ( aspectRatio && evalAspectRatio( aspectRatio ) ) || - ( width && height && width / height ) || - naturalWidth / naturalHeight || - 1; - - const currentWidth = ! width && height ? height * ratio : width; - const currentHeight = ! height && width ? width / ratio : height; + numericRatio || customRatio || naturalWidth / naturalHeight || 1; + const currentWidth = + ! numericWidth && numericHeight + ? numericHeight * ratio + : numericWidth; + const currentHeight = + ! numericHeight && numericWidth + ? numericWidth / ratio + : numericHeight; const minWidth = naturalWidth < naturalHeight ? MIN_SIZE : MIN_SIZE * ratio; @@ -687,10 +687,14 @@ export default function Image( { onResizeStart={ onResizeStart } onResizeStop={ ( event, direction, elt ) => { onResizeStop(); + // Since the aspect ratio is locked when resizing, we can + // use the width of the resized element to calculate the + // height in CSS to prevent stretching when the max-width + // is reached. setAttributes( { - width: elt.offsetWidth, - height: elt.offsetHeight, - aspectRatio: undefined, + width: `${ elt.offsetWidth }px`, + height: 'auto', + aspectRatio: `${ ratio }`, } ); } } resizeRatio={ align === 'center' ? 2 : 1 } diff --git a/packages/block-library/src/image/save.js b/packages/block-library/src/image/save.js index 6fa8c6b2342f3..81565af09abab 100644 --- a/packages/block-library/src/image/save.js +++ b/packages/block-library/src/image/save.js @@ -61,8 +61,6 @@ export default function save( { attributes } ) { width, height, } } - width={ width } - height={ height } title={ title } /> ); diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v2-add-is-resized-class.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v2-add-is-resized-class.serialized.html index 7ce56e11fa75e..9a66da6c01898 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v2-add-is-resized-class.serialized.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v2-add-is-resized-class.serialized.html @@ -1,3 +1,3 @@ -
+
diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v3-add-align-wrapper.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v3-add-align-wrapper.serialized.html index 7ce56e11fa75e..9a66da6c01898 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v3-add-align-wrapper.serialized.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v3-add-align-wrapper.serialized.html @@ -1,3 +1,3 @@ -
+
diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v4-remove-align-wrapper.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v4-remove-align-wrapper.serialized.html index cfdc52e3cbb6e..99da2155bce88 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v4-remove-align-wrapper.serialized.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v4-remove-align-wrapper.serialized.html @@ -1,3 +1,3 @@ -
+
diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v6-add-style-width-height.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v6-add-style-width-height.serialized.html index ad70fe65f3582..807ba3abc9f9c 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v6-add-style-width-height.serialized.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v6-add-style-width-height.serialized.html @@ -1,3 +1,3 @@ -
+
diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.html b/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.html new file mode 100644 index 0000000000000..7210aee3564b5 --- /dev/null +++ b/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.html @@ -0,0 +1,3 @@ + +
+ diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.json b/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.json new file mode 100644 index 0000000000000..b49c515f8e5ab --- /dev/null +++ b/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.json @@ -0,0 +1,15 @@ +[ + { + "name": "core/image", + "isValid": true, + "attributes": { + "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", + "alt": "", + "caption": "", + "sizeSlug": "large", + "width": "164px", + "height": "164px" + }, + "innerBlocks": [] + } +] diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.parsed.json b/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.parsed.json new file mode 100644 index 0000000000000..fbd8627807b3d --- /dev/null +++ b/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.parsed.json @@ -0,0 +1,15 @@ +[ + { + "blockName": "core/image", + "attrs": { + "width": 164, + "height": 164, + "sizeSlug": "large" + }, + "innerBlocks": [], + "innerHTML": "\n
\"\"
\n", + "innerContent": [ + "\n
\"\"
\n" + ] + } +] diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.serialized.html new file mode 100644 index 0000000000000..5392d261af89d --- /dev/null +++ b/test/integration/fixtures/blocks/core__image__deprecated-v7-string-width-height-attributes.serialized.html @@ -0,0 +1,3 @@ + +
+ From d564a13f58f1a3e6d94c63e7d5a63144cd768882 Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Sat, 5 Aug 2023 04:40:43 +0900 Subject: [PATCH 04/22] Image Block: Don't render `DimensionsTool` if it is not resizable (#53181) --- packages/block-library/src/image/image.js | 38 ++++++++++++----------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index a880c20ed59ab..fe8f8e7f6aeb1 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -477,24 +477,26 @@ export default function Image( { /> ) } - { - // Rebuilding the object forces setting `undefined` - // for values that are removed since setAttributes - // doesn't do anything with keys that aren't set. - setAttributes( { - width: newValue.width, - height: newValue.height, - scale: newValue.scale, - aspectRatio: newValue.aspectRatio, - } ); - } } - defaultScale="cover" - defaultAspectRatio="auto" - scaleOptions={ scaleOptions } - unitsOptions={ dimensionsUnitsOptions } - /> + { isResizable && ( + { + // Rebuilding the object forces setting `undefined` + // for values that are removed since setAttributes + // doesn't do anything with keys that aren't set. + setAttributes( { + width: newValue.width, + height: newValue.height, + scale: newValue.scale, + aspectRatio: newValue.aspectRatio, + } ); + } } + defaultScale="cover" + defaultAspectRatio="auto" + scaleOptions={ scaleOptions } + unitsOptions={ dimensionsUnitsOptions } + /> + ) } Date: Tue, 8 Aug 2023 17:58:39 +1000 Subject: [PATCH 05/22] Fix missing Replace button in content-locked Image blocks (#53410) * Revert "don't display BlockContextualToolbar at all in contentonly locking (#53110)" This reverts commit 5efce0ecec77fec764c30ce53f6368554ce9eb1a. * Alternative fix to hide BlockContextualToolbar when there are no controls --- .../block-controls/use-has-block-controls.js | 35 +++++++++++++++++++ .../block-tools/block-contextual-toolbar.js | 15 ++++---- .../src/components/block-tools/style.scss | 4 --- 3 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 packages/block-editor/src/components/block-controls/use-has-block-controls.js diff --git a/packages/block-editor/src/components/block-controls/use-has-block-controls.js b/packages/block-editor/src/components/block-controls/use-has-block-controls.js new file mode 100644 index 0000000000000..f7884cc1882ed --- /dev/null +++ b/packages/block-editor/src/components/block-controls/use-has-block-controls.js @@ -0,0 +1,35 @@ +/** + * WordPress dependencies + */ +import { __experimentalUseSlotFills as useSlotFills } from '@wordpress/components'; +import warning from '@wordpress/warning'; + +/** + * Internal dependencies + */ +import groups from './groups'; + +export function useHasAnyBlockControls() { + let hasAnyBlockControls = false; + for ( const group in groups ) { + // It is safe to violate the rules of hooks here as the `groups` object + // is static and will not change length between renders. Do not return + // early as that will cause the hook to be called a different number of + // times between renders. + // eslint-disable-next-line react-hooks/rules-of-hooks + if ( useHasBlockControls( group ) ) { + hasAnyBlockControls = true; + } + } + return hasAnyBlockControls; +} + +export function useHasBlockControls( group = 'default' ) { + const Slot = groups[ group ]?.Slot; + const fills = useSlotFills( Slot?.__unstableName ); + if ( ! Slot ) { + warning( `Unknown BlockControls group "${ group }" provided.` ); + return null; + } + return !! fills?.length; +} diff --git a/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js b/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js index 7dcd88d1cfd10..9667cb21d99b7 100644 --- a/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js +++ b/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js @@ -25,6 +25,7 @@ import NavigableToolbar from '../navigable-toolbar'; import BlockToolbar from '../block-toolbar'; import { store as blockEditorStore } from '../../store'; import { unlock } from '../../lock-unlock'; +import { useHasAnyBlockControls } from '../block-controls/use-has-block-controls'; function BlockContextualToolbar( { focusOnMount, isFixed, ...props } ) { // When the toolbar is fixed it can be collapsed @@ -34,10 +35,10 @@ function BlockContextualToolbar( { focusOnMount, isFixed, ...props } ) { const isLargeViewport = useViewportMatch( 'medium' ); const { blockType, + blockEditingMode, hasParents, showParentSelector, selectedBlockClientId, - isContentOnly, } = useSelect( ( select ) => { const { getBlockName, @@ -58,9 +59,8 @@ function BlockContextualToolbar( { focusOnMount, isFixed, ...props } ) { blockType: _selectedBlockClientId && getBlockType( getBlockName( _selectedBlockClientId ) ), + blockEditingMode: getBlockEditingMode( _selectedBlockClientId ), hasParents: parents.length, - isContentOnly: - getBlockEditingMode( _selectedBlockClientId ) === 'contentOnly', showParentSelector: parentBlockType && getBlockEditingMode( firstParentClientId ) === 'default' && @@ -78,10 +78,13 @@ function BlockContextualToolbar( { focusOnMount, isFixed, ...props } ) { setIsCollapsed( false ); }, [ selectedBlockClientId ] ); + const isToolbarEnabled = + ! blockType || + hasBlockSupport( blockType, '__experimentalToolbar', true ); + const hasAnyBlockControls = useHasAnyBlockControls(); if ( - isContentOnly || - ( blockType && - ! hasBlockSupport( blockType, '__experimentalToolbar', true ) ) + ! isToolbarEnabled || + ( blockEditingMode !== 'default' && ! hasAnyBlockControls ) ) { return null; } diff --git a/packages/block-editor/src/components/block-tools/style.scss b/packages/block-editor/src/components/block-tools/style.scss index 1f08727bbfb9b..828e1ebe9b348 100644 --- a/packages/block-editor/src/components/block-tools/style.scss +++ b/packages/block-editor/src/components/block-tools/style.scss @@ -121,10 +121,6 @@ } } - &:has(.block-editor-block-toolbar:empty) { - display: none; - } - // Add a scrim to the right of the collapsed button. &.is-collapsed::after { content: ""; From cc90b611e2e748cef6d2b8fb27e7a86db790fb9f Mon Sep 17 00:00:00 2001 From: Andrei Draganescu Date: Tue, 8 Aug 2023 11:48:25 +0300 Subject: [PATCH 06/22] fix the go to for non pages by showing it only for pages (#53408) --- .../leaf-more-menu.js | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menus/leaf-more-menu.js b/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menus/leaf-more-menu.js index 14d78405b3abe..6b093ad27e25b 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menus/leaf-more-menu.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menus/leaf-more-menu.js @@ -126,16 +126,17 @@ export default function LeafMoreMenu( props ) { > { __( 'Move down' ) } - { block.attributes?.id && ( - { - onGoToPage( block ); - onClose(); - } } - > - { goToLabel } - - ) } + { block.attributes?.type === 'page' && + block.attributes?.id && ( + { + onGoToPage( block ); + onClose(); + } } + > + { goToLabel } + + ) } Date: Wed, 9 Aug 2023 10:24:00 +0400 Subject: [PATCH 07/22] Site Editor: Fix document actions label helper method (#52974) * Site Editor: Fix document actions label helper method * Add missing useSelect dep * Fix e2e tests * Move the label map at the file level to avoid recreating the object on every render --- .../document-actions/index.js | 39 +++++++------------ test/e2e/specs/site-editor/title.spec.js | 4 +- 2 files changed, 15 insertions(+), 28 deletions(-) diff --git a/packages/edit-site/src/components/header-edit-mode/document-actions/index.js b/packages/edit-site/src/components/header-edit-mode/document-actions/index.js index b644b0fe2afd5..143135bda3ce4 100644 --- a/packages/edit-site/src/components/header-edit-mode/document-actions/index.js +++ b/packages/edit-site/src/components/header-edit-mode/document-actions/index.js @@ -6,7 +6,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { sprintf, __, isRTL } from '@wordpress/i18n'; +import { __, isRTL } from '@wordpress/i18n'; import { useSelect, useDispatch } from '@wordpress/data'; import { Button, @@ -33,8 +33,18 @@ import { store as coreStore } from '@wordpress/core-data'; import useEditedEntityRecord from '../../use-edited-entity-record'; import { store as editSiteStore } from '../../../store'; +const typeLabels = { + wp_block: __( 'Editing pattern:' ), + wp_navigation: __( 'Editing navigation menu:' ), + wp_template: __( 'Editing template:' ), + wp_template_part: __( 'Editing template part:' ), +}; + export default function DocumentActions() { - const isPage = useSelect( ( select ) => select( editSiteStore ).isPage() ); + const isPage = useSelect( + ( select ) => select( editSiteStore ).isPage(), + [] + ); return isPage ? : ; } @@ -118,8 +128,6 @@ function TemplateDocumentActions( { className, onBack } ) { ); } - const entityLabel = getEntityLabel( record.type ); - let typeIcon = icon; if ( record.type === 'wp_navigation' ) { typeIcon = navigationIcon; @@ -134,11 +142,7 @@ function TemplateDocumentActions( { className, onBack } ) { onBack={ onBack } > - { sprintf( - /* translators: %s: the entity being edited, like "template"*/ - __( 'Editing %s: ' ), - entityLabel - ) } + { typeLabels[ record.type ] ?? typeLabels.wp_template } { getTitle() } @@ -184,20 +188,3 @@ function BaseDocumentActions( { className, icon, children, onBack } ) { ); } - -function getEntityLabel( entityType ) { - let label = ''; - switch ( entityType ) { - case 'wp_navigation': - label = 'navigation menu'; - break; - case 'wp_template_part': - label = 'template part'; - break; - default: - label = 'template'; - break; - } - - return label; -} diff --git a/test/e2e/specs/site-editor/title.spec.js b/test/e2e/specs/site-editor/title.spec.js index 21cfc54482970..aa2942670c5a8 100644 --- a/test/e2e/specs/site-editor/title.spec.js +++ b/test/e2e/specs/site-editor/title.spec.js @@ -26,7 +26,7 @@ test.describe( 'Site editor title', () => { 'role=region[name="Editor top bar"i] >> role=heading[level=1]' ); - await expect( title ).toHaveText( 'Editing template: Index' ); + await expect( title ).toHaveText( 'Editing template:Index' ); } ); test( 'displays the selected template name in the title for the header template', async ( { @@ -43,6 +43,6 @@ test.describe( 'Site editor title', () => { 'role=region[name="Editor top bar"i] >> role=heading[level=1]' ); - await expect( title ).toHaveText( 'Editing template part: header' ); + await expect( title ).toHaveText( 'Editing template part:header' ); } ); } ); From 3f0c87a80f233a46b4b6504be0e4d0aeee6b1a07 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Wed, 9 Aug 2023 14:55:13 -0600 Subject: [PATCH 08/22] Image: Clear aspect ratio when wide aligned (#53439) --- packages/block-library/src/image/image.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index fe8f8e7f6aeb1..001369a4b3513 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -326,7 +326,12 @@ export default function Image( { function updateAlignment( nextAlign ) { const extraUpdatedAttributes = [ 'wide', 'full' ].includes( nextAlign ) - ? { width: undefined, height: undefined } + ? { + width: undefined, + height: undefined, + aspectRatio: undefined, + scale: undefined, + } : {}; setAttributes( { ...extraUpdatedAttributes, From 2c25cd2671ea57ebe3f34d5a6e8ddeab3584867c Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 10 Aug 2023 09:57:25 +0400 Subject: [PATCH 09/22] RichText: Remove 'Footnotes' when interactive formatting is disabled (#53474) Introduce a new 'interactive' setting for format types --- .../src/components/rich-text/use-format-types.js | 6 +++--- packages/block-library/src/footnotes/format.js | 1 + packages/rich-text/src/register-format-type.js | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/use-format-types.js b/packages/block-editor/src/components/rich-text/use-format-types.js index f798e41ede4df..9d26d61943249 100644 --- a/packages/block-editor/src/components/rich-text/use-format-types.js +++ b/packages/block-editor/src/components/rich-text/use-format-types.js @@ -66,21 +66,21 @@ export function useFormatTypes( { } ) { const allFormatTypes = useSelect( formatTypesSelector, [] ); const formatTypes = useMemo( () => { - return allFormatTypes.filter( ( { name, tagName } ) => { + return allFormatTypes.filter( ( { name, interactive, tagName } ) => { if ( allowedFormats && ! allowedFormats.includes( name ) ) { return false; } if ( withoutInteractiveFormatting && - interactiveContentTags.has( tagName ) + ( interactive || interactiveContentTags.has( tagName ) ) ) { return false; } return true; } ); - }, [ allFormatTypes, allowedFormats, interactiveContentTags ] ); + }, [ allFormatTypes, allowedFormats, withoutInteractiveFormatting ] ); const keyedSelected = useSelect( ( select ) => formatTypes.reduce( ( accumulator, type ) => { diff --git a/packages/block-library/src/footnotes/format.js b/packages/block-library/src/footnotes/format.js index c7730c53316b7..2145845652b66 100644 --- a/packages/block-library/src/footnotes/format.js +++ b/packages/block-library/src/footnotes/format.js @@ -37,6 +37,7 @@ export const format = { attributes: { 'data-fn': 'data-fn', }, + interactive: true, contentEditable: false, [ usesContextKey ]: [ 'postType' ], edit: function Edit( { diff --git a/packages/rich-text/src/register-format-type.js b/packages/rich-text/src/register-format-type.js index 8ea19a97f595f..a3ca5b64903f9 100644 --- a/packages/rich-text/src/register-format-type.js +++ b/packages/rich-text/src/register-format-type.js @@ -13,6 +13,7 @@ import { store as richTextStore } from './store'; * unique across all registered formats. * @property {string} tagName The HTML tag this format will wrap the * selection with. + * @property {boolean} interactive Whether format makes content interactive or not. * @property {string} [className] A class to match the format. * @property {string} title Name of the format. * @property {Function} edit Should return a component for the user to From 6e1ddbf1924ffcd7a0e50177bc90b672afbc6533 Mon Sep 17 00:00:00 2001 From: Dean Sas Date: Fri, 11 Aug 2023 01:49:17 +0100 Subject: [PATCH 10/22] Preserve block style variations when securing theme json (#53466) * Preserve block style variations when securing theme json Valid and safe block style variations were being removed by `WP_Theme_JSON_Gutenberg::remove_insecure_properties` when securing the theme.json. When this was a problem varied depending upon site configuration, but out-of-the-box it was a problem for administrators on multi-site installs. This change adds explicit processing of variations in `remove_insecure_properties` so that they won't get removed. * Add another variation sanitisation test This test checks that when removing insecure properties an unknown/unsupported property is removed from the variation. --- lib/class-wp-theme-json-gutenberg.php | 14 +++++ phpunit/class-wp-theme-json-test.php | 79 +++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 7313afeba91bc..70816ff6d5917 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -2906,6 +2906,20 @@ public static function remove_insecure_properties( $theme_json ) { if ( ! empty( $output ) ) { _wp_array_set( $sanitized, $metadata['path'], $output ); } + + if ( isset( $metadata['variations'] ) ) { + foreach ( $metadata['variations'] as $variation ) { + $variation_input = _wp_array_get( $theme_json, $variation['path'], array() ); + if ( empty( $variation_input ) ) { + continue; + } + + $variation_output = static::remove_insecure_styles( $variation_input ); + if ( ! empty( $variation_output ) ) { + _wp_array_set( $sanitized, $variation['path'], $variation_output ); + } + } + } } $setting_nodes = static::get_setting_nodes( $theme_json ); diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index bd1d578a1297b..2acab0fd33356 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -1702,6 +1702,85 @@ public function data_get_styles_for_block_with_style_variations() { ); } + public function test_block_style_variations() { + wp_set_current_user( static::$administrator_id ); + + $expected = array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'styles' => array( + 'blocks' => array( + 'core/button' => array( + 'color' => array( + 'background' => 'blue', + ), + 'variations' => array( + 'outline' => array( + 'color' => array( + 'background' => 'purple', + ), + ), + ), + ), + ), + ), + ); + + $actual = WP_Theme_JSON_Gutenberg::remove_insecure_properties( $expected ); + + $this->assertSameSetsWithIndex( $expected, $actual ); + } + + public function test_block_style_variations_with_invalid_properties() { + wp_set_current_user( static::$administrator_id ); + + $partially_invalid_variation = array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'styles' => array( + 'blocks' => array( + 'core/button' => array( + 'color' => array( + 'background' => 'blue', + ), + 'variations' => array( + 'outline' => array( + 'color' => array( + 'background' => 'purple', + ), + 'invalid' => array( + 'value' => 'should be stripped', + ), + ), + ), + ), + ), + ), + ); + + $expected = array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'styles' => array( + 'blocks' => array( + 'core/button' => array( + 'color' => array( + 'background' => 'blue', + ), + 'variations' => array( + 'outline' => array( + 'color' => array( + 'background' => 'purple', + ), + ), + ), + ), + ), + ), + ); + + $actual = WP_Theme_JSON_Gutenberg::remove_insecure_properties( $partially_invalid_variation ); + + $this->assertSameSetsWithIndex( $expected, $actual ); + } + public function test_update_separator_declarations() { // If only background is defined, test that includes border-color to the style so it is applied on the front end. $theme_json = new WP_Theme_JSON_Gutenberg( From e46b446daea894a5a0ff40ee6086c3bdff844816 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Fri, 11 Aug 2023 07:37:45 +0200 Subject: [PATCH 11/22] Site editor: add missing i18n in `HomeTemplateDetails` (#53543) * Site editor: add missing i18n in `HomeTemplateDetails` * Lint fix --- .../home-template-details.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-template/home-template-details.js b/packages/edit-site/src/components/sidebar-navigation-screen-template/home-template-details.js index c740a1baf37c3..5c25f7768dee0 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-template/home-template-details.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-template/home-template-details.js @@ -198,8 +198,10 @@ export default function HomeTemplateDetails() { From 4c487cd7853e3f60c66cf832ed393627583deb2d Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Mon, 14 Aug 2023 17:01:09 +1000 Subject: [PATCH 12/22] Fix: Snack bar not fixed on certain pages in the Site Editor (#53207) --- packages/base-styles/_z-index.scss | 1 + packages/edit-site/src/components/page/index.js | 16 ++++++++-------- .../edit-site/src/components/page/style.scss | 13 ++++++++----- .../edit-site/src/components/table/style.scss | 1 + 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/base-styles/_z-index.scss b/packages/base-styles/_z-index.scss index 7987e1b4b5b4d..11a31a0dd268a 100644 --- a/packages/base-styles/_z-index.scss +++ b/packages/base-styles/_z-index.scss @@ -189,6 +189,7 @@ $z-layers: ( ".edit-site-layout__hub": 3, ".edit-site-layout__header": 2, ".edit-site-page-header": 2, + ".edit-site-page-content": 1, ".edit-site-layout__canvas-container": 2, ".edit-site-layout__sidebar": 1, ".edit-site-layout__canvas-container.is-resizing::after": 100, diff --git a/packages/edit-site/src/components/page/index.js b/packages/edit-site/src/components/page/index.js index a713989a3ce0a..02d0bd2e746ee 100644 --- a/packages/edit-site/src/components/page/index.js +++ b/packages/edit-site/src/components/page/index.js @@ -26,17 +26,17 @@ export default function Page( { return ( - { ! hideTitleFromUI && title && ( -
- ) }
+ { ! hideTitleFromUI && title && ( +
+ ) } { children } -
+ ); } diff --git a/packages/edit-site/src/components/page/style.scss b/packages/edit-site/src/components/page/style.scss index e29849e408c0d..8da7df8e0385b 100644 --- a/packages/edit-site/src/components/page/style.scss +++ b/packages/edit-site/src/components/page/style.scss @@ -2,7 +2,7 @@ color: $gray-800; background: $white; flex-grow: 1; - overflow: auto; + overflow: hidden; margin: 0; margin-top: $header-height; @include break-medium() { @@ -13,8 +13,7 @@ .edit-site-page-header { padding: 0 $grid-unit-40; - height: $header-height; - padding-left: $grid-unit-40; + min-height: $header-height; border-bottom: 1px solid $gray-100; background: $white; position: sticky; @@ -33,6 +32,10 @@ } .edit-site-page-content { - padding: $grid-unit-40 $grid-unit-40; - overflow-x: auto; + height: 100%; + display: flex; + overflow: auto; + flex-flow: column; + position: relative; + z-index: z-index(".edit-site-page-content"); } diff --git a/packages/edit-site/src/components/table/style.scss b/packages/edit-site/src/components/table/style.scss index a53b2c836f54c..85c741575d5a4 100644 --- a/packages/edit-site/src/components/table/style.scss +++ b/packages/edit-site/src/components/table/style.scss @@ -1,5 +1,6 @@ .edit-site-table-wrapper { width: 100%; + padding: $grid-unit-40; } .edit-site-table { From 1cb6459d69ec716849851a083d18a773eb9e9840 Mon Sep 17 00:00:00 2001 From: James Koster Date: Wed, 2 Aug 2023 18:00:00 +0100 Subject: [PATCH 13/22] Fix document title alignment in command palette button (#53224) --- .../header-edit-mode/document-actions/style.scss | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss b/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss index 25b2c7b6eaabb..2fdcf8d281625 100644 --- a/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss +++ b/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss @@ -17,6 +17,10 @@ width: min(100%, 380px); } + &:hover { + background-color: $gray-200; + } + .components-button { border-radius: $grid-unit-05; @@ -26,10 +30,6 @@ } } - @include break-medium() { - width: 50%; - } - @include break-large() { width: min(100%, 450px); } @@ -46,6 +46,9 @@ color: var(--wp-block-synced-color); overflow: hidden; + // Offset the layout based on the width of the ⌘K label. This ensures the title is centrally aligned. + padding-left: $grid-unit-40; + &:hover { color: var(--wp-block-synced-color); } @@ -60,6 +63,7 @@ overflow: hidden; text-overflow: ellipsis; color: var(--wp-block-synced-color); + max-width: 50%; } .edit-site-document-actions.is-page & { @@ -83,6 +87,7 @@ .edit-site-document-actions__shortcut { color: $gray-800; + min-width: $grid-unit-40; } .edit-site-document-actions__back.components-button.has-icon.has-text { @@ -91,9 +96,11 @@ color: $gray-700; gap: 0; z-index: 1; + position: absolute; &:hover { color: currentColor; + background-color: transparent; } .edit-site-document-actions.is-animated & { From 96b6b1ed9ba3dccab6418c7e610abf3830451692 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Fri, 11 Aug 2023 13:19:40 +1000 Subject: [PATCH 14/22] Fallback to default max viewport if layout wide size is fluid. (#53551) --- lib/block-supports/typography.php | 2 +- .../components/global-styles/typography-utils.js | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index 469b429f9b3dd..d7438ad1fb12e 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -451,7 +451,7 @@ function gutenberg_get_typography_font_size_value( $preset, $should_use_fluid_ty $fluid_settings = isset( $typography_settings['fluid'] ) && is_array( $typography_settings['fluid'] ) ? $typography_settings['fluid'] : array(); // Defaults. - $default_maximum_viewport_width = isset( $layout_settings['wideSize'] ) ? $layout_settings['wideSize'] : '1600px'; + $default_maximum_viewport_width = isset( $layout_settings['wideSize'] ) && ! empty( gutenberg_get_typography_value_and_unit( $layout_settings['wideSize'] ) ) ? $layout_settings['wideSize'] : '1600px'; $default_minimum_viewport_width = '320px'; $default_minimum_font_size_factor_max = 0.75; $default_minimum_font_size_factor_min = 0.25; diff --git a/packages/block-editor/src/components/global-styles/typography-utils.js b/packages/block-editor/src/components/global-styles/typography-utils.js index 8eaefefbdb83e..d0b01743cf030 100644 --- a/packages/block-editor/src/components/global-styles/typography-utils.js +++ b/packages/block-editor/src/components/global-styles/typography-utils.js @@ -7,7 +7,10 @@ /** * Internal dependencies */ -import { getComputedFluidTypographyValue } from '../font-sizes/fluid-utils'; +import { + getComputedFluidTypographyValue, + getTypographyValueAndUnit, +} from '../font-sizes/fluid-utils'; /** * @typedef {Object} FluidPreset @@ -98,11 +101,16 @@ function isFluidTypographyEnabled( typographySettings ) { export function getFluidTypographyOptionsFromSettings( settings ) { const typographySettings = settings?.typography; const layoutSettings = settings?.layout; - return isFluidTypographyEnabled( typographySettings ) && + const defaultMaxViewportWidth = getTypographyValueAndUnit( layoutSettings?.wideSize + ) + ? layoutSettings?.wideSize + : null; + return isFluidTypographyEnabled( typographySettings ) && + defaultMaxViewportWidth ? { fluid: { - maxViewPortWidth: layoutSettings.wideSize, + maxViewportWidth: defaultMaxViewportWidth, ...typographySettings.fluid, }, } From d5275a52d8d7061d4819ef274e644cee8fc700b2 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Wed, 2 Aug 2023 14:26:28 +0100 Subject: [PATCH 15/22] Link Control: persist advanced settings toggle state to preferences if available (#52799) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Link Control: Create a preference for whether the advanced section is open * move the useSelect to the component that uses it * Supply preference setter via settings * Pass setter to Post Editor * Provide local state fallbacks in absence of preference store settings * Conditionalise display of settings drawer to “edit” mode only * Extract to constant to improve comprehension * Fix bug in preferences resolution * Improve comments * Add e2e scaffold * Fix e2e test to correctly assert on feature * Remove focused test * Reinstate original logic to hide settings when not required * Scaffold documentation * Revert providing prefs via settings * Refactor to use `core/block-editor` as preference scope * Update docs * Reinstate remaining original conditional * tentative fix for the e2e test * Try a different syntax for shiftAlt * another attempt to fix the e2e test --------- Co-authored-by: Dave Smith Co-authored-by: MaggieCabrera --- .../src/components/link-control/README.md | 15 +++- .../src/components/link-control/index.js | 49 +++++++++-- .../src/components/link-control/test/index.js | 3 +- test/e2e/specs/editor/blocks/links.spec.js | 88 +++++++++++++++++++ 4 files changed, 145 insertions(+), 10 deletions(-) diff --git a/packages/block-editor/src/components/link-control/README.md b/packages/block-editor/src/components/link-control/README.md index c3fc7262adb95..fef68318867e8 100644 --- a/packages/block-editor/src/components/link-control/README.md +++ b/packages/block-editor/src/components/link-control/README.md @@ -15,6 +15,16 @@ The distinction between the two components is perhaps best summarized by the fol - `` - an input for presenting and managing selection behaviors associated with choosing a URL, optionally from a pool of available candidates. - `` - includes the features of ``, plus additional UI and behaviors to control how this URL applies to the concept of a "link". This includes link "settings" (eg: "opens in new tab", etc) and dynamic, "on the fly" link creation capabilities. +## Persistent "Advanced" (settings) toggle state + +By default the link "settings" are hidden and can be toggled open/closed by way of a button labelled `Advanced` in the UI. + +In some circumstances if may be desirable to persist the toggle state of this portion of the UI so that it remains in the last state triggered by user interaction. + +For example, once the user has toggled the UI to "open", then it may remain open across all links on the site until such time as the user toggles the UI back again. + +Consumers who which to take advantage of this functionality should ensure that their block editor environment utilizes the [`@wordpress/preferences`](packages/preferences/README.md) package. By default the `` component will attempt to persist the state of UI to a setting named `linkControlSettingsDrawer` with a scope of `core/block-editor`. If the preferences package is not available then local state is used and the setting will not be persisted. + ## Search Suggestions When creating links the `LinkControl` component will handle two kinds of input from users: @@ -69,9 +79,7 @@ An array of settings objects associated with a link (for example: a setting to d To disable settings, pass in an empty array. for example: ```jsx - + ``` ### onChange @@ -192,6 +200,7 @@ A `suggestion` should have the following shape: )} /> ``` + ### renderControlBottom - Type: `Function` diff --git a/packages/block-editor/src/components/link-control/index.js b/packages/block-editor/src/components/link-control/index.js index 41455c4ecf970..a2025d1338338 100644 --- a/packages/block-editor/src/components/link-control/index.js +++ b/packages/block-editor/src/components/link-control/index.js @@ -12,6 +12,8 @@ import { useRef, useState, useEffect } from '@wordpress/element'; import { focus } from '@wordpress/dom'; import { ENTER } from '@wordpress/keycodes'; import { isShallowEqualObjects } from '@wordpress/is-shallow-equal'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { store as preferencesStore } from '@wordpress/preferences'; /** * Internal dependencies @@ -101,6 +103,9 @@ import { DEFAULT_LINK_SETTINGS } from './constants'; const noop = () => {}; +const PREFERENCE_SCOPE = 'core/block-editor'; +const PREFERENCE_KEY = 'linkControlSettingsDrawer'; + /** * Renders a link control. A link control is a controlled input which maintains * a value associated with a link (HTML anchor element) and relevant settings @@ -133,6 +138,41 @@ function LinkControl( { withCreateSuggestion = true; } + const [ settingsOpen, setSettingsOpen ] = useState( false ); + + const { advancedSettingsPreference } = useSelect( ( select ) => { + const prefsStore = select( preferencesStore ); + + return { + advancedSettingsPreference: + prefsStore.get( PREFERENCE_SCOPE, PREFERENCE_KEY ) ?? false, + }; + }, [] ); + + const { set: setPreference } = useDispatch( preferencesStore ); + + /** + * Sets the open/closed state of the Advanced Settings Drawer, + * optionlly persisting the state to the user's preferences. + * + * Note that Block Editor components can be consumed by non-WordPress + * environments which may not have preferences setup. + * Therefore a local state is also used as a fallback. + * + * @param {boolean} prefVal the open/closed state of the Advanced Settings Drawer. + */ + const setSettingsOpenWithPreference = ( prefVal ) => { + if ( setPreference ) { + setPreference( PREFERENCE_SCOPE, PREFERENCE_KEY, prefVal ); + } + setSettingsOpen( prefVal ); + }; + + // Block Editor components can be consumed by non-WordPress environments + // which may not have these preferences setup. + // Therefore a local state is used as a fallback. + const isSettingsOpen = advancedSettingsPreference || settingsOpen; + const isMounting = useRef( true ); const wrapperNode = useRef(); const textInputRef = useRef(); @@ -140,8 +180,6 @@ function LinkControl( { const settingsKeys = settings.map( ( { id } ) => id ); - const [ settingsOpen, setSettingsOpen ] = useState( false ); - const [ internalControlValue, setInternalControlValue, @@ -207,7 +245,6 @@ function LinkControl( { wrapperNode.current.ownerDocument.activeElement ); - setSettingsOpen( false ); setIsEditingLink( false ); }; @@ -292,7 +329,6 @@ function LinkControl( { const shownUnlinkControl = onRemove && value && ! isEditingLink && ! isCreatingPage; - const showSettings = !! settings?.length && isEditingLink && hasLinkValue; const showActions = isEditingLink && hasLinkValue; // Only show text control once a URL value has been committed @@ -302,6 +338,7 @@ function LinkControl( { const isEditing = ( isEditingLink || ! value ) && ! isCreatingPage; const isDisabled = ! valueHasChanges || currentInputIsEmpty; + const showSettings = !! settings?.length && isEditingLink && hasLinkValue; return (
{ ! currentInputIsEmpty && ( { } ); describe( 'Addition Settings UI', () => { - it( 'should not show a means to toggle the link settings when not editing a link', async () => { + it( 'should hide advanced link settings when not editing a link', async () => { const selectedLink = fauxEntitySuggestions[ 0 ]; const LinkControlConsumer = () => { @@ -1723,6 +1723,7 @@ describe( 'Addition Settings UI', () => { expect( settingsToggle ).not.toBeInTheDocument(); } ); + it( 'should provides a means to toggle the link settings', async () => { const selectedLink = fauxEntitySuggestions[ 0 ]; diff --git a/test/e2e/specs/editor/blocks/links.spec.js b/test/e2e/specs/editor/blocks/links.spec.js index 8443a04d0417e..b84f954566fd5 100644 --- a/test/e2e/specs/editor/blocks/links.spec.js +++ b/test/e2e/specs/editor/blocks/links.spec.js @@ -145,4 +145,92 @@ test.describe( 'Links', () => { }, ] ); } ); + + test( 'toggle state of advanced link settings is preserved across editing links', async ( { + page, + editor, + pageUtils, + } ) => { + // Create a block with some text. + await editor.insertBlock( { + name: 'core/paragraph', + } ); + await page.keyboard.type( 'This is Gutenberg WordPress' ); + + // Select "WordPress". + await pageUtils.pressKeys( 'shiftAlt+ArrowLeft' ); + + // Create a link. + await pageUtils.pressKeys( 'primary+k' ); + await page.keyboard.type( 'w.org' ); + await page.keyboard.press( 'Enter' ); + + // Move to edge of text "Gutenberg". + await pageUtils.pressKeys( 'shiftAlt+ArrowLeft' ); // If you just use Alt here it won't work on windows. + await pageUtils.pressKeys( 'ArrowLeft' ); + await pageUtils.pressKeys( 'ArrowLeft' ); + + // Select "Gutenberg". + await pageUtils.pressKeys( 'shiftAlt+ArrowLeft' ); + + // Create a link. + await pageUtils.pressKeys( 'primary+k' ); + await page.keyboard.type( 'https://wordpress.org/plugins/gutenberg/' ); + await page.keyboard.press( 'Enter' ); + + // Move back into the link. + await pageUtils.pressKeys( 'shiftAlt+ArrowLeft' ); + await pageUtils.pressKeys( 'primary+k' ); + + // Toggle the Advanced settings to be open. + // This should set the editor preference to persist this + // UI state. + await page + .getByRole( 'region', { + name: 'Editor content', + } ) + .getByRole( 'button', { + name: 'Advanced', + } ) + .click(); + + // Move focus out of Link UI and into Paragraph block. + await pageUtils.pressKeys( 'Escape' ); + + // Move caret back into the "WordPress" link to trigger + // the Link UI for that link. + await pageUtils.pressKeys( 'Alt+ArrowRight' ); + await pageUtils.pressKeys( 'ArrowRight' ); + await pageUtils.pressKeys( 'ArrowRight' ); + + // Switch Link UI to "edit" mode. + await page.getByRole( 'button', { name: 'Edit' } ).click(); + + // Check that the Advanced settings are still expanded/open + // and I can see the open in new tab checkbox. This verifies + // that the editor preference was persisted. + await expect( page.getByLabel( 'Open in new tab' ) ).toBeVisible(); + + // Toggle the Advanced settings back to being closed. + await page + .getByRole( 'region', { + name: 'Editor content', + } ) + .getByRole( 'button', { + name: 'Advanced', + } ) + .click(); + + // Move focus out of Link UI and into Paragraph block. + await pageUtils.pressKeys( 'Escape' ); + + // Move caret back into the "Gutenberg" link and open + // the Link UI for that link. + await pageUtils.pressKeys( 'shiftAlt+ArrowLeft' ); + await pageUtils.pressKeys( 'primary+k' ); + + // Check that the Advanced settings are still closed. + // This verifies that the editor preference was persisted. + await expect( page.getByLabel( 'Open in new tab' ) ).not.toBeVisible(); + } ); } ); From 7605074e26cd69c3018ac9fe54f198be81998181 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Fri, 11 Aug 2023 14:39:31 +1000 Subject: [PATCH 16/22] Add tests for fluid layout + typography (#53554) --- .../global-styles/test/typography-utils.js | 10 ++++++++++ phpunit/block-supports/typography-test.php | 5 +++++ .../block-theme-child-with-fluid-layout/style.css | 8 ++++++++ .../block-theme-child-with-fluid-layout/theme.json | 12 ++++++++++++ 4 files changed, 35 insertions(+) create mode 100644 phpunit/data/themedir1/block-theme-child-with-fluid-layout/style.css create mode 100644 phpunit/data/themedir1/block-theme-child-with-fluid-layout/theme.json diff --git a/packages/block-editor/src/components/global-styles/test/typography-utils.js b/packages/block-editor/src/components/global-styles/test/typography-utils.js index cfbf0ea68edd9..8416e8d531368 100644 --- a/packages/block-editor/src/components/global-styles/test/typography-utils.js +++ b/packages/block-editor/src/components/global-styles/test/typography-utils.js @@ -561,6 +561,16 @@ describe( 'typography utils', () => { }, expected: { fluid: { maxViewPortWidth: '10px' } }, }, + { + message: 'should not merge `layout.wideSize` if it is fluid', + settings: { + typography: { fluid: { minFontSize: '16px' } }, + layout: { wideSize: 'clamp(1000px, 85vw, 2000px)' }, + }, + expected: { + fluid: { minFontSize: '16px' }, + }, + }, ].forEach( ( { message, settings, expected } ) => { it( `${ message }`, () => { expect( diff --git a/phpunit/block-supports/typography-test.php b/phpunit/block-supports/typography-test.php index e3e136eabc692..d2bc68e04e12c 100644 --- a/phpunit/block-supports/typography-test.php +++ b/phpunit/block-supports/typography-test.php @@ -686,6 +686,11 @@ public function data_generate_block_supports_font_size_fixtures() { 'theme_slug' => 'block-theme-child-with-fluid-typography-config', 'expected_output' => 'font-size:15px;', ), + 'returns clamp value using default config if layout is fluid' => array( + 'font_size_value' => '15px', + 'theme_slug' => 'block-theme-child-with-fluid-layout', + 'expected_output' => 'font-size:clamp(14px, 0.875rem + ((1vw - 3.2px) * 0.078), 15px);', + ), ); } diff --git a/phpunit/data/themedir1/block-theme-child-with-fluid-layout/style.css b/phpunit/data/themedir1/block-theme-child-with-fluid-layout/style.css new file mode 100644 index 0000000000000..193b8f098af64 --- /dev/null +++ b/phpunit/data/themedir1/block-theme-child-with-fluid-layout/style.css @@ -0,0 +1,8 @@ +/* +Theme Name: Block Theme Child Theme With Fluid Layout +Theme URI: https://wordpress.org/ +Description: For testing purposes only. +Template: block-theme +Version: 1.0.0 +Text Domain: block-theme-child-with-fluid-layout +*/ diff --git a/phpunit/data/themedir1/block-theme-child-with-fluid-layout/theme.json b/phpunit/data/themedir1/block-theme-child-with-fluid-layout/theme.json new file mode 100644 index 0000000000000..6985da16c6063 --- /dev/null +++ b/phpunit/data/themedir1/block-theme-child-with-fluid-layout/theme.json @@ -0,0 +1,12 @@ +{ + "version": 2, + "settings": { + "appearanceTools": true, + "layout": { + "wideSize": "clamp(1000px, 85vw, 2000px)" + }, + "typography": { + "fluid": true + } + } +} From c81f322f4938a4c81a30e5f462622a6a6d43e4c5 Mon Sep 17 00:00:00 2001 From: Mitchell Austin Date: Mon, 14 Aug 2023 21:08:10 -0700 Subject: [PATCH 17/22] Fix support of sticky position in non-iframed post editor (#53540) * Fix support of sticky position in non-iframed post editor --- .../src/components/visual-editor/index.js | 17 +++++++++-------- .../src/components/visual-editor/style.scss | 6 +++++- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/edit-post/src/components/visual-editor/index.js b/packages/edit-post/src/components/visual-editor/index.js index 29e6e15da4579..c48282e12651c 100644 --- a/packages/edit-post/src/components/visual-editor/index.js +++ b/packages/edit-post/src/components/visual-editor/index.js @@ -338,11 +338,19 @@ export default function VisualEditor( { styles } ) { .is-root-container.alignfull { max-width: none; margin-left: auto; margin-right: auto;} .is-root-container.alignfull:where(.is-layout-flow) > :not(.alignleft):not(.alignright) { max-width: none;}`; + const isToBeIframed = + ( ( hasV3BlocksOnly || ( isGutenbergPlugin && isBlockBasedTheme ) ) && + ! hasMetaBoxes ) || + isTemplateMode || + deviceType === 'Tablet' || + deviceType === 'Mobile'; + return ( @@ -359,14 +367,7 @@ export default function VisualEditor( { styles } ) { className={ previewMode } > diff --git a/packages/edit-post/src/components/visual-editor/style.scss b/packages/edit-post/src/components/visual-editor/style.scss index 00678f9867ec3..fa61cc9889cf9 100644 --- a/packages/edit-post/src/components/visual-editor/style.scss +++ b/packages/edit-post/src/components/visual-editor/style.scss @@ -2,7 +2,11 @@ position: relative; display: flex; flex-flow: column; - overflow: hidden; + // In the iframed canvas this keeps extra scrollbars from appearing (when block toolbars overflow). In the + // legacy (non-iframed) canvas, overflow must not be hidden in order to maintain support for sticky positioning. + &:not(.has-inline-canvas) { + overflow: hidden; + } // Gray preview overlay (desktop/tablet/mobile) is intentionally not set on an element with scrolling content like // interface-interface-skeleton__content. This causes graphical glitches (flashes of the background color) From 0139ded9b927012e553b34e0406a6b7e4f7bdafc Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 16 Aug 2023 12:03:19 +1000 Subject: [PATCH 18/22] Revert "Footnotes: Fix recursion into updating attributes when attributes is not an object (#53257)" This reverts commit ab04074d185e6691128edb2b69875d50916ac6c0. --- packages/core-data/src/entity-provider.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/core-data/src/entity-provider.js b/packages/core-data/src/entity-provider.js index 3039105d7c55c..6cc1e021841b4 100644 --- a/packages/core-data/src/entity-provider.js +++ b/packages/core-data/src/entity-provider.js @@ -229,15 +229,6 @@ export function useEntityBlockEditor( kind, name, { id: _id } = {} ) { ); function updateAttributes( attributes ) { - // Only attempt to update attributes, if attributes is an object. - if ( - ! attributes || - Array.isArray( attributes ) || - typeof attributes !== 'object' - ) { - return attributes; - } - attributes = { ...attributes }; for ( const key in attributes ) { From 093496aea10f5648eb294a15e8a1899644fbcde9 Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Tue, 29 Aug 2023 20:32:20 +0900 Subject: [PATCH 19/22] Fix: indicator style when block moving mode (#53972) --- packages/block-editor/src/components/block-list/content.scss | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/block-list/content.scss b/packages/block-editor/src/components/block-list/content.scss index a163ddaa78955..52f2621773077 100644 --- a/packages/block-editor/src/components/block-list/content.scss +++ b/packages/block-editor/src/components/block-list/content.scss @@ -85,7 +85,6 @@ .block-editor-block-list__block.is-highlighted, .block-editor-block-list__block.is-highlighted ~ .is-multi-selected, &.is-navigate-mode .block-editor-block-list__block.is-selected, - & .is-block-moving-mode.block-editor-block-list__block.has-child-selected, .block-editor-block-list__block:not([contenteditable]):focus { outline: none; @@ -113,8 +112,6 @@ // Moving blocks using keyboard (Ellipsis > Move). & .is-block-moving-mode.block-editor-block-list__block.is-selected { - box-shadow: none; - outline: none; &::after { content: ""; @@ -130,6 +127,8 @@ top: -$default-block-margin * 0.5; border-radius: $radius-block-ui; border-top: 4px solid $gray-400; + bottom: auto; + box-shadow: none; } } From 7f41dd3565540fb39a4ffe125a2642b3048c938c Mon Sep 17 00:00:00 2001 From: Andrei Draganescu Date: Tue, 15 Aug 2023 20:16:47 +0300 Subject: [PATCH 20/22] Fix post editor top toolbar with custom fields in Safari (#53688) --- .../interface/src/components/interface-skeleton/style.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/interface/src/components/interface-skeleton/style.scss b/packages/interface/src/components/interface-skeleton/style.scss index a45239b529ddd..d7ce996226ba5 100644 --- a/packages/interface/src/components/interface-skeleton/style.scss +++ b/packages/interface/src/components/interface-skeleton/style.scss @@ -88,6 +88,12 @@ html.interface-interface-skeleton__html-container { // to "bleed" through the header. // See https://github.com/WordPress/gutenberg/issues/32631 z-index: z-index(".interface-interface-skeleton__content"); + + // On Safari the z-index is not respected when the element is fixed. + // Setting it to auto fixes the problem + @include break-medium() { + z-index: auto; + } } .interface-interface-skeleton__secondary-sidebar, From 6ae0c48695fef702931d6f77ba2c137b9bda999c Mon Sep 17 00:00:00 2001 From: Andrei Draganescu Date: Tue, 15 Aug 2023 15:49:14 +0300 Subject: [PATCH 21/22] Set top toolbar size dynamically (#53526) * fix the top toolbar size in the space remaining after plugin items are pinned * only resize above the tablet breakpoint * fix fixed block toolbar collapse button when icon labels are shown * Update height and scroll behavior * move the layout effect to the affected component, fixes for fullscreen, no block selected, icon labels height --------- Co-authored-by: jasmussen --- .../src/components/block-toolbar/style.scss | 10 +++ .../block-tools/block-contextual-toolbar.js | 78 ++++++++++++++++++- .../src/components/block-tools/style.scss | 40 ++++++++-- 3 files changed, 121 insertions(+), 7 deletions(-) diff --git a/packages/block-editor/src/components/block-toolbar/style.scss b/packages/block-editor/src/components/block-toolbar/style.scss index 0b49c9299212f..eef1678e2dfab 100644 --- a/packages/block-editor/src/components/block-toolbar/style.scss +++ b/packages/block-editor/src/components/block-toolbar/style.scss @@ -252,6 +252,16 @@ flex-shrink: 1; } + @include break-medium() { + .block-editor-block-contextual-toolbar.is-fixed { + .components-toolbar, + .components-toolbar-group { + flex-shrink: 0; + } + } + } + + .block-editor-rich-text__inline-format-toolbar-group { .components-button + .components-button { margin-left: 6px; diff --git a/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js b/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js index 9667cb21d99b7..455ea6e569277 100644 --- a/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js +++ b/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js @@ -7,7 +7,12 @@ import classnames from 'classnames'; * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { useEffect, useRef, useState } from '@wordpress/element'; +import { + useLayoutEffect, + useEffect, + useRef, + useState, +} from '@wordpress/element'; import { hasBlockSupport, store as blocksStore } from '@wordpress/blocks'; import { useSelect } from '@wordpress/data'; import { @@ -78,6 +83,77 @@ function BlockContextualToolbar( { focusOnMount, isFixed, ...props } ) { setIsCollapsed( false ); }, [ selectedBlockClientId ] ); + const isLargerThanTabletViewport = useViewportMatch( 'large', '>=' ); + const isFullscreen = + document.body.classList.contains( 'is-fullscreen-mode' ); + + useLayoutEffect( () => { + // don't do anything if not fixed toolbar + if ( ! isFixed || ! blockType ) { + return; + } + + const blockToolbar = document.querySelector( + '.block-editor-block-contextual-toolbar' + ); + + if ( ! blockToolbar ) { + return; + } + + if ( ! isLargerThanTabletViewport ) { + // set the width of the toolbar to auto + blockToolbar.style = {}; + return; + } + + if ( isCollapsed ) { + // set the width of the toolbar to auto + blockToolbar.style.width = 'auto'; + return; + } + + // get the width of the pinned items in the post editor + const pinnedItems = document.querySelector( + '.edit-post-header__settings' + ); + + // get the width of the left header in the site editor + const leftHeader = document.querySelector( + '.edit-site-header-edit-mode__end' + ); + + const computedToolbarStyle = window.getComputedStyle( blockToolbar ); + const computedPinnedItemsStyle = pinnedItems + ? window.getComputedStyle( pinnedItems ) + : false; + const computedLeftHeaderStyle = leftHeader + ? window.getComputedStyle( leftHeader ) + : false; + + const marginLeft = parseFloat( computedToolbarStyle.marginLeft ); + const pinnedItemsWidth = computedPinnedItemsStyle + ? parseFloat( computedPinnedItemsStyle.width ) + 10 // 10 is the pinned items padding + : 0; + const leftHeaderWidth = computedLeftHeaderStyle + ? parseFloat( computedLeftHeaderStyle.width ) + : 0; + + // set the new witdth of the toolbar + blockToolbar.style.width = `calc(100% - ${ + leftHeaderWidth + + pinnedItemsWidth + + marginLeft + + ( isFullscreen ? 0 : 160 ) // the width of the admin sidebar expanded + }px)`; + }, [ + isFixed, + isLargerThanTabletViewport, + isCollapsed, + isFullscreen, + blockType, + ] ); + const isToolbarEnabled = ! blockType || hasBlockSupport( blockType, '__experimentalToolbar', true ); diff --git a/packages/block-editor/src/components/block-tools/style.scss b/packages/block-editor/src/components/block-tools/style.scss index 828e1ebe9b348..6a987929dffb7 100644 --- a/packages/block-editor/src/components/block-tools/style.scss +++ b/packages/block-editor/src/components/block-tools/style.scss @@ -110,6 +110,12 @@ z-index: z-index(".block-editor-block-popover"); display: block; width: 100%; + overflow: hidden; + + .block-editor-block-toolbar { + overflow: auto; + overflow-y: hidden; + } border: none; border-bottom: $border-width solid $gray-200; @@ -133,14 +139,14 @@ // on desktop and tablet viewports the toolbar is fixed // on top of interface header + $toolbar-margin: $grid-unit-80 * 3 - 2 * $grid-unit + $grid-unit-05; @include break-medium() { &.is-fixed { - // leave room for block inserter, undo and redo, list view - margin-left: $grid-unit-80 * 3 - 2 * $grid-unit + $grid-unit-05; + margin-left: $toolbar-margin; // position on top of interface header position: fixed; - top: $admin-bar-height + $grid-unit - $border-width; + top: $admin-bar-height; // Don't fill up when empty min-height: initial; // remove the border @@ -148,18 +154,32 @@ // has to be flex for collapse button to fit display: flex; + // Mimic the height of the parent, vertically align center, and provide a max-height. + height: $header-height; + align-items: center; + &.is-collapsed { width: initial; } + &:empty { + width: initial; + } + .is-fullscreen-mode & { // leave room for block inserter, undo and redo, list view // and some margin left margin-left: $grid-unit-80 * 4 - 2 * $grid-unit; - top: $grid-unit - $border-width; + + top: 0; + &.is-collapsed { width: initial; } + + &:empty { + width: initial; + } } & > .block-editor-block-toolbar.is-showing-movers { @@ -245,7 +265,7 @@ .show-icon-labels & { - margin-left: $grid-unit-80 + 2 * $grid-unit; // inserter and margin ; + margin-left: $grid-unit-80 + 2 * $grid-unit; // inserter and margin .is-fullscreen-mode & { margin-left: $grid-unit * 18; // site hub, inserter and margin @@ -318,7 +338,12 @@ // except for the inserter on the left @include break-medium() { &.is-fixed { - width: 100%; + width: calc(100% - #{$toolbar-margin}); + + .show-icon-labels & { + width: calc(100% + 40px - #{$toolbar-margin}); //there are no undo, redo and list view buttons + } + } } @@ -328,6 +353,9 @@ @include break-large() { &.is-fixed { width: auto; + .show-icon-labels & { + width: auto; //there are no undo, redo and list view buttons + } } .is-fullscreen-mode &.is-fixed { // in full screen mode we need to account for From d67ed5efb2fa12e565f86ebbc3e714a8096c7f98 Mon Sep 17 00:00:00 2001 From: ramon Date: Thu, 31 Aug 2023 15:41:39 +1000 Subject: [PATCH 22/22] Roll back camelCase change in 96b6b1e --- .../src/components/global-styles/typography-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/global-styles/typography-utils.js b/packages/block-editor/src/components/global-styles/typography-utils.js index d0b01743cf030..f38e8ffff60fd 100644 --- a/packages/block-editor/src/components/global-styles/typography-utils.js +++ b/packages/block-editor/src/components/global-styles/typography-utils.js @@ -110,7 +110,7 @@ export function getFluidTypographyOptionsFromSettings( settings ) { defaultMaxViewportWidth ? { fluid: { - maxViewportWidth: defaultMaxViewportWidth, + maxViewPortWidth: defaultMaxViewportWidth, ...typographySettings.fluid, }, }