diff --git a/backport-changelog/6.6/7036.md b/backport-changelog/6.6/7036.md new file mode 100644 index 0000000000000..afc4d16bf011b --- /dev/null +++ b/backport-changelog/6.6/7036.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/7036 + +* https://github.com/WordPress/gutenberg/pull/63436 diff --git a/backport-changelog/6.7/6991.md b/backport-changelog/6.7/6991.md new file mode 100644 index 0000000000000..4d5f1f85ec768 --- /dev/null +++ b/backport-changelog/6.7/6991.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/6991 + +* https://github.com/WordPress/gutenberg/pull/61382 diff --git a/changelog.txt b/changelog.txt index 370057893699c..0ac0a89f5a239 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,28 @@ == Changelog == += 18.8.0-rc.3 = + + +## Changelog + +### Bug Fixes + +#### Layout +- Fix invalid css for nested fullwidth layouts with zero padding applied. ([63436](https://github.com/WordPress/gutenberg/pull/63436)) + +#### Typography +- Font Appearance Control: Refactor font appearance fallbacks. ([63215](https://github.com/WordPress/gutenberg/pull/63215)) + + + + +## Contributors + +The following contributors merged PRs in this release: + +@mikachan @richtabor + + = 18.8.0-rc.2 = diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index 67cebe47fc41b..08a299bc17b71 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -61,7 +61,7 @@ Prompt visitors to take action with a group of button-style links. ([Source](htt - **Name:** core/buttons - **Category:** design - **Allowed Blocks:** core/button -- **Supports:** align (full, wide), anchor, interactivity (clientNavigation), layout (default, ~~allowInheriting~~, ~~allowSwitching~~), spacing (blockGap, margin), typography (fontSize, lineHeight), ~~html~~ +- **Supports:** align (full, wide), anchor, color (background, gradients, ~~text~~), interactivity (clientNavigation), layout (default, ~~allowInheriting~~, ~~allowSwitching~~), spacing (blockGap, margin, padding), typography (fontSize, lineHeight), ~~html~~ ## Calendar @@ -79,7 +79,7 @@ Display a list of all categories. ([Source](https://github.com/WordPress/gutenbe - **Name:** core/categories - **Category:** widgets - **Supports:** align, interactivity (clientNavigation), spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~ -- **Attributes:** displayAsDropdown, showEmpty, showHierarchy, showOnlyTopLevel, showPostCounts +- **Attributes:** displayAsDropdown, label, showEmpty, showHierarchy, showLabel, showOnlyTopLevel, showPostCounts ## Code @@ -783,7 +783,7 @@ Give quoted text visual emphasis. "In quoting others, we cite ourselves." — Ju - **Name:** core/quote - **Category:** text -- **Supports:** anchor, background (backgroundImage, backgroundSize), color (background, gradients, heading, link, text), dimensions (minHeight), interactivity (clientNavigation), layout (~~allowEditing~~), spacing (blockGap), typography (fontSize, lineHeight), ~~html~~ +- **Supports:** anchor, background (backgroundImage, backgroundSize), color (background, gradients, heading, link, text), dimensions (minHeight), interactivity (clientNavigation), layout (~~allowEditing~~), spacing (blockGap, margin, padding), typography (fontSize, lineHeight), ~~html~~ - **Attributes:** citation, textAlign, value ## Read More diff --git a/docs/reference-guides/theme-json-reference/theme-json-living.md b/docs/reference-guides/theme-json-reference/theme-json-living.md index cf9ea9bc39113..d3f0b111d994d 100644 --- a/docs/reference-guides/theme-json-reference/theme-json-living.md +++ b/docs/reference-guides/theme-json-reference/theme-json-living.md @@ -216,6 +216,7 @@ Background styles. | backgroundPosition | string, object | | | backgroundRepeat | string, object | | | backgroundSize | string, object | | +| backgroundAttachment | string, object | | --- diff --git a/lib/block-supports/background.php b/lib/block-supports/background.php index 57b8d75f03d35..811608127f47e 100644 --- a/lib/block-supports/background.php +++ b/lib/block-supports/background.php @@ -52,12 +52,12 @@ function gutenberg_render_background_support( $block_content, $block ) { return $block_content; } - $background_styles = array(); - $background_styles['backgroundImage'] = $block_attributes['style']['background']['backgroundImage'] ?? null; - $background_styles['backgroundSize'] = $block_attributes['style']['background']['backgroundSize'] ?? null; - $background_styles['backgroundPosition'] = $block_attributes['style']['background']['backgroundPosition'] ?? null; - $background_styles['backgroundRepeat'] = $block_attributes['style']['background']['backgroundRepeat'] ?? null; - + $background_styles = array(); + $background_styles['backgroundImage'] = $block_attributes['style']['background']['backgroundImage'] ?? null; + $background_styles['backgroundSize'] = $block_attributes['style']['background']['backgroundSize'] ?? null; + $background_styles['backgroundPosition'] = $block_attributes['style']['background']['backgroundPosition'] ?? null; + $background_styles['backgroundRepeat'] = $block_attributes['style']['background']['backgroundRepeat'] ?? null; + $background_styles['backgroundAttachment'] = $block_attributes['style']['background']['backgroundAttachment'] ?? null; if ( ! empty( $background_styles['backgroundImage'] ) ) { $background_styles['backgroundSize'] = $background_styles['backgroundSize'] ?? 'cover'; // If the background size is set to `contain` and no position is set, set the position to `center`. diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index ac1f0c57ae9fc..350d158cd6e24 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -306,14 +306,22 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support * They're added separately because padding might only be set on one side. */ if ( isset( $block_spacing_values['declarations']['padding-right'] ) ) { - $padding_right = $block_spacing_values['declarations']['padding-right']; + $padding_right = $block_spacing_values['declarations']['padding-right']; + // Add unit if 0. + if ( '0' === $padding_right ) { + $padding_right = '0px'; + } $layout_styles[] = array( 'selector' => "$selector > .alignfull", 'declarations' => array( 'margin-right' => "calc($padding_right * -1)" ), ); } if ( isset( $block_spacing_values['declarations']['padding-left'] ) ) { - $padding_left = $block_spacing_values['declarations']['padding-left']; + $padding_left = $block_spacing_values['declarations']['padding-left']; + // Add unit if 0. + if ( '0' === $padding_left ) { + $padding_left = '0px'; + } $layout_styles[] = array( 'selector' => "$selector > .alignfull", 'declarations' => array( 'margin-left' => "calc($padding_left * -1)" ), diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 049b1c3e9124a..df46c3399a2a7 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -234,6 +234,7 @@ class WP_Theme_JSON_Gutenberg { 'background-position' => array( 'background', 'backgroundPosition' ), 'background-repeat' => array( 'background', 'backgroundRepeat' ), 'background-size' => array( 'background', 'backgroundSize' ), + 'background-attachment' => array( 'background', 'backgroundAttachment' ), 'border-radius' => array( 'border', 'radius' ), 'border-top-left-radius' => array( 'border', 'radius', 'topLeft' ), 'border-top-right-radius' => array( 'border', 'radius', 'topRight' ), @@ -503,10 +504,11 @@ class WP_Theme_JSON_Gutenberg { */ const VALID_STYLES = array( 'background' => array( - 'backgroundImage' => null, - 'backgroundPosition' => null, - 'backgroundRepeat' => null, - 'backgroundSize' => null, + 'backgroundImage' => null, + 'backgroundAttachment' => null, + 'backgroundPosition' => null, + 'backgroundRepeat' => null, + 'backgroundSize' => null, ), 'border' => array( 'color' => null, diff --git a/package-lock.json b/package-lock.json index fe39c663c3107..a2ccc632899f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gutenberg", - "version": "18.8.0-rc.2", + "version": "18.8.0-rc.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "gutenberg", - "version": "18.8.0-rc.2", + "version": "18.8.0-rc.3", "hasInstallScript": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -98,7 +98,7 @@ "@octokit/rest": "16.26.0", "@octokit/types": "6.34.0", "@octokit/webhooks-types": "5.8.0", - "@playwright/test": "1.43.0", + "@playwright/test": "1.45.1", "@pmmmwh/react-refresh-webpack-plugin": "0.5.11", "@react-native/babel-preset": "0.73.10", "@react-native/metro-babel-transformer": "0.73.10", @@ -6927,18 +6927,18 @@ } }, "node_modules/@playwright/test": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.0.tgz", - "integrity": "sha512-Ebw0+MCqoYflop7wVKj711ccbNlrwTBCtjY5rlbiY9kHL2bCYxq+qltK6uPsVBGGAOb033H2VO0YobcQVxoW7Q==", + "version": "1.45.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.45.1.tgz", + "integrity": "sha512-Wo1bWTzQvGA7LyKGIZc8nFSTFf2TkthGIFBR+QVNilvwouGzFd4PYukZe3rvf5PSqjHi1+1NyKSDZKcQWETzaA==", "dev": true, "dependencies": { - "playwright": "1.43.0" + "playwright": "1.45.1" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { @@ -41994,33 +41994,33 @@ "dev": true }, "node_modules/playwright": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.0.tgz", - "integrity": "sha512-SiOKHbVjTSf6wHuGCbqrEyzlm6qvXcv7mENP+OZon1I07brfZLGdfWV0l/efAzVx7TF3Z45ov1gPEkku9q25YQ==", + "version": "1.45.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.45.1.tgz", + "integrity": "sha512-Hjrgae4kpSQBr98nhCj3IScxVeVUixqj+5oyif8TdIn2opTCPEzqAqNMeK42i3cWDCVu9MI+ZsGWw+gVR4ISBg==", "dev": true, "dependencies": { - "playwright-core": "1.43.0" + "playwright-core": "1.45.1" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" }, "optionalDependencies": { "fsevents": "2.3.2" } }, "node_modules/playwright-core": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.0.tgz", - "integrity": "sha512-iWFjyBUH97+pUFiyTqSLd8cDMMOS0r2ZYz2qEsPjH8/bX++sbIJT35MSwKnp1r/OQBAqC5XO99xFbJ9XClhf4w==", + "version": "1.45.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.45.1.tgz", + "integrity": "sha512-LF4CUUtrUu2TCpDw4mcrAIuYrEjVDfT1cHbJMfwnE2+1b8PZcFzPNgvZCvq2JfQ4aTjRCCHw5EJ2tmr2NSzdPg==", "dev": true, "bin": { "playwright-core": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/please-upgrade-node": { @@ -55671,7 +55671,7 @@ "npm": ">=8.19.2" }, "peerDependencies": { - "@playwright/test": "^1.43.0", + "@playwright/test": "^1.45.1", "react": "^18.0.0", "react-dom": "^18.0.0" } @@ -60996,12 +60996,12 @@ } }, "@playwright/test": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.0.tgz", - "integrity": "sha512-Ebw0+MCqoYflop7wVKj711ccbNlrwTBCtjY5rlbiY9kHL2bCYxq+qltK6uPsVBGGAOb033H2VO0YobcQVxoW7Q==", + "version": "1.45.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.45.1.tgz", + "integrity": "sha512-Wo1bWTzQvGA7LyKGIZc8nFSTFf2TkthGIFBR+QVNilvwouGzFd4PYukZe3rvf5PSqjHi1+1NyKSDZKcQWETzaA==", "dev": true, "requires": { - "playwright": "1.43.0" + "playwright": "1.45.1" } }, "@pmmmwh/react-refresh-webpack-plugin": { @@ -88856,19 +88856,19 @@ "dev": true }, "playwright": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.0.tgz", - "integrity": "sha512-SiOKHbVjTSf6wHuGCbqrEyzlm6qvXcv7mENP+OZon1I07brfZLGdfWV0l/efAzVx7TF3Z45ov1gPEkku9q25YQ==", + "version": "1.45.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.45.1.tgz", + "integrity": "sha512-Hjrgae4kpSQBr98nhCj3IScxVeVUixqj+5oyif8TdIn2opTCPEzqAqNMeK42i3cWDCVu9MI+ZsGWw+gVR4ISBg==", "dev": true, "requires": { "fsevents": "2.3.2", - "playwright-core": "1.43.0" + "playwright-core": "1.45.1" } }, "playwright-core": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.0.tgz", - "integrity": "sha512-iWFjyBUH97+pUFiyTqSLd8cDMMOS0r2ZYz2qEsPjH8/bX++sbIJT35MSwKnp1r/OQBAqC5XO99xFbJ9XClhf4w==", + "version": "1.45.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.45.1.tgz", + "integrity": "sha512-LF4CUUtrUu2TCpDw4mcrAIuYrEjVDfT1cHbJMfwnE2+1b8PZcFzPNgvZCvq2JfQ4aTjRCCHw5EJ2tmr2NSzdPg==", "dev": true }, "please-upgrade-node": { diff --git a/package.json b/package.json index 2922cc799aee0..02de8255d1836 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "18.8.0-rc.2", + "version": "18.8.0-rc.3", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", @@ -110,7 +110,7 @@ "@octokit/rest": "16.26.0", "@octokit/types": "6.34.0", "@octokit/webhooks-types": "5.8.0", - "@playwright/test": "1.43.0", + "@playwright/test": "1.45.1", "@pmmmwh/react-refresh-webpack-plugin": "0.5.11", "@react-native/babel-preset": "0.73.10", "@react-native/metro-babel-transformer": "0.73.10", @@ -303,7 +303,7 @@ "lint:pkg-json": "wp-scripts lint-pkg-json . 'packages/*/package.json'", "native": "npm run --prefix packages/react-native-editor", "other:changelog": "node ./bin/plugin/cli.js changelog", - "other:check-licenses": "concurrently \"wp-scripts check-licenses --prod --gpl2 --ignore=@react-native-community/cli,@react-native-community/cli-platform-ios\" \"wp-scripts check-licenses --dev\"", + "other:check-licenses": "concurrently \"wp-scripts check-licenses --prod --gpl2 --ignore=@react-native-community/cli,@react-native-community/cli-platform-ios,@ampproject/remapping,human-signals,fb-watchman,bser,walker,chrome-launcher,lighthouse-logger,chromium-edge-launcher\" \"wp-scripts check-licenses --dev --ignore=jackspeak,path-scurry,package-json-from-dist\"", "preother:check-local-changes": "npm run docs:build", "other:check-local-changes": "node ./bin/check-local-changes.js", "other:cherry-pick": "node ./bin/cherry-pick.mjs", diff --git a/packages/block-editor/src/components/block-inspector/index.js b/packages/block-editor/src/components/block-inspector/index.js index e01cd09575269..9daf29f8043bb 100644 --- a/packages/block-editor/src/components/block-inspector/index.js +++ b/packages/block-editor/src/components/block-inspector/index.js @@ -132,6 +132,10 @@ const BlockInspector = ( { showNoBlockSelectedMessage = true } ) => { label={ __( 'Color' ) } className="color-block-support-panel__inner-wrapper" /> + { label={ __( 'Color' ) } className="color-block-support-panel__inner-wrapper" /> + { label={ borderPanelLabel } /> -
diff --git a/packages/block-editor/src/components/block-switcher/pattern-transformations-menu.js b/packages/block-editor/src/components/block-switcher/pattern-transformations-menu.js index 792f6d0bb2012..46fd83c92d91f 100644 --- a/packages/block-editor/src/components/block-switcher/pattern-transformations-menu.js +++ b/packages/block-editor/src/components/block-switcher/pattern-transformations-menu.js @@ -3,7 +3,7 @@ */ import { __ } from '@wordpress/i18n'; import { useState } from '@wordpress/element'; -import { useInstanceId } from '@wordpress/compose'; +import { useInstanceId, useViewportMatch } from '@wordpress/compose'; import { chevronRight } from '@wordpress/icons'; import { @@ -34,6 +34,7 @@ function PatternTransformationsMenu( { } ) { const [ showTransforms, setShowTransforms ] = useState( false ); const patterns = useTransformedPatterns( statePatterns, blocks ); + if ( ! patterns.length ) { return null; } @@ -60,21 +61,22 @@ function PatternTransformationsMenu( { } function PreviewPatternsPopover( { patterns, onSelect } ) { + const isMobile = useViewportMatch( 'medium', '<' ); + return ( -
-
- -
- -
-
-
+
+ +
+ +
+
); } diff --git a/packages/block-editor/src/components/block-switcher/preview-block-popover.js b/packages/block-editor/src/components/block-switcher/preview-block-popover.js index 78e29f4ad09fb..f978ed43af1da 100644 --- a/packages/block-editor/src/components/block-switcher/preview-block-popover.js +++ b/packages/block-editor/src/components/block-switcher/preview-block-popover.js @@ -3,6 +3,7 @@ */ import { __ } from '@wordpress/i18n'; import { Popover } from '@wordpress/components'; +import { useViewportMatch } from '@wordpress/compose'; /** * Internal dependencies @@ -10,22 +11,27 @@ import { Popover } from '@wordpress/components'; import BlockPreview from '../block-preview'; export default function PreviewBlockPopover( { blocks } ) { + const isMobile = useViewportMatch( 'medium', '<' ); + + if ( isMobile ) { + return null; + } + return ( -
-
- -
-
- { __( 'Preview' ) } -
- +
+ +
+
+ { __( 'Preview' ) }
- -
+ +
+
); } diff --git a/packages/block-editor/src/components/block-switcher/style.scss b/packages/block-editor/src/components/block-switcher/style.scss index 5eaba08bf94ae..afcb576bd8db4 100644 --- a/packages/block-editor/src/components/block-switcher/style.scss +++ b/packages/block-editor/src/components/block-switcher/style.scss @@ -84,27 +84,18 @@ min-width: 300px; } -.block-editor-block-switcher__popover__preview__parent { - .block-editor-block-switcher__popover__preview__container { - position: absolute; - top: -$grid-unit-15; - left: calc(100% + #{$grid-unit-20}); - } +.block-editor-block-switcher__popover-preview-container { + left: 0; + position: absolute; + top: -$border-width; + width: 100%; + bottom: 0; + pointer-events: none; } -.block-editor-block-switcher__preview__popover { - display: none; +.block-editor-block-switcher__popover-preview { overflow: hidden; - // Position correctly. Needs specificity. - &.components-popover { - margin-top: $grid-unit-15 - $border-width; - } - - @include break-medium() { - display: block; - } - .components-popover__content { width: 300px; border: $border-width solid $gray-900; diff --git a/packages/block-editor/src/components/global-styles/background-panel.js b/packages/block-editor/src/components/global-styles/background-panel.js index 18ecc26b002d0..25ff5887eb5e6 100644 --- a/packages/block-editor/src/components/global-styles/background-panel.js +++ b/packages/block-editor/src/components/global-styles/background-panel.js @@ -451,6 +451,9 @@ function BackgroundSizeControls( { const positionValue = style?.background?.backgroundPosition || inheritedValue?.background?.backgroundPosition; + const attachmentValue = + style?.background?.backgroundAttachment || + inheritedValue?.background?.backgroundAttachment; /* * An `undefined` value is replaced with any supplied @@ -546,8 +549,17 @@ function BackgroundSizeControls( { ) ); + const toggleScrollWithPage = () => + onChange( + setImmutably( + style, + [ 'background', 'backgroundAttachment' ], + attachmentValue === 'fixed' ? 'scroll' : 'fixed' + ) + ); + return ( - + + { - const { user: config, setUserConfig } = useContext( GlobalStylesContext ); + const { user, setUserConfig } = useContext( GlobalStylesContext ); + const config = { + settings: user.settings, + styles: user.styles, + }; const canReset = !! config && ! fastDeepEqual( config, EMPTY_CONFIG ); return [ canReset, diff --git a/packages/block-editor/src/components/global-styles/style.scss b/packages/block-editor/src/components/global-styles/style.scss index f57bc79074153..bbd1964b81cea 100644 --- a/packages/block-editor/src/components/global-styles/style.scss +++ b/packages/block-editor/src/components/global-styles/style.scss @@ -103,8 +103,13 @@ .block-editor-global-styles-background-panel__image-tools-panel-item { border: 1px solid $gray-300; border-radius: 2px; + // Full width. ToolsPanel lays out children in a grid. grid-column: 1 / -1; + + // Ensure the dropzone is positioned to the size of the item. + position: relative; + // Since there is no option to skip rendering the drag'n'drop icon in drop // zone, we hide it for now. .components-drop-zone__content-icon { 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 115de8cdf2563..41a7d6b5e37b8 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 @@ -6,6 +6,8 @@ import { getFluidTypographyOptionsFromSettings, getMergedFontFamiliesAndFontFamilyFaces, findNearestFontWeight, + findNearestFontStyle, + findNearestStyleAndWeight, } from '../typography-utils'; describe( 'typography utils', () => { @@ -951,6 +953,329 @@ describe( 'typography utils', () => { ); } ); + describe( 'findNearestFontStyle', () => { + [ + { + message: + 'should return empty string when newFontStyleValue is `undefined`', + availableFontStyles: undefined, + newFontStyleValue: undefined, + expected: '', + }, + { + message: + 'should return newFontStyleValue value when availableFontStyles is empty', + availableFontStyles: [], + newFontStyleValue: 'italic', + expected: 'italic', + }, + { + message: + 'should return empty string if there is no new font style available', + availableFontStyles: [ { name: 'Normal', value: 'normal' } ], + newFontStyleValue: 'italic', + expected: '', + }, + { + message: + 'should return empty string if the new font style is invalid', + availableFontStyles: [ + { name: 'Regular', value: 'normal' }, + { name: 'Italic', value: 'italic' }, + ], + newFontStyleValue: 'not-valid', + expected: '', + }, + { + message: 'should return italic if oblique is not available', + availableFontStyles: [ + { name: 'Regular', value: 'normal' }, + { name: 'Italic', value: 'italic' }, + ], + newFontStyleValue: 'oblique', + expected: 'italic', + }, + { + message: 'should return normal if normal is available', + availableFontStyles: [ + { name: 'Regular', value: 'normal' }, + { name: 'Italic', value: 'italic' }, + ], + newFontStyleValue: 'normal', + expected: 'normal', + }, + ].forEach( + ( { + message, + availableFontStyles, + newFontStyleValue, + expected, + } ) => { + it( `${ message }`, () => { + expect( + findNearestFontStyle( + availableFontStyles, + newFontStyleValue + ) + ).toEqual( expected ); + } ); + } + ); + } ); + + describe( 'findNearestStyleAndWeight', () => { + [ + { + message: 'should return empty object when all values are empty', + fontFamilyFaces: [], + fontStyle: undefined, + fontWeight: undefined, + expected: {}, + }, + { + message: + 'should return original fontStyle and fontWeight when fontFamilyFaces is empty', + fontFamilyFaces: [], + fontStyle: 'italic', + fontWeight: '700', + expected: { + nearestFontStyle: 'italic', + nearestFontWeight: '700', + }, + }, + { + message: + 'should return undefined values if both fontStyle and fontWeight are not available', + fontFamilyFaces: [ + { + fontFamily: 'ABeeZee', + fontStyle: 'italic', + fontWeight: '400', + src: [ + 'file:./assets/fonts/esDT31xSG-6AGleN2tCkkJUCGpG-GQ.woff2', + ], + }, + ], + fontStyle: undefined, + fontWeight: undefined, + expected: { + nearestFontStyle: undefined, + nearestFontWeight: undefined, + }, + }, + { + message: + 'should return nearest fontStyle and fontWeight for normal/400', + fontFamilyFaces: [ + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'normal', + fontWeight: '400', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Regular.woff2', + ], + }, + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'italic', + fontWeight: '400', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Italic.woff2', + ], + }, + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'normal', + fontWeight: '700', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Bold.woff2', + ], + }, + ], + fontStyle: 'normal', + fontWeight: '400', + expected: { + nearestFontStyle: 'normal', + nearestFontWeight: '400', + }, + }, + { + message: + 'should return nearest fontStyle and fontWeight for normal/100', + fontFamilyFaces: [ + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'normal', + fontWeight: '400', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Regular.woff2', + ], + }, + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'italic', + fontWeight: '400', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Italic.woff2', + ], + }, + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'normal', + fontWeight: '700', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Bold.woff2', + ], + }, + ], + fontStyle: 'normal', + fontWeight: '100', + expected: { + nearestFontStyle: 'normal', + nearestFontWeight: '400', + }, + }, + { + message: + 'should return nearest fontStyle and fontWeight for italic/900', + fontFamilyFaces: [ + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'normal', + fontWeight: '400', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Regular.woff2', + ], + }, + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'italic', + fontWeight: '400', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Italic.woff2', + ], + }, + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'normal', + fontWeight: '700', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Bold.woff2', + ], + }, + ], + fontStyle: 'italic', + fontWeight: '900', + expected: { + nearestFontStyle: 'italic', + nearestFontWeight: '700', + }, + }, + { + message: + 'should return nearest fontStyle and fontWeight for oblique/600', + fontFamilyFaces: [ + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'normal', + fontWeight: '400', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Regular.woff2', + ], + }, + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'italic', + fontWeight: '700', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Bold.woff2', + ], + }, + ], + fontStyle: 'oblique', + fontWeight: '600', + expected: { + nearestFontStyle: 'italic', + nearestFontWeight: '700', + }, + }, + { + message: + 'should return nearest fontStyle and fontWeight for 300 font weight and empty font style', + fontFamilyFaces: [ + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'normal', + fontWeight: '400', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Regular.woff2', + ], + }, + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'italic', + fontWeight: '700', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Bold.woff2', + ], + }, + ], + fontStyle: undefined, + fontWeight: '300', + expected: { + nearestFontStyle: 'normal', + nearestFontWeight: '400', + }, + }, + { + message: + 'should return nearest fontStyle and fontWeight for oblique font style and empty font weight', + fontFamilyFaces: [ + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'normal', + fontWeight: '400', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Regular.woff2', + ], + }, + { + fontFamily: 'IBM Plex Mono', + fontStyle: 'italic', + fontWeight: '700', + src: [ + 'file:./assets/fonts/ibm-plex-mono/IBMPlexMono-Bold.woff2', + ], + }, + ], + fontStyle: 'oblique', + fontWeight: undefined, + expected: { + nearestFontStyle: 'italic', + nearestFontWeight: '400', + }, + }, + ].forEach( + ( { + message, + fontFamilyFaces, + fontStyle, + fontWeight, + expected, + } ) => { + it( `${ message }`, () => { + expect( + findNearestStyleAndWeight( + fontFamilyFaces, + fontStyle, + fontWeight + ) + ).toEqual( expected ); + } ); + } + ); + } ); + describe( 'typography utils', () => { [ { diff --git a/packages/block-editor/src/components/global-styles/typography-panel.js b/packages/block-editor/src/components/global-styles/typography-panel.js index c497ea4683391..f6a389a5bc96d 100644 --- a/packages/block-editor/src/components/global-styles/typography-panel.js +++ b/packages/block-editor/src/components/global-styles/typography-panel.js @@ -25,9 +25,8 @@ import { getValueFromVariable, useToolsPanelDropdownMenuProps } from './utils'; import { setImmutably } from '../../utils/object'; import { getMergedFontFamiliesAndFontFamilyFaces, - findNearestFontWeight, + findNearestStyleAndWeight, } from './typography-utils'; -import { getFontStylesAndWeights } from '../../utils/get-font-styles-and-weights'; const MIN_TEXT_COLUMNS = 1; const MAX_TEXT_COLUMNS = 6; @@ -236,57 +235,50 @@ export default function TypographyPanel( { const hasFontWeights = settings?.typography?.fontWeight; const fontStyle = decodeValue( inheritedValue?.typography?.fontStyle ); const fontWeight = decodeValue( inheritedValue?.typography?.fontWeight ); - const setFontAppearance = ( { - fontStyle: newFontStyle, - fontWeight: newFontWeight, - } ) => { - onChange( { - ...value, - typography: { - ...value?.typography, - fontStyle: newFontStyle || undefined, - fontWeight: newFontWeight || undefined, - }, - } ); - }; + const { nearestFontStyle, nearestFontWeight } = findNearestStyleAndWeight( + fontFamilyFaces, + fontStyle, + fontWeight + ); + const setFontAppearance = useCallback( + ( { fontStyle: newFontStyle, fontWeight: newFontWeight } ) => { + // Only update the font style and weight if they have changed. + if ( newFontStyle !== fontStyle || newFontWeight !== fontWeight ) { + onChange( { + ...value, + typography: { + ...value?.typography, + fontStyle: newFontStyle || undefined, + fontWeight: newFontWeight || undefined, + }, + } ); + } + }, + [ fontStyle, fontWeight, onChange, value ] + ); const hasFontAppearance = () => !! value?.typography?.fontStyle || !! value?.typography?.fontWeight; - const resetFontAppearance = () => { + const resetFontAppearance = useCallback( () => { setFontAppearance( {} ); - }; + }, [ setFontAppearance ] ); - // Check if previous font style and weight values are available in the new font family + // Check if previous font style and weight values are available in the new font family. useEffect( () => { - const { fontStyles, fontWeights, isSystemFont } = - getFontStylesAndWeights( fontFamilyFaces ); - const hasFontStyle = fontStyles?.some( - ( { value: fs } ) => fs === fontStyle - ); - const hasFontWeight = fontWeights?.some( - ( { value: fw } ) => fw === fontWeight - ); - - // Try to set nearest available font weight - if ( ! hasFontWeight && fontWeight ) { + if ( nearestFontStyle && nearestFontWeight ) { setFontAppearance( { - fontStyle, - fontWeight: findNearestFontWeight( fontWeights, fontWeight ), + fontStyle: nearestFontStyle, + fontWeight: nearestFontWeight, } ); - } - - // Set the same weight and style values if the font family is a system font or if both are the same - if ( isSystemFont || ( hasFontStyle && hasFontWeight ) ) { - setFontAppearance( { - fontStyle, - fontWeight, - } ); - } - - // Reset font appearance if the font family does not have the selected font style - if ( ! hasFontStyle ) { + } else { + // Reset font appearance if there are no available styles or weights. resetFontAppearance(); } - }, [ fontFamily ] ); + }, [ + nearestFontStyle, + nearestFontWeight, + resetFontAppearance, + setFontAppearance, + ] ); // Line Height const hasLineHeightEnabled = useHasLineHeightControl( settings ); 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 0d4c1b29b8b66..59ff04bf21ebc 100644 --- a/packages/block-editor/src/components/global-styles/typography-utils.js +++ b/packages/block-editor/src/components/global-styles/typography-utils.js @@ -11,6 +11,7 @@ import { getComputedFluidTypographyValue, getTypographyValueAndUnit, } from '../font-sizes/fluid-utils'; +import { getFontStylesAndWeights } from '../../utils/get-font-styles-and-weights'; /** * @typedef {Object} FluidPreset @@ -127,9 +128,9 @@ export function getFluidTypographyOptionsFromSettings( settings ) { * Returns an object of merged font families and the font faces from the selected font family * based on the theme.json settings object and the currently selected font family. * - * @param {Object} settings Theme.json settings - * @param {string} selectedFontFamily Decoded font family string - * @return {Object} Merged font families and font faces from the selected font family + * @param {Object} settings Theme.json settings. + * @param {string} selectedFontFamily Decoded font family string. + * @return {Object} Merged font families and font faces from the selected font family. */ export function getMergedFontFamiliesAndFontFamilyFaces( settings, @@ -153,11 +154,10 @@ export function getMergedFontFamiliesAndFontFamilyFaces( * Returns the nearest font weight value from the available font weight list based on the new font weight. * The nearest font weight is the one with the smallest difference from the new font weight. * - * @param {Array} availableFontWeights Array of available font weights - * @param {string} newFontWeightValue New font weight value - * @return {string} Nearest font weight + * @param {Array} availableFontWeights Array of available font weights. + * @param {string} newFontWeightValue New font weight value. + * @return {string} Nearest font weight. */ - export function findNearestFontWeight( availableFontWeights, newFontWeightValue @@ -185,3 +185,99 @@ export function findNearestFontWeight( return nearestFontWeight; } + +/** + * Returns the nearest font style based on the new font style. + * Defaults to an empty string if the new font style is not valid or available. + * + * @param {Array} availableFontStyles Array of available font weights. + * @param {string} newFontStyleValue New font style value. + * @return {string} Nearest font style or an empty string. + */ +export function findNearestFontStyle( availableFontStyles, newFontStyleValue ) { + if ( typeof newFontStyleValue !== 'string' || ! newFontStyleValue ) { + return ''; + } + + const validStyles = [ 'normal', 'italic', 'oblique' ]; + if ( ! validStyles.includes( newFontStyleValue ) ) { + return ''; + } + + if ( + ! availableFontStyles || + availableFontStyles.length === 0 || + availableFontStyles.find( + ( style ) => style.value === newFontStyleValue + ) + ) { + return newFontStyleValue; + } + + if ( + newFontStyleValue === 'oblique' && + ! availableFontStyles.find( ( style ) => style.value === 'oblique' ) + ) { + return 'italic'; + } + + return ''; +} + +/** + * Returns the nearest font style and weight based on the available font family faces and the new font style and weight. + * + * @param {Array} fontFamilyFaces Array of available font family faces. + * @param {string} fontStyle New font style. Defaults to previous value. + * @param {string} fontWeight New font weight. Defaults to previous value. + * @return {Object} Nearest font style and font weight. + */ +export function findNearestStyleAndWeight( + fontFamilyFaces, + fontStyle, + fontWeight +) { + let nearestFontStyle = fontStyle; + let nearestFontWeight = fontWeight; + + const { fontStyles, fontWeights, combinedStyleAndWeightOptions } = + getFontStylesAndWeights( fontFamilyFaces ); + + // Check if the new font style and weight are available in the font family faces. + const hasFontStyle = fontStyles?.some( + ( { value: fs } ) => fs === fontStyle + ); + const hasFontWeight = fontWeights?.some( + ( { value: fw } ) => fw === fontWeight + ); + + if ( ! hasFontStyle ) { + /* + * Default to italic if oblique is not available. + * Or find the nearest font style based on the nearest font weight. + */ + nearestFontStyle = fontStyle + ? findNearestFontStyle( fontStyles, fontStyle ) + : combinedStyleAndWeightOptions?.find( + ( option ) => + option.style.fontWeight === + findNearestFontWeight( fontWeights, fontWeight ) + )?.style?.fontStyle; + } + + if ( ! hasFontWeight ) { + /* + * Find the nearest font weight based on available weights. + * Or find the nearest font weight based on the nearest font style. + */ + nearestFontWeight = fontWeight + ? findNearestFontWeight( fontWeights, fontWeight ) + : combinedStyleAndWeightOptions?.find( + ( option ) => + option.style.fontStyle === + ( nearestFontStyle || fontStyle ) + )?.style?.fontWeight; + } + + return { nearestFontStyle, nearestFontWeight }; +} diff --git a/packages/block-editor/src/hooks/grid-visualizer.js b/packages/block-editor/src/hooks/grid-visualizer.js index ffad5edd9842c..44102208c4d1d 100644 --- a/packages/block-editor/src/hooks/grid-visualizer.js +++ b/packages/block-editor/src/hooks/grid-visualizer.js @@ -39,7 +39,7 @@ function GridTools( { clientId, layout } ) { const addGridVisualizerToBlockEdit = createHigherOrderComponent( ( BlockEdit ) => ( props ) => { if ( props.attributes.layout?.type !== 'grid' ) { - return ; + return ; } return ( @@ -48,7 +48,7 @@ const addGridVisualizerToBlockEdit = createHigherOrderComponent( clientId={ props.clientId } layout={ props.attributes.layout } /> - + ); }, diff --git a/packages/block-editor/src/layouts/constrained.js b/packages/block-editor/src/layouts/constrained.js index 03d2c642d02bd..2e671e8e53975 100644 --- a/packages/block-editor/src/layouts/constrained.js +++ b/packages/block-editor/src/layouts/constrained.js @@ -234,15 +234,23 @@ export default { const paddingValues = getCSSRules( style ); paddingValues.forEach( ( rule ) => { if ( rule.key === 'paddingRight' ) { + // Add unit if 0, to avoid calc(0 * -1) which is invalid. + const paddingRightValue = + rule.value === '0' ? '0px' : rule.value; + output += ` ${ appendSelectors( selector, '> .alignfull' ) } { - margin-right: calc(${ rule.value } * -1); + margin-right: calc(${ paddingRightValue } * -1); } `; } else if ( rule.key === 'paddingLeft' ) { + // Add unit if 0, to avoid calc(0 * -1) which is invalid. + const paddingLeftValue = + rule.value === '0' ? '0px' : rule.value; + output += ` ${ appendSelectors( selector, '> .alignfull' ) } { - margin-left: calc(${ rule.value } * -1); + margin-left: calc(${ paddingLeftValue } * -1); } `; } diff --git a/packages/block-library/src/block/edit.js b/packages/block-library/src/block/edit.js index 5fdeba99dcef6..86c9483c98b34 100644 --- a/packages/block-library/src/block/edit.js +++ b/packages/block-library/src/block/edit.js @@ -156,7 +156,11 @@ function ReusableBlockEdit( { getBlockEditingMode: _getBlockEditingMode, } = select( blockEditorStore ); const { getBlockBindingsSource } = unlock( select( blocksStore ) ); - const canEdit = canUser( 'update', 'blocks', ref ); + const canEdit = canUser( 'update', { + kind: 'postType', + name: 'wp_block', + id: ref, + } ); // For editing link to the site editor if the theme and user permissions support it. return { diff --git a/packages/block-library/src/buttons/block.json b/packages/block-library/src/buttons/block.json index 015290a4c7cc5..220f6ef8fd1e2 100644 --- a/packages/block-library/src/buttons/block.json +++ b/packages/block-library/src/buttons/block.json @@ -13,8 +13,16 @@ "align": [ "wide", "full" ], "html": false, "__experimentalExposeControlsToChildren": true, + "color": { + "gradients": true, + "text": false, + "__experimentalDefaultControls": { + "background": true + } + }, "spacing": { "blockGap": true, + "padding": true, "margin": [ "top", "bottom" ], "__experimentalDefaultControls": { "blockGap": true @@ -33,6 +41,18 @@ "fontSize": true } }, + "__experimentalBorder": { + "color": true, + "radius": true, + "style": true, + "width": true, + "__experimentalDefaultControls": { + "color": true, + "radius": true, + "style": true, + "width": true + } + }, "layout": { "allowSwitching": false, "allowInheriting": false, diff --git a/packages/block-library/src/categories/block.json b/packages/block-library/src/categories/block.json index 820ac8945f50f..7f74befa3b681 100644 --- a/packages/block-library/src/categories/block.json +++ b/packages/block-library/src/categories/block.json @@ -26,6 +26,14 @@ "showEmpty": { "type": "boolean", "default": false + }, + "label": { + "type": "string", + "__experimentalRole": "content" + }, + "showLabel": { + "type": "boolean", + "default": true } }, "supports": { diff --git a/packages/block-library/src/categories/edit.js b/packages/block-library/src/categories/edit.js index 0c4df48d7c3dc..48d505eeb75ae 100644 --- a/packages/block-library/src/categories/edit.js +++ b/packages/block-library/src/categories/edit.js @@ -14,7 +14,11 @@ import { VisuallyHidden, } from '@wordpress/components'; import { useInstanceId } from '@wordpress/compose'; -import { InspectorControls, useBlockProps } from '@wordpress/block-editor'; +import { + InspectorControls, + useBlockProps, + RichText, +} from '@wordpress/block-editor'; import { decodeEntities } from '@wordpress/html-entities'; import { __ } from '@wordpress/i18n'; import { pin } from '@wordpress/icons'; @@ -27,6 +31,8 @@ export default function CategoriesEdit( { showPostCounts, showOnlyTopLevel, showEmpty, + label, + showLabel, }, setAttributes, className, @@ -92,9 +98,22 @@ export default function CategoriesEdit( { const categoriesList = getCategoriesList( parentId ); return ( <> - - { __( 'Categories' ) } - + { showLabel ? ( + + setAttributes( { label: html } ) + } + /> + ) : ( + + { label ? label : __( 'Categories' ) } + + ) }