diff --git a/.eslintrc.js b/.eslintrc.js index 5d7c6b40890510..9ac141fd09a04c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -407,6 +407,24 @@ module.exports = { ], }, }, + { + files: [ 'packages/edit-post/**', 'packages/edit-site/**' ], + rules: { + 'no-restricted-imports': [ + 'error', + { + paths: [ + ...restrictedImports, + { + name: '@wordpress/interface', + message: + 'The edit-post and edit-site package should not directly import the interface package. They should import them from the private APIs of the editor package instead.', + }, + ], + }, + ], + }, + }, { files: [ 'packages/interactivity*/src/**' ], rules: { diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d356c6113543ea..c90179f0e80943 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -47,7 +47,7 @@ /packages/block-editor/src/components/link-control @getdave # Widgets -/packages/edit-widgets @draganescu @talldan @adamziel @kevin940726 +/packages/edit-widgets @draganescu @adamziel @kevin940726 /packages/customize-widgets /packages/widgets diff --git a/changelog.txt b/changelog.txt index 02864f4ea4bf25..735ee72bc9f23f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,19 @@ == Changelog == += 18.1.1 = + +## Bug Fixes + +- Add null check to prevent errors in `get_block_template` filter ([60491](https://github.com/WordPress/gutenberg/pull/60491)) +- Fix activating a theme in site editor when previewing ([60699](https://github.com/WordPress/gutenberg/pull/60699)) + +## Contributors + +The following contributors merged PRs in this release: + +@okmttdhr @ntsekouras + + = 18.1.0 = ## Changelog diff --git a/docs/getting-started/devenv/get-started-with-wp-scripts.md b/docs/getting-started/devenv/get-started-with-wp-scripts.md index b6271620514df4..16f1bbc6015b5b 100644 --- a/docs/getting-started/devenv/get-started-with-wp-scripts.md +++ b/docs/getting-started/devenv/get-started-with-wp-scripts.md @@ -4,7 +4,7 @@ The [`@wordpress/scripts`](https://developer.wordpress.org/block-editor/referenc A JavaScript build step refers to the process of transforming, bundling, and optimizing JavaScript source code and related assets into a format suitable for production environments. These build steps often take modern JavaScript (ESNext and JSX) and convert it to a version compatible with most browsers. They can also bundle multiple files into one, minify the code to reduce file size and perform various other tasks to optimize the code. -You will typically be working with ESNext and JSX when building for the Block Editor, and most examples in the Block Editor Handbook are written in these syntaxes. Learning how to set up a build step is essential. However, configuring the necessary tools like [webpack](https://webpack.js.org/), [Babel](https://babeljs.io/), and [ESLint](https://eslint.org/) can become complex. This is where `wp-scripts` comes in. +You will typically be working with ESNext and JSX when building for the Block Editor, and all examples in the Block Editor Handbook are written in these syntaxes. Learning how to set up a build step is essential. However, configuring the necessary tools like [webpack](https://webpack.js.org/), [Babel](https://babeljs.io/), and [ESLint](https://eslint.org/) can become complex. This is where `wp-scripts` comes in. Here are a few things that `wp-scripts` can do: diff --git a/docs/how-to-guides/platform/custom-block-editor.md b/docs/how-to-guides/platform/custom-block-editor.md index 65f8c412c45d33..a7abb00adacec6 100644 --- a/docs/how-to-guides/platform/custom-block-editor.md +++ b/docs/how-to-guides/platform/custom-block-editor.md @@ -24,7 +24,7 @@ By the end of this article, you will have a solid understanding of the block edi ## Code syntax -The code snippets in this guide use JSX syntax. However, you could use plain JavaScript if you prefer. However, once familiar with JSX, many developers find it easier to read and write, so most code examples in the Block Editor Handbook use this syntax. +The code snippets in this guide use JSX syntax. However, you could use plain JavaScript if you prefer. However, once familiar with JSX, many developers find it easier to read and write, so all code examples in the Block Editor Handbook use this syntax. ## What you're going to be building diff --git a/docs/how-to-guides/themes/global-settings-and-styles.md b/docs/how-to-guides/themes/global-settings-and-styles.md index cd5557d40e55c6..37f0ee8951c3c9 100644 --- a/docs/how-to-guides/themes/global-settings-and-styles.md +++ b/docs/how-to-guides/themes/global-settings-and-styles.md @@ -265,6 +265,7 @@ The settings section has the following structure: "fontWeight": true, "letterSpacing": true, "lineHeight": false, + "textAlign": true, "textColumns": false, "textDecoration": true, "textTransform": true diff --git a/docs/reference-guides/block-api/block-attributes.md b/docs/reference-guides/block-api/block-attributes.md index 935b38155f1e72..52a325ff9253de 100644 --- a/docs/reference-guides/block-api/block-attributes.md +++ b/docs/reference-guides/block-api/block-attributes.md @@ -375,9 +375,6 @@ Attribute definition: From here, meta attributes can be read and written by a block using the same interface as any attribute: - -{% JSX %} - ```js edit( { attributes, setAttributes } ) { function onChange( event ) { diff --git a/docs/reference-guides/block-api/block-supports.md b/docs/reference-guides/block-api/block-supports.md index 057047434eb69d..b327cd0c03a9ee 100644 --- a/docs/reference-guides/block-api/block-supports.md +++ b/docs/reference-guides/block-api/block-supports.md @@ -149,13 +149,13 @@ When a background image is selected, the image data is stored in the `style.back When a background images is selected and its position or size are changed, the background-position is stored in the `style.background.backgroundPosition` and its background-size in `style.background.backgroundSize` attribute. - `style`: an attribute of `object` type with no default assigned. This is added when `backgroundImage` or `backgroundSize` support is declared. It stores the custom values set by the user. - - `background`: an attribute of `object` type. - - `backgroundImage`: an attribute of `object` type, containing information about the selected image + - `background`: an attribute of `object` type. + - `backgroundImage`: an attribute of `object` type, containing information about the selected image - `url`: type `string`, URL to the image - `id`: type `int`, media attachment ID - `source`: type `string`, at the moment the only value is `file` - - `title`: type `string`, title of the media attachment - - `backgroundPosition`: an attribute of `string` type, defining the background images position, selected by FocalPointPicker and used in CSS as the [`background-position`](https://developer.mozilla.org/en-US/docs/Web/CSS/background-position) value. + - `title`: type `string`, title of the media attachment + - `backgroundPosition`: an attribute of `string` type, defining the background images position, selected by FocalPointPicker and used in CSS as the [`background-position`](https://developer.mozilla.org/en-US/docs/Web/CSS/background-position) value. - `backgroundSize`: an attribute of `string` type. defining the CSS [`background-size`](https://developer.mozilla.org/en-US/docs/Web/CSS/background-size) value. The block can apply a default background image, position and size by specifying its own attribute with a default. For example: @@ -484,10 +484,10 @@ When the block declares support for `color.link`, the attributes definition is e color: { text: 'var:preset|color|contrast', }, - ":hover": { - color: { - text: "#000000" - } + ":hover": { + color: { + text: "#000000" + } } } } @@ -973,6 +973,7 @@ supports: { - Subproperties: - `fontSize`: type `boolean`, default value `false` - `lineHeight`: type `boolean`, default value `false` + - `textAlign`: type `boolean` or `array`, default value `false` The presence of this object signals that a block supports some typography related properties. When it does, the block editor will show a typography UI allowing the user to control their values. @@ -983,6 +984,8 @@ supports: { fontSize: true, // Enable support and UI control for line-height. lineHeight: true, + // Enable support and UI control for text alignment. + textAlign: true, }, } ``` @@ -1063,3 +1066,47 @@ attributes: { } } ``` + +### typography.textAlign + +_**Note:** Since WordPress 6.6._ + +- Type: `boolean` or `array` +- Default value: `false` + +This property adds block toolbar controls which allow to change block's text alignment. + +```js +supports: { + typography: { + // Declare support for block's text alignment. + // This adds support for all the options: + // left, center, right. + textAlign: true + } +} +``` + +```js +supports: { + typography: { + // Declare support for specific text alignment options. + textAlign: [ 'left', 'right' ] + } +} +``` + +When the block declares support for `textAlign`, the attributes definition is extended to include a new attribute `style` of `object` type with no default assigned. It stores the custom value set by the user. The block can apply a default style by specifying its own `style` attribute with a default. For example: + +```js +attributes: { + style: { + type: 'object', + default: { + typography: { + textAlign: 'value' + } + } + } +} +``` diff --git a/docs/reference-guides/block-api/block-variations.md b/docs/reference-guides/block-api/block-variations.md index 96930dc6b9b625..0440858810b65a 100644 --- a/docs/reference-guides/block-api/block-variations.md +++ b/docs/reference-guides/block-api/block-variations.md @@ -1,6 +1,6 @@ # Variations -The Block Variations API allows you to define multiple versions (variations) of a block. A block variation differs from the original block by a set of initial attributes or inner blocks. When you insert the block variation into the Editor, these attributes and/or inner blocks are applied. +The Block Variations API allows you to define multiple versions (variations) of a block. A block variation differs from the original block by a set of initial attributes or inner blocks. When you insert the block variation into the Editor, these attributes and/or inner blocks are applied. Variations are an excellent way to create iterations of existing blocks without building entirely new blocks from scratch. @@ -55,8 +55,8 @@ Block variations can be declared during a block's registration by providing the To create a variation for an existing block, such as a Core block, use `wp.blocks.registerBlockVariation()`. This function accepts the name of the block and the object defining the variation. ```js -wp.blocks.registerBlockVariation( - 'core/embed', +wp.blocks.registerBlockVariation( + 'core/embed', { name: 'custom-embed', attributes: { providerNameSlug: 'custom' }, @@ -66,7 +66,7 @@ wp.blocks.registerBlockVariation( ## Removing a block variation -Block variations can also be easily removed. To do so, use `wp.blocks.unregisterBlockVariation()`. This function accepts the name of the block and the `name` of the variation that should be unregistered. +Block variations can also be easily removed. To do so, use `wp.blocks.unregisterBlockVariation()`. This function accepts the name of the block and the `name` of the variation that should be unregistered. ```js wp.blocks.unregisterBlockVariation( 'core/embed', 'youtube' ); @@ -84,9 +84,9 @@ variations: [ name: 'blue', title: __( 'Blue Quote' ), isDefault: true, - attributes: { - color: 'blue', - className: 'is-style-blue-quote' + attributes: { + color: 'blue', + className: 'is-style-blue-quote' }, icon: 'format-quote', isActive: ( blockAttributes, variationAttributes ) => @@ -99,16 +99,16 @@ variations: [ By default, all variations will show up in the Inserter in addition to the original block type item. However, setting the `isDefault` flag for any variations listed will override the regular block type in the Inserter. This is a great tool for curating the Editor experience to your specific needs. -For example, if you want Media & Text block to display the image on the right by default, you could create a variation like this: +For example, if you want Media & Text block to display the image on the right by default, you could create a variation like this: ```js wp.blocks.registerBlockVariation( - 'core/media-text', + 'core/media-text', { name: 'media-text-media-right', title: __( 'Media & Text' ), isDefault: true, - attributes: { + attributes: { mediaPosition: 'right' } } @@ -125,20 +125,53 @@ The solution is to unregister the other variation before registering your variat ## Using `isActive` -While the `isActive` property is optional, you will often want to use it to display information about the block variation after the block has been inserted. For example, this API is used in `useBlockDisplayInformation` hook to fetch and display proper information in places like the `BlockCard` or `Breadcrumbs` components. +While the `isActive` property is optional, it's recommended. This API is used by the block editor to check which variation is active, and display the correct variation's title, icon and description when an instance of the variation is selected in the editor. + +If `isActive` is not set, the Editor cannot distinguish between an instance of the original block and your variation, so the original block information will be displayed. + +The property can be set to either a function or an array of strings (`string[]`). -If `isActive` is not set, the Editor cannot distinguish between the original block and your variation, so the original block information will be displayed. +The function version of this property accepts a block instance's `blockAttributes` as the first argument, and the `variationAttributes` declared for a variation as the second argument. These arguments can be used to determine if a variation is active by comparing them and returning a `true` or `false` (indicating whether this variation is inactive for this block instance). -The property can use either a function or an array of strings (`string[]`). The function accepts `blockAttributes` and `variationAttributes`, which can be used to determine if a variation is active. In the Embed block, the primary differentiator is the `providerNameSlug` attribute, so if you wanted to determine if the YouTube Embed variation was active, you could do something like this: +As an example, in the core Embed block, the `providerNameSlug` attribute is used to determine the embed provider (e.g. 'youtube' or 'twitter'). The variations may be declared like this: +```js +const variations = [ + { + name: 'twitter', + title: 'Twitter', + icon: embedTwitterIcon, + keywords: [ 'tweet', __( 'social' ) ], + description: __( 'Embed a tweet.' ), + patterns: [ /^https?:\/\/(www\.)?twitter\.com\/.+/i ], + attributes: { providerNameSlug: 'twitter', responsive: true }, + }, + { + name: 'youtube', + title: 'YouTube', + icon: embedYouTubeIcon, + keywords: [ __( 'music' ), __( 'video' ) ], + description: __( 'Embed a YouTube video.' ), + patterns: [ + /^https?:\/\/((m|www)\.)?youtube\.com\/.+/i, + /^https?:\/\/youtu\.be\/.+/i, + ], + attributes: { providerNameSlug: 'youtube', responsive: true }, + }, + // ... +] ``` + + The `isActive` function can compare the block instance value for `providerNameSlug` to the value declared in the variation's declaration (the values in the code snippet above) to determine which embed variation is active: + +```js isActive: ( blockAttributes, variationAttributes ) => blockAttributes.providerNameSlug === variationAttributes.providerNameSlug, ``` -You can also use a `string[]` to tell which attributes should be compared as a shorthand. Each attribute will be checked and the variation will be active if all of them match. Using the same example of the YouTube Embed variation, the string version would look like this: +The `string[]` version is used to declare which attributes should be compared as a shorthand. Each attribute will be checked and the variation will be active if all of them match. Using the same example for the embed block, the string version would look like this: -``` +```js isActive: [ 'providerNameSlug' ] ``` @@ -175,4 +208,4 @@ wp.blocks.registerBlockVariation( The `isActive` check on both variations tests the `textColor`, but each variations uses `vivid-red`. Since the `paragraph-red` variation is registered first, once the `paragraph-red-grey` variation is inserted into the Editor, it will have the title `Red Paragraph` instead of `Red/Grey Paragraph`. As soon as the Editor finds a match, it stops checking. -There have been [discussions](https://github.com/WordPress/gutenberg/issues/41303#issuecomment-1526193087) around how the API can be improved, but as of WordPress 6.3, this remains an issue to watch out for. \ No newline at end of file +There have been [discussions](https://github.com/WordPress/gutenberg/issues/41303#issuecomment-1526193087) around how the API can be improved, but as of WordPress 6.3, this remains an issue to watch out for. diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index d0eb25b807e6d7..3c8ee800d31aa4 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -860,7 +860,7 @@ Displays the name of this site. Update the block, and the changes apply everywhe ## Social Icon -Display an icon linking to a social media profile or site. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/social-link)) +Display an icon linking to a social profile or site. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/social-link)) - **Name:** core/social-link - **Category:** widgets @@ -870,7 +870,7 @@ Display an icon linking to a social media profile or site. ([Source](https://git ## Social Icons -Display icons linking to your social media profiles or sites. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/social-links)) +Display icons linking to your social profiles or sites. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/social-links)) - **Name:** core/social-links - **Category:** widgets diff --git a/docs/reference-guides/data/data-core-edit-site.md b/docs/reference-guides/data/data-core-edit-site.md index a2bc9ea1bfb968..1f050ca98576a3 100644 --- a/docs/reference-guides/data/data-core-edit-site.md +++ b/docs/reference-guides/data/data-core-edit-site.md @@ -371,7 +371,7 @@ Resolves the template for a page and displays both. If no path is given, attempt _Returns_ -- `number`: The resolved template ID for the page route. +- `Object`: Action object. ### setTemplate 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 00b1f7971f3d91..0377f6a3c3e05d 100644 --- a/docs/reference-guides/theme-json-reference/theme-json-living.md +++ b/docs/reference-guides/theme-json-reference/theme-json-living.md @@ -185,6 +185,7 @@ Settings related to typography. | fluid | undefined | false | | | letterSpacing | boolean | true | | | lineHeight | boolean | false | | +| textAlign | boolean | true | | | textColumns | boolean | false | | | textDecoration | boolean | true | | | writingMode | boolean | false | | @@ -268,6 +269,7 @@ Typography styles. | fontWeight | string, object | | | letterSpacing | string, object | | | lineHeight | string, object | | +| textAlign | string | | | textColumns | string | | | textDecoration | string, object | | | writingMode | string, object | | diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 2403583c66156b..554a88b4eeec3f 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -292,32 +292,32 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support 'declarations' => array( 'max-width' => 'none' ), ) ); + } - if ( isset( $block_spacing ) ) { - $block_spacing_values = gutenberg_style_engine_get_styles( - array( - 'spacing' => $block_spacing, - ) - ); + if ( isset( $block_spacing ) ) { + $block_spacing_values = gutenberg_style_engine_get_styles( + array( + 'spacing' => $block_spacing, + ) + ); - /* - * Handle negative margins for alignfull children of blocks with custom padding set. - * 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']; - $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']; - $layout_styles[] = array( - 'selector' => "$selector > .alignfull", - 'declarations' => array( 'margin-left' => "calc($padding_left * -1)" ), - ); - } + /* + * Handle negative margins for alignfull children of blocks with custom padding set. + * 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']; + $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']; + $layout_styles[] = array( + 'selector' => "$selector > .alignfull", + 'declarations' => array( 'margin-left' => "calc($padding_left * -1)" ), + ); } } diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index 8fceda4d5daba0..fa2a7b81e94e21 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -26,6 +26,7 @@ function gutenberg_register_typography_support( $block_type ) { $has_font_weight_support = $typography_supports['__experimentalFontWeight'] ?? false; $has_letter_spacing_support = $typography_supports['__experimentalLetterSpacing'] ?? false; $has_line_height_support = $typography_supports['lineHeight'] ?? false; + $has_text_align_support = $typography_supports['textAlign'] ?? false; $has_text_columns_support = $typography_supports['textColumns'] ?? false; $has_text_decoration_support = $typography_supports['__experimentalTextDecoration'] ?? false; $has_text_transform_support = $typography_supports['__experimentalTextTransform'] ?? false; @@ -37,6 +38,7 @@ function gutenberg_register_typography_support( $block_type ) { || $has_font_weight_support || $has_letter_spacing_support || $has_line_height_support + || $has_text_align_support || $has_text_columns_support || $has_text_decoration_support || $has_text_transform_support @@ -95,6 +97,7 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) { $has_font_weight_support = $typography_supports['__experimentalFontWeight'] ?? false; $has_letter_spacing_support = $typography_supports['__experimentalLetterSpacing'] ?? false; $has_line_height_support = $typography_supports['lineHeight'] ?? false; + $has_text_align_support = $typography_supports['textAlign'] ?? false; $has_text_columns_support = $typography_supports['textColumns'] ?? false; $has_text_decoration_support = $typography_supports['__experimentalTextDecoration'] ?? false; $has_text_transform_support = $typography_supports['__experimentalTextTransform'] ?? false; @@ -106,6 +109,7 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) { $should_skip_font_style = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontStyle' ); $should_skip_font_weight = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontWeight' ); $should_skip_line_height = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'lineHeight' ); + $should_skip_text_align = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'textAlign' ); $should_skip_text_columns = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'textColumns' ); $should_skip_text_decoration = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'textDecoration' ); $should_skip_text_transform = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'textTransform' ); @@ -143,6 +147,10 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) { $typography_block_styles['lineHeight'] = $block_attributes['style']['typography']['lineHeight'] ?? null; } + if ( $has_text_align_support && ! $should_skip_text_align ) { + $typography_block_styles['textAlign'] = $block_attributes['style']['typography']['textAlign'] ?? null; + } + if ( $has_text_columns_support && ! $should_skip_text_columns && isset( $block_attributes['style']['typography']['textColumns'] ) ) { $typography_block_styles['textColumns'] = $block_attributes['style']['typography']['textColumns'] ?? null; } @@ -167,13 +175,22 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) { } $attributes = array(); + $classnames = array(); $styles = gutenberg_style_engine_get_styles( array( 'typography' => $typography_block_styles ), array( 'convert_vars_to_classnames' => true ) ); if ( ! empty( $styles['classnames'] ) ) { - $attributes['class'] = $styles['classnames']; + $classnames[] = $styles['classnames']; + } + + if ( $has_text_align_support && ! $should_skip_text_align && isset( $block_attributes['style']['typography']['textAlign'] ) ) { + $classnames[] = 'has-text-align-' . $block_attributes['style']['typography']['textAlign']; + } + + if ( ! empty( $classnames ) ) { + $attributes['class'] = implode( ' ', $classnames ); } if ( ! empty( $styles['css'] ) ) { diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index aafc20a2debd51..a665235d7e774e 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -244,6 +244,7 @@ class WP_Theme_JSON_Gutenberg { 'border-left-width' => array( 'border', 'left', 'width' ), 'border-left-style' => array( 'border', 'left', 'style' ), 'color' => array( 'color', 'text' ), + 'text-align' => array( 'typography', 'textAlign' ), 'column-count' => array( 'typography', 'textColumns' ), 'font-family' => array( 'typography', 'fontFamily' ), 'font-size' => array( 'typography', 'fontSize' ), @@ -436,6 +437,7 @@ class WP_Theme_JSON_Gutenberg { 'fontWeight' => null, 'letterSpacing' => null, 'lineHeight' => null, + 'textAlign' => null, 'textColumns' => null, 'textDecoration' => null, 'textTransform' => null, @@ -531,6 +533,7 @@ class WP_Theme_JSON_Gutenberg { 'fontWeight' => null, 'letterSpacing' => null, 'lineHeight' => null, + 'textAlign' => null, 'textColumns' => null, 'textDecoration' => null, 'textTransform' => null, diff --git a/lib/global-styles-and-settings.php b/lib/global-styles-and-settings.php index 9419ae4a716b98..70b3f7078e62ac 100644 --- a/lib/global-styles-and-settings.php +++ b/lib/global-styles-and-settings.php @@ -207,7 +207,7 @@ function gutenberg_get_global_styles_base_custom_css() { * * @since 6.6.0 * - * @global WP_Styles $wp_styles + * @global WP_Styles $wp_styles */ function gutenberg_add_global_styles_block_custom_css() { global $wp_styles; @@ -247,9 +247,9 @@ function gutenberg_add_global_styles_block_custom_css() { /** * Adds global style rules to the inline style for each block. * - * @return void - * * @global WP_Styles $wp_styles + * + * @return void */ function gutenberg_add_global_styles_for_blocks() { global $wp_styles; diff --git a/lib/theme.json b/lib/theme.json index 2e40ccadffef85..ece76b5f63cb29 100644 --- a/lib/theme.json +++ b/lib/theme.json @@ -263,6 +263,7 @@ "fontWeight": true, "letterSpacing": true, "lineHeight": false, + "textAlign": false, "textColumns": false, "textDecoration": true, "textTransform": true, diff --git a/package-lock.json b/package-lock.json index cbe3fc949f69df..a225b5e1c111b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gutenberg", - "version": "18.1.0", + "version": "18.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "gutenberg", - "version": "18.1.0", + "version": "18.1.1", "hasInstallScript": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -54088,7 +54088,6 @@ "@wordpress/hooks": "file:../hooks", "@wordpress/i18n": "file:../i18n", "@wordpress/icons": "file:../icons", - "@wordpress/interface": "file:../interface", "@wordpress/keyboard-shortcuts": "file:../keyboard-shortcuts", "@wordpress/keycodes": "file:../keycodes", "@wordpress/media-utils": "file:../media-utils", @@ -54141,7 +54140,6 @@ "@wordpress/html-entities": "file:../html-entities", "@wordpress/i18n": "file:../i18n", "@wordpress/icons": "file:../icons", - "@wordpress/interface": "file:../interface", "@wordpress/keyboard-shortcuts": "file:../keyboard-shortcuts", "@wordpress/keycodes": "file:../keycodes", "@wordpress/media-utils": "file:../media-utils", @@ -54243,6 +54241,7 @@ "@wordpress/html-entities": "file:../html-entities", "@wordpress/i18n": "file:../i18n", "@wordpress/icons": "file:../icons", + "@wordpress/interface": "file:../interface", "@wordpress/keyboard-shortcuts": "file:../keyboard-shortcuts", "@wordpress/keycodes": "file:../keycodes", "@wordpress/media-utils": "file:../media-utils", @@ -69193,7 +69192,6 @@ "@wordpress/hooks": "file:../hooks", "@wordpress/i18n": "file:../i18n", "@wordpress/icons": "file:../icons", - "@wordpress/interface": "file:../interface", "@wordpress/keyboard-shortcuts": "file:../keyboard-shortcuts", "@wordpress/keycodes": "file:../keycodes", "@wordpress/media-utils": "file:../media-utils", @@ -69237,7 +69235,6 @@ "@wordpress/html-entities": "file:../html-entities", "@wordpress/i18n": "file:../i18n", "@wordpress/icons": "file:../icons", - "@wordpress/interface": "file:../interface", "@wordpress/keyboard-shortcuts": "file:../keyboard-shortcuts", "@wordpress/keycodes": "file:../keycodes", "@wordpress/media-utils": "file:../media-utils", @@ -69321,6 +69318,7 @@ "@wordpress/html-entities": "file:../html-entities", "@wordpress/i18n": "file:../i18n", "@wordpress/icons": "file:../icons", + "@wordpress/interface": "file:../interface", "@wordpress/keyboard-shortcuts": "file:../keyboard-shortcuts", "@wordpress/keycodes": "file:../keycodes", "@wordpress/media-utils": "file:../media-utils", diff --git a/package.json b/package.json index c7043fa9cc06e6..2d4fd09fd87ea1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "18.1.0", + "version": "18.1.1", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", diff --git a/packages/block-editor/src/components/block-inspector/index.js b/packages/block-editor/src/components/block-inspector/index.js index 136cdef91286e2..5c52ca62e01d69 100644 --- a/packages/block-editor/src/components/block-inspector/index.js +++ b/packages/block-editor/src/components/block-inspector/index.js @@ -300,7 +300,7 @@ const BlockInspectorSingleBlock = ( { clientId, blockName } ) => {
diff --git a/packages/block-editor/src/components/block-variation-transforms/index.js b/packages/block-editor/src/components/block-variation-transforms/index.js index f005515a63f17b..bcaf7f9f6662ba 100644 --- a/packages/block-editor/src/components/block-variation-transforms/index.js +++ b/packages/block-editor/src/components/block-variation-transforms/index.js @@ -116,7 +116,9 @@ function VariationsToggleGroupControl( { { variations.map( ( variation ) => ( + } value={ variation.name } label={ selectedValue === variation.name 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 c1354bbc4a4e14..ef1f9673d601f9 100644 --- a/packages/block-editor/src/components/global-styles/background-panel.js +++ b/packages/block-editor/src/components/global-styles/background-panel.js @@ -40,6 +40,10 @@ import MediaReplaceFlow from '../media-replace-flow'; import { store as blockEditorStore } from '../../store'; const IMAGE_BACKGROUND_TYPE = 'image'; +const DEFAULT_CONTROLS = { + backgroundImage: true, + backgroundSize: false, +}; /** * Checks site settings to see if the background panel may be used. @@ -135,28 +139,30 @@ export const backgroundPositionToCoords = ( value ) => { }; function InspectorImagePreview( { label, filename, url: imgUrl } ) { - const imgLabel = label || getFilename( imgUrl ); + const imgLabel = + label || getFilename( imgUrl ) || __( 'Add background image' ); + return ( - - - { imgUrl && ( + + { imgUrl && ( + - ) } - + + ) } { mediaUpload( { - allowedTypes: [ 'image' ], + allowedTypes: [ IMAGE_BACKGROUND_TYPE ], filesList, onFileChange( [ image ] ) { if ( isBlobURL( image?.url ) ) { @@ -295,7 +301,7 @@ function BackgroundImageToolsPanelItem( { onSelect={ onSelectMedia } name={ @@ -518,6 +524,7 @@ function BackgroundToolsPanel( { value, panelId, children, + headerLabel, } ) { const resetAll = () => { const updatedValue = resetAllFilter( value ); @@ -527,8 +534,8 @@ function BackgroundToolsPanel( { return ( { return { @@ -568,6 +571,7 @@ export default function BackgroundPanel( { value={ value } onChange={ onChange } panelId={ panelId } + headerLabel={ headerLabel } > { /> hasBorderSupport( nameOrType, 'color' ), backgroundColor: hasBackgroundColorSupport, + textAlign: hasTextAlignSupport, textColor: hasTextColorSupport, gradient: hasGradientSupport, className: hasCustomClassNameSupport, diff --git a/packages/block-editor/src/hooks/index.js b/packages/block-editor/src/hooks/index.js index 0c7c59b20ec674..ec5cf29b49c5a6 100644 --- a/packages/block-editor/src/hooks/index.js +++ b/packages/block-editor/src/hooks/index.js @@ -21,6 +21,7 @@ import dimensions from './dimensions'; import duotone from './duotone'; import fontFamily from './font-family'; import fontSize from './font-size'; +import textAlign from './text-align'; import border from './border'; import position from './position'; import layout from './layout'; @@ -34,6 +35,7 @@ import './use-bindings-attributes'; createBlockEditFilter( [ align, + textAlign, anchor, customClassName, style, @@ -47,6 +49,7 @@ createBlockEditFilter( ); createBlockListBlockFilter( [ align, + textAlign, background, style, color, @@ -60,6 +63,7 @@ createBlockListBlockFilter( [ ] ); createBlockSaveFilter( [ align, + textAlign, anchor, ariaLabel, customClassName, diff --git a/packages/block-editor/src/hooks/supports.js b/packages/block-editor/src/hooks/supports.js index 4e116494029bf1..75f2bdf2dc219e 100644 --- a/packages/block-editor/src/hooks/supports.js +++ b/packages/block-editor/src/hooks/supports.js @@ -20,6 +20,11 @@ const FONT_STYLE_SUPPORT_KEY = 'typography.__experimentalFontStyle'; * Key within block settings' support array indicating support for font weight. */ const FONT_WEIGHT_SUPPORT_KEY = 'typography.__experimentalFontWeight'; +/** + * Key within block settings' supports array indicating support for text + * align e.g. settings found in `block.json`. + */ +const TEXT_ALIGN_SUPPORT_KEY = 'typography.textAlign'; /** * Key within block settings' supports array indicating support for text * columns e.g. settings found in `block.json`. @@ -53,6 +58,7 @@ const TYPOGRAPHY_SUPPORT_KEYS = [ FONT_STYLE_SUPPORT_KEY, FONT_WEIGHT_SUPPORT_KEY, FONT_FAMILY_SUPPORT_KEY, + TEXT_ALIGN_SUPPORT_KEY, TEXT_COLUMNS_SUPPORT_KEY, TEXT_DECORATION_SUPPORT_KEY, TEXT_TRANSFORM_SUPPORT_KEY, @@ -212,6 +218,24 @@ export const hasBackgroundColorSupport = ( nameOrType ) => { return colorSupport && colorSupport.background !== false; }; +/** + * Returns true if the block defines support for text-align. + * + * @param {string|Object} nameOrType Block name or type object. + * @return {boolean} Whether the block supports the feature. + */ +export const hasTextAlignSupport = ( nameOrType ) => + hasBlockSupport( nameOrType, TEXT_ALIGN_SUPPORT_KEY ); + +/** + * Returns the block support value for text-align, if defined. + * + * @param {string|Object} nameOrType Block name or type object. + * @return {unknown} The block support value. + */ +export const getTextAlignSupport = ( nameOrType ) => + getBlockSupport( nameOrType, TEXT_ALIGN_SUPPORT_KEY ); + /** * Returns true if the block defines support for background color. * diff --git a/packages/block-editor/src/hooks/test/text-align.js b/packages/block-editor/src/hooks/test/text-align.js new file mode 100644 index 00000000000000..3b7d338193b30b --- /dev/null +++ b/packages/block-editor/src/hooks/test/text-align.js @@ -0,0 +1,114 @@ +/** + * WordPress dependencies + */ +import { + getBlockTypes, + registerBlockType, + unregisterBlockType, +} from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import { getValidTextAlignments, addAssignedTextAlign } from '../text-align'; + +const noop = () => {}; + +describe( 'textAlign', () => { + const blockSettings = { + save: noop, + category: 'text', + title: 'block title', + edit: ( { children } ) => <>{ children }, + }; + + afterEach( () => { + getBlockTypes().forEach( ( block ) => { + unregisterBlockType( block.name ); + } ); + } ); + + describe( 'getValidTextAlignments()', () => { + it( 'should return an empty array if block does not define align support', () => { + expect( getValidTextAlignments() ).toEqual( [] ); + } ); + + it( 'should return all custom text aligns set', () => { + expect( getValidTextAlignments( [ 'left', 'right' ] ) ).toEqual( [ + 'left', + 'right', + ] ); + } ); + + it( 'should return all text aligns sorted when provided in the random order', () => { + expect( + getValidTextAlignments( [ 'right', 'center', 'left' ] ) + ).toEqual( [ 'left', 'center', 'right' ] ); + } ); + + it( 'should return all text aligns if block defines text align support as true', () => { + expect( getValidTextAlignments( true ) ).toEqual( [ + 'left', + 'center', + 'right', + ] ); + } ); + + it( 'should remove incorrect text aligns', () => { + expect( + getValidTextAlignments( [ 'left', 'right', 'justify' ] ) + ).toEqual( [ 'left', 'right' ] ); + } ); + } ); + + describe( 'addAssignedTextAlign', () => { + it( 'should do nothing if block does not support text align', () => { + registerBlockType( 'core/foo', blockSettings ); + + const props = addAssignedTextAlign( + { + className: 'foo', + }, + 'core/foo', + { + typography: { + textAlign: 'center', + }, + } + ); + + expect( props ).toEqual( { + className: 'foo', + } ); + } ); + + it( 'should do add text align classname if block supports text align', () => { + registerBlockType( 'core/foo', { + ...blockSettings, + supports: { + typography: { + textAlign: true, + }, + }, + } ); + + const props = addAssignedTextAlign( + { + className: 'foo', + }, + 'core/foo', + { + style: { + typography: { + textAlign: 'center', + }, + }, + } + ); + + expect( props ).toEqual( { + className: 'has-text-align-center foo', + } ); + } ); + } ); +} ); diff --git a/packages/block-editor/src/hooks/test/use-typography-props.js b/packages/block-editor/src/hooks/test/use-typography-props.js index 77b2e0cdf33cb7..c226b7f8199b9f 100644 --- a/packages/block-editor/src/hooks/test/use-typography-props.js +++ b/packages/block-editor/src/hooks/test/use-typography-props.js @@ -12,13 +12,15 @@ describe( 'getTypographyClassesAndStyles', () => { typography: { letterSpacing: '22px', fontSize: '2rem', + textAlign: 'center', textColumns: 3, textTransform: 'uppercase', }, }, }; expect( getTypographyClassesAndStyles( attributes ) ).toEqual( { - className: 'has-tofu-font-family has-large-font-size', + className: + 'has-tofu-font-family has-text-align-center has-large-font-size', style: { columnCount: 3, letterSpacing: '22px', diff --git a/packages/block-editor/src/hooks/text-align.js b/packages/block-editor/src/hooks/text-align.js new file mode 100644 index 00000000000000..daa8df6cc82106 --- /dev/null +++ b/packages/block-editor/src/hooks/text-align.js @@ -0,0 +1,178 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { getBlockSupport, hasBlockSupport } from '@wordpress/blocks'; +import { alignLeft, alignRight, alignCenter } from '@wordpress/icons'; + +/** + * Internal dependencies + */ +import { AlignmentControl, BlockControls } from '../components'; +import { useBlockEditingMode } from '../components/block-editing-mode'; +import { cleanEmptyObject, shouldSkipSerialization } from './utils'; +import { TYPOGRAPHY_SUPPORT_KEY } from './typography'; + +export const TEXT_ALIGN_SUPPORT_KEY = 'typography.textAlign'; + +const TEXT_ALIGNMENT_OPTIONS = [ + { + icon: alignLeft, + title: __( 'Align text left' ), + align: 'left', + }, + { + icon: alignCenter, + title: __( 'Align text center' ), + align: 'center', + }, + { + icon: alignRight, + title: __( 'Align text right' ), + align: 'right', + }, +]; + +const VALID_TEXT_ALIGNMENTS = [ 'left', 'center', 'right' ]; + +/** + * Returns the valid text alignments. + * Takes into consideration the text aligns supported by a block. + * Exported just for testing purposes, not exported outside the module. + * + * @param {?boolean|string[]} blockTextAlign Text aligns supported by the block. + * + * @return {string[]} Valid text alignments. + */ +export function getValidTextAlignments( blockTextAlign ) { + let validTextAlignments; + if ( Array.isArray( blockTextAlign ) ) { + validTextAlignments = VALID_TEXT_ALIGNMENTS.filter( ( textAlign ) => + blockTextAlign.includes( textAlign ) + ); + } else if ( blockTextAlign === true ) { + // `true` includes all alignments... + validTextAlignments = [ ...VALID_TEXT_ALIGNMENTS ]; + } else { + validTextAlignments = []; + } + + return validTextAlignments; +} + +function BlockEditTextAlignmentToolbarControlsPure( { + style, + name: blockName, + setAttributes, +} ) { + const validTextAlignments = getValidTextAlignments( + getBlockSupport( blockName, TEXT_ALIGN_SUPPORT_KEY ) + ); + const blockEditingMode = useBlockEditingMode(); + if ( ! validTextAlignments.length || blockEditingMode !== 'default' ) { + return null; + } + + const textAlignmentControls = TEXT_ALIGNMENT_OPTIONS.filter( ( control ) => + validTextAlignments.includes( control.align ) + ); + + const onChange = ( newTextAlignValue ) => { + const newStyle = { + ...style, + typography: { + ...style?.typography, + textAlign: newTextAlignValue, + }, + }; + + setAttributes( { style: cleanEmptyObject( newStyle ) } ); + }; + + return ( + + + + ); +} + +export default { + edit: BlockEditTextAlignmentToolbarControlsPure, + useBlockProps, + addSaveProps: addAssignedTextAlign, + attributeKeys: [ 'style' ], + hasSupport( name ) { + return hasBlockSupport( name, TEXT_ALIGN_SUPPORT_KEY, false ); + }, +}; + +function useBlockProps( { name, style } ) { + if ( ! style?.typography?.textAlign ) { + return null; + } + + const validTextAlignments = getValidTextAlignments( + getBlockSupport( name, TEXT_ALIGN_SUPPORT_KEY ) + ); + + if ( ! validTextAlignments.length ) { + return null; + } + + if ( + shouldSkipSerialization( name, TYPOGRAPHY_SUPPORT_KEY, 'textAlign' ) + ) { + return null; + } + + const textAlign = style.typography.textAlign; + + const className = classnames( { + [ `has-text-align-${ textAlign }` ]: textAlign, + } ); + return { className }; +} + +/** + * Override props assigned to save component to inject text alignment class + * name if block supports it. + * + * @param {Object} props Additional props applied to save element. + * @param {Object} blockType Block type. + * @param {Object} attributes Block attributes. + * + * @return {Object} Filtered props applied to save element. + */ +export function addAssignedTextAlign( props, blockType, attributes ) { + if ( ! attributes?.style?.typography?.textAlign ) { + return props; + } + + const { textAlign } = attributes.style.typography; + const blockTextAlign = getBlockSupport( blockType, TEXT_ALIGN_SUPPORT_KEY ); + const isTextAlignValid = + getValidTextAlignments( blockTextAlign ).includes( textAlign ); + if ( + isTextAlignValid && + ! shouldSkipSerialization( + blockType, + TYPOGRAPHY_SUPPORT_KEY, + 'textAlign' + ) + ) { + props.className = classnames( + `has-text-align-${ textAlign }`, + props.className + ); + } + return props; +} diff --git a/packages/block-editor/src/hooks/typography.js b/packages/block-editor/src/hooks/typography.js index 12d0075527bec5..cf3f4327c8f034 100644 --- a/packages/block-editor/src/hooks/typography.js +++ b/packages/block-editor/src/hooks/typography.js @@ -17,6 +17,7 @@ import { import { LINE_HEIGHT_SUPPORT_KEY } from './line-height'; import { FONT_FAMILY_SUPPORT_KEY } from './font-family'; import { FONT_SIZE_SUPPORT_KEY } from './font-size'; +import { TEXT_ALIGN_SUPPORT_KEY } from './text-align'; import { cleanEmptyObject } from './utils'; import { store as blockEditorStore } from '../store'; @@ -40,6 +41,7 @@ export const TYPOGRAPHY_SUPPORT_KEYS = [ FONT_STYLE_SUPPORT_KEY, FONT_WEIGHT_SUPPORT_KEY, FONT_FAMILY_SUPPORT_KEY, + TEXT_ALIGN_SUPPORT_KEY, TEXT_COLUMNS_SUPPORT_KEY, TEXT_DECORATION_SUPPORT_KEY, WRITING_MODE_SUPPORT_KEY, diff --git a/packages/block-editor/src/hooks/use-typography-props.js b/packages/block-editor/src/hooks/use-typography-props.js index a63f77468c7233..3986bbf7cfe17e 100644 --- a/packages/block-editor/src/hooks/use-typography-props.js +++ b/packages/block-editor/src/hooks/use-typography-props.js @@ -45,9 +45,12 @@ export function getTypographyClassesAndStyles( attributes, settings ) { const fontFamilyClassName = !! attributes?.fontFamily ? `has-${ kebabCase( attributes.fontFamily ) }-font-family` : ''; - + const textAlignClassName = !! attributes?.style?.typography?.textAlign + ? `has-text-align-${ attributes?.style?.typography?.textAlign }` + : ''; const className = classnames( fontFamilyClassName, + textAlignClassName, getFontSizeClass( attributes?.fontSize ) ); diff --git a/packages/block-editor/src/hooks/utils.js b/packages/block-editor/src/hooks/utils.js index 6d75f2c2a686d2..2148b2bb8e5ce7 100644 --- a/packages/block-editor/src/hooks/utils.js +++ b/packages/block-editor/src/hooks/utils.js @@ -220,6 +220,7 @@ export function useBlockSettings( name, parentLayout ) { fontStyle, fontWeight, lineHeight, + textAlign, textColumns, textDecoration, writingMode, @@ -271,6 +272,7 @@ export function useBlockSettings( name, parentLayout ) { 'typography.fontStyle', 'typography.fontWeight', 'typography.lineHeight', + 'typography.textAlign', 'typography.textColumns', 'typography.textDecoration', 'typography.writingMode', @@ -360,6 +362,7 @@ export function useBlockSettings( name, parentLayout ) { fontStyle, fontWeight, lineHeight, + textAlign, textColumns, textDecoration, textTransform, @@ -402,6 +405,7 @@ export function useBlockSettings( name, parentLayout ) { fontStyle, fontWeight, lineHeight, + textAlign, textColumns, textDecoration, textTransform, diff --git a/packages/block-library/src/block/test/edit.native.js b/packages/block-library/src/block/test/edit.native.js index 0b719dd06609df..f184fa164ce71b 100644 --- a/packages/block-library/src/block/test/edit.native.js +++ b/packages/block-library/src/block/test/edit.native.js @@ -45,6 +45,7 @@ const getMockedReusableBlock = ( id ) => ( { title: { raw: `Reusable block - ${ id }` }, type: 'wp_block', meta: { footnotes: '' }, + wp_pattern_category: [], } ); beforeAll( () => { diff --git a/packages/block-library/src/cover/editor.scss b/packages/block-library/src/cover/editor.scss index 4e2a07ffe8e4ee..6aa10657ec6f2e 100644 --- a/packages/block-library/src/cover/editor.scss +++ b/packages/block-library/src/cover/editor.scss @@ -30,9 +30,18 @@ } // Applied while media is being uploaded - &.is-transient::before { - background-color: #fff; - opacity: 0.3; + &.is-transient { + position: relative; + + &::before { + background-color: #fff; + content: ""; + height: 100%; + opacity: 0.3; + position: absolute; + width: 100%; + z-index: 1; + } } // Shown while media is being uploaded diff --git a/packages/block-library/src/latest-posts/edit.js b/packages/block-library/src/latest-posts/edit.js index 0efe538b01f629..1ef7bd5e5fed7b 100644 --- a/packages/block-library/src/latest-posts/edit.js +++ b/packages/block-library/src/latest-posts/edit.js @@ -431,7 +431,7 @@ export default function LatestPostsEdit( { attributes, setAttributes } ) { const dateFormat = getSettings().formats.date; return ( -
+ <> { inspectorControls } @@ -518,7 +518,6 @@ export default function LatestPostsEdit( { attributes, setAttributes } ) {
{ addLinkToFeaturedImage ? ( ) } -
+ ); } diff --git a/packages/block-library/src/latest-posts/index.php b/packages/block-library/src/latest-posts/index.php index 6bff971beef576..913a9ae2d430e1 100644 --- a/packages/block-library/src/latest-posts/index.php +++ b/packages/block-library/src/latest-posts/index.php @@ -157,7 +157,7 @@ function render_block_core_latest_posts( $attributes ) { $trimmed_excerpt = substr( $trimmed_excerpt, 0, -11 ); $trimmed_excerpt .= sprintf( /* translators: 1: A URL to a post, 2: Hidden accessibility text: Post title */ - __( '… Read more: %2$s' ), + __( '… Read more: %2$s' ), esc_url( $post_link ), esc_html( $title ) ); diff --git a/packages/block-library/src/post-featured-image/dimension-controls.js b/packages/block-library/src/post-featured-image/dimension-controls.js index 3c380d3dfe0125..d59d586eb04b4a 100644 --- a/packages/block-library/src/post-featured-image/dimension-controls.js +++ b/packages/block-library/src/post-featured-image/dimension-controls.js @@ -10,7 +10,11 @@ import { __experimentalUseCustomUnits as useCustomUnits, __experimentalToolsPanelItem as ToolsPanelItem, } from '@wordpress/components'; -import { InspectorControls, useSettings } from '@wordpress/block-editor'; +import { + useSettings, + store as blockEditorStore, +} from '@wordpress/block-editor'; +import { useSelect } from '@wordpress/data'; const SCALE_OPTIONS = ( <> @@ -51,12 +55,25 @@ const DimensionControls = ( { clientId, attributes: { aspectRatio, width, height, scale, sizeSlug }, setAttributes, - imageSizeOptions = [], + media, } ) => { const [ availableUnits ] = useSettings( 'spacing.units' ); const units = useCustomUnits( { availableUnits: availableUnits || [ 'px', '%', 'vw', 'em', 'rem' ], } ); + const imageSizes = useSelect( + ( select ) => select( blockEditorStore ).getSettings().imageSizes, + [] + ); + const imageSizeOptions = imageSizes + .filter( ( { slug } ) => { + return media?.media_details?.sizes?.[ slug ]?.source_url; + } ) + .map( ( { name, slug } ) => ( { + value: slug, + label: name, + } ) ); + const onDimensionChange = ( dimension, nextValue ) => { const parsedValue = parseFloat( nextValue ); /** @@ -75,7 +92,7 @@ const DimensionControls = ( { height || ( aspectRatio && aspectRatio !== 'auto' ); return ( - + <> !! aspectRatio } label={ __( 'Aspect ratio' ) } @@ -230,7 +247,7 @@ const DimensionControls = ( { /> ) } - + ); }; diff --git a/packages/block-library/src/post-featured-image/edit.js b/packages/block-library/src/post-featured-image/edit.js index d1d03c0d4b52a1..14e9bfdc74a87b 100644 --- a/packages/block-library/src/post-featured-image/edit.js +++ b/packages/block-library/src/post-featured-image/edit.js @@ -6,6 +6,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ +import { isBlobURL } from '@wordpress/blob'; import { useEntityProp, store as coreStore } from '@wordpress/core-data'; import { useSelect, useDispatch } from '@wordpress/data'; import { @@ -14,6 +15,7 @@ import { PanelBody, Placeholder, Button, + Spinner, TextControl, } from '@wordpress/components'; import { @@ -22,12 +24,11 @@ import { MediaPlaceholder, MediaReplaceFlow, useBlockProps, - store as blockEditorStore, __experimentalUseBorderProps as useBorderProps, __experimentalGetShadowClassesAndStyles as getShadowClassesAndStyles, useBlockEditingMode, } from '@wordpress/block-editor'; -import { useMemo } from '@wordpress/element'; +import { useMemo, useEffect, useState } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; import { upload } from '@wordpress/icons'; import { store as noticesStore } from '@wordpress/notices'; @@ -70,6 +71,7 @@ export default function PostFeaturedImageEdit( { linkTarget, useFirstImageFromPost, } = attributes; + const [ temporaryURL, setTemporaryURL ] = useState(); const [ storedFeaturedImage, setFeaturedImage ] = useEntityProp( 'postType', @@ -129,21 +131,11 @@ export default function PostFeaturedImageEdit( { const mediaUrl = getMediaSourceUrlBySizeSlug( media, sizeSlug ); - const imageSizes = useSelect( - ( select ) => select( blockEditorStore ).getSettings().imageSizes, - [] - ); - const imageSizeOptions = imageSizes - .filter( ( { slug } ) => { - return media?.media_details?.sizes?.[ slug ]?.source_url; - } ) - .map( ( { name, slug } ) => ( { - value: slug, - label: name, - } ) ); - const blockProps = useBlockProps( { style: { width, height, aspectRatio }, + className: classnames( { + 'is-transient': temporaryURL, + } ), } ); const borderProps = useBorderProps( attributes ); const shadowProps = getShadowClassesAndStyles( attributes ); @@ -173,26 +165,42 @@ export default function PostFeaturedImageEdit( { if ( value?.id ) { setFeaturedImage( value.id ); } + + if ( value?.url && isBlobURL( value.url ) ) { + setTemporaryURL( value.url ); + } }; + // Reset temporary url when media is available. + useEffect( () => { + if ( mediaUrl && temporaryURL ) { + setTemporaryURL(); + } + }, [ mediaUrl, temporaryURL ] ); + const { createErrorNotice } = useDispatch( noticesStore ); const onUploadError = ( message ) => { createErrorNotice( message, { type: 'snackbar' } ); + setTemporaryURL(); }; const controls = blockEditingMode === 'default' && ( <> - - + + + + + + - ); + image = + ! media && ! temporaryURL ? ( + placeholder() + ) : ( + <> + { + { temporaryURL && } + + ); } /** @@ -343,7 +355,7 @@ export default function PostFeaturedImageEdit( { */ return ( <> - { controls } + { ! temporaryURL && controls } { !! media && ! isDescendentOfQueryLoop && ( { const { dimRatio } = attributes; - const { gradientValue, setGradient } = __experimentalUseGradient(); + const { gradientValue, setGradient } = useGradient(); const colorGradientSettings = useMultipleOriginColorsAndGradients(); if ( ! colorGradientSettings.hasColorsOrGradients ) { @@ -31,7 +30,7 @@ const Overlay = ( { } return ( - + <> - + ); }; diff --git a/packages/block-library/src/query/edit/enhanced-pagination-modal.js b/packages/block-library/src/query/edit/enhanced-pagination-modal.js index 0411363e6e1a10..21838184f6bd6a 100644 --- a/packages/block-library/src/query/edit/enhanced-pagination-modal.js +++ b/packages/block-library/src/query/edit/enhanced-pagination-modal.js @@ -43,7 +43,7 @@ export default function EnhancedPaginationModal( { if ( hasBlocksFromPlugins ) { notice = __( - 'Currently, avoiding full page reloads is not possible when non-interactive or non-clientNavigation compatible blocks from plugins are present inside the Query block.' + 'Currently, avoiding full page reloads is not possible when non-interactive or non-client Navigation compatible blocks from plugins are present inside the Query block.' ) + ' ' + notice; diff --git a/packages/block-library/src/separator/style.scss b/packages/block-library/src/separator/style.scss index 84622211e5a207..d40dd2f05844ed 100644 --- a/packages/block-library/src/separator/style.scss +++ b/packages/block-library/src/separator/style.scss @@ -1,12 +1,4 @@ .wp-block-separator { - border-top: 2px solid currentColor; - // Default, thin style, is stored in theme.scss so it can be opted out of - - // Unset the left, right and bottom borders by default, otherwise some browsers will render them as "inset". - border-left: none; - border-right: none; - border-bottom: none; - // Dots style &.is-style-dots { // Override any background themes often set on the hr tag for this style. @@ -28,3 +20,14 @@ } } } + +// Lowest specificity to avoid overriding global styles. +:where(.wp-block-separator) { + border-top: 2px solid currentColor; + // Default, thin style, is stored in theme.scss so it can be opted out of + + // Unset the left, right and bottom borders by default, otherwise some browsers will render them as "inset". + border-left: none; + border-right: none; + border-bottom: none; +} diff --git a/packages/block-library/src/site-logo/edit.js b/packages/block-library/src/site-logo/edit.js index fc4bcae2d2b0f3..af7ae6f7a8f120 100644 --- a/packages/block-library/src/site-logo/edit.js +++ b/packages/block-library/src/site-logo/edit.js @@ -73,9 +73,7 @@ const SiteLogo = ( { const [ { naturalWidth, naturalHeight }, setNaturalSize ] = useState( {} ); const [ isEditingImage, setIsEditingImage ] = useState( false ); const { toggleSelection } = useDispatch( blockEditorStore ); - const classes = classnames( 'custom-logo-link', { - 'is-transient': isBlobURL( logoUrl ), - } ); + const classes = classnames( 'custom-logo-link' ); const { imageEditing, maxWidth, title } = useSelect( ( select ) => { const settings = select( blockEditorStore ).getSettings(); const siteEntities = select( coreStore ).getEntityRecord( @@ -113,17 +111,20 @@ const SiteLogo = ( { } const img = ( - { { - setNaturalSize( { - naturalWidth: event.target.naturalWidth, - naturalHeight: event.target.naturalHeight, - } ); - } } - /> + <> + { { + setNaturalSize( { + naturalWidth: event.target.naturalWidth, + naturalHeight: event.target.naturalHeight, + } ); + } } + /> + { isBlobURL( logoUrl ) && } + ); let imgWrapper = img; @@ -434,6 +435,7 @@ export default function LogoEdit( { }; }, [] ); const { getSettings } = useSelect( blockEditorStore ); + const [ temporaryURL, setTemporaryURL ] = useState(); const { editEntityRecord } = useDispatch( coreStore ); @@ -480,6 +482,7 @@ export default function LogoEdit( { if ( ! media.id && media.url ) { // This is a temporary blob image. + setTemporaryURL( media.url ); setLogo( undefined ); return; } @@ -495,6 +498,7 @@ export default function LogoEdit( { const { createErrorNotice } = useDispatch( noticesStore ); const onUploadError = ( message ) => { createErrorNotice( message, { type: 'snackbar' } ); + setTemporaryURL(); }; const onFilesDrop = ( filesList ) => { @@ -503,6 +507,7 @@ export default function LogoEdit( { filesList, onFileChange( [ image ] ) { if ( isBlobURL( image?.url ) ) { + setTemporaryURL( image.url ); return; } onInitialSelectLogo( image ); @@ -517,7 +522,7 @@ export default function LogoEdit( { onError: onUploadError, onRemoveLogo, }; - const controls = canUserEdit && logoUrl && ( + const controls = canUserEdit && logoUrl && ! temporaryURL && ( @@ -528,22 +533,32 @@ export default function LogoEdit( { if ( isLoading ) { logoImage = ; } - if ( !! logoUrl ) { + + // Reset temporary url when logoUrl is available. + useEffect( () => { + if ( logoUrl && temporaryURL ) { + setTemporaryURL(); + } + }, [ logoUrl, temporaryURL ] ); + + if ( !! logoUrl || !! temporaryURL ) { logoImage = ( - + <> + + ); } const placeholder = ( content ) => { @@ -568,6 +583,7 @@ export default function LogoEdit( { const classes = classnames( className, { 'is-default-size': ! width, + 'is-transient': temporaryURL, } ); const blockProps = useBlockProps( { className: classes } ); @@ -631,8 +647,8 @@ export default function LogoEdit( {
{ controls } { mediaInspectorPanel } - { !! logoUrl && logoImage } - { ! logoUrl && ! canUserEdit && ( + { ( !! logoUrl || !! temporaryURL ) && logoImage } + { ! temporaryURL && ! logoUrl && ! canUserEdit && ( { !! isLoading && ( @@ -641,7 +657,7 @@ export default function LogoEdit( { ) } ) } - { ! logoUrl && canUserEdit && ( + { ! temporaryURL && ! logoUrl && canUserEdit && ( setAttributes( { url: nextURL } ) } - placeholder={ __( 'Enter address' ) } + placeholder={ __( 'Enter social link' ) } + label={ __( 'Enter social link' ) } + hideLabelFromVision disableSuggestions onKeyDown={ ( event ) => { if ( @@ -91,7 +93,7 @@ const SocialLinkEdit = ( { setAttributes, clientId, } ) => { - const { url, service, label, rel } = attributes; + const { url, service, label = '', rel } = attributes; const { showLabels, iconColor, @@ -113,7 +115,12 @@ const SocialLinkEdit = ( { const IconComponent = getIconBySite( service ); const socialLinkName = getNameBySite( service ); - const socialLinkLabel = label ?? socialLinkName; + // The initial label (ie. the link text) is an empty string. + // We want to prevent empty links so that the link text always fallbacks to + // the social name, even when users enter and save an empty string or only + // spaces. The PHP render callback fallbacks to the social name as well. + const socialLinkText = label.trim() === '' ? socialLinkName : label; + const blockProps = useBlockProps( { className: classes, style: { @@ -125,25 +132,19 @@ const SocialLinkEdit = ( { return ( <> - + - setAttributes( { label: value || undefined } ) + setAttributes( { label: value } ) } + placeholder={ socialLinkName } /> @@ -168,18 +169,18 @@ const SocialLinkEdit = ( { 'screen-reader-text': ! showLabels, } ) } > - { socialLinkLabel } + { socialLinkText } - { isSelected && showURLPopover && ( - - ) } + { isSelected && showURLPopover && ( + + ) } ); diff --git a/packages/block-library/src/social-link/index.php b/packages/block-library/src/social-link/index.php index 69a145c0ff6028..5e2bc616d0e5ac 100644 --- a/packages/block-library/src/social-link/index.php +++ b/packages/block-library/src/social-link/index.php @@ -19,9 +19,11 @@ function render_block_core_social_link( $attributes, $content, $block ) { $open_in_new_tab = isset( $block->context['openInNewTab'] ) ? $block->context['openInNewTab'] : false; + $text = ! empty( $attributes['label'] ) ? trim( $attributes['label'] ) : ''; + $service = isset( $attributes['service'] ) ? $attributes['service'] : 'Icon'; $url = isset( $attributes['url'] ) ? $attributes['url'] : false; - $label = ! empty( $attributes['label'] ) ? $attributes['label'] : block_core_social_link_get_name( $service ); + $text = $text ? $text : block_core_social_link_get_name( $service ); $rel = isset( $attributes['rel'] ) ? $attributes['rel'] : ''; $show_labels = array_key_exists( 'showLabels', $block->context ) ? $block->context['showLabels'] : false; @@ -57,7 +59,7 @@ function render_block_core_social_link( $attributes, $content, $block ) { $link = '
  • '; $link .= ''; $link .= $icon; - $link .= '' . esc_html( $label ) . ''; + $link .= '' . esc_html( $text ) . ''; $link .= '
  • '; $processor = new WP_HTML_Tag_Processor( $link ); diff --git a/packages/block-library/src/social-links/block.json b/packages/block-library/src/social-links/block.json index 0c8c7be1eba9a5..45dbd9d698953f 100644 --- a/packages/block-library/src/social-links/block.json +++ b/packages/block-library/src/social-links/block.json @@ -5,7 +5,7 @@ "title": "Social Icons", "category": "widgets", "allowedBlocks": [ "core/social-link" ], - "description": "Display icons linking to your social media profiles or sites.", + "description": "Display icons linking to your social profiles or sites.", "keywords": [ "links" ], "textdomain": "default", "attributes": { diff --git a/packages/block-library/src/social-links/edit.js b/packages/block-library/src/social-links/edit.js index 38a68e7f2dab2c..52d26be50a6c9e 100644 --- a/packages/block-library/src/social-links/edit.js +++ b/packages/block-library/src/social-links/edit.js @@ -203,7 +203,7 @@ export function SocialLinksEdit( props ) { /> setAttributes( { showLabels: ! showLabels } ) diff --git a/packages/blocks/src/api/constants.js b/packages/blocks/src/api/constants.js index 62933d69d764f4..08b4e084e2ec9b 100644 --- a/packages/blocks/src/api/constants.js +++ b/packages/blocks/src/api/constants.js @@ -228,6 +228,11 @@ export const __EXPERIMENTAL_STYLE_PROPERTY = { }, useEngine: true, }, + textAlign: { + value: [ 'typography', 'textAlign' ], + support: [ 'typography', 'textAlign' ], + useEngine: false, + }, textDecoration: { value: [ 'typography', 'textDecoration' ], support: [ 'typography', '__experimentalTextDecoration' ], diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 48827c815c5854..9378ab8d342e30 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Deprecation + +- `Navigation`: Soft deprecate component ([#59182](https://github.com/WordPress/gutenberg/pull/59182)). + ### Enhancements - `ExternalLink`: Use unicode arrow instead of svg icon ([#60255](https://github.com/WordPress/gutenberg/pull/60255)). @@ -19,6 +23,11 @@ - `Tabs`: Fallback to first enabled tab if no active tab id ([#60681](https://github.com/WordPress/gutenberg/pull/60681)). +### Internal + +- Remove CSS hack for Internet Explorer 11 ([#60727](https://github.com/WordPress/gutenberg/pull/60727)). +- `CheckboxControl`: Streamline size styles ([#60475](https://github.com/WordPress/gutenberg/pull/60475)). + ## 27.3.0 (2024-04-03) ### Bug Fix diff --git a/packages/components/src/checkbox-control/style.scss b/packages/components/src/checkbox-control/style.scss index 4121250a7308a2..1821d49b4fcf47 100644 --- a/packages/components/src/checkbox-control/style.scss +++ b/packages/components/src/checkbox-control/style.scss @@ -1,5 +1,11 @@ -$checkbox-input-size: 20px; -$checkbox-input-size-sm: 24px; // Width & height for small viewports. +.components-checkbox-control { + // Careful, these CSS vars have experimental overrides in Data Views (packages/dataviews/src/style.scss). + --checkbox-input-size: 24px; // Width & height for small viewports. + + @include break-small() { + --checkbox-input-size: 20px; + } +} .components-checkbox-control__input[type="checkbox"] { @include checkbox-control; @@ -14,13 +20,8 @@ $checkbox-input-size-sm: 24px; // Width & height for small viewports. padding: 0 !important; text-align: center; vertical-align: top; - width: $checkbox-input-size-sm; - height: $checkbox-input-size-sm; - - @include break-small() { - height: $checkbox-input-size; - width: $checkbox-input-size; - } + width: var(--checkbox-input-size); + height: var(--checkbox-input-size); appearance: none; transition: 0.1s border-color ease-in-out; @@ -51,29 +52,26 @@ $checkbox-input-size-sm: 24px; // Width & height for small viewports. display: inline-block; margin-right: 12px; vertical-align: middle; - width: $checkbox-input-size-sm; - height: $checkbox-input-size-sm; - - @include break-small() { - width: $checkbox-input-size; - height: $checkbox-input-size; - } + width: var(--checkbox-input-size); + aspect-ratio: 1; } svg.components-checkbox-control__checked, svg.components-checkbox-control__indeterminate { + --checkmark-size: var(--checkbox-input-size); + fill: $white; cursor: pointer; position: absolute; - left: 0; - top: 0; - width: $button-size-small; - height: $button-size-small; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + width: var(--checkmark-size); + height: var(--checkmark-size); + user-select: none; + pointer-events: none; @include break-small() { - left: -2px; - top: -2px; + --checkmark-size: calc(var(--checkbox-input-size) + 4px); } - user-select: none; - pointer-events: none; } diff --git a/packages/components/src/combobox-control/README.md b/packages/components/src/combobox-control/README.md index 9b64076be32402..b84e01b7d6a077 100644 --- a/packages/components/src/combobox-control/README.md +++ b/packages/components/src/combobox-control/README.md @@ -110,8 +110,8 @@ Custom renderer invoked for each option in the suggestion list. The render prop ## Related components -- Like this component, but without a search input, the `CustomSelectControl` component. +- Like this component, but without a search input, the [`CustomSelectControl`](https://developer.wordpress.org/block-editor/reference-guides/components/custom-select-control/) component. -- To select one option from a set, when you want to show all the available options at once, use the `Radio` component. -- To select one or more items from a set, use the `CheckboxControl` component. -- To toggle a single setting on or off, use the `ToggleControl` component. +- To select one option from a set, when you want to show all the available options at once, use the [`RadioControl`](https://developer.wordpress.org/block-editor/reference-guides/components/radio-control/) component. +- To select one or more items from a set, use the [`CheckboxControl`](https://developer.wordpress.org/block-editor/reference-guides/components/checkbox-control/) component. +- To toggle a single setting on or off, use the [`ToggleControl`](https://developer.wordpress.org/block-editor/reference-guides/components/toggle-control/) component. diff --git a/packages/components/src/dimension-control/stories/index.story.tsx b/packages/components/src/dimension-control/stories/index.story.tsx index 0698125c446ca7..1220be3d4eea1f 100644 --- a/packages/components/src/dimension-control/stories/index.story.tsx +++ b/packages/components/src/dimension-control/stories/index.story.tsx @@ -29,10 +29,10 @@ export default { mobile, }, }, - parameters: { - controls: { expanded: true }, - docs: { canvas: { sourceState: 'shown' } }, - }, + }, + parameters: { + controls: { expanded: true }, + docs: { canvas: { sourceState: 'shown' } }, }, } as Meta< typeof DimensionControl >; diff --git a/packages/components/src/navigation/README.md b/packages/components/src/navigation/README.md index 3a1fa992611b62..b294eb78331eef 100644 --- a/packages/components/src/navigation/README.md +++ b/packages/components/src/navigation/README.md @@ -1,5 +1,9 @@ # Navigation +
    +This component is deprecated. Consider using `Navigator` instead. +
    +
    This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes.
    diff --git a/packages/components/src/navigation/back-button/index.tsx b/packages/components/src/navigation/back-button/index.tsx index 182faa8773726d..f1fb79ae40d484 100644 --- a/packages/components/src/navigation/back-button/index.tsx +++ b/packages/components/src/navigation/back-button/index.tsx @@ -64,6 +64,9 @@ function UnforwardedNavigationBackButton( ); } +/** + * @deprecated Use `Navigator` instead. + */ export const NavigationBackButton = forwardRef( UnforwardedNavigationBackButton ); diff --git a/packages/components/src/navigation/group/index.tsx b/packages/components/src/navigation/group/index.tsx index cd91fb97365d26..60febcf7644569 100644 --- a/packages/components/src/navigation/group/index.tsx +++ b/packages/components/src/navigation/group/index.tsx @@ -19,6 +19,9 @@ import type { NavigationGroupProps } from '../types'; let uniqueId = 0; +/** + * @deprecated Use `Navigator` instead. + */ export function NavigationGroup( { children, className, diff --git a/packages/components/src/navigation/index.tsx b/packages/components/src/navigation/index.tsx index dfc1b26cb33ad0..9ccd4f46e5f182 100644 --- a/packages/components/src/navigation/index.tsx +++ b/packages/components/src/navigation/index.tsx @@ -28,6 +28,8 @@ const noop = () => {}; /** * Render a navigation list with optional groupings and hierarchy. * + * @deprecated Use `Navigator` instead. + * * ```jsx * import { * __experimentalNavigation as Navigation, diff --git a/packages/components/src/navigation/item/index.tsx b/packages/components/src/navigation/item/index.tsx index 2fd1aebefcbbac..d234ed1a549b59 100644 --- a/packages/components/src/navigation/item/index.tsx +++ b/packages/components/src/navigation/item/index.tsx @@ -22,6 +22,9 @@ import type { NavigationItemProps } from '../types'; const noop = () => {}; +/** + * @deprecated Use `Navigator` instead. + */ export function NavigationItem( props: NavigationItemProps ) { const { badge, diff --git a/packages/components/src/navigation/menu/index.tsx b/packages/components/src/navigation/menu/index.tsx index b001bd0fa0f3d8..8fcddf3faddb9e 100644 --- a/packages/components/src/navigation/menu/index.tsx +++ b/packages/components/src/navigation/menu/index.tsx @@ -23,6 +23,9 @@ import { MenuUI } from '../styles/navigation-styles'; import type { NavigationMenuProps } from '../types'; +/** + * @deprecated Use `Navigator` instead. + */ export function NavigationMenu( props: NavigationMenuProps ) { const { backButtonLabel, diff --git a/packages/components/src/navigation/stories/index.story.tsx b/packages/components/src/navigation/stories/index.story.tsx index e0a3f1e1397576..2f09ace29f16e5 100644 --- a/packages/components/src/navigation/stories/index.story.tsx +++ b/packages/components/src/navigation/stories/index.story.tsx @@ -19,8 +19,14 @@ import { MoreExamplesStory } from './utils/more-examples'; import { HideIfEmptyStory } from './utils/hide-if-empty'; import './style.css'; +/** + * Render a navigation list with optional groupings and hierarchy. + * + * This component is deprecated. Consider using `Navigator` instead. + */ const meta: Meta< typeof Navigation > = { - title: 'Components (Experimental)/Navigation', + title: 'Components (Deprecated)/Navigation', + id: 'components-navigation', component: Navigation, subcomponents: { // @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170 diff --git a/packages/components/src/navigator/navigator-provider/component.tsx b/packages/components/src/navigator/navigator-provider/component.tsx index 368e78d799d72d..15eb4d6bd3b1d3 100644 --- a/packages/components/src/navigator/navigator-provider/component.tsx +++ b/packages/components/src/navigator/navigator-provider/component.tsx @@ -80,6 +80,13 @@ function goTo( ...restOptions } = options; + const isNavigatingToSamePath = + locationHistory.length > 0 && + locationHistory[ locationHistory.length - 1 ].path === path; + if ( isNavigatingToSamePath ) { + return locationHistory; + } + const isNavigatingToPreviousPath = isBack && locationHistory.length > 1 && @@ -157,13 +164,6 @@ function routerReducer( locationHistory = goBack( state ); break; case 'goto': - if ( - locationHistory.length && - action.path === - locationHistory[ locationHistory.length - 1 ].path - ) { - break; - } locationHistory = goTo( state, action.path, action.options ); break; case 'gotoparent': diff --git a/packages/components/src/placeholder/style.scss b/packages/components/src/placeholder/style.scss index eda0dd3329d39c..fedf374063541b 100644 --- a/packages/components/src/placeholder/style.scss +++ b/packages/components/src/placeholder/style.scss @@ -8,18 +8,14 @@ text-align: left; margin: 0; color: $gray-900; + display: flex; + flex-direction: column; + align-items: flex-start; // Some editor styles unset this. -moz-font-smoothing: subpixel-antialiased; -webkit-font-smoothing: subpixel-antialiased; - // IE11 doesn't read rules inside this query. They are applied only to modern browsers. - @supports (position: sticky) { - display: flex; - flex-direction: column; - justify-content: top; - align-items: flex-start; - } // Block UI appearance. border-radius: $radius-block-ui; diff --git a/packages/components/src/toolbar/toolbar-group/style.scss b/packages/components/src/toolbar/toolbar-group/style.scss index 487fd614045259..668968d40babbe 100644 --- a/packages/components/src/toolbar/toolbar-group/style.scss +++ b/packages/components/src/toolbar/toolbar-group/style.scss @@ -56,12 +56,7 @@ div.components-toolbar { & > div { - // IE11 does not support `position: sticky`, or Flex very well, so use block. - display: block; - @supports (position: sticky) { - display: flex; - } - + display: flex; margin: 0; } diff --git a/packages/dataviews/src/style.scss b/packages/dataviews/src/style.scss index 1d6a6ec3b6c07b..681068dd5e9c64 100644 --- a/packages/dataviews/src/style.scss +++ b/packages/dataviews/src/style.scss @@ -92,10 +92,6 @@ &.dataviews-view-table__checkbox-column { padding-right: 0; } - - .components-checkbox-control__input-container { - margin: $grid-unit-05; - } } tr { border-bottom: 1px solid $gray-100; @@ -532,16 +528,25 @@ justify-content: center; } -.dataviews-view-table-selection-checkbox label { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border: 0; +.dataviews-view-table-selection-checkbox { + // Experimental override for CheckboxControl size (fragile) + --checkbox-input-size: 24px; + @include break-small() { + --checkbox-input-size: 16px; + } + + line-height: 0; + label { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; + } } .dataviews-filters__custom-menu-radio-item-prefix { diff --git a/packages/dataviews/src/view-table.js b/packages/dataviews/src/view-table.js index aa186bb8e85441..b217dfe7802bbc 100644 --- a/packages/dataviews/src/view-table.js +++ b/packages/dataviews/src/view-table.js @@ -298,8 +298,7 @@ function TableRow( {
    @@ -426,8 +425,7 @@ function ViewTable( { node.declarations.some( ( declaration ) => { if ( declaration.id.type === 'ObjectPattern' ) { return declaration.id.properties.some( - ( property ) => property.key.name === name + ( property ) => + property.key?.name === name || + property.argument?.name === name ); } return declaration.id.name === name; diff --git a/packages/docgen/test/get-intermediate-representation.js b/packages/docgen/test/get-intermediate-representation.js index 43001aaedeeae3..e61f3101ad8438 100644 --- a/packages/docgen/test/get-intermediate-representation.js +++ b/packages/docgen/test/get-intermediate-representation.js @@ -284,6 +284,47 @@ describe( 'Intermediate Representation', () => { } ), ] ) ); + it( 'named identifier with RestElements', () => { + expect( + parse( ` + /** + * RestElement example. + */ + const { someKey, ...someApi } = { someKey: 2, restOne: 1, restTwo: 2 }; + + export {someApi}; + ` ) + ).toEqual( [ + { + description: 'RestElement example.', + lineEnd: 6, + lineStart: 6, + name: 'someApi', + path: 'test-code.ts', + tags: [], + }, + ] ); + } ); + + it( 'named identifier with undocumented RestElement', () => { + expect( + parse( ` + const { someKey, ...otherKeys } = { someKey: 2, restOne: 1, restTwo: 2 }; + + export const someApi = {}; + ` ) + ).toEqual( [ + { + description: 'Undocumented declaration.', + lineEnd: 3, + lineStart: 3, + name: 'someApi', + path: 'test-code.ts', + tags: [], + }, + ] ); + } ); + it( 'named identifier with destructuring', () => expect( parse( ` diff --git a/packages/edit-post/package.json b/packages/edit-post/package.json index 2de988fa00d6cd..111161edddf505 100644 --- a/packages/edit-post/package.json +++ b/packages/edit-post/package.json @@ -45,7 +45,6 @@ "@wordpress/hooks": "file:../hooks", "@wordpress/i18n": "file:../i18n", "@wordpress/icons": "file:../icons", - "@wordpress/interface": "file:../interface", "@wordpress/keyboard-shortcuts": "file:../keyboard-shortcuts", "@wordpress/keycodes": "file:../keycodes", "@wordpress/media-utils": "file:../media-utils", diff --git a/packages/edit-post/src/components/header/index.js b/packages/edit-post/src/components/header/index.js index 0f692967b3ee1f..c600e5b94c6ee6 100644 --- a/packages/edit-post/src/components/header/index.js +++ b/packages/edit-post/src/components/header/index.js @@ -22,7 +22,6 @@ import { useEffect, useRef, useState } from '@wordpress/element'; import { useSelect } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { next, previous } from '@wordpress/icons'; -import { PinnedItems } from '@wordpress/interface'; import { useViewportMatch } from '@wordpress/compose'; import { Button, @@ -42,7 +41,7 @@ import { store as editPostStore } from '../../store'; import { unlock } from '../../lock-unlock'; const { useShowBlockTools } = unlock( blockEditorPrivateApis ); -const { DocumentTools, PostViewLink, PreviewDropdown } = +const { DocumentTools, PostViewLink, PreviewDropdown, PinnedItems } = unlock( editorPrivateApis ); const slideY = { diff --git a/packages/edit-post/src/components/header/index.native.js b/packages/edit-post/src/components/header/index.native.js index aada04e264490a..ff892dd6916606 100644 --- a/packages/edit-post/src/components/header/index.native.js +++ b/packages/edit-post/src/components/header/index.native.js @@ -7,7 +7,7 @@ import { Keyboard } from 'react-native'; * WordPress dependencies */ import { Component } from '@wordpress/element'; -import '@wordpress/interface'; +import '@wordpress/editor'; /** * Internal dependencies diff --git a/packages/edit-post/src/components/header/more-menu/index.js b/packages/edit-post/src/components/header/more-menu/index.js index 0924af9ecaf742..f39f8cb7adab11 100644 --- a/packages/edit-post/src/components/header/more-menu/index.js +++ b/packages/edit-post/src/components/header/more-menu/index.js @@ -3,7 +3,6 @@ */ import { __ } from '@wordpress/i18n'; import { MenuGroup, DropdownMenu } from '@wordpress/components'; -import { ActionItem, PinnedItems } from '@wordpress/interface'; import { useViewportMatch } from '@wordpress/compose'; import { privateApis as editorPrivateApis } from '@wordpress/editor'; import { moreVertical } from '@wordpress/icons'; @@ -16,7 +15,7 @@ import ToolsMoreMenuGroup from '../tools-more-menu-group'; import WritingMenu from '../writing-menu'; import { unlock } from '../../../lock-unlock'; -const { ModeSwitcher } = unlock( editorPrivateApis ); +const { ModeSwitcher, ActionItem, PinnedItems } = unlock( editorPrivateApis ); const MoreMenu = ( { showIconLabels } ) => { const isLargeViewport = useViewportMatch( 'large' ); diff --git a/packages/edit-post/src/components/header/plugin-more-menu-item/index.js b/packages/edit-post/src/components/header/plugin-more-menu-item/index.js index d9675974704626..10cba81c3ae24c 100644 --- a/packages/edit-post/src/components/header/plugin-more-menu-item/index.js +++ b/packages/edit-post/src/components/header/plugin-more-menu-item/index.js @@ -1,10 +1,17 @@ /** * WordPress dependencies */ -import { ActionItem } from '@wordpress/interface'; import { compose } from '@wordpress/compose'; import { MenuItem } from '@wordpress/components'; import { withPluginContext } from '@wordpress/plugins'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; + +/** + * Internal dependencies + */ +import { unlock } from '../../../lock-unlock'; + +const { ActionItem } = unlock( editorPrivateApis ); /** * Renders a menu item in `Plugins` group in `More Menu` drop down, and can be used to as a button or link depending on the props provided. diff --git a/packages/edit-post/src/components/header/plugin-sidebar-more-menu-item/index.js b/packages/edit-post/src/components/header/plugin-sidebar-more-menu-item/index.js index 133e5ae2ba301f..c8dda954b81932 100644 --- a/packages/edit-post/src/components/header/plugin-sidebar-more-menu-item/index.js +++ b/packages/edit-post/src/components/header/plugin-sidebar-more-menu-item/index.js @@ -1,7 +1,14 @@ /** * WordPress dependencies */ -import { ComplementaryAreaMoreMenuItem } from '@wordpress/interface'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; + +/** + * Internal dependencies + */ +import { unlock } from '../../../lock-unlock'; + +const { ComplementaryAreaMoreMenuItem } = unlock( editorPrivateApis ); /** * Renders a menu item in `Plugins` group in `More Menu` drop down, diff --git a/packages/edit-post/src/components/header/preferences-menu-item/index.js b/packages/edit-post/src/components/header/preferences-menu-item/index.js index 037a896fc7f070..09eb41c844cd2a 100644 --- a/packages/edit-post/src/components/header/preferences-menu-item/index.js +++ b/packages/edit-post/src/components/header/preferences-menu-item/index.js @@ -4,7 +4,14 @@ import { useDispatch } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { MenuItem } from '@wordpress/components'; -import { store as interfaceStore } from '@wordpress/interface'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; + +/** + * Internal dependencies + */ +import { unlock } from '../../../lock-unlock'; + +const { interfaceStore } = unlock( editorPrivateApis ); /** * Internal dependencies diff --git a/packages/edit-post/src/components/keyboard-shortcut-help-modal/index.js b/packages/edit-post/src/components/keyboard-shortcut-help-modal/index.js index 666a24f2df4fc7..c393208713ce93 100644 --- a/packages/edit-post/src/components/keyboard-shortcut-help-modal/index.js +++ b/packages/edit-post/src/components/keyboard-shortcut-help-modal/index.js @@ -14,7 +14,7 @@ import { } from '@wordpress/keyboard-shortcuts'; import { withSelect, withDispatch, useSelect } from '@wordpress/data'; import { compose } from '@wordpress/compose'; -import { store as interfaceStore } from '@wordpress/interface'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; /** * Internal dependencies @@ -22,7 +22,9 @@ import { store as interfaceStore } from '@wordpress/interface'; import { textFormattingShortcuts } from './config'; import Shortcut from './shortcut'; import DynamicShortcut from './dynamic-shortcut'; +import { unlock } from '../../lock-unlock'; +const { interfaceStore } = unlock( editorPrivateApis ); export const KEYBOARD_SHORTCUT_HELP_MODAL_NAME = 'edit-post/keyboard-shortcut-help'; diff --git a/packages/edit-post/src/components/layout/index.js b/packages/edit-post/src/components/layout/index.js index 6fc9ab570e5ac9..fe8f132f2568d9 100644 --- a/packages/edit-post/src/components/layout/index.js +++ b/packages/edit-post/src/components/layout/index.js @@ -28,12 +28,6 @@ import { ScrollLock } from '@wordpress/components'; import { useViewportMatch } from '@wordpress/compose'; import { PluginArea } from '@wordpress/plugins'; import { __, _x, sprintf } from '@wordpress/i18n'; -import { - ComplementaryArea, - FullscreenMode, - InterfaceSkeleton, - store as interfaceStore, -} from '@wordpress/interface'; import { useState, useEffect, useCallback, useMemo } from '@wordpress/element'; import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; import { store as noticesStore } from '@wordpress/notices'; @@ -56,7 +50,6 @@ import SettingsSidebar from '../sidebar/settings-sidebar'; import MetaBoxes from '../meta-boxes'; import WelcomeGuide from '../welcome-guide'; import ActionsPanel from './actions-panel'; -import StartPageOptions from '../start-page-options'; import { store as editPostStore } from '../../store'; import { unlock } from '../../lock-unlock'; import useCommonCommands from '../../hooks/commands/use-common-commands'; @@ -64,7 +57,14 @@ import useCommonCommands from '../../hooks/commands/use-common-commands'; const { getLayoutStyles } = unlock( blockEditorPrivateApis ); const { useCommands } = unlock( coreCommandsPrivateApis ); const { useCommandContext } = unlock( commandsPrivateApis ); -const { InserterSidebar, ListViewSidebar } = unlock( editorPrivateApis ); +const { + InserterSidebar, + ListViewSidebar, + ComplementaryArea, + FullscreenMode, + InterfaceSkeleton, + interfaceStore, +} = unlock( editorPrivateApis ); const interfaceLabels = { /* translators: accessibility text for the editor top bar landmark region. */ @@ -364,7 +364,6 @@ function Layout( { initialPost } ) { - { ! isDistractionFree && } diff --git a/packages/edit-post/src/components/preferences-modal/index.js b/packages/edit-post/src/components/preferences-modal/index.js index 326677aeffc5a1..b9232f628cf7fb 100644 --- a/packages/edit-post/src/components/preferences-modal/index.js +++ b/packages/edit-post/src/components/preferences-modal/index.js @@ -5,7 +5,6 @@ import { __ } from '@wordpress/i18n'; import { useViewportMatch } from '@wordpress/compose'; import { useSelect, useDispatch } from '@wordpress/data'; -import { store as interfaceStore } from '@wordpress/interface'; import { privateApis as preferencesPrivateApis } from '@wordpress/preferences'; import { privateApis as editorPrivateApis } from '@wordpress/editor'; @@ -19,7 +18,7 @@ import EnablePublishSidebarOption from './enable-publish-sidebar'; const { PreferencesModalSection, PreferenceToggleControl } = unlock( preferencesPrivateApis ); -const { PreferencesModal } = unlock( editorPrivateApis ); +const { PreferencesModal, interfaceStore } = unlock( editorPrivateApis ); export const PREFERENCES_MODAL_NAME = 'edit-post/preferences'; diff --git a/packages/edit-post/src/components/sidebar/plugin-sidebar/index.js b/packages/edit-post/src/components/sidebar/plugin-sidebar/index.js index ac0bf9f52bed5d..f62dccbadeecc0 100644 --- a/packages/edit-post/src/components/sidebar/plugin-sidebar/index.js +++ b/packages/edit-post/src/components/sidebar/plugin-sidebar/index.js @@ -1,11 +1,20 @@ /** * WordPress dependencies */ -import { ComplementaryArea } from '@wordpress/interface'; import { useSelect } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; -import { store as editorStore } from '@wordpress/editor'; +import { + store as editorStore, + privateApis as editorPrivateApis, +} from '@wordpress/editor'; + +/** + * Internal dependencies + */ +import { unlock } from '../../../lock-unlock'; + +const { ComplementaryArea } = unlock( editorPrivateApis ); /** * Renders a sidebar when activated. The contents within the `PluginSidebar` will appear as content within the sidebar. diff --git a/packages/edit-post/src/components/sidebar/settings-sidebar/index.js b/packages/edit-post/src/components/sidebar/settings-sidebar/index.js index 27b85cffa08643..b80edf2e6483ee 100644 --- a/packages/edit-post/src/components/sidebar/settings-sidebar/index.js +++ b/packages/edit-post/src/components/sidebar/settings-sidebar/index.js @@ -15,7 +15,6 @@ import { } from '@wordpress/element'; import { isRTL, __ } from '@wordpress/i18n'; import { drawerLeft, drawerRight } from '@wordpress/icons'; -import { store as interfaceStore } from '@wordpress/interface'; import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; import { store as editorStore, @@ -40,8 +39,8 @@ import { store as editPostStore } from '../../../store'; import { privateApis as componentsPrivateApis } from '@wordpress/components'; import { unlock } from '../../../lock-unlock'; -const { PostCardPanel, PostActions } = unlock( editorPrivateApis ); - +const { PostCardPanel, PostActions, interfaceStore } = + unlock( editorPrivateApis ); const { Tabs } = unlock( componentsPrivateApis ); const { PatternOverridesPanel } = unlock( editorPrivateApis ); diff --git a/packages/edit-post/src/hooks/commands/use-common-commands.js b/packages/edit-post/src/hooks/commands/use-common-commands.js index d3d2024d009ceb..09fe186d90b03f 100644 --- a/packages/edit-post/src/hooks/commands/use-common-commands.js +++ b/packages/edit-post/src/hooks/commands/use-common-commands.js @@ -13,8 +13,10 @@ import { } from '@wordpress/icons'; import { useCommand } from '@wordpress/commands'; import { store as preferencesStore } from '@wordpress/preferences'; -import { store as interfaceStore } from '@wordpress/interface'; -import { store as editorStore } from '@wordpress/editor'; +import { + store as editorStore, + privateApis as editorPrivateApis, +} from '@wordpress/editor'; import { store as noticesStore } from '@wordpress/notices'; /** @@ -23,6 +25,9 @@ import { store as noticesStore } from '@wordpress/notices'; import { KEYBOARD_SHORTCUT_HELP_MODAL_NAME } from '../../components/keyboard-shortcut-help-modal'; import { PREFERENCES_MODAL_NAME } from '../../components/preferences-modal'; import { store as editPostStore } from '../../store'; +import { unlock } from '../../lock-unlock'; + +const { interfaceStore } = unlock( editorPrivateApis ); export default function useCommonCommands() { const { openGeneralSidebar, closeGeneralSidebar } = diff --git a/packages/edit-post/src/plugins/keyboard-shortcuts-help-menu-item/index.js b/packages/edit-post/src/plugins/keyboard-shortcuts-help-menu-item/index.js index 930f420a241299..6f222dd34e22cd 100644 --- a/packages/edit-post/src/plugins/keyboard-shortcuts-help-menu-item/index.js +++ b/packages/edit-post/src/plugins/keyboard-shortcuts-help-menu-item/index.js @@ -5,12 +5,15 @@ import { MenuItem } from '@wordpress/components'; import { withDispatch } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { displayShortcut } from '@wordpress/keycodes'; -import { store as interfaceStore } from '@wordpress/interface'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; /** * Internal dependencies */ import { KEYBOARD_SHORTCUT_HELP_MODAL_NAME } from '../../components/keyboard-shortcut-help-modal'; +import { unlock } from '../../lock-unlock'; + +const { interfaceStore } = unlock( editorPrivateApis ); export function KeyboardShortcutsHelpMenuItem( { openModal } ) { return ( diff --git a/packages/edit-post/src/store/actions.js b/packages/edit-post/src/store/actions.js index f22edb94a3fee8..fec4ade849f4ed 100644 --- a/packages/edit-post/src/store/actions.js +++ b/packages/edit-post/src/store/actions.js @@ -2,9 +2,11 @@ * WordPress dependencies */ import apiFetch from '@wordpress/api-fetch'; -import { store as interfaceStore } from '@wordpress/interface'; import { store as preferencesStore } from '@wordpress/preferences'; -import { store as editorStore } from '@wordpress/editor'; +import { + store as editorStore, + privateApis as editorPrivateApis, +} from '@wordpress/editor'; import deprecated from '@wordpress/deprecated'; import { addFilter } from '@wordpress/hooks'; @@ -15,6 +17,8 @@ import { getMetaBoxContainer } from '../utils/meta-boxes'; import { store as editPostStore } from '.'; import { unlock } from '../lock-unlock'; +const { interfaceStore } = unlock( editorPrivateApis ); + /** * Returns an action object used in signalling that the user opened an editor sidebar. * diff --git a/packages/edit-post/src/store/selectors.js b/packages/edit-post/src/store/selectors.js index 791b384d1e8185..eb752f14ace23a 100644 --- a/packages/edit-post/src/store/selectors.js +++ b/packages/edit-post/src/store/selectors.js @@ -2,10 +2,12 @@ * WordPress dependencies */ import { createSelector, createRegistrySelector } from '@wordpress/data'; -import { store as interfaceStore } from '@wordpress/interface'; import { store as preferencesStore } from '@wordpress/preferences'; import { store as coreStore } from '@wordpress/core-data'; -import { store as editorStore } from '@wordpress/editor'; +import { + store as editorStore, + privateApis as editorPrivateApis, +} from '@wordpress/editor'; import deprecated from '@wordpress/deprecated'; /** @@ -13,6 +15,7 @@ import deprecated from '@wordpress/deprecated'; */ import { unlock } from '../lock-unlock'; +const { interfaceStore } = unlock( editorPrivateApis ); const EMPTY_ARRAY = []; const EMPTY_OBJECT = {}; diff --git a/packages/edit-post/src/store/test/actions.js b/packages/edit-post/src/store/test/actions.js index cb872d30ee3e21..cb0a3fb32952a9 100644 --- a/packages/edit-post/src/store/test/actions.js +++ b/packages/edit-post/src/store/test/actions.js @@ -2,17 +2,22 @@ * WordPress dependencies */ import { createRegistry } from '@wordpress/data'; -import { store as interfaceStore } from '@wordpress/interface'; import { store as preferencesStore } from '@wordpress/preferences'; import { store as noticesStore } from '@wordpress/notices'; import { store as coreStore } from '@wordpress/core-data'; import { store as blockEditorStore } from '@wordpress/block-editor'; -import { store as editorStore } from '@wordpress/editor'; +import { + store as editorStore, + privateApis as editorPrivateApis, +} from '@wordpress/editor'; /** * Internal dependencies */ import { store as editPostStore } from '..'; +import { unlock } from '../../lock-unlock'; + +const { interfaceStore } = unlock( editorPrivateApis ); function createRegistryWithStores() { // Create a registry and register used stores. diff --git a/packages/edit-post/src/style.scss b/packages/edit-post/src/style.scss index 4ba063905d8b2e..7cae91f847a78c 100644 --- a/packages/edit-post/src/style.scss +++ b/packages/edit-post/src/style.scss @@ -1,4 +1,3 @@ -@import "../../interface/src/style.scss"; @import "./components/header/style.scss"; @import "./components/header/fullscreen-mode-close/style.scss"; @import "./components/keyboard-shortcut-help-modal/style.scss"; @@ -11,7 +10,6 @@ @import "./components/text-editor/style.scss"; @import "./components/visual-editor/style.scss"; @import "./components/welcome-guide/style.scss"; -@import "./components/start-page-options/style.scss"; /** * Animations diff --git a/packages/edit-site/package.json b/packages/edit-site/package.json index 06acfe7c748b4f..c5562642076763 100644 --- a/packages/edit-site/package.json +++ b/packages/edit-site/package.json @@ -51,7 +51,6 @@ "@wordpress/html-entities": "file:../html-entities", "@wordpress/i18n": "file:../i18n", "@wordpress/icons": "file:../icons", - "@wordpress/interface": "file:../interface", "@wordpress/keyboard-shortcuts": "file:../keyboard-shortcuts", "@wordpress/keycodes": "file:../keycodes", "@wordpress/media-utils": "file:../media-utils", diff --git a/packages/edit-site/src/components/block-editor/block-inspector-button.js b/packages/edit-site/src/components/block-editor/block-inspector-button.js index 758ca50272adeb..295d318d6da75b 100644 --- a/packages/edit-site/src/components/block-editor/block-inspector-button.js +++ b/packages/edit-site/src/components/block-editor/block-inspector-button.js @@ -5,8 +5,8 @@ import { __ } from '@wordpress/i18n'; import { speak } from '@wordpress/a11y'; import { MenuItem } from '@wordpress/components'; import { useSelect, useDispatch } from '@wordpress/data'; -import { store as interfaceStore } from '@wordpress/interface'; import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; /** * Internal dependencies @@ -14,6 +14,9 @@ import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; import { store as editSiteStore } from '../../store'; import { STORE_NAME } from '../../store/constants'; import { SIDEBAR_BLOCK } from '../sidebar-edit-mode/constants'; +import { unlock } from '../../lock-unlock'; + +const { interfaceStore } = unlock( editorPrivateApis ); export default function BlockInspectorButton( { onClick = () => {} } ) { const { shortcut, isBlockInspectorOpen } = useSelect( diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index ba04333b985bde..a95c671f8e7671 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -24,11 +24,6 @@ import { store as blockEditorStore, BlockInspector, } from '@wordpress/block-editor'; -import { - InterfaceSkeleton, - ComplementaryArea, - store as interfaceStore, -} from '@wordpress/interface'; import { EditorKeyboardShortcutsRegister, EditorKeyboardShortcuts, @@ -68,6 +63,9 @@ const { ExperimentalEditorProvider: EditorProvider, InserterSidebar, ListViewSidebar, + InterfaceSkeleton, + ComplementaryArea, + interfaceStore, } = unlock( editorPrivateApis ); const interfaceLabels = { diff --git a/packages/edit-site/src/components/global-styles/background-panel.js b/packages/edit-site/src/components/global-styles/background-panel.js index cae8bdba61871f..2addf109873aae 100644 --- a/packages/edit-site/src/components/global-styles/background-panel.js +++ b/packages/edit-site/src/components/global-styles/background-panel.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; +import { __ } from '@wordpress/i18n'; /** * Internal dependencies @@ -28,13 +29,22 @@ export default function BackgroundPanel() { } ); const [ settings ] = useGlobalSetting( '' ); + const defaultControls = { + backgroundImage: true, + backgroundSize: + !! style?.background?.backgroundImage && + !! inheritedStyle?.background?.backgroundImage, + }; + return ( ); } diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js index 26ec6ede016b2c..ca8fb54d5e4858 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js @@ -100,9 +100,9 @@ function FontLibraryProvider( { children } ) { * This function is called when the user activates or deactivates a font family. * It only updates the global styles post content in the database for new font families. * This avoids saving other styles/settings changed by the user using other parts of the editor. - * + * * It uses the font families from the param to avoid using the font families from an outdated state. - * + * * @param {Array} fonts - The font families that will be saved to the database. */ const saveFontFamilies = async ( fonts ) => { @@ -137,7 +137,7 @@ function FontLibraryProvider( { children } ) { * Base Theme Fonts are the fonts defined in the theme.json *file*. * * Uses the fonts from global styles + the ones from the theme.json file that hasn't repeated slugs. - * Avoids incosistencies with the fonts listed in the font library modal as base (unactivated). + * Avoids inconsistencies with the fonts listed in the font library modal as base (inactivated). * These inconsistencies can happen when the active theme fonts in global styles aren't defined in theme.json file as when a theme style variation is applied. */ const baseThemeFonts = baseFontFamilies?.theme @@ -283,27 +283,27 @@ function FontLibraryProvider( { children } ) { } // Install the fonts (upload the font files to the server and create the post in the database). - let sucessfullyInstalledFontFaces = []; - let unsucessfullyInstalledFontFaces = []; + let successfullyInstalledFontFaces = []; + let unsuccessfullyInstalledFontFaces = []; if ( fontFamilyToInstall?.fontFace?.length > 0 ) { const response = await batchInstallFontFaces( installedFontFamily.id, makeFontFacesFormData( fontFamilyToInstall ) ); - sucessfullyInstalledFontFaces = response?.successes; - unsucessfullyInstalledFontFaces = response?.errors; + successfullyInstalledFontFaces = response?.successes; + unsuccessfullyInstalledFontFaces = response?.errors; } - // Use the sucessfully installed font faces + // Use the successfully installed font faces // As well as any font faces that were already installed (those will be activated) if ( - sucessfullyInstalledFontFaces?.length > 0 || + successfullyInstalledFontFaces?.length > 0 || alreadyInstalledFontFaces?.length > 0 ) { // Use font data from REST API not from client to ensure // correct font information is used. installedFontFamily.fontFace = [ - ...sucessfullyInstalledFontFaces, + ...successfullyInstalledFontFaces, ]; fontFamiliesToActivate.push( installedFontFamily ); @@ -321,13 +321,13 @@ function FontLibraryProvider( { children } ) { if ( isANewFontFamily && fontFamilyToInstall?.fontFace?.length > 0 && - sucessfullyInstalledFontFaces?.length === 0 + successfullyInstalledFontFaces?.length === 0 ) { await fetchUninstallFontFamily( installedFontFamily.id ); } installationErrors = installationErrors.concat( - unsucessfullyInstalledFontFaces + unsuccessfullyInstalledFontFaces ); } diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js b/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js index 4368d72645959b..1a1853ac62a381 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js @@ -19,12 +19,12 @@ import { __experimentalHeading as Heading, Notice, SelectControl, - Spinner, FlexItem, Flex, Button, DropdownMenu, SearchControl, + privateApis as componentsPrivateApis, } from '@wordpress/components'; import { debounce } from '@wordpress/compose'; import { sprintf, __, _x } from '@wordpress/i18n'; @@ -45,6 +45,8 @@ import GoogleFontsConfirmDialog from './google-fonts-confirm-dialog'; import { downloadFontFaceAssets } from './utils'; import { sortFontFaces } from './utils/sort-font-faces'; import CollectionFontVariant from './collection-font-variant'; +import { unlock } from '../../../lock-unlock'; +const { ProgressBar } = unlock( componentsPrivateApis ); const DEFAULT_CATEGORY = { slug: 'all', @@ -136,6 +138,8 @@ function FontCollection( { slug } ) { [ collectionFonts, filters ] ); + const isLoading = ! selectedCollection?.font_families && ! notice; + // NOTE: The height of the font library modal unavailable to use for rendering font family items is roughly 417px // The height of each font family item is 61px. const windowHeight = Math.max( window.innerHeight, MIN_WINDOW_HEIGHT ); @@ -260,235 +264,255 @@ function FontCollection( { slug } ) { return (
    - - - - - - { selectedCollection.name } - - { selectedCollection.description } - - - - - - - - - - - { categories && - categories.map( ( category ) => ( - - ) ) } - - - - - - - { ! selectedCollection?.font_families && ! notice && ( - - ) } + { isLoading && ( +
    + +
    + ) } - { !! selectedCollection?.font_families?.length && - ! fonts.length && ( - - { __( - 'No fonts found. Try with a different search term' + { ! isLoading && ( + <> + + + + + + { selectedCollection.name } + + + { selectedCollection.description } + + + + + + + + + + + + { categories && + categories.map( ( category ) => ( + + ) ) } + + + + + + + { !! selectedCollection?.font_families?.length && + ! fonts.length && ( + + { __( + 'No fonts found. Try with a different search term' + ) } + ) } + +
    + { items.map( ( font ) => ( + { + setSelectedFont( + font.font_family_settings + ); + } } + /> + ) ) } +
    +
    + + + + { + setSelectedFont( null ); + setNotice( null ); + } } + label={ __( 'Back' ) } + /> + + { selectedFont?.name } + + + { notice && ( + <> + + setNotice( null ) } + > + { notice.message } + + + + ) } + + + { __( 'Select font variants to install.' ) } - ) } - -
    - { items.map( ( font ) => ( - { - setSelectedFont( - font.font_family_settings - ); - } } - /> - ) ) } -
    -
    - - - - { - setSelectedFont( null ); - setNotice( null ); - } } - label={ __( 'Back' ) } - /> - + + + { getSortedFontFaces( selectedFont ).map( + ( face, i ) => ( + + ) + ) } + + + +
    + + { selectedFont && ( + - { selectedFont?.name } - - - { notice && ( - <> - - setNotice( null ) } + + ) } - - { __( 'Select font variants to install.' ) } - - - - { getSortedFontFaces( selectedFont ).map( - ( face, i ) => ( - - ) - ) } - - -
    -
    - - { selectedFont && ( - - - - ) } - { ! selectedFont && ( - - - - - { createInterpolateElement( - sprintf( - // translators: %s: Total number of pages. - _x( - 'Page of %s', - 'paging' - ), - totalPages - ), - { - CurrentPageControl: ( - { - return { - label: i + 1, - value: i + 1, - }; - } ) } - onChange={ ( newPage ) => - setPage( parseInt( newPage ) ) - } - size={ 'compact' } - __nextHasNoMarginBottom - /> - ), - } - ) } - - - - + { ! selectedFont && ( + + + + + { createInterpolateElement( + sprintf( + // translators: %s: Total number of pages. + _x( + 'Page of %s', + 'paging' + ), + totalPages + ), + { + CurrentPageControl: ( + { + return { + label: i + 1, + value: i + 1, + }; + } ) } + onChange={ ( newPage ) => + setPage( + parseInt( newPage ) + ) + } + size={ 'compact' } + __nextHasNoMarginBottom + /> + ), + } + ) } + + + + + ) } + ) }
    ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js b/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js index 16011a20e82fbd..b33bb1b639d000 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js @@ -15,7 +15,6 @@ import { __experimentalVStack as VStack, Flex, Notice, - Spinner, privateApis as componentsPrivateApis, } from '@wordpress/components'; import { store as coreStore } from '@wordpress/core-data'; @@ -114,163 +113,171 @@ function InstalledFonts() { return (
    { isResolvingLibrary && ( - - - - - +
    + +
    ) } - - - { notice && ( - <> - - setNotice( null ) } - > - { notice.message } - - - - ) } - { baseCustomFonts.length > 0 && ( - <> - - { __( 'Installed Fonts' ) } - - - { baseCustomFonts.map( ( font ) => ( - { - handleSetLibraryFontSelected( font ); - } } - /> - ) ) } - - - ) } + { ! isResolvingLibrary && ( + <> + + + { notice && ( + <> + + setNotice( null ) } + > + { notice.message } + + + + ) } + { baseCustomFonts.length > 0 && ( + <> + + { __( 'Installed Fonts' ) } + + + { baseCustomFonts.map( ( font ) => ( + { + handleSetLibraryFontSelected( + font + ); + } } + /> + ) ) } + + + ) } - { baseThemeFonts.length > 0 && ( - <> - - { __( 'Theme Fonts' ) } - - - { baseThemeFonts.map( ( font ) => ( - 0 && ( + <> + + { __( 'Theme Fonts' ) } + + + { baseThemeFonts.map( ( font ) => ( + { + handleSetLibraryFontSelected( + font + ); + } } + /> + ) ) } + + ) } + + + + + + + { - handleSetLibraryFontSelected( font ); + handleSetLibraryFontSelected( null ); } } + label={ __( 'Back' ) } /> - ) ) } - - ) } - - - - + + { libraryFontSelected?.name } + + + { notice && ( + <> + + setNotice( null ) } + > + { notice.message } + + + + ) } + + + { __( + 'Choose font variants. Keep in mind that too many variants could make your site slower.' + ) } + + + + + { getFontFacesToDisplay( + libraryFontSelected + ).map( ( face, i ) => ( + + ) ) } + + + - - + { isInstalling && } + { shouldDisplayDeleteButton && ( + + ) } + - ) } - - + { __( 'Update' ) } + + + + ) }
    ); } diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/style.scss b/packages/edit-site/src/components/global-styles/font-library-modal/style.scss index ccf4eb7ea623fc..201d4d87a3fb16 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/style.scss +++ b/packages/edit-site/src/components/global-styles/font-library-modal/style.scss @@ -7,7 +7,6 @@ $footer-height: 70px; // the content width, we should use that prop instead of this style. // see https://github.com/WordPress/gutenberg/issues/54471. &.font-library-modal { - @include break-medium() { width: 65vw; } @@ -35,9 +34,22 @@ $footer-height: 70px; } .font-library-modal__tabpanel-layout { - margin-top: $grid-unit-40; + .font-library-modal__loading { + width: 100%; + height: 100%; + display: flex; + position: absolute; + left: 0; + top: 0; + align-items: center; + justify-content: center; + // Push down so that the progress bar is centered vertically. + // It should be 120px (72px modal header height + 48px tab height) + padding-top: $header-height + $grid-unit-15 + $grid-unit-60; + } + .font-library-modal__tabpanel-layout__footer { border-top: 1px solid $gray-300; margin: 0 #{$grid-unit-40 * -1} #{$grid-unit-40 * -1}; @@ -72,19 +84,19 @@ $footer-height: 70px; .font-library-modal__font-card__count { color: $gray-700; } -} -.font-library-modal__font-variant_demo-image { - display: block; - height: $grid-unit-30; - width: auto; -} + .font-library-modal__font-variant_demo-image { + display: block; + height: $grid-unit-30; + width: auto; + } -.font-library-modal__font-variant_demo-text { - white-space: nowrap; - flex-shrink: 0; - transition: opacity 0.3s ease-in-out; - @include reduce-motion("transition"); + .font-library-modal__font-variant_demo-text { + white-space: nowrap; + flex-shrink: 0; + transition: opacity 0.3s ease-in-out; + @include reduce-motion("transition"); + } } .font-library-modal__font-variant { diff --git a/packages/edit-site/src/components/global-styles/root-menu.js b/packages/edit-site/src/components/global-styles/root-menu.js index 97598635f7b859..c747efee635d88 100644 --- a/packages/edit-site/src/components/global-styles/root-menu.js +++ b/packages/edit-site/src/components/global-styles/root-menu.js @@ -64,9 +64,9 @@ function RootMenu() { - { __( 'Background' ) } + { __( 'Background image' ) } ) } diff --git a/packages/edit-site/src/components/global-styles/screen-background.js b/packages/edit-site/src/components/global-styles/screen-background.js index 5e8a7832a42b46..e6d338ffcbef1e 100644 --- a/packages/edit-site/src/components/global-styles/screen-background.js +++ b/packages/edit-site/src/components/global-styles/screen-background.js @@ -20,7 +20,7 @@ function ScreenBackground() { const hasBackgroundPanel = useHasBackgroundPanel( settings ); return ( <> - + { hasBackgroundPanel && } ); diff --git a/packages/edit-site/src/components/header-edit-mode/index.js b/packages/edit-site/src/components/header-edit-mode/index.js index aed1d9584b2ca6..c54098558798ac 100644 --- a/packages/edit-site/src/components/header-edit-mode/index.js +++ b/packages/edit-site/src/components/header-edit-mode/index.js @@ -14,7 +14,6 @@ import { } from '@wordpress/block-editor'; import { useSelect } from '@wordpress/data'; import { useEffect, useRef, useState } from '@wordpress/element'; -import { PinnedItems } from '@wordpress/interface'; import { __ } from '@wordpress/i18n'; import { next, previous } from '@wordpress/icons'; import { @@ -44,7 +43,8 @@ import { unlock } from '../../lock-unlock'; import { FOCUSABLE_ENTITIES } from '../../utils/constants'; const { useShowBlockTools } = unlock( blockEditorPrivateApis ); -const { PostViewLink, PreviewDropdown } = unlock( editorPrivateApis ); +const { PostViewLink, PreviewDropdown, PinnedItems } = + unlock( editorPrivateApis ); export default function HeaderEditMode() { const { diff --git a/packages/edit-site/src/components/header-edit-mode/more-menu/index.js b/packages/edit-site/src/components/header-edit-mode/more-menu/index.js index 00a61aa7492ec3..f297899e37b9d0 100644 --- a/packages/edit-site/src/components/header-edit-mode/more-menu/index.js +++ b/packages/edit-site/src/components/header-edit-mode/more-menu/index.js @@ -11,7 +11,6 @@ import { VisuallyHidden, DropdownMenu, } from '@wordpress/components'; -import { ActionItem, store as interfaceStore } from '@wordpress/interface'; import { PreferenceToggleMenuItem, store as preferencesStore, @@ -39,7 +38,8 @@ import WelcomeGuideMenuItem from './welcome-guide-menu-item'; import CopyContentMenuItem from './copy-content-menu-item'; import { unlock } from '../../../lock-unlock'; -const { ModeSwitcher } = unlock( editorPrivateApis ); +const { ModeSwitcher, ActionItem, interfaceStore } = + unlock( editorPrivateApis ); export default function MoreMenu( { showIconLabels } ) { const { openModal } = useDispatch( interfaceStore ); diff --git a/packages/edit-site/src/components/header-edit-mode/plugin-more-menu-item/index.js b/packages/edit-site/src/components/header-edit-mode/plugin-more-menu-item/index.js index edb093a487e772..67c6f286e0b608 100644 --- a/packages/edit-site/src/components/header-edit-mode/plugin-more-menu-item/index.js +++ b/packages/edit-site/src/components/header-edit-mode/plugin-more-menu-item/index.js @@ -1,10 +1,17 @@ /** * WordPress dependencies */ -import { ActionItem } from '@wordpress/interface'; import { compose } from '@wordpress/compose'; import { MenuItem } from '@wordpress/components'; import { withPluginContext } from '@wordpress/plugins'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; + +/** + * Internal dependencies + */ +import { unlock } from '../../../lock-unlock'; + +const { ActionItem } = unlock( editorPrivateApis ); /** * Renders a menu item in `Plugins` group in `More Menu` drop down, and can be used to as a button or link depending on the props provided. diff --git a/packages/edit-site/src/components/header-edit-mode/plugin-sidebar-more-menu-item/index.js b/packages/edit-site/src/components/header-edit-mode/plugin-sidebar-more-menu-item/index.js index 4d6c8008497241..18541ff76d12b9 100644 --- a/packages/edit-site/src/components/header-edit-mode/plugin-sidebar-more-menu-item/index.js +++ b/packages/edit-site/src/components/header-edit-mode/plugin-sidebar-more-menu-item/index.js @@ -1,7 +1,14 @@ /** * WordPress dependencies */ -import { ComplementaryAreaMoreMenuItem } from '@wordpress/interface'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; + +/** + * Internal dependencies + */ +import { unlock } from '../../../lock-unlock'; + +const { ComplementaryAreaMoreMenuItem } = unlock( editorPrivateApis ); /** * Renders a menu item in `Plugins` group in `More Menu` drop down, diff --git a/packages/edit-site/src/components/keyboard-shortcut-help-modal/index.js b/packages/edit-site/src/components/keyboard-shortcut-help-modal/index.js index b1d85f88dd91ef..bc2d2f48dd9772 100644 --- a/packages/edit-site/src/components/keyboard-shortcut-help-modal/index.js +++ b/packages/edit-site/src/components/keyboard-shortcut-help-modal/index.js @@ -12,8 +12,13 @@ import { useShortcut, store as keyboardShortcutsStore, } from '@wordpress/keyboard-shortcuts'; -import { store as interfaceStore } from '@wordpress/interface'; import { useSelect, useDispatch } from '@wordpress/data'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; + +/** + * Internal dependencies + */ +import { unlock } from '../../lock-unlock'; /** * Internal dependencies @@ -22,6 +27,7 @@ import { textFormattingShortcuts } from './config'; import Shortcut from './shortcut'; import DynamicShortcut from './dynamic-shortcut'; +const { interfaceStore } = unlock( editorPrivateApis ); export const KEYBOARD_SHORTCUT_HELP_MODAL_NAME = 'edit-site/keyboard-shortcut-help'; diff --git a/packages/edit-site/src/components/keyboard-shortcuts/edit-mode.js b/packages/edit-site/src/components/keyboard-shortcuts/edit-mode.js index b3675c757ea018..33ca83afa32959 100644 --- a/packages/edit-site/src/components/keyboard-shortcuts/edit-mode.js +++ b/packages/edit-site/src/components/keyboard-shortcuts/edit-mode.js @@ -4,8 +4,8 @@ import { useShortcut } from '@wordpress/keyboard-shortcuts'; import { useDispatch, useSelect } from '@wordpress/data'; import { store as blockEditorStore } from '@wordpress/block-editor'; -import { store as interfaceStore } from '@wordpress/interface'; import { createBlock } from '@wordpress/blocks'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; /** * Internal dependencies @@ -13,6 +13,9 @@ import { createBlock } from '@wordpress/blocks'; import { store as editSiteStore } from '../../store'; import { SIDEBAR_BLOCK } from '../sidebar-edit-mode/constants'; import { STORE_NAME } from '../../store/constants'; +import { unlock } from '../../lock-unlock'; + +const { interfaceStore } = unlock( editorPrivateApis ); function KeyboardShortcutsEditMode() { const isBlockInspectorOpen = useSelect( diff --git a/packages/edit-site/src/components/layout/index.js b/packages/edit-site/src/components/layout/index.js index 1ff31c973a99cd..51f55302f16e75 100644 --- a/packages/edit-site/src/components/layout/index.js +++ b/packages/edit-site/src/components/layout/index.js @@ -19,7 +19,6 @@ import { } from '@wordpress/compose'; import { __ } from '@wordpress/i18n'; import { useState } from '@wordpress/element'; -import { NavigableRegion } from '@wordpress/interface'; import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; import { CommandMenu, @@ -31,6 +30,7 @@ import { store as blockEditorStore, } from '@wordpress/block-editor'; import { privateApis as coreCommandsPrivateApis } from '@wordpress/core-commands'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; /** * Internal dependencies @@ -55,6 +55,7 @@ import useMovingAnimation from './animation'; const { useCommands } = unlock( coreCommandsPrivateApis ); const { useCommandContext } = unlock( commandsPrivateApis ); const { useGlobalStyle } = unlock( blockEditorPrivateApis ); +const { NavigableRegion } = unlock( editorPrivateApis ); const ANIMATION_DURATION = 0.3; diff --git a/packages/edit-site/src/components/page-patterns/header.js b/packages/edit-site/src/components/page-patterns/header.js index ce078900a52297..7cca997c7dd02e 100644 --- a/packages/edit-site/src/components/page-patterns/header.js +++ b/packages/edit-site/src/components/page-patterns/header.js @@ -40,8 +40,10 @@ export default function PatternsHeader( { const templatePartArea = templatePartAreas.find( ( area ) => area.area === categoryId ); - title = templatePartArea?.label; - description = templatePartArea?.description; + title = templatePartArea?.label || __( 'All Template Parts' ); + description = + templatePartArea?.description || + __( 'Includes every template part defined for any area.' ); } else if ( type === PATTERN_TYPES.theme ) { patternCategory = patternCategories.find( ( category ) => category.name === categoryId diff --git a/packages/edit-site/src/components/page-patterns/index.js b/packages/edit-site/src/components/page-patterns/index.js index 6fa84df7a01712..1f8521071530cc 100644 --- a/packages/edit-site/src/components/page-patterns/index.js +++ b/packages/edit-site/src/components/page-patterns/index.js @@ -451,7 +451,7 @@ export default function DataviewsPatterns() { } ); } }, - [ history ] + [ history, categoryId, type ] ); const [ editAction, viewRevisionsAction ] = usePostActions( onActionPerformed, diff --git a/packages/edit-site/src/components/page-patterns/search-items.js b/packages/edit-site/src/components/page-patterns/search-items.js index b5231964a78d68..8aa4b349f48d7c 100644 --- a/packages/edit-site/src/components/page-patterns/search-items.js +++ b/packages/edit-site/src/components/page-patterns/search-items.js @@ -16,6 +16,7 @@ const { extractWords, getNormalizedSearchTerms, normalizeString } = unlock( * Internal dependencies */ import { + TEMPLATE_PART_ALL_AREAS_CATEGORY, PATTERN_DEFAULT_CATEGORY, PATTERN_USER_CATEGORY, PATTERN_TYPES, @@ -48,6 +49,7 @@ const removeMatchingTerms = ( unmatchedTerms, unprocessedTerms ) => { */ export const searchItems = ( items = [], searchInput = '', config = {} ) => { const normalizedSearchTerms = getNormalizedSearchTerms( searchInput ); + // Filter patterns by category: the default category indicates that all patterns will be shown. const onlyFilterByCategory = config.categoryId !== PATTERN_DEFAULT_CATEGORY && @@ -100,6 +102,7 @@ function getItemSearchRank( item, searchTerm, config ) { let rank = categoryId === PATTERN_DEFAULT_CATEGORY || + categoryId === TEMPLATE_PART_ALL_AREAS_CATEGORY || ( categoryId === PATTERN_USER_CATEGORY && item.type === PATTERN_TYPES.user ) || hasCategory( item, categoryId ) diff --git a/packages/edit-site/src/components/page/index.js b/packages/edit-site/src/components/page/index.js index 02d0bd2e746eec..db3e1ad366430b 100644 --- a/packages/edit-site/src/components/page/index.js +++ b/packages/edit-site/src/components/page/index.js @@ -6,13 +6,18 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { NavigableRegion } from '@wordpress/interface'; -import { EditorSnackbars } from '@wordpress/editor'; +import { + EditorSnackbars, + privateApis as editorPrivateApis, +} from '@wordpress/editor'; /** * Internal dependencies */ import Header from './header'; +import { unlock } from '../../lock-unlock'; + +const { NavigableRegion } = unlock( editorPrivateApis ); export default function Page( { title, diff --git a/packages/edit-site/src/components/pattern-modal/duplicate.js b/packages/edit-site/src/components/pattern-modal/duplicate.js index 8de13e9cf39479..e59decbf8b260c 100644 --- a/packages/edit-site/src/components/pattern-modal/duplicate.js +++ b/packages/edit-site/src/components/pattern-modal/duplicate.js @@ -2,10 +2,10 @@ * WordPress dependencies */ import { useDispatch, useSelect } from '@wordpress/data'; -import { store as interfaceStore } from '@wordpress/interface'; import { privateApis as patternsPrivateApis } from '@wordpress/patterns'; import { privateApis as routerPrivateApis } from '@wordpress/router'; import { getQueryArgs } from '@wordpress/url'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; /** * Internal dependencies @@ -17,6 +17,7 @@ import useEditedEntityRecord from '../use-edited-entity-record'; const { DuplicatePatternModal } = unlock( patternsPrivateApis ); const { useHistory } = unlock( routerPrivateApis ); +const { interfaceStore } = unlock( editorPrivateApis ); export default function PatternDuplicateModal() { const { record } = useEditedEntityRecord(); diff --git a/packages/edit-site/src/components/pattern-modal/rename.js b/packages/edit-site/src/components/pattern-modal/rename.js index 3175451bd16460..8c817172cc2099 100644 --- a/packages/edit-site/src/components/pattern-modal/rename.js +++ b/packages/edit-site/src/components/pattern-modal/rename.js @@ -2,8 +2,8 @@ * WordPress dependencies */ import { useDispatch, useSelect } from '@wordpress/data'; -import { store as interfaceStore } from '@wordpress/interface'; import { privateApis as patternsPrivateApis } from '@wordpress/patterns'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; /** * Internal dependencies @@ -13,6 +13,7 @@ import { unlock } from '../../lock-unlock'; import useEditedEntityRecord from '../use-edited-entity-record'; const { RenamePatternModal } = unlock( patternsPrivateApis ); +const { interfaceStore } = unlock( editorPrivateApis ); export default function PatternRenameModal() { const { record: pattern } = useEditedEntityRecord(); diff --git a/packages/edit-site/src/components/preferences-modal/index.js b/packages/edit-site/src/components/preferences-modal/index.js index 4d719fedad234f..89d113cb8d1b71 100644 --- a/packages/edit-site/src/components/preferences-modal/index.js +++ b/packages/edit-site/src/components/preferences-modal/index.js @@ -1,7 +1,6 @@ /** * WordPress dependencies */ -import { store as interfaceStore } from '@wordpress/interface'; import { useSelect, useDispatch } from '@wordpress/data'; import { privateApis as editorPrivateApis } from '@wordpress/editor'; @@ -10,7 +9,7 @@ import { privateApis as editorPrivateApis } from '@wordpress/editor'; */ import { unlock } from '../../lock-unlock'; -const { PreferencesModal } = unlock( editorPrivateApis ); +const { PreferencesModal, interfaceStore } = unlock( editorPrivateApis ); export const PREFERENCES_MODAL_NAME = 'edit-site/preferences'; diff --git a/packages/edit-site/src/components/save-panel/index.js b/packages/edit-site/src/components/save-panel/index.js index 8a09a81ab38e5b..b3545e0566fca6 100644 --- a/packages/edit-site/src/components/save-panel/index.js +++ b/packages/edit-site/src/components/save-panel/index.js @@ -14,7 +14,6 @@ import { } from '@wordpress/editor'; import { useDispatch, useSelect } from '@wordpress/data'; import { __, sprintf } from '@wordpress/i18n'; -import { NavigableRegion } from '@wordpress/interface'; import { store as coreStore } from '@wordpress/core-data'; /** @@ -26,7 +25,8 @@ import { useActivateTheme } from '../../utils/use-activate-theme'; import { useActualCurrentTheme } from '../../utils/use-actual-current-theme'; import { isPreviewingTheme } from '../../utils/is-previewing-theme'; -const { EntitiesSavedStatesExtensible } = unlock( privateApis ); +const { EntitiesSavedStatesExtensible, NavigableRegion } = + unlock( privateApis ); const EntitiesSavedStatesForPreview = ( { onClose } ) => { const isDirtyProps = useEntitiesSavedStatesIsDirty(); diff --git a/packages/edit-site/src/components/sidebar-edit-mode/default-sidebar.js b/packages/edit-site/src/components/sidebar-edit-mode/default-sidebar.js index f92ca4c75929cb..7cbd18565e51f7 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/default-sidebar.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/default-sidebar.js @@ -1,10 +1,15 @@ /** * WordPress dependencies */ -import { - ComplementaryArea, - ComplementaryAreaMoreMenuItem, -} from '@wordpress/interface'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; + +/** + * Internal dependencies + */ +import { unlock } from '../../lock-unlock'; + +const { ComplementaryArea, ComplementaryAreaMoreMenuItem } = + unlock( editorPrivateApis ); export default function DefaultSidebar( { className, diff --git a/packages/edit-site/src/components/sidebar-edit-mode/global-styles-sidebar.js b/packages/edit-site/src/components/sidebar-edit-mode/global-styles-sidebar.js index 5cc0baa489ec73..db02312bbf5640 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/global-styles-sidebar.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/global-styles-sidebar.js @@ -12,9 +12,11 @@ import { __ } from '@wordpress/i18n'; import { styles, seen, backup } from '@wordpress/icons'; import { useSelect, useDispatch } from '@wordpress/data'; import { useEffect } from '@wordpress/element'; -import { store as interfaceStore } from '@wordpress/interface'; import { store as preferencesStore } from '@wordpress/preferences'; -import { store as editorStore } from '@wordpress/editor'; +import { + store as editorStore, + privateApis as editorPrivateApis, +} from '@wordpress/editor'; /** * Internal dependencies @@ -26,6 +28,8 @@ import { GlobalStylesMenuSlot } from '../global-styles/ui'; import { unlock } from '../../lock-unlock'; import { store as coreStore } from '@wordpress/core-data'; +const { interfaceStore } = unlock( editorPrivateApis ); + export default function GlobalStylesSidebar() { const { shouldClearCanvasContainerView, diff --git a/packages/edit-site/src/components/sidebar-edit-mode/index.js b/packages/edit-site/src/components/sidebar-edit-mode/index.js index 38b2ca0665cc4b..71eb093e980039 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/index.js @@ -9,9 +9,9 @@ import { isRTL, __ } from '@wordpress/i18n'; import { drawerLeft, drawerRight } from '@wordpress/icons'; import { useCallback, useContext, useEffect, useRef } from '@wordpress/element'; import { useSelect, useDispatch } from '@wordpress/data'; -import { store as interfaceStore } from '@wordpress/interface'; import { store as blockEditorStore } from '@wordpress/block-editor'; import { store as coreStore } from '@wordpress/core-data'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; /** * Internal dependencies @@ -27,7 +27,7 @@ import { store as editSiteStore } from '../../store'; import { unlock } from '../../lock-unlock'; const { Tabs } = unlock( componentsPrivateApis ); - +const { interfaceStore } = unlock( editorPrivateApis ); const { Slot: InspectorSlot, Fill: InspectorFill } = createSlotFill( 'EditSiteSidebarInspector' ); diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss index b57d3f6b3e9c98..426bf103bb41ab 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss @@ -1,11 +1,3 @@ -.edit-site-page-card__actions { - flex-shrink: 0; -} - -.edit-site-page-panels__swap-template__confirm-modal__actions { - margin-top: $grid-unit-30; -} - .edit-site-change-status__content { .components-popover__content { min-width: 320px; diff --git a/packages/edit-site/src/components/sidebar-edit-mode/plugin-sidebar/index.js b/packages/edit-site/src/components/sidebar-edit-mode/plugin-sidebar/index.js index 23eafa7b473054..a67dd885758c00 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/plugin-sidebar/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/plugin-sidebar/index.js @@ -1,7 +1,14 @@ /** * WordPress dependencies */ -import { ComplementaryArea } from '@wordpress/interface'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; + +/** + * Internal dependencies + */ +import { unlock } from '../../../lock-unlock'; + +const { ComplementaryArea } = unlock( editorPrivateApis ); /** * Renders a sidebar when activated. The contents within the `PluginSidebar` will appear as content within the sidebar. diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-page/index.js b/packages/edit-site/src/components/sidebar-navigation-screen-page/index.js index 3ac1e00127c0fb..d6a43fd9b6a911 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-page/index.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-page/index.js @@ -108,7 +108,10 @@ export default function SidebarNavigationScreenPage( { backPath } ) { ) } actions={ <> - + setCanvasMode( 'edit' ) } label={ __( 'Edit' ) } diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/index.js b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/index.js index 587c24e326c2dd..933ef256cf0459 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/index.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/index.js @@ -38,6 +38,22 @@ function TemplatePartGroup( { areas, currentArea, currentType } ) { { __( 'Template parts' ) }
    + templateParts?.length || 0 + ) + .reduce( ( acc, val ) => acc + val, 0 ) } + icon={ getTemplatePartIcon() } /* no name, so it provides the fallback icon */ + label={ __( 'All template parts' ) } + id={ 'all-parts' } + type={ TEMPLATE_PART_POST_TYPE } + isActive={ + currentArea === 'all-parts' && + currentType === TEMPLATE_PART_POST_TYPE + } + /> { Object.entries( areas ).map( ( [ area, { label, templateParts } ] ) => ( { + RenderModal: ( { items, closeModal, onActionPerformed } ) => { const [ item ] = items; const originalTitle = decodeEntities( typeof item.title === 'string' ? item.title : item.title.rendered @@ -455,6 +455,7 @@ const renamePostAction = { createSuccessNotice( __( 'Name updated' ), { type: 'snackbar', } ); + onActionPerformed?.( items ); } catch ( error ) { const errorMessage = error.message && error.code !== 'unknown_error' @@ -582,7 +583,7 @@ const resetTemplateAction = { variant="primary" onClick={ async () => { await onConfirm( items ); - onActionPerformed?.(); + onActionPerformed?.( items ); closeModal(); } } > @@ -650,7 +651,7 @@ const deleteTemplateAction = { await removeTemplates( templates, { allowUndo: false, } ); - onActionPerformed?.(); + onActionPerformed?.( templates ); closeModal(); } } > @@ -676,7 +677,7 @@ const renameTemplateAction = { } return true; }, - RenderModal: ( { items: templates, closeModal } ) => { + RenderModal: ( { items: templates, closeModal, onActionPerformed } ) => { const template = templates[ 0 ]; const title = decodeEntities( template.title.rendered ); const [ editedTitle, setEditedTitle ] = useState( title ); @@ -718,6 +719,7 @@ const renameTemplateAction = { type: 'snackbar', } ); + onActionPerformed?.( templates ); } catch ( error ) { const fallbackErrorMessage = template.type === TEMPLATE_POST_TYPE diff --git a/packages/editor/src/components/post-actions/index.js b/packages/editor/src/components/post-actions/index.js index 379231b0a9dff0..f671f7b038ee29 100644 --- a/packages/editor/src/components/post-actions/index.js +++ b/packages/editor/src/components/post-actions/index.js @@ -2,7 +2,6 @@ * WordPress dependencies */ import { useSelect } from '@wordpress/data'; -import { store as coreStore } from '@wordpress/core-data'; import { useMemo, useState, Fragment, Children } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { @@ -40,25 +39,18 @@ const POST_ACTIONS_WHILE_EDITING = [ 'move-to-trash', ]; -export default function PostActions( { onActionPerformed } ) { - const { postType, postId } = useSelect( ( select ) => { - const { getCurrentPostType, getCurrentPostId } = select( editorStore ); +export default function PostActions( { onActionPerformed, buttonProps } ) { + const { postType, item } = useSelect( ( select ) => { + const { getCurrentPostType, getCurrentPost } = select( editorStore ); return { postType: getCurrentPostType(), - postId: getCurrentPostId(), + item: getCurrentPost(), }; } ); const actions = usePostActions( onActionPerformed, POST_ACTIONS_WHILE_EDITING ); - const item = useSelect( - ( select ) => { - const { getEditedEntityRecord } = select( coreStore ); - return getEditedEntityRecord( 'postType', postType, postId ); - }, - [ postType, postId ] - ); const { primaryActions, secondaryActions } = useMemo( () => { return actions.reduce( @@ -96,6 +88,7 @@ export default function PostActions( { onActionPerformed } ) { ! primaryActions.length && ! secondaryActions.length } className="editor-all-actions-button" + { ...buttonProps } /> } placement="bottom-end" diff --git a/packages/editor/src/components/post-card-panel/index.js b/packages/editor/src/components/post-card-panel/index.js index 757040f6336b69..a8419c0feb8c2f 100644 --- a/packages/editor/src/components/post-card-panel/index.js +++ b/packages/editor/src/components/post-card-panel/index.js @@ -19,6 +19,7 @@ import { __, _x, _n, sprintf } from '@wordpress/i18n'; import { humanTimeDiff } from '@wordpress/date'; import { decodeEntities } from '@wordpress/html-entities'; import { count as wordCount } from '@wordpress/wordcount'; +import { useMemo } from '@wordpress/element'; /** * Internal dependencies @@ -32,40 +33,34 @@ import { unlock } from '../../lock-unlock'; import TemplateAreas from '../template-areas'; export default function PostCardPanel( { className, actions } ) { - const { - modified, - title, - templateInfo, - icon, - postType, - postContent, - isPostsPage, - } = useSelect( ( select ) => { - const { - getEditedPostAttribute, - getCurrentPostType, - getCurrentPostId, - __experimentalGetTemplateInfo, - } = select( editorStore ); - const { getEditedEntityRecord, getEntityRecord } = select( coreStore ); - const siteSettings = getEntityRecord( 'root', 'site' ); - const _type = getCurrentPostType(); - const _id = getCurrentPostId(); - const _record = getEditedEntityRecord( 'postType', _type, _id ); - const _templateInfo = __experimentalGetTemplateInfo( _record ); - return { - title: _templateInfo?.title || getEditedPostAttribute( 'title' ), - modified: getEditedPostAttribute( 'modified' ), - id: _id, - postType: _type, - templateInfo: _templateInfo, - icon: unlock( select( editorStore ) ).getPostIcon( _type, { - area: _record?.area, - } ), - isPostsPage: +_id === siteSettings?.page_for_posts, - postContent: getEditedPostAttribute( 'content' ), - }; - }, [] ); + const { modified, title, templateInfo, icon, postType, isPostsPage } = + useSelect( ( select ) => { + const { + getEditedPostAttribute, + getCurrentPostType, + getCurrentPostId, + __experimentalGetTemplateInfo, + } = select( editorStore ); + const { getEditedEntityRecord, getEntityRecord } = + select( coreStore ); + const siteSettings = getEntityRecord( 'root', 'site' ); + const _type = getCurrentPostType(); + const _id = getCurrentPostId(); + const _record = getEditedEntityRecord( 'postType', _type, _id ); + const _templateInfo = __experimentalGetTemplateInfo( _record ); + return { + title: + _templateInfo?.title || getEditedPostAttribute( 'title' ), + modified: getEditedPostAttribute( 'modified' ), + id: _id, + postType: _type, + templateInfo: _templateInfo, + icon: unlock( select( editorStore ) ).getPostIcon( _type, { + area: _record?.area, + } ), + isPostsPage: +_id === siteSettings?.page_for_posts, + }; + }, [] ); const description = templateInfo?.description; const lastEditedText = modified && @@ -111,9 +106,7 @@ export default function PostCardPanel( { className, actions } ) { spacing={ 2 } > { description && { description } } - { showPostContentInfo && ( - - ) } + { showPostContentInfo && } { lastEditedText && ( { lastEditedText } ) } @@ -130,16 +123,21 @@ export default function PostCardPanel( { className, actions } ) { const AVERAGE_READING_RATE = 189; // This component renders the wordcount and reading time for the post. -function PostContentInfo( { postContent } ) { +function PostContentInfo() { + const postContent = useSelect( + ( select ) => select( editorStore ).getEditedPostAttribute( 'content' ), + [] + ); /* * translators: If your word count is based on single characters (e.g. East Asian characters), * enter 'characters_excluding_spaces' or 'characters_including_spaces'. Otherwise, enter 'words'. * Do not translate into your own language. */ const wordCountType = _x( 'words', 'Word count type. Do not translate!' ); - const wordsCounted = postContent - ? wordCount( postContent, wordCountType ) - : 0; + const wordsCounted = useMemo( + () => ( postContent ? wordCount( postContent, wordCountType ) : 0 ), + [ postContent, wordCountType ] + ); if ( ! wordsCounted ) { return null; } diff --git a/packages/editor/src/components/provider/index.js b/packages/editor/src/components/provider/index.js index 5d4b2c0079a741..b1a2164e1274ef 100644 --- a/packages/editor/src/components/provider/index.js +++ b/packages/editor/src/components/provider/index.js @@ -26,6 +26,7 @@ import NavigationBlockEditingMode from './navigation-block-editing-mode'; import { useHideBlocksFromInserter } from './use-hide-blocks-from-inserter'; import useCommands from '../commands'; import BlockRemovalWarnings from '../block-removal-warnings'; +import StartPageOptions from '../start-page-options'; const { ExperimentalBlockEditorProvider } = unlock( blockEditorPrivateApis ); const { PatternsMenuItems } = unlock( editPatternsPrivateApis ); @@ -267,6 +268,7 @@ export const ExperimentalEditorProvider = withRegistryProvider( ) } + diff --git a/packages/editor/src/components/provider/with-registry-provider.js b/packages/editor/src/components/provider/with-registry-provider.js index d463c04f74d98e..32c30a9f8d6873 100644 --- a/packages/editor/src/components/provider/with-registry-provider.js +++ b/packages/editor/src/components/provider/with-registry-provider.js @@ -35,6 +35,7 @@ const withRegistryProvider = createHigherOrderComponent( }, registry ); + // Todo: The interface store should also be created per instance. newRegistry.registerStore( 'core/editor', storeConfig ); setSubRegistry( newRegistry ); }, [ registry ] ); diff --git a/packages/edit-post/src/components/start-page-options/index.js b/packages/editor/src/components/start-page-options/index.js similarity index 58% rename from packages/edit-post/src/components/start-page-options/index.js rename to packages/editor/src/components/start-page-options/index.js index 0ef3e166e8ee1a..70e7ecd642d4c5 100644 --- a/packages/edit-post/src/components/start-page-options/index.js +++ b/packages/editor/src/components/start-page-options/index.js @@ -3,19 +3,19 @@ */ import { Modal } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useState, useMemo } from '@wordpress/element'; +import { useState, useMemo, useEffect } from '@wordpress/element'; import { store as blockEditorStore, __experimentalBlockPatternsList as BlockPatternsList, } from '@wordpress/block-editor'; import { useSelect, useDispatch } from '@wordpress/data'; import { useAsyncList } from '@wordpress/compose'; -import { store as editorStore } from '@wordpress/editor'; +import { store as coreStore } from '@wordpress/core-data'; /** * Internal dependencies */ -import { store as editPostStore } from '../../store'; +import { store as editorStore } from '../../store'; function useStartPatterns() { // A pattern is a start pattern if it includes 'core/post-content' in its blockTypes, @@ -23,11 +23,19 @@ function useStartPatterns() { // the current post type is part of the postTypes declared. const { blockPatternsWithPostContentBlockType, postType } = useSelect( ( select ) => { - const { getPatternsByBlockTypes } = select( blockEditorStore ); - const { getCurrentPostType } = select( editorStore ); + const { getPatternsByBlockTypes, getBlocksByName } = + select( blockEditorStore ); + const { getCurrentPostType, getRenderingMode } = + select( editorStore ); + const rootClientId = + getRenderingMode() === 'post-only' + ? '' + : getBlocksByName( 'core/post-content' )?.[ 0 ]; return { - blockPatternsWithPostContentBlockType: - getPatternsByBlockTypes( 'core/post-content' ), + blockPatternsWithPostContentBlockType: getPatternsByBlockTypes( + 'core/post-content', + rootClientId + ), postType: getCurrentPostType(), }; }, @@ -49,13 +57,21 @@ function useStartPatterns() { function PatternSelection( { blockPatterns, onChoosePattern } ) { const shownBlockPatterns = useAsyncList( blockPatterns ); - const { resetEditorBlocks } = useDispatch( editorStore ); + const { editEntityRecord } = useDispatch( coreStore ); + const { postType, postId } = useSelect( ( select ) => { + const { getCurrentPostType, getCurrentPostId } = select( editorStore ); + + return { + postType: getCurrentPostType(), + postId: getCurrentPostId(), + }; + }, [] ); return ( { - resetEditorBlocks( blocks ); + editEntityRecord( 'postType', postType, postId, { blocks } ); onChoosePattern(); } } /> @@ -72,12 +88,11 @@ function StartPageOptionsModal( { onClose } ) { return ( -
    +
    { - const { isCleanNewPost, getRenderingMode } = select( editorStore ); - const { isFeatureActive } = select( editPostStore ); + const { shouldEnableModal, postType, postId } = useSelect( ( select ) => { + const { + isEditedPostDirty, + isEditedPostEmpty, + getCurrentPostType, + getCurrentPostId, + getEditorSettings, + } = select( editorStore ); + const { __unstableIsPreviewMode: isPreviewMode } = getEditorSettings(); - return ( - getRenderingMode() === 'post-only' && - ! isFeatureActive( 'welcomeGuide' ) && - isCleanNewPost() - ); + return { + shouldEnableModal: + ! isPreviewMode && ! isEditedPostDirty() && isEditedPostEmpty(), + postType: getCurrentPostType(), + postId: getCurrentPostId(), + }; }, [] ); + useEffect( () => { + // Should reset the modal state when navigating to a new page/post. + setIsClosed( false ); + }, [ postType, postId ] ); + if ( ! shouldEnableModal || isClosed ) { return null; } diff --git a/packages/edit-post/src/components/start-page-options/style.scss b/packages/editor/src/components/start-page-options/style.scss similarity index 83% rename from packages/edit-post/src/components/start-page-options/style.scss rename to packages/editor/src/components/start-page-options/style.scss index 52f3f5ff9a8889..129d670526c709 100644 --- a/packages/edit-post/src/components/start-page-options/style.scss +++ b/packages/editor/src/components/start-page-options/style.scss @@ -1,5 +1,5 @@ // 2 column masonry layout. -.edit-post-start-page-options__modal-content .block-editor-block-patterns-list { +.editor-start-page-options__modal-content .block-editor-block-patterns-list { column-count: 2; column-gap: $grid-unit-30; diff --git a/packages/editor/src/private-apis.js b/packages/editor/src/private-apis.js index 4bdcbb1042b228..db5036d14df028 100644 --- a/packages/editor/src/private-apis.js +++ b/packages/editor/src/private-apis.js @@ -1,3 +1,8 @@ +/** + * WordPress dependencies + */ +import * as interfaceApis from '@wordpress/interface'; + /** * Internal dependencies */ @@ -20,6 +25,8 @@ import PostActions from './components/post-actions'; import { usePostActions } from './components/post-actions/actions'; import PostCardPanel from './components/post-card-panel'; +const { store: interfaceStore, ...remainingInterfaceApis } = interfaceApis; + export const privateApis = {}; lock( privateApis, { DocumentTools, @@ -41,4 +48,6 @@ lock( privateApis, { // This is a temporary private API while we're updating the site editor to use EditorProvider. useBlockEditorSettings, + interfaceStore, + ...remainingInterfaceApis, } ); diff --git a/packages/editor/src/style.scss b/packages/editor/src/style.scss index 865635f228891e..8d9737c2a4d0e8 100644 --- a/packages/editor/src/style.scss +++ b/packages/editor/src/style.scss @@ -1,3 +1,5 @@ +@import "../../interface/src/style.scss"; + @import "./components/autocompleters/style.scss"; @import "./components/block-manager/style.scss"; @import "./components/document-bar/style.scss"; @@ -30,5 +32,6 @@ @import "./components/post-visibility/style.scss"; @import "./components/post-trash/style.scss"; @import "./components/preview-dropdown/style.scss"; +@import "./components/start-page-options/style.scss"; @import "./components/table-of-contents/style.scss"; @import "./components/template-areas/style.scss"; diff --git a/schemas/json/block.json b/schemas/json/block.json index 672de711be79f3..92bcecf90b9b60 100644 --- a/schemas/json/block.json +++ b/schemas/json/block.json @@ -597,6 +597,22 @@ "type": "boolean", "description": "This value signals that a block supports the line-height CSS style property. When it does, the block editor will show an UI control for the user to set its value if the theme declares support.\n\nWhen the block declares support for lineHeight, its attributes definition is extended to include a new attribute style of object type with no default assigned. It stores the custom value set by the user. The block can apply a default style by specifying its own style attribute with a default", "default": false + }, + "textAlign": { + "description": "This property adds block toolbar controls which allow to change block's text alignment.", + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "type": "string", + "enum": [ "left", "center", "right" ] + } + } + ], + "default": false } } }, diff --git a/schemas/json/theme.json b/schemas/json/theme.json index 63889366b7bd40..7cb34945b56810 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -551,6 +551,11 @@ "type": "boolean", "default": false }, + "textAlign": { + "description": "Allow users to set the text align.", + "type": "boolean", + "default": true + }, "textColumns": { "description": "Allow users to set the number of text columns.", "type": "boolean", @@ -1629,6 +1634,10 @@ } ] }, + "textAlign": { + "description": "Sets the `text-align` CSS property.", + "type": "string" + }, "textColumns": { "description": "Sets the `column-count` CSS property.", "type": "string" diff --git a/storybook/manager-head.html b/storybook/manager-head.html index 21ee902c02a36d..629f06bf98edf9 100644 --- a/storybook/manager-head.html +++ b/storybook/manager-head.html @@ -1,10 +1,19 @@