From c3f00773cf989153c7b5f42e0cd3fab0399ca6fd Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Wed, 22 Nov 2023 21:37:36 +0900 Subject: [PATCH 01/45] NavigableContainers: Fix doc typo in onKeyDown prop (#56352) * NavigableContainers: Fix doc typo in onKeyDown prop * Update changelog * Remove changelog --- packages/components/src/navigable-container/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/navigable-container/README.md b/packages/components/src/navigable-container/README.md index a982219248f50..bbc1f16dcb8f6 100644 --- a/packages/components/src/navigable-container/README.md +++ b/packages/components/src/navigable-container/README.md @@ -24,7 +24,7 @@ Gets an offset, given an event. - Required: No -### `onKeydown`: `( event: KeyboardEvent ) => void` +### `onKeyDown`: `( event: KeyboardEvent ) => void` A callback invoked on the keydown event. From 3539a97717b684bb93907f0e8f915842610098d3 Mon Sep 17 00:00:00 2001 From: Maggie Date: Wed, 22 Nov 2023 13:38:19 +0100 Subject: [PATCH 02/45] Improve tooltip for parent blocks on the block toolbar (#56146) * improve tolltip for parent blocks on the block toolbar * fixed tests * missing test * another missing test * fixed another test --- .../src/components/block-parent-selector/index.js | 2 +- packages/block-library/src/cover/test/edit.js | 2 +- .../specs/editor/various/pattern-blocks.test.js | 2 +- test/e2e/specs/editor/blocks/list.spec.js | 12 ++++++------ .../plugins/inner-blocks-allowed-blocks.spec.js | 12 +++++++++--- .../editor/various/toolbar-roving-tabindex.spec.js | 6 +++--- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/block-editor/src/components/block-parent-selector/index.js b/packages/block-editor/src/components/block-parent-selector/index.js index 31e0b1b8fd8cf..80b314eeb42e5 100644 --- a/packages/block-editor/src/components/block-parent-selector/index.js +++ b/packages/block-editor/src/components/block-parent-selector/index.js @@ -74,7 +74,7 @@ export default function BlockParentSelector() { onClick={ () => selectBlock( firstParentClientId ) } label={ sprintf( /* translators: %s: Name of the block's parent. */ - __( 'Select %s' ), + __( 'Select parent block: %s' ), blockInformation?.title ) } showTooltip diff --git a/packages/block-library/src/cover/test/edit.js b/packages/block-library/src/cover/test/edit.js index d1febe3c6fa11..879b77636255a 100644 --- a/packages/block-library/src/cover/test/edit.js +++ b/packages/block-library/src/cover/test/edit.js @@ -53,7 +53,7 @@ async function createAndSelectBlock() { ); await userEvent.click( screen.getByRole( 'button', { - name: 'Select Cover', + name: 'Select parent block: Cover', } ) ); } diff --git a/packages/e2e-tests/specs/editor/various/pattern-blocks.test.js b/packages/e2e-tests/specs/editor/various/pattern-blocks.test.js index cb5187a390e8b..0d00e3d9a545b 100644 --- a/packages/e2e-tests/specs/editor/various/pattern-blocks.test.js +++ b/packages/e2e-tests/specs/editor/various/pattern-blocks.test.js @@ -350,7 +350,7 @@ describe( 'Pattern blocks', () => { expect( reusableBlockWithParagraph ).toBeTruthy(); // Convert back to regular blocks. - await clickBlockToolbarButton( 'Select Edited block' ); + await clickBlockToolbarButton( 'Select parent block: Edited block' ); await clickBlockToolbarButton( 'Options' ); await clickMenuItem( 'Detach' ); await page.waitForXPath( selector, { diff --git a/test/e2e/specs/editor/blocks/list.spec.js b/test/e2e/specs/editor/blocks/list.spec.js index f10a266a41e65..48d50a862a50b 100644 --- a/test/e2e/specs/editor/blocks/list.spec.js +++ b/test/e2e/specs/editor/blocks/list.spec.js @@ -354,7 +354,7 @@ test.describe( 'List (@firefox)', () => { await page.keyboard.type( 'one' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'two' ); - await editor.clickBlockToolbarButton( 'Select List' ); + await editor.clickBlockToolbarButton( 'Select parent block: List' ); await editor.transformBlockTo( 'core/paragraph' ); await expect.poll( editor.getEditedPostContent ).toBe( @@ -397,7 +397,7 @@ test.describe( 'List (@firefox)', () => { await page.keyboard.type( 'one' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'two' ); - await editor.clickBlockToolbarButton( 'Select List' ); + await editor.clickBlockToolbarButton( 'Select parent block: List' ); await editor.transformBlockTo( 'core/quote' ); await expect.poll( editor.getEditedPostContent ).toBe( @@ -674,7 +674,7 @@ test.describe( 'List (@firefox)', () => { test( 'should change the base list type', async ( { editor } ) => { await editor.insertBlock( { name: 'core/list' } ); - await editor.clickBlockToolbarButton( 'Select List' ); + await editor.clickBlockToolbarButton( 'Select parent block: List' ); await editor.clickBlockToolbarButton( 'Ordered' ); await expect.poll( editor.getEditedPostContent ).toBe( ` @@ -694,7 +694,7 @@ test.describe( 'List (@firefox)', () => { await page.keyboard.press( 'Enter' ); await editor.clickBlockToolbarButton( 'Indent' ); await page.keyboard.type( '1' ); - await editor.clickBlockToolbarButton( 'Select List' ); + await editor.clickBlockToolbarButton( 'Select parent block: List' ); await editor.clickBlockToolbarButton( 'Ordered' ); await expect.poll( editor.getEditedPostContent ).toBe( @@ -1232,7 +1232,7 @@ test.describe( 'List (@firefox)', () => { await page.keyboard.type( '2' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( '3' ); - await editor.clickBlockToolbarButton( 'Select List' ); + await editor.clickBlockToolbarButton( 'Select parent block: List' ); await editor.clickBlockToolbarButton( 'Ordered' ); await expect.poll( editor.getEditedPostContent ).toBe( @@ -1264,7 +1264,7 @@ test.describe( 'List (@firefox)', () => { await page.keyboard.type( 'b' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'c' ); - await editor.clickBlockToolbarButton( 'Select List' ); + await editor.clickBlockToolbarButton( 'Select parent block: List' ); await editor.clickBlockToolbarButton( 'Unordered' ); await expect.poll( editor.getEditedPostContent ).toBe( diff --git a/test/e2e/specs/editor/plugins/inner-blocks-allowed-blocks.spec.js b/test/e2e/specs/editor/plugins/inner-blocks-allowed-blocks.spec.js index c0627121f1649..eaf171adf9313 100644 --- a/test/e2e/specs/editor/plugins/inner-blocks-allowed-blocks.spec.js +++ b/test/e2e/specs/editor/plugins/inner-blocks-allowed-blocks.spec.js @@ -130,13 +130,17 @@ test.describe( 'Allowed Blocks Setting on InnerBlocks', () => { await blockListBox.getByRole( 'option', { name: 'List' } ).click(); // Select the list wrapper and then parent block. await page.keyboard.press( 'ArrowUp' ); - await editor.clickBlockToolbarButton( 'Select Allowed Blocks Dynamic' ); + await editor.clickBlockToolbarButton( + 'Select parent block: Allowed Blocks Dynamic' + ); // Insert the image. await blockAppender.click(); await blockListBox.getByRole( 'option', { name: 'Image' } ).click(); - await editor.clickBlockToolbarButton( 'Select Allowed Blocks Dynamic' ); + await editor.clickBlockToolbarButton( + 'Select parent block: Allowed Blocks Dynamic' + ); await blockAppender.click(); // It should display a different allowed block list. @@ -147,7 +151,9 @@ test.describe( 'Allowed Blocks Setting on InnerBlocks', () => { await blockListBox.getByRole( 'option', { name: 'Gallery' } ).click(); - await editor.clickBlockToolbarButton( 'Select Allowed Blocks Dynamic' ); + await editor.clickBlockToolbarButton( + 'Select parent block: Allowed Blocks Dynamic' + ); await blockAppender.click(); // It should display a different allowed block list. diff --git a/test/e2e/specs/editor/various/toolbar-roving-tabindex.spec.js b/test/e2e/specs/editor/various/toolbar-roving-tabindex.spec.js index e706dfc3607dc..70509348983e6 100644 --- a/test/e2e/specs/editor/various/toolbar-roving-tabindex.spec.js +++ b/test/e2e/specs/editor/various/toolbar-roving-tabindex.spec.js @@ -59,9 +59,9 @@ test.describe( 'Toolbar roving tabindex', () => { await page.keyboard.type( 'List' ); await ToolbarRovingTabindexUtils.testBlockToolbarKeyboardNavigation( 'List text', - 'Select List' + 'Select parent block: List' ); - await page.click( `role=button[name="Select List"i]` ); + await page.click( `role=button[name="Select parent block: List"i]` ); await ToolbarRovingTabindexUtils.wrapCurrentBlockWithGroup( 'List' ); await ToolbarRovingTabindexUtils.testGroupKeyboardNavigation( 'Block: List', @@ -201,7 +201,7 @@ class ToolbarRovingTabindexUtils { await this.page.keyboard.press( 'ArrowRight' ); await this.expectLabelToHaveFocus( currentBlockLabel ); await this.pageUtils.pressKeys( 'shift+Tab' ); - await this.expectLabelToHaveFocus( 'Select Group' ); + await this.expectLabelToHaveFocus( 'Select parent block: Group' ); await this.page.keyboard.press( 'ArrowRight' ); await this.expectLabelToHaveFocus( currentBlockTitle ); } From c5ac49093e11ee641f8599fe47d2276820d429ef Mon Sep 17 00:00:00 2001 From: Luis Felipe Zaguini <26530524+zaguiini@users.noreply.github.com> Date: Wed, 22 Nov 2023 10:08:09 -0300 Subject: [PATCH 03/45] PostCSS style transformation: fail gracefully instead of throwing an error (#56093) * PostCSS style transformation: fail gracefully instead of throwing error * Display better warning messages --- .../src/utils/test/transform-styles.js | 49 +++++++++++++++++++ .../src/utils/transform-styles/index.js | 44 ++++++++++++----- 2 files changed, 80 insertions(+), 13 deletions(-) diff --git a/packages/block-editor/src/utils/test/transform-styles.js b/packages/block-editor/src/utils/test/transform-styles.js index f162a0b2f6048..38eaa1947d2a8 100644 --- a/packages/block-editor/src/utils/test/transform-styles.js +++ b/packages/block-editor/src/utils/test/transform-styles.js @@ -4,6 +4,55 @@ import transformStyles from '../transform-styles'; describe( 'transformStyles', () => { + describe( 'error handling', () => { + beforeEach( () => { + // Intentionally suppress the expected console errors and warnings to reduce + // noise in the test output. + jest.spyOn( console, 'warn' ).mockImplementation( jest.fn() ); + } ); + + it( 'should not throw error in case of invalid css', () => { + const run = () => + transformStyles( + [ + { + css: 'h1 { color: red;', // invalid CSS + }, + ], + '.my-namespace' + ); + + expect( run ).not.toThrow(); + expect( console ).toHaveWarned(); + } ); + + it( 'should warn invalid css in the console', () => { + const run = () => + transformStyles( + [ + { + css: 'h1 { color: red; }', // valid CSS + }, + { + css: 'h1 { color: red;', // invalid CSS + }, + ], + '.my-namespace' + ); + + const [ validCSS, invalidCSS ] = run(); + + expect( validCSS ).toBe( '.my-namespace h1 { color: red; }' ); + expect( invalidCSS ).toBe( null ); + + expect( console ).toHaveWarnedWith( + 'wp.blockEditor.transformStyles Failed to transform CSS.', + ':1:1: Unclosed block\n> 1 | h1 { color: red;\n | ^' + // ^^^^ In PostCSS, a tab is equal four spaces + ); + } ); + } ); + describe( 'selector wrap', () => { it( 'should wrap regular selectors', () => { const input = `h1 { color: red; }`; diff --git a/packages/block-editor/src/utils/transform-styles/index.js b/packages/block-editor/src/utils/transform-styles/index.js index 8f5e1702307a4..4da6f6ce23795 100644 --- a/packages/block-editor/src/utils/transform-styles/index.js +++ b/packages/block-editor/src/utils/transform-styles/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import postcss from 'postcss'; +import postcss, { CssSyntaxError } from 'postcss'; import wrap from 'postcss-prefixwrap'; import rebaseUrl from 'postcss-urlrebase'; @@ -19,18 +19,36 @@ import rebaseUrl from 'postcss-urlrebase'; */ const transformStyles = ( styles, wrapperSelector = '' ) => { return styles.map( ( { css, ignoredSelectors = [], baseURL } ) => { - return postcss( - [ - wrapperSelector && - wrap( wrapperSelector, { - ignoredSelectors: [ - ...ignoredSelectors, - wrapperSelector, - ], - } ), - baseURL && rebaseUrl( { rootUrl: baseURL } ), - ].filter( Boolean ) - ).process( css, {} ).css; // use sync PostCSS API + try { + return postcss( + [ + wrapperSelector && + wrap( wrapperSelector, { + ignoredSelectors: [ + ...ignoredSelectors, + wrapperSelector, + ], + } ), + baseURL && rebaseUrl( { rootUrl: baseURL } ), + ].filter( Boolean ) + ).process( css, {} ).css; // use sync PostCSS API + } catch ( error ) { + if ( error instanceof CssSyntaxError ) { + // eslint-disable-next-line no-console + console.warn( + 'wp.blockEditor.transformStyles Failed to transform CSS.', + error.message + '\n' + error.showSourceCode( false ) + ); + } else { + // eslint-disable-next-line no-console + console.warn( + 'wp.blockEditor.transformStyles Failed to transform CSS.', + error + ); + } + + return null; + } } ); }; From f73f8d2ae1e4769ccac645c4f6ae0819729f6926 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 22 Nov 2023 15:03:55 +0100 Subject: [PATCH 04/45] Documentation: Add the attributes definition page to the create block tutorial of the platform docs (#56429) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Héctor <27339341+priethor@users.noreply.github.com> --- platform-docs/docs/create-block/attributes.md | 86 ++++++++++++++++++- .../docs/create-block/block-supports.md | 2 +- .../docs/create-block/using-styles.md | 2 +- 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/platform-docs/docs/create-block/attributes.md b/platform-docs/docs/create-block/attributes.md index 044b326ae54a5..a2da8ee5c3694 100644 --- a/platform-docs/docs/create-block/attributes.md +++ b/platform-docs/docs/create-block/attributes.md @@ -1,5 +1,87 @@ --- -sidebar_position: 4 +sidebar_position: 2 --- -# Block attributes \ No newline at end of file +# Block Attributes + +Attributes are the way a block stores data, they define the structure of a block. Upon serialization, some attributes are saved into the HTML output while others are kept in a the HTML block comment delimiters. + +For this block tutorial, we want to allow the user to type a message that we will display stylized in the saved content. So, we need to add a **message** attribute that will hold the user message. The following code defines a **message** attribute; the attribute type is a string. When serializing the blocks, the message will be saved within a `div`container. This means that we're going to source the value attribute using `text` source from the selector, which is a `div` tag. + +```js +const attributes = { + message: { + type: 'string', + source: 'text', + selector: 'div', + 'default': '' + } +}; +``` + +Add this to the settings arguments of the `registerBlockType` function call. + +**Note:** The text source is equivalent to `innerText` attribute of a DOM element. + +## Edit and Save + +The **attributes** are passed to both the `edit` and `save` functions. The **setAttributes** function is also passed, but only to the `edit` function. The **setAttributes** function is used to set the values. + +The `attributes` is a JavaScript object containing the values of each attribute, or default values if defined. The `setAttributes` is a function to update an attribute. + +```js +function Edit( { attributes, setAttributes } ) { + // ... +} + +function Save( { attributes } ) { + // ... +} + +registerBlockType( 'gutenpride/gutenpride-block', { + // ... + attributes, + edit: Edit, + save: Save, +} ); +``` + +## TextControl Component + +For our example block, the component we are going to use is the **TextControl** component, which is similar to an HTML text input field. You can see [the documentation for the `TextControl` component](https://developer.wordpress.org/block-editor/reference-guides/components/text-control/). You can browse an [interactive set of components in this Storybook](https://wordpress.github.io/gutenberg/). + +The component is added similar to an HTML tag, setting a label, the `value` is set to the `attributes.message` and the `onChange` function uses the `setAttributes` to update the message attribute value. + +The save function will simply write the `attributes.message` as a `div` tag since that is how we defined it to be parsed. Update the `edit.js` and `save.js` files to the following, replacing the existing functions. + +**edit.js** file: + +```js +import { useBlockProps } from '@wordpress/block-editor'; +import { TextControl } from '@wordpress/components'; + +function Edit( { attributes, setAttributes } ) { + return ( +
+ setAttributes( { message: val } ) } + /> +
+ ); +} +``` + +**save.js** file: + +```jsx +import { useBlockProps } from '@wordpress/block-editor'; + +function Save( { attributes } ) { + const blockProps = useBlockProps.save(); + return
{ attributes.message }
; +} +``` + +Reload the editor and add the block. You can now type a message in the editor and it will be included in the serialized HTML output. diff --git a/platform-docs/docs/create-block/block-supports.md b/platform-docs/docs/create-block/block-supports.md index 20cfccebd4b05..4a245f210d654 100644 --- a/platform-docs/docs/create-block/block-supports.md +++ b/platform-docs/docs/create-block/block-supports.md @@ -1,3 +1,3 @@ --- -sidebar_position: 3 +sidebar_position: 4 --- diff --git a/platform-docs/docs/create-block/using-styles.md b/platform-docs/docs/create-block/using-styles.md index 1d5ac2bcd0721..c8d1bb91d5961 100644 --- a/platform-docs/docs/create-block/using-styles.md +++ b/platform-docs/docs/create-block/using-styles.md @@ -1,5 +1,5 @@ --- -sidebar_position: 2 +sidebar_position: 3 --- # Using styles and stylesheets \ No newline at end of file From fbc962cc618775a8df9d2a6b36b4785010dd0e14 Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Wed, 22 Nov 2023 23:20:33 +0900 Subject: [PATCH 05/45] Theme JSON schema: add heading/button key to color definition (#55674) * Theme JSON schema: add heading/button key to color definition * Update docs * Add "in a block" --- .../theme-json-reference/theme-json-living.md | 2 ++ schemas/json/theme.json | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) 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 4890386ca8333..492cdaf089cc4 100644 --- a/docs/reference-guides/theme-json-reference/theme-json-living.md +++ b/docs/reference-guides/theme-json-reference/theme-json-living.md @@ -95,6 +95,8 @@ Settings related to colors. | link | boolean | false | | | palette | array | | color, name, slug | | text | boolean | true | | +| heading | boolean | true | | +| button | boolean | true | | --- diff --git a/schemas/json/theme.json b/schemas/json/theme.json index 5a24f1b16c1a3..68c649e337d82 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -200,7 +200,7 @@ } }, "link": { - "description": "Allow users to set link colors.", + "description": "Allow users to set link colors in a block.", "type": "boolean", "default": false }, @@ -228,7 +228,17 @@ } }, "text": { - "description": "Allow users to set text colors.", + "description": "Allow users to set text colors in a block.", + "type": "boolean", + "default": true + }, + "heading": { + "description": "Allow users to set heading colors in a block.", + "type": "boolean", + "default": true + }, + "button": { + "description": "Allow users to set button colors in a block.", "type": "boolean", "default": true } From 8b59123df5e19a95142ef0e299d0713e99a129da Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 22 Nov 2023 18:33:58 +0400 Subject: [PATCH 06/45] Playwright Utils: Fix the method of getting post ID in 'publishPost' (#56421) * Playwright Utils: Fix the method of getting post ID in 'publishPost' * Update sidebar permalink e2e test --- .../src/editor/publish-post.ts | 11 +++++------ .../specs/editor/various/sidebar-permalink.spec.js | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/e2e-test-utils-playwright/src/editor/publish-post.ts b/packages/e2e-test-utils-playwright/src/editor/publish-post.ts index 09cca7417c4de..0a2b9e64dc597 100644 --- a/packages/e2e-test-utils-playwright/src/editor/publish-post.ts +++ b/packages/e2e-test-utils-playwright/src/editor/publish-post.ts @@ -28,12 +28,11 @@ export async function publishPost( this: Editor ) { 'role=region[name="Editor publish"i] >> role=button[name="Publish"i]' ); - const urlString = await this.page - .getByRole( 'region', { name: 'Editor publish' } ) - .getByRole( 'textbox', { name: 'address' } ) - .inputValue(); - const url = new URL( urlString ); - const postId = url.searchParams.get( 'p' ); + await this.page + .getByRole( 'button', { name: 'Dismiss this notice' } ) + .filter( { hasText: 'published' } ) + .waitFor(); + const postId = new URL( this.page.url() ).searchParams.get( 'post' ); return typeof postId === 'string' ? parseInt( postId, 10 ) : null; } diff --git a/test/e2e/specs/editor/various/sidebar-permalink.spec.js b/test/e2e/specs/editor/various/sidebar-permalink.spec.js index dcc16844d424a..96283e4b6b15f 100644 --- a/test/e2e/specs/editor/various/sidebar-permalink.spec.js +++ b/test/e2e/specs/editor/various/sidebar-permalink.spec.js @@ -48,7 +48,7 @@ test.describe( 'Sidebar Permalink', () => { await editor.canvas .getByRole( 'textbox', { name: 'Add title' } ) .fill( 'aaaaa' ); - await editor.saveDraft(); + await editor.publishPost(); // Start editing again. await editor.canvas .getByRole( 'textbox', { name: 'Add title' } ) From 57f117111c5f043bb89c0790d3759461a539bb59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Wed, 22 Nov 2023 16:20:57 +0100 Subject: [PATCH 07/45] Documentation: add new section to release docs about troubleshooting the release (#56436) --- docs/contributors/code/release.md | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/docs/contributors/code/release.md b/docs/contributors/code/release.md index 8c8ed3ff3c334..d19be240f4870 100644 --- a/docs/contributors/code/release.md +++ b/docs/contributors/code/release.md @@ -25,6 +25,7 @@ Similar requirements apply to releasing WordPress's [npm packages](https://devel - [Automated cherry-picking](#automated-cherry-picking) - [Manual cherry-picking](#manual-cherry-picking) - [Publishing the release](#publishing-the-release) + - [Troubleshooting the release](#troubleshooting-the-release) - [Documenting the release](#documenting-the-release) - [Selecting the release highlights](#selecting-the-release-highlights) - [Requesting release assets](#requesting-release-assets) @@ -253,6 +254,41 @@ Once approved, the new Gutenberg version will be available to WordPress users al The final step is to write a release post on [make.wordpress.org/core](https://make.wordpress.org/core/). You can find some tips on that below. +#### Troubleshooting the release + +> The plugin was published to the WordPress.org plugin directory but the workflow failed. + +This has happened ocassionally, see [this one](https://github.com/WordPress/gutenberg/actions/runs/6955409957/job/18924124118) for example. + +It's important to check that: + +- the plugin from the directory works as expected +- the ZIP contents (see [Downloads](https://plugins.trac.wordpress.org/browser/gutenberg/)) looks correct (doesn't have anything obvious missing) +- the [Gutenberg SVN repo](https://plugins.trac.wordpress.org/browser/gutenberg/) has two new commits (see [the log](https://plugins.trac.wordpress.org/browser/gutenberg/)): + - the `trunk` folder should have "Commiting version X.Y.Z" + - there is a new `tags/X.Y.Z` folder with the same contents as `trunk` whose latest commit is "Tagging version X.Y.Z" + +Most likely, the tag folder couldn't be created. This is a [known issue](https://plugins.trac.wordpress.org/browser/gutenberg/) that [can be fixed manually](https://github.com/WordPress/gutenberg/issues/55295#issuecomment-1759292978). + +Either substitute SVN_USERNAME, SVN_PASSWORD, and VERSION for the proper values or set them as global environment variables first: + +```sh +# CHECKOUT THE REPOSITORY +svn checkout https://plugins.svn.wordpress.org/gutenberg/trunk --username "$SVN_USERNAME" --password "$SVN_PASSWORD" gutenberg-svn + +# MOVE TO THE LOCAL FOLDER +cd gutenberg-svn + +# IF YOU HAPPEN TO HAVE ALREADY THE REPO LOCALLY +# AND DIDN'T CHECKOUT, MAKE SURE IT IS UPDATED +# svn up . + +# COPY CURRENT TRUNK INTO THE NEW TAGS FOLDER +svn copy https://plugins.svn.wordpress.org/gutenberg/trunk https://plugins.svn.wordpress.org/gutenberg/tags/$VERSION -m 'Tagging version $VERSION' --no-auth-cache --non-interactive --username "$SVN_USERNAME" --password "$SVN_PASSWORD" +``` + +Ask around if you need help with any of this. + ### Documenting the release Documenting the release is led by the release manager with the help of [Gutenberg development team](https://developer.wordpress.org/block-editor/block-editor/contributors/repository-management/#teams) members. This process is comprised of a series of sequential steps that, because of the number of people involved, and the coordination required, need to adhere to a timeline between the RC and stable releases. Stable Gutenberg releases happen on Wednesdays, one week after the initial RC. From 16945143459acfe7085834c6b7358d8a7eeaa03d Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Wed, 22 Nov 2023 16:10:49 +0000 Subject: [PATCH 08/45] Migrating block editor `BlockPatternsList` component (#56210) - Removes `__unstableComposite` imports from `@wordpress/components` - Adds private `Composite*` exports from `@wordpress/components` - Refactors `BlockPatternsList` and `BlockPattern` to use updated `Composite` components - Additionally renames list component to be consistent with codebase --- .../components/block-patterns-list/README.md | 8 +-- .../components/block-patterns-list/index.js | 70 ++++++++++++------- .../components/block-patterns-list/style.scss | 7 ++ .../pattern-category-previews.js | 4 +- 4 files changed, 58 insertions(+), 31 deletions(-) diff --git a/packages/block-editor/src/components/block-patterns-list/README.md b/packages/block-editor/src/components/block-patterns-list/README.md index 7b30dcecc7bbd..8b798f93b7190 100644 --- a/packages/block-editor/src/components/block-patterns-list/README.md +++ b/packages/block-editor/src/components/block-patterns-list/README.md @@ -1,6 +1,6 @@ # Block Patterns List -The `BlockPatternList` component makes a list of the different registered block patterns. It uses the `BlockPreview` component to display a preview for each block pattern. +The `BlockPatternsList` component makes a list of the different registered block patterns. It uses the `BlockPreview` component to display a preview for each block pattern. For more infos about blocks patterns, read [this](https://make.wordpress.org/core/2020/07/16/block-patterns-in-wordpress-5-5/). @@ -18,10 +18,10 @@ For more infos about blocks patterns, read [this](https://make.wordpress.org/cor Renders a block patterns list. ```jsx -import { BlockPatternList } from '@wordpress/block-editor'; +import { BlockPatternsList } from '@wordpress/block-editor'; -const MyBlockPatternList = () => ( - ( + { if ( showTooltip ) { return { children }; @@ -35,11 +40,11 @@ const WithToolTip = ( { showTooltip, title, children } ) => { }; function BlockPattern( { + id, isDraggable, pattern, onClick, onHover, - composite, showTooltip, } ) { const [ isDragging, setIsDragging ] = useState( false ); @@ -78,17 +83,27 @@ function BlockPattern( { title={ pattern.title } > + } + id={ id } onClick={ () => { onClick( pattern, blocks ); onHover?.( null ); @@ -100,10 +115,6 @@ function BlockPattern( { onHover?.( pattern ); } } onMouseLeave={ () => onHover?.( null ) } - aria-label={ pattern.title } - aria-describedby={ - pattern.description ? descriptionId : undefined - } > { + // We reset the active composite item whenever the + // available patterns change, to make sure that + // focus is put back to the start. + setActiveId( undefined ); + }, [ setActiveId, shownPatterns, blockPatterns ] ); + return ( ) : ( @@ -191,4 +211,4 @@ function BlockPatternList( ); } -export default forwardRef( BlockPatternList ); +export default forwardRef( BlockPatternsList ); diff --git a/packages/block-editor/src/components/block-patterns-list/style.scss b/packages/block-editor/src/components/block-patterns-list/style.scss index e3b38deff5ef7..8009dfbcce1f2 100644 --- a/packages/block-editor/src/components/block-patterns-list/style.scss +++ b/packages/block-editor/src/components/block-patterns-list/style.scss @@ -18,6 +18,13 @@ .block-editor-block-patterns-list__item { height: 100%; + // This is derived from the top padding set on + // `.block-editor-block-patterns-explorer__list` + scroll-margin-top: $grid-unit-30; + // This is derived from the bottom padding set on + // `.block-editor-block-patterns-explorer__list` and + // the bottom margin set on `...__list-item` above + scroll-margin-bottom: ($grid-unit-40 + $grid-unit-30); .block-editor-block-preview__container { display: flex; diff --git a/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js b/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js index 76864a6a00ccc..9e5b6373e54d8 100644 --- a/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js +++ b/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js @@ -22,7 +22,7 @@ import { * Internal dependencies */ import usePatternsState from '../hooks/use-patterns-state'; -import BlockPatternList from '../../block-patterns-list'; +import BlockPatternsList from '../../block-patterns-list'; import usePatternsPaging from '../hooks/use-patterns-paging'; import { PatternsFilter } from './patterns-filter'; import { usePatternCategories } from './use-pattern-categories'; @@ -159,7 +159,7 @@ export function PatternCategoryPreviews( { { currentCategoryPatterns.length > 0 && ( - Date: Wed, 22 Nov 2023 17:48:15 +0100 Subject: [PATCH 09/45] Slot: add styles prop to bubblesVirtually version (#56428) * Slot: add `styles` prop to `bubblesVirtually` version * CHANHGELOG * Update CHANGELOG * Enhance clarity of JSDoc comments --- packages/components/CHANGELOG.md | 4 ++++ packages/components/src/slot-fill/README.md | 2 +- packages/components/src/slot-fill/types.ts | 24 +++++++++++++++------ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index eb6e595e304ec..cd1705d6cafd7 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -6,6 +6,10 @@ - `Tabs`: Memoize and expose the component context ([#56224](https://github.com/WordPress/gutenberg/pull/56224)). +### Internal + +- `Slot`: add `style` prop to `bubblesVirtually` version ([#56428](https://github.com/WordPress/gutenberg/pull/56428)) + ## 25.12.0 (2023-11-16) ### Bug Fix diff --git a/packages/components/src/slot-fill/README.md b/packages/components/src/slot-fill/README.md index a04416bdee50d..9059566deefdf 100644 --- a/packages/components/src/slot-fill/README.md +++ b/packages/components/src/slot-fill/README.md @@ -68,7 +68,7 @@ Both `Slot` and `Fill` accept a `name` string prop, where a `Slot` with a given - By default, events will bubble to their parents on the DOM hierarchy (native event bubbling) - If `bubblesVirtually` is set to true, events will bubble to their virtual parent in the React elements hierarchy instead. -`Slot` with `bubblesVirtually` set to true also accept an optional `className` to add to the slot container. +`Slot` with `bubblesVirtually` set to true also accept optional `className` and `style` props to add to the slot container. `Slot` **without** `bubblesVirtually` accepts an optional `children` function prop, which takes `fills` as a param. It allows you to perform additional processing and wrap `fills` conditionally. diff --git a/packages/components/src/slot-fill/types.ts b/packages/components/src/slot-fill/types.ts index 763fa799c8d86..8abb9b941c527 100644 --- a/packages/components/src/slot-fill/types.ts +++ b/packages/components/src/slot-fill/types.ts @@ -36,15 +36,21 @@ export type SlotComponentProps = /** * A function that returns nodes to be rendered. - * Not supported when `bubblesVirtually` is true. + * Supported only when `bubblesVirtually` is `false`. */ children?: never; /** - * className. - * Not supported when `bubblesVirtually` is true. + * Additional className for the `Slot` component. + * Supported only when `bubblesVirtually` is `true`. */ className?: string; + + /** + * Additional styles for the `Slot` component. + * Supported only when `bubblesVirtually` is `true`. + */ + style?: React.CSSProperties; } ) | ( SlotPropBase & { /** @@ -56,15 +62,21 @@ export type SlotComponentProps = /** * A function that returns nodes to be rendered. - * Not supported when `bubblesVirtually` is true. + * Supported only when `bubblesVirtually` is `false`. */ children?: ( fills: ReactNode ) => ReactNode; /** - * className. - * Not supported when `bubblesVirtually` is false. + * Additional className for the `Slot` component. + * Supported only when `bubblesVirtually` is `true`. */ className?: never; + + /** + * Additional styles for the `Slot` component. + * Supported only when `bubblesVirtually` is `true`. + */ + style?: never; } ); export type FillComponentProps = { From 20975005ead870e5bb96a0544d9d5960ec8be7a4 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Wed, 22 Nov 2023 17:14:09 +0000 Subject: [PATCH 10/45] Add focus rings to focusable disabled buttons (#56383) Fixes the CSS to only remove borders from disabled secondary/tertiary buttons when they don't have focus --- packages/components/CHANGELOG.md | 4 ++++ packages/components/src/button/style.scss | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index cd1705d6cafd7..9a3beb0342396 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Enhancements + +- `Button`: Add focus rings to focusable disabled buttons ([#56383](https://github.com/WordPress/gutenberg/pull/56383)). + ### Experimental - `Tabs`: Memoize and expose the component context ([#56224](https://github.com/WordPress/gutenberg/pull/56224)). diff --git a/packages/components/src/button/style.scss b/packages/components/src/button/style.scss index 03273056cfa17..4b11d9169a090 100644 --- a/packages/components/src/button/style.scss +++ b/packages/components/src/button/style.scss @@ -129,8 +129,11 @@ background: transparent; transform: none; opacity: 1; - box-shadow: none; - outline: none; + + &:not(:focus) { + box-shadow: none; + outline: none; + } } } From 564f23618997af9beb075f78bb265d28f9e0acc7 Mon Sep 17 00:00:00 2001 From: Luis Felipe Zaguini <26530524+zaguiini@users.noreply.github.com> Date: Wed, 22 Nov 2023 14:24:43 -0300 Subject: [PATCH 11/45] Additional CSS: fix on change validation (#56434) --- .../block-editor/src/components/global-styles/advanced-panel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/global-styles/advanced-panel.js b/packages/block-editor/src/components/global-styles/advanced-panel.js index 4460de0351318..af43552c0a3eb 100644 --- a/packages/block-editor/src/components/global-styles/advanced-panel.js +++ b/packages/block-editor/src/components/global-styles/advanced-panel.js @@ -30,7 +30,7 @@ export default function AdvancedPanel( { } ); if ( cssError ) { const [ transformed ] = transformStyles( - [ { css: value } ], + [ { css: newValue } ], '.editor-styles-wrapper' ); if ( transformed ) { From e3a6917ff0353bba5d40660acb1bc273de2b2541 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 22 Nov 2023 22:27:08 +0400 Subject: [PATCH 12/45] Block Settings: Only display parent block selector on small screens (#56431) --- .../block-settings-dropdown.js | 72 ++++++++++--------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js b/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js index bb8e00d0c11db..4d43865a7f83a 100644 --- a/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js +++ b/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js @@ -20,7 +20,7 @@ import { store as keyboardShortcutsStore, __unstableUseShortcutEventMatch, } from '@wordpress/keyboard-shortcuts'; -import { pipe, useCopyToClipboard } from '@wordpress/compose'; +import { pipe, useCopyToClipboard, useViewportMatch } from '@wordpress/compose'; /** * Internal dependencies @@ -47,6 +47,38 @@ function CopyMenuItem( { blocks, onCopy, label } ) { return { copyMenuItemLabel }; } +function ParentSelectorMenuItem( { parentClientId, parentBlockType } ) { + const isSmallViewport = useViewportMatch( 'medium', '<' ); + const { selectBlock } = useDispatch( blockEditorStore ); + + // Allows highlighting the parent block outline when focusing or hovering + // the parent block selector within the child. + const menuItemRef = useRef(); + const gesturesProps = useShowHoveredOrFocusedGestures( { + ref: menuItemRef, + highlightParent: true, + } ); + + if ( ! isSmallViewport ) { + return null; + } + + return ( + } + onClick={ () => selectBlock( parentClientId ) } + > + { sprintf( + /* translators: %s: Name of the block's parent. */ + __( 'Select parent block (%s)' ), + parentBlockType.title + ) } + + ); +} + export function BlockSettingsDropdown( { block, clientIds, @@ -132,8 +164,6 @@ export function BlockSettingsDropdown( { }; }, [] ); const isMatch = __unstableUseShortcutEventMatch(); - - const { selectBlock } = useDispatch( blockEditorStore ); const hasSelectedBlocks = selectedBlockClientIds.length > 0; const updateSelectionAfterDuplicate = useCallback( @@ -175,14 +205,6 @@ export function BlockSettingsDropdown( { const removeBlockLabel = count === 1 ? __( 'Delete' ) : __( 'Delete blocks' ); - // Allows highlighting the parent block outline when focusing or hovering - // the parent block selector within the child. - const selectParentButtonRef = useRef(); - const showParentOutlineGestures = useShowHoveredOrFocusedGestures( { - ref: selectParentButtonRef, - highlightParent: true, - } ); - // This can occur when the selected block (the parent) // displays child blocks within a List View. const parentBlockIsSelected = @@ -297,30 +319,12 @@ export function BlockSettingsDropdown( { /> { ! parentBlockIsSelected && !! firstParentClientId && ( - - } - onClick={ () => - selectBlock( - firstParentClientId - ) + - { sprintf( - /* translators: %s: Name of the block's parent. */ - __( - 'Select parent block (%s)' - ), - parentBlockType.title - ) } - + parentBlockType={ parentBlockType } + /> ) } { count === 1 && ( Date: Wed, 22 Nov 2023 21:16:56 +0000 Subject: [PATCH 13/45] Add 'View site' action to 'Site updated' snackbar (#52693) * Add 'View site' action to 'Site updated' snackbar * Both Snackbars... --- .../edit-site/src/components/save-hub/index.js | 15 +++++++++++++++ .../components/entities-saved-states/index.js | 17 ++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/save-hub/index.js b/packages/edit-site/src/components/save-hub/index.js index f43e843ee73c1..6afd52c1f4c2a 100644 --- a/packages/edit-site/src/components/save-hub/index.js +++ b/packages/edit-site/src/components/save-hub/index.js @@ -106,6 +106,15 @@ export default function SaveHub() { label = __( 'Saving' ); } + const { homeUrl } = useSelect( ( select ) => { + const { + getUnstableBase, // Site index. + } = select( coreStore ); + return { + homeUrl: getUnstableBase()?.home, + }; + }, [] ); + const saveCurrentEntity = async () => { if ( ! dirtyCurrentEntity ) return; @@ -135,6 +144,12 @@ export default function SaveHub() { createSuccessNotice( __( 'Site updated.' ), { type: 'snackbar', + actions: [ + { + label: __( 'View site' ), + url: homeUrl, + }, + ], id: saveNoticeId, } ); } catch ( error ) { diff --git a/packages/editor/src/components/entities-saved-states/index.js b/packages/editor/src/components/entities-saved-states/index.js index 07097969fffc8..a47dd29fef036 100644 --- a/packages/editor/src/components/entities-saved-states/index.js +++ b/packages/editor/src/components/entities-saved-states/index.js @@ -3,7 +3,7 @@ */ import { Button, Flex, FlexItem } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useDispatch } from '@wordpress/data'; +import { useSelect, useDispatch } from '@wordpress/data'; import { useCallback, useRef } from '@wordpress/element'; import { store as coreStore } from '@wordpress/core-data'; import { store as blockEditorStore } from '@wordpress/block-editor'; @@ -85,6 +85,15 @@ export function EntitiesSavedStatesExtensible( { const saveEnabled = saveEnabledProp ?? isDirty; + const { homeUrl } = useSelect( ( select ) => { + const { + getUnstableBase, // Site index. + } = select( coreStore ); + return { + homeUrl: getUnstableBase()?.home, + }; + }, [] ); + const saveCheckedEntities = () => { const saveNoticeId = 'site-editor-save-success'; removeNotice( saveNoticeId ); @@ -149,6 +158,12 @@ export function EntitiesSavedStatesExtensible( { createSuccessNotice( __( 'Site updated.' ), { type: 'snackbar', id: saveNoticeId, + actions: [ + { + label: __( 'View site' ), + url: homeUrl, + }, + ], } ); } } ) From aac7844d5ba4a8768926fff55ad0d819f8f2fb9f Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Wed, 22 Nov 2023 21:18:35 +0000 Subject: [PATCH 14/45] Update Changelog for 17.0.3 --- changelog.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/changelog.txt b/changelog.txt index 0f86c2d8f593b..8494a56d7160d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,17 @@ == Changelog == += 17.0.3 = + +## Changelog + +### Bug Fixes + +#### Block Editor + +- PostCSS style transformation: fail gracefully instead of throwing an error (https://github.com/WordPress/gutenberg/pull/56093) + + + = 17.1.0 = From 799c807e6c1b2ad1eeb27e68806498477f4bae0b Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Thu, 23 Nov 2023 09:54:45 +1100 Subject: [PATCH 15/45] Post Schedule Panel: Fix Sass deprecation warning for division (#56412) --- packages/editor/src/components/post-schedule/style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/src/components/post-schedule/style.scss b/packages/editor/src/components/post-schedule/style.scss index ca5bc19ae7d5c..23cb185167db5 100644 --- a/packages/editor/src/components/post-schedule/style.scss +++ b/packages/editor/src/components/post-schedule/style.scss @@ -18,6 +18,6 @@ height: auto; // The line height + the padding should be the same as the button size. - padding: ( ( $button-size - $grid-unit-20 ) / 2 ) 12px; + padding: math.div($button-size - $grid-unit-20, 2) 12px; line-height: $grid-unit-20; } From 8a2f5bc6b7266b477ced853dce87623bbe53fe64 Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Thu, 23 Nov 2023 10:57:23 +0900 Subject: [PATCH 16/45] Post Template: fix incorrect offset query (#56440) * Post Template: fix incorrect offset query * Remove unnecessary code --- packages/block-library/src/post-template/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/post-template/edit.js b/packages/block-library/src/post-template/edit.js index 025a8bf4f6c93..2e668674e8530 100644 --- a/packages/block-library/src/post-template/edit.js +++ b/packages/block-library/src/post-template/edit.js @@ -123,7 +123,7 @@ export default function PostTemplateEdit( { slug: templateSlug.replace( 'category-', '' ), } ); const query = { - offset: perPage ? perPage + offset : 0, + offset: offset || 0, order, orderby: orderBy, }; From 84de158e1631982a325b71f833b1164a1337e8c3 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Thu, 23 Nov 2023 13:19:04 +1100 Subject: [PATCH 17/45] Fix fatal error when calling undefined block library function. (#56459) --- .../class-wp-navigation-block-renderer.php | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/compat/wordpress-6.5/class-wp-navigation-block-renderer.php b/lib/compat/wordpress-6.5/class-wp-navigation-block-renderer.php index 0e9166a7c7d54..e2eb4e10414fe 100644 --- a/lib/compat/wordpress-6.5/class-wp-navigation-block-renderer.php +++ b/lib/compat/wordpress-6.5/class-wp-navigation-block-renderer.php @@ -170,7 +170,7 @@ private static function get_inner_blocks_html( $attributes, $inner_blocks ) { // Add directives to the submenu if needed. if ( $has_submenus && $should_load_view_script ) { $tags = new WP_HTML_Tag_Processor( $inner_blocks_html ); - $inner_blocks_html = block_core_navigation_add_directives_to_submenu( $tags, $attributes ); + $inner_blocks_html = gutenberg_block_core_navigation_add_directives_to_submenu( $tags, $attributes ); } return $inner_blocks_html; @@ -195,7 +195,7 @@ private static function get_inner_blocks_from_navigation_post( $attributes ) { // 'parse_blocks' includes a null block with '\n\n' as the content when // it encounters whitespace. This code strips it. - $compacted_blocks = block_core_navigation_filter_out_empty_blocks( $parsed_blocks ); + $compacted_blocks = gutenberg_block_core_navigation_filter_out_empty_blocks( $parsed_blocks ); // TODO - this uses the full navigation block attributes for the // context which could be refined. @@ -210,7 +210,7 @@ private static function get_inner_blocks_from_navigation_post( $attributes ) { * @return WP_Block_List Returns the inner blocks for the navigation block. */ private static function get_inner_blocks_from_fallback( $attributes ) { - $fallback_blocks = block_core_navigation_get_fallback_blocks(); + $fallback_blocks = gutenberg_block_core_navigation_get_fallback_blocks(); // Fallback my have been filtered so do basic test for validity. if ( empty( $fallback_blocks ) || ! is_array( $fallback_blocks ) ) { @@ -245,9 +245,9 @@ private static function get_inner_blocks( $attributes, $block ) { defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN && array_key_exists( '__unstableLocation', $attributes ) && ! array_key_exists( 'ref', $attributes ) && - ! empty( block_core_navigation_get_menu_items_at_location( $attributes['__unstableLocation'] ) ) + ! empty( gutenberg_block_core_navigation_get_menu_items_at_location( $attributes['__unstableLocation'] ) ) ) { - $inner_blocks = block_core_navigation_get_inner_blocks_from_unstable_location( $attributes ); + $inner_blocks = gutenberg_block_core_navigation_get_inner_blocks_from_unstable_location( $attributes ); } // Load inner blocks from the navigation post. @@ -270,7 +270,7 @@ private static function get_inner_blocks( $attributes, $block ) { */ $inner_blocks = apply_filters( 'block_core_navigation_render_inner_blocks', $inner_blocks ); - $post_ids = block_core_navigation_get_post_ids( $inner_blocks ); + $post_ids = gutenberg_block_core_navigation_get_post_ids( $inner_blocks ); if ( $post_ids ) { _prime_post_caches( $post_ids, false, false ); } @@ -353,8 +353,8 @@ private static function get_layout_class( $attributes ) { private static function get_classes( $attributes ) { // Restore legacy classnames for submenu positioning. $layout_class = static::get_layout_class( $attributes ); - $colors = block_core_navigation_build_css_colors( $attributes ); - $font_sizes = block_core_navigation_build_css_font_sizes( $attributes ); + $colors = gutenberg_block_core_navigation_build_css_colors( $attributes ); + $font_sizes = gutenberg_block_core_navigation_build_css_font_sizes( $attributes ); $is_responsive_menu = static::is_responsive( $attributes ); // Manually add block support text decoration as CSS class. @@ -378,8 +378,8 @@ private static function get_classes( $attributes ) { * @return string Returns the styles for the navigation block. */ private static function get_styles( $attributes ) { - $colors = block_core_navigation_build_css_colors( $attributes ); - $font_sizes = block_core_navigation_build_css_font_sizes( $attributes ); + $colors = gutenberg_block_core_navigation_build_css_colors( $attributes ); + $font_sizes = gutenberg_block_core_navigation_build_css_font_sizes( $attributes ); $block_styles = isset( $attributes['styles'] ) ? $attributes['styles'] : ''; return $block_styles . $colors['inline_styles'] . $font_sizes['inline_styles']; } @@ -394,7 +394,7 @@ private static function get_styles( $attributes ) { */ private static function get_responsive_container_markup( $attributes, $inner_blocks, $inner_blocks_html ) { $should_load_view_script = static::should_load_view_script( $attributes, $inner_blocks ); - $colors = block_core_navigation_build_css_colors( $attributes ); + $colors = gutenberg_block_core_navigation_build_css_colors( $attributes ); $modal_unique_id = wp_unique_id( 'modal-' ); $is_hidden_by_default = isset( $attributes['overlayMenu'] ) && 'always' === $attributes['overlayMenu']; @@ -627,7 +627,7 @@ public static function render( $attributes, $content, $block ) { $inner_blocks = static::get_inner_blocks( $attributes, $block ); // Prevent navigation blocks referencing themselves from rendering. - if ( block_core_navigation_block_contains_core_navigation( $inner_blocks ) ) { + if ( gutenberg_block_core_navigation_block_contains_core_navigation( $inner_blocks ) ) { return ''; } From 084eefebd28ecc79bd0f1d474e8ef215f9651d83 Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Thu, 23 Nov 2023 03:21:19 +0000 Subject: [PATCH 18/45] Bump plugin version to 17.1.1 --- gutenberg.php | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gutenberg.php b/gutenberg.php index 018c269f4f565..a88e153766888 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -5,7 +5,7 @@ * Description: Printing since 1440. This is the development plugin for the block editor, site editor, and other future WordPress core functionality. * Requires at least: 6.2 * Requires PHP: 7.0 - * Version: 17.1.0 + * Version: 17.1.1 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/package-lock.json b/package-lock.json index 601aafc18b268..d82b2404c610e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gutenberg", - "version": "17.1.0", + "version": "17.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "gutenberg", - "version": "17.1.0", + "version": "17.1.1", "hasInstallScript": true, "license": "GPL-2.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 43ca7f0858f60..960ccd074ae60 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "17.1.0", + "version": "17.1.1", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", From 8059f984c2f31b0b95e7eb6a25e4205667ea83cf Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Thu, 23 Nov 2023 03:38:08 +0000 Subject: [PATCH 19/45] Update Changelog for 17.1.1 --- changelog.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/changelog.txt b/changelog.txt index 8494a56d7160d..b3750479e99fa 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,16 @@ == Changelog == += 17.1.1 = + +# Changelog + +## Bug Fixes + +### Block Library + +Fix fatal error when calling undefined block library function. #56459 + + = 17.0.3 = ## Changelog From c57fb7b872945bf9f99253e3ccd0818da0406569 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Thu, 23 Nov 2023 15:05:22 +1100 Subject: [PATCH 20/45] Cover block: Pass dropZoneElement reference to fix dragging within cover block area (#56312) * Cover block: Pass dropZoneElement reference to fix dragging and dropping within cover block area * Move to using a simple ref --- packages/block-library/src/cover/edit/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/block-library/src/cover/edit/index.js b/packages/block-library/src/cover/edit/index.js index ab49d58b766b0..8c5488584094c 100644 --- a/packages/block-library/src/cover/edit/index.js +++ b/packages/block-library/src/cover/edit/index.js @@ -335,6 +335,7 @@ function CoverEdit( { templateInsertUpdatesSelection: true, allowedBlocks, templateLock, + dropZoneElement: ref.current, } ); From 6510154314c70d302268690cf80cd121828deb41 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 23 Nov 2023 08:59:30 +0100 Subject: [PATCH 21/45] Move the DisableNonContentBlocks component to the editor package (#56423) --- .../block-editor/site-editor-canvas.js | 4 +-- .../back-to-page-notification.js | 0 .../edit-template-notification.js | 0 .../index.js | 31 +++++++------------ .../src/components/provider/constants.js | 5 +++ .../disable-non-page-content-blocks.js | 6 ++-- .../editor/src/components/provider/index.js | 10 +++--- 7 files changed, 26 insertions(+), 30 deletions(-) rename packages/edit-site/src/components/{page-content-focus-manager => page-content-focus-notifications}/back-to-page-notification.js (100%) rename packages/edit-site/src/components/{page-content-focus-manager => page-content-focus-notifications}/edit-template-notification.js (100%) rename packages/edit-site/src/components/{page-content-focus-manager => page-content-focus-notifications}/index.js (58%) create mode 100644 packages/editor/src/components/provider/constants.js rename packages/{edit-site/src/components/page-content-focus-manager => editor/src/components/provider}/disable-non-page-content-blocks.js (89%) diff --git a/packages/edit-site/src/components/block-editor/site-editor-canvas.js b/packages/edit-site/src/components/block-editor/site-editor-canvas.js index 643fa84559f60..0d2d522c8b3e1 100644 --- a/packages/edit-site/src/components/block-editor/site-editor-canvas.js +++ b/packages/edit-site/src/components/block-editor/site-editor-canvas.js @@ -27,7 +27,7 @@ import { NAVIGATION_POST_TYPE, } from '../../utils/constants'; import { unlock } from '../../lock-unlock'; -import PageContentFocusManager from '../page-content-focus-manager'; +import PageContentFocusNotifications from '../page-content-focus-notifications'; const LAYOUT = { type: 'default', @@ -149,7 +149,7 @@ export default function SiteEditorCanvas() { ) } - + ); } diff --git a/packages/edit-site/src/components/page-content-focus-manager/back-to-page-notification.js b/packages/edit-site/src/components/page-content-focus-notifications/back-to-page-notification.js similarity index 100% rename from packages/edit-site/src/components/page-content-focus-manager/back-to-page-notification.js rename to packages/edit-site/src/components/page-content-focus-notifications/back-to-page-notification.js diff --git a/packages/edit-site/src/components/page-content-focus-manager/edit-template-notification.js b/packages/edit-site/src/components/page-content-focus-notifications/edit-template-notification.js similarity index 100% rename from packages/edit-site/src/components/page-content-focus-manager/edit-template-notification.js rename to packages/edit-site/src/components/page-content-focus-notifications/edit-template-notification.js diff --git a/packages/edit-site/src/components/page-content-focus-manager/index.js b/packages/edit-site/src/components/page-content-focus-notifications/index.js similarity index 58% rename from packages/edit-site/src/components/page-content-focus-manager/index.js rename to packages/edit-site/src/components/page-content-focus-notifications/index.js index 05bcc0da003cf..2b0e636f5231e 100644 --- a/packages/edit-site/src/components/page-content-focus-manager/index.js +++ b/packages/edit-site/src/components/page-content-focus-notifications/index.js @@ -7,27 +7,21 @@ import { useEffect } from '@wordpress/element'; * Internal dependencies */ import { store as editSiteStore } from '../../store'; -import DisableNonPageContentBlocks from './disable-non-page-content-blocks'; import EditTemplateNotification from './edit-template-notification'; import BackToPageNotification from './back-to-page-notification'; import { unlock } from '../../lock-unlock'; -export default function PageContentFocusManager( { contentRef } ) { - const { hasPageContentFocus, pageContentFocusType, canvasMode } = useSelect( - ( select ) => { - const { getPageContentFocusType, getCanvasMode } = unlock( - select( editSiteStore ) - ); - const _canvasMode = getCanvasMode(); - return { - canvasMode: _canvasMode, - pageContentFocusType: getPageContentFocusType(), - hasPageContentFocus: - select( editSiteStore ).hasPageContentFocus(), - }; - }, - [] - ); +export default function PageContentFocusNotifications( { contentRef } ) { + const { pageContentFocusType, canvasMode } = useSelect( ( select ) => { + const { getPageContentFocusType, getCanvasMode } = unlock( + select( editSiteStore ) + ); + const _canvasMode = getCanvasMode(); + return { + canvasMode: _canvasMode, + pageContentFocusType: getPageContentFocusType(), + }; + }, [] ); const { setPageContentFocusType } = unlock( useDispatch( editSiteStore ) ); /* @@ -39,11 +33,10 @@ export default function PageContentFocusManager( { contentRef } ) { if ( canvasMode !== 'edit' && !! pageContentFocusType ) { setPageContentFocusType( null ); } - }, [ canvasMode, pageContentFocusType ] ); + }, [ canvasMode, pageContentFocusType, setPageContentFocusType ] ); return ( <> - { hasPageContentFocus && } diff --git a/packages/editor/src/components/provider/constants.js b/packages/editor/src/components/provider/constants.js new file mode 100644 index 0000000000000..a81b2fd37563a --- /dev/null +++ b/packages/editor/src/components/provider/constants.js @@ -0,0 +1,5 @@ +export const PAGE_CONTENT_BLOCK_TYPES = [ + 'core/post-title', + 'core/post-featured-image', + 'core/post-content', +]; diff --git a/packages/edit-site/src/components/page-content-focus-manager/disable-non-page-content-blocks.js b/packages/editor/src/components/provider/disable-non-page-content-blocks.js similarity index 89% rename from packages/edit-site/src/components/page-content-focus-manager/disable-non-page-content-blocks.js rename to packages/editor/src/components/provider/disable-non-page-content-blocks.js index 2f81f80d0ce63..048b01d026c24 100644 --- a/packages/edit-site/src/components/page-content-focus-manager/disable-non-page-content-blocks.js +++ b/packages/editor/src/components/provider/disable-non-page-content-blocks.js @@ -11,7 +11,7 @@ import { useEffect } from '@wordpress/element'; /** * Internal dependencies */ -import { PAGE_CONTENT_BLOCK_TYPES } from '../../utils/constants'; +import { PAGE_CONTENT_BLOCK_TYPES } from './constants'; function DisableBlock( { clientId } ) { const isDescendentOfQueryLoop = useSelect( @@ -46,9 +46,7 @@ export default function DisableNonPageContentBlocks() { const clientIds = useSelect( ( select ) => { const { __experimentalGetGlobalBlocksByName } = select( blockEditorStore ); - return __experimentalGetGlobalBlocksByName( - Object.keys( PAGE_CONTENT_BLOCK_TYPES ) - ); + return __experimentalGetGlobalBlocksByName( PAGE_CONTENT_BLOCK_TYPES ); }, [] ); return clientIds.map( ( clientId ) => { diff --git a/packages/editor/src/components/provider/index.js b/packages/editor/src/components/provider/index.js index 5fa79eedef987..75f1769927715 100644 --- a/packages/editor/src/components/provider/index.js +++ b/packages/editor/src/components/provider/index.js @@ -22,16 +22,13 @@ import withRegistryProvider from './with-registry-provider'; import { store as editorStore } from '../../store'; import useBlockEditorSettings from './use-block-editor-settings'; import { unlock } from '../../lock-unlock'; +import DisableNonPageContentBlocks from './disable-non-page-content-blocks'; +import { PAGE_CONTENT_BLOCK_TYPES } from './constants'; const { ExperimentalBlockEditorProvider } = unlock( blockEditorPrivateApis ); const { PatternsMenuItems } = unlock( editPatternsPrivateApis ); const noop = () => {}; -export const PAGE_CONTENT_BLOCK_TYPES = [ - 'core/post-title', - 'core/post-featured-image', - 'core/post-content', -]; /** * For the Navigation block editor, we need to force the block editor to contentOnly for that block. @@ -308,6 +305,9 @@ export const ExperimentalEditorProvider = withRegistryProvider( > { children } + { [ 'post-only', 'template-locked' ].includes( + mode + ) && } From c03a097faadb66a2725dc96e8c23772abe6e0559 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 23 Nov 2023 12:19:23 +0400 Subject: [PATCH 22/45] Block Editor: Optimize 'Connections' inspector controls (#56443) --- .../block-editor/src/hooks/custom-fields.js | 133 +++++++++--------- 1 file changed, 68 insertions(+), 65 deletions(-) diff --git a/packages/block-editor/src/hooks/custom-fields.js b/packages/block-editor/src/hooks/custom-fields.js index 31721569781b6..adb9df15824a7 100644 --- a/packages/block-editor/src/hooks/custom-fields.js +++ b/packages/block-editor/src/hooks/custom-fields.js @@ -34,6 +34,65 @@ function addAttribute( settings ) { return settings; } +function CustomFieldsControl( props ) { + const blockEditingMode = useBlockEditingMode(); + if ( blockEditingMode !== 'default' ) { + return null; + } + + // If the block is a paragraph or image block, we need to know which + // attribute to use for the connection. Only the `content` attribute + // of the paragraph block and the `url` attribute of the image block are supported. + let attributeName; + if ( props.name === 'core/paragraph' ) attributeName = 'content'; + if ( props.name === 'core/image' ) attributeName = 'url'; + + return ( + + + { + if ( nextValue === '' ) { + props.setAttributes( { + connections: undefined, + [ attributeName ]: undefined, + placeholder: undefined, + } ); + } else { + props.setAttributes( { + connections: { + attributes: { + // The attributeName will be either `content` or `url`. + [ attributeName ]: { + // Source will be variable, could be post_meta, user_meta, term_meta, etc. + // Could even be a custom source like a social media attribute. + source: 'meta_fields', + value: nextValue, + }, + }, + }, + [ attributeName ]: undefined, + placeholder: sprintf( + 'This content will be replaced on the frontend by the value of "%s" custom field.', + nextValue + ), + } ); + } + } } + /> + + + ); +} + /** * Override the default edit UI to include a new block inspector control for * assigning a connection to blocks that has support for connections. @@ -46,7 +105,6 @@ function addAttribute( settings ) { */ const withCustomFieldsControls = createHigherOrderComponent( ( BlockEdit ) => { return ( props ) => { - const blockEditingMode = useBlockEditingMode(); const hasCustomFieldsSupport = hasBlockSupport( props.name, '__experimentalConnections', @@ -56,72 +114,17 @@ const withCustomFieldsControls = createHigherOrderComponent( ( BlockEdit ) => { // Check if the current block is a paragraph or image block. // Currently, only these two blocks are supported. if ( ! [ 'core/paragraph', 'core/image' ].includes( props.name ) ) { - return ; + return ; } - // If the block is a paragraph or image block, we need to know which - // attribute to use for the connection. Only the `content` attribute - // of the paragraph block and the `url` attribute of the image block are supported. - let attributeName; - if ( props.name === 'core/paragraph' ) attributeName = 'content'; - if ( props.name === 'core/image' ) attributeName = 'url'; - - if ( hasCustomFieldsSupport && props.isSelected ) { - return ( - <> - - { blockEditingMode === 'default' && ( - - - { - if ( nextValue === '' ) { - props.setAttributes( { - connections: undefined, - [ attributeName ]: undefined, - placeholder: undefined, - } ); - } else { - props.setAttributes( { - connections: { - attributes: { - // The attributeName will be either `content` or `url`. - [ attributeName ]: { - // Source will be variable, could be post_meta, user_meta, term_meta, etc. - // Could even be a custom source like a social media attribute. - source: 'meta_fields', - value: nextValue, - }, - }, - }, - [ attributeName ]: undefined, - placeholder: sprintf( - 'This content will be replaced on the frontend by the value of "%s" custom field.', - nextValue - ), - } ); - } - } } - /> - - - ) } - - ); - } - - return ; + return ( + <> + + { hasCustomFieldsSupport && props.isSelected && ( + + ) } + + ); }; }, 'withCustomFieldsControls' ); From 56d1b71bb8d22e4619d90ca05d8018c2822c0385 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Thu, 23 Nov 2023 09:47:50 +0100 Subject: [PATCH 23/45] [RNMobile] Fix ungroup functionality in `WarningMaxDepthExceeded` component (#56445) --- .../warning-max-depth-exceeded.native.js | 90 ++++++++++++------- 1 file changed, 57 insertions(+), 33 deletions(-) diff --git a/packages/block-editor/src/components/inner-blocks/warning-max-depth-exceeded.native.js b/packages/block-editor/src/components/inner-blocks/warning-max-depth-exceeded.native.js index 57a7b7a60483c..e363db4961c7c 100644 --- a/packages/block-editor/src/components/inner-blocks/warning-max-depth-exceeded.native.js +++ b/packages/block-editor/src/components/inner-blocks/warning-max-depth-exceeded.native.js @@ -8,7 +8,7 @@ import { TouchableWithoutFeedback, View } from 'react-native'; */ import { __, sprintf } from '@wordpress/i18n'; import { useState } from '@wordpress/element'; -import { useDispatch, useSelect } from '@wordpress/data'; +import { useSelect } from '@wordpress/data'; /** * Internal dependencies @@ -18,54 +18,71 @@ import UnsupportedBlockDetails from '../unsupported-block-details'; import { store as blockEditorStore } from '../../store'; import { MAX_NESTING_DEPTH } from './constants'; import useUnsupportedBlockEditor from '../use-unsupported-block-editor'; +import { + useConvertToGroupButtons, + useConvertToGroupButtonProps, +} from '../convert-to-group-buttons'; + +const EMPTY_ARRAY = []; const WarningMaxDepthExceeded = ( { clientId } ) => { const [ showDetails, setShowDetails ] = useState( false ); - const { isSelected, innerBlocks } = useSelect( - ( select ) => { - const { getBlock, isBlockSelected } = select( blockEditorStore ); - return { - innerBlocks: getBlock( clientId )?.innerBlocks || [], - isSelected: isBlockSelected( clientId ), - }; - }, + const isSelected = useSelect( + ( select ) => select( blockEditorStore ).isBlockSelected( clientId ), [ clientId ] ); - const { replaceBlocks } = useDispatch( blockEditorStore ); + + // We rely on the logic related to the Group/Ungroup buttons used in the block options to + // determine whether to use the Ungroup action. + const convertToGroupButtonProps = useConvertToGroupButtonProps( [ + clientId, + ] ); + const { isUngroupable } = convertToGroupButtonProps; + const convertToGroupButtons = useConvertToGroupButtons( { + ...convertToGroupButtonProps, + } ); + const onUngroup = convertToGroupButtons.ungroup.onSelect; const { isUnsupportedBlockEditorSupported, canEnableUnsupportedBlockEditor, } = useUnsupportedBlockEditor( clientId ); - const onUngroup = () => { - if ( ! innerBlocks.length ) { - return; - } - - replaceBlocks( clientId, innerBlocks ); - }; - - let description; - // When UBE can't be used, the description mentions using the web browser to edit the block. + /* translators: Warning related to having blocks deeply nested. %d: The deepest nesting level. */ + const descriptionFormat = __( + 'Blocks nested deeper than %d levels may not render properly in the mobile editor.' + ); + let description = sprintf( descriptionFormat, MAX_NESTING_DEPTH ); if ( ! isUnsupportedBlockEditorSupported && ! canEnableUnsupportedBlockEditor ) { - /* translators: Warning related to having blocks deeply nested. %d: The deepest nesting level. */ - const descriptionFormat = __( - 'Blocks nested deeper than %d levels may not render properly in the mobile editor. For this reason, we recommend flattening the content by ungrouping the block or editing the block using your web browser.' - ); - description = sprintf( descriptionFormat, MAX_NESTING_DEPTH ); + // When UBE can't be used, the description mentions using the web browser to edit the block. + description += + ' ' + + /* translators: Recommendation included in a warning related to having blocks deeply nested. */ + __( + 'For this reason, we recommend editing the block using your web browser.' + ); } // Otherwise, the description mentions using the web editor (i.e. UBE). else { - /* translators: Warning related to having blocks deeply nested. %d: The deepest nesting level. */ - const descriptionFormat = __( - 'Blocks nested deeper than %d levels may not render properly in the mobile editor. For this reason, we recommend flattening the content by ungrouping the block or editing the block using the web editor.' - ); - description = sprintf( descriptionFormat, MAX_NESTING_DEPTH ); + description += + ' ' + + /* translators: Recommendation included in a warning related to having blocks deeply nested. */ + __( + 'For this reason, we recommend editing the block using the web editor.' + ); + } + // If the block can be flattened, we also suggest to ungroup the block. + if ( isUngroupable ) { + description += + ' ' + + /* translators: Alternative option included in a warning related to having blocks deeply nested. */ + __( + 'Alternatively, you can flatten the content by ungrouping the block.' + ); } return ( @@ -88,9 +105,16 @@ const WarningMaxDepthExceeded = ( { clientId } ) => { onCloseSheet={ () => setShowDetails( false ) } title={ __( 'Deeply nested block' ) } description={ description } - customActions={ [ - { label: __( 'Ungroup block' ), onPress: onUngroup }, - ] } + customActions={ + isUngroupable + ? [ + { + label: __( 'Ungroup block' ), + onPress: onUngroup, + }, + ] + : EMPTY_ARRAY + } /> From 726fc065983a202447c8cafe593759e6529bfbf0 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Thu, 23 Nov 2023 11:38:41 +0200 Subject: [PATCH 24/45] Dataviews: Remove link from author (#56467) --- packages/edit-site/src/components/dataviews/dataviews.js | 4 ++-- packages/edit-site/src/components/page-pages/index.js | 8 -------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/packages/edit-site/src/components/dataviews/dataviews.js b/packages/edit-site/src/components/dataviews/dataviews.js index 682060203de7c..78d0ea83abb8e 100644 --- a/packages/edit-site/src/components/dataviews/dataviews.js +++ b/packages/edit-site/src/components/dataviews/dataviews.js @@ -56,8 +56,8 @@ export default function DataViews( { return (
- - + + { search && ( item._embedded?.author[ 0 ]?.name, - render: ( { item } ) => { - const author = item._embedded?.author[ 0 ]; - return ( - - { author.name } - - ); - }, type: ENUMERATION_TYPE, elements: authors?.map( ( { id, name } ) => ( { From 2477561b4738b883fe41b2677be6006d3d733c6c Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 23 Nov 2023 13:47:59 +0400 Subject: [PATCH 25/45] useEntityRecord: Improve unit tests (#56415) * useEntityRecord: Improve unit tests Co-authored-by: Kai Hao * Add comment --------- Co-authored-by: Kai Hao --- .../src/hooks/test/use-entity-record.js | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/packages/core-data/src/hooks/test/use-entity-record.js b/packages/core-data/src/hooks/test/use-entity-record.js index 1fe68c84a951b..fa1dea6df8146 100644 --- a/packages/core-data/src/hooks/test/use-entity-record.js +++ b/packages/core-data/src/hooks/test/use-entity-record.js @@ -116,22 +116,29 @@ describe( 'useEntityRecord', () => { } ); it( 'does not resolve entity record when disabled via options', async () => { - // Provide response triggerFetch.mockImplementation( () => TEST_RECORD ); let data; - const TestComponent = () => { - data = useEntityRecord( 'root', 'widget', 2, { - options: { enabled: false }, - } ); + const TestComponent = ( { enabled } ) => { + data = useEntityRecord( 'root', 'widget', 1, { enabled } ); return
; }; - render( + const UI = ( { enabled } ) => ( - + ); + const { rerender } = render( ); + + // A minimum delay for a fetch request. The same delay is used again as a control. + await act( + () => new Promise( ( resolve ) => setTimeout( resolve, 0 ) ) + ); + expect( triggerFetch ).toHaveBeenCalledTimes( 1 ); + + rerender( ); + expect( data ).toEqual( { edit: expect.any( Function ), editedRecord: {}, @@ -141,14 +148,10 @@ describe( 'useEntityRecord', () => { save: expect.any( Function ), } ); - // Fetch request should have been issued. - await waitFor( () => { - expect( triggerFetch ).not.toHaveBeenCalled(); - } ); - await waitFor( () => - expect( triggerFetch ).not.toHaveBeenCalledWith( { - path: '/wp/v2/widgets/2?context=edit', - } ) + // The same delay. + await act( + () => new Promise( ( resolve ) => setTimeout( resolve, 0 ) ) ); + expect( triggerFetch ).toHaveBeenCalledTimes( 1 ); } ); } ); From ea60d43e9545af7ed774c2201bfaba3151a63aa6 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Thu, 23 Nov 2023 11:51:51 +0200 Subject: [PATCH 26/45] DataViews: Make disabled pagination buttons focusable (#56422) --- packages/edit-site/src/components/dataviews/pagination.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/edit-site/src/components/dataviews/pagination.js b/packages/edit-site/src/components/dataviews/pagination.js index 7948cf01ecfc2..25672208d993c 100644 --- a/packages/edit-site/src/components/dataviews/pagination.js +++ b/packages/edit-site/src/components/dataviews/pagination.js @@ -48,6 +48,7 @@ function Pagination( { onChangeView( { ...view, page: 1 } ) } disabled={ view.page === 1 } + __experimentalIsFocusable label={ __( 'First page' ) } icon={ previous } showTooltip @@ -58,6 +59,7 @@ function Pagination( { onChangeView( { ...view, page: view.page - 1 } ) } disabled={ view.page === 1 } + __experimentalIsFocusable label={ __( 'Previous page' ) } icon={ chevronLeft } showTooltip @@ -115,6 +117,7 @@ function Pagination( { onChangeView( { ...view, page: view.page + 1 } ) } disabled={ view.page >= totalPages } + __experimentalIsFocusable label={ __( 'Next page' ) } icon={ chevronRight } showTooltip @@ -125,6 +128,7 @@ function Pagination( { onChangeView( { ...view, page: totalPages } ) } disabled={ view.page >= totalPages } + __experimentalIsFocusable label={ __( 'Last page' ) } icon={ next } showTooltip From 0b6c4a003f90b18509ee6d3d120435444dc15e43 Mon Sep 17 00:00:00 2001 From: Marco Ciampini Date: Thu, 23 Nov 2023 13:42:17 +0100 Subject: [PATCH 27/45] DropdownMenu V2: add support for rendering in legacy popover slot (#56342) * DropdownMenuV2: support rendering in slotfill * Add temporary stories * CHANGELOG --- packages/components/CHANGELOG.md | 1 + .../src/dropdown-menu-v2-ariakit/index.tsx | 14 ++++ .../stories/index.story.tsx | 66 +++++++++++++++++++ .../src/dropdown-menu-v2-ariakit/types.ts | 7 ++ .../src/dropdown-menu/stories/index.story.tsx | 52 +++++++++++++++ packages/components/src/popover/index.tsx | 2 +- 6 files changed, 141 insertions(+), 1 deletion(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 9a3beb0342396..cbb12e0146b55 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -12,6 +12,7 @@ ### Internal +- `DropdownMenuV2`: add support for rendering in legacy popover slot ([#56342](https://github.com/WordPress/gutenberg/pull/56342)). - `Slot`: add `style` prop to `bubblesVirtually` version ([#56428](https://github.com/WordPress/gutenberg/pull/56428)) ## 25.12.0 (2023-11-16) diff --git a/packages/components/src/dropdown-menu-v2-ariakit/index.tsx b/packages/components/src/dropdown-menu-v2-ariakit/index.tsx index 10b93d8c552c1..b992c7b4c7b5a 100644 --- a/packages/components/src/dropdown-menu-v2-ariakit/index.tsx +++ b/packages/components/src/dropdown-menu-v2-ariakit/index.tsx @@ -26,6 +26,11 @@ import { SVG, Circle } from '@wordpress/primitives'; import { useContextSystem, contextConnect } from '../context'; import type { WordPressComponentProps } from '../context'; import Icon from '../icon'; +import { useSlot } from '../slot-fill'; +import { + SLOT_NAME as POPOVER_DEFAULT_SLOT_NAME, + slotNameContext, +} from '../popover'; import type { DropdownMenuContext as DropdownMenuContextType, DropdownMenuProps, @@ -182,6 +187,9 @@ const UnconnectedDropdownMenu = ( shift, modal = true, + // Other props + slotName: slotNameProp = POPOVER_DEFAULT_SLOT_NAME, + // From internal components context variant, @@ -270,6 +278,11 @@ const UnconnectedDropdownMenu = ( [ computedDirection ] ); + // Render the portal in the default slot used by the legacy Popover component. + const slotName = useContext( slotNameContext ) || slotNameProp; + const slot = useSlot( slotName ); + const portalContainer = slot.ref?.current; + return ( <> { /* Menu trigger */ } @@ -305,6 +318,7 @@ const UnconnectedDropdownMenu = ( wrapperProps={ wrapperProps } hideOnEscape={ hideOnEscape } unmountOnHide + portalElement={ portalContainer } > { children } diff --git a/packages/components/src/dropdown-menu-v2-ariakit/stories/index.story.tsx b/packages/components/src/dropdown-menu-v2-ariakit/stories/index.story.tsx index a6319c6cfdc93..147de3861b160 100644 --- a/packages/components/src/dropdown-menu-v2-ariakit/stories/index.story.tsx +++ b/packages/components/src/dropdown-menu-v2-ariakit/stories/index.story.tsx @@ -28,6 +28,7 @@ import { import Icon from '../../icon'; import Button from '../../button'; import Modal from '../../modal'; +import Popover from '../../popover'; import { createSlotFill, Provider as SlotFillProvider } from '../../slot-fill'; import { ContextSystemProvider } from '../../context'; @@ -501,3 +502,68 @@ InsideModal.parameters = { source: { type: 'code' }, }, }; + +export const WithDefaultSlotFill: StoryFn< typeof DropdownMenu > = ( + props +) => ( + + { /* @ts-expect-error Slot is not currently typed on Popover */ } + + + Top level item + Open submenu } + > + Nested item + + + +); +WithDefaultSlotFill.args = { + ...Default.args, +}; + +export const WithNamedSlotFill: StoryFn< typeof DropdownMenu > = ( props ) => ( + + { /* @ts-expect-error Slot is not currently typed on Popover */ } + + + Top level item + Open submenu } + > + Nested item + + + +); +WithNamedSlotFill.args = { + ...Default.args, + slotName: 'dropdown-menu-slot-with-name', +}; + +// @ts-expect-error __unstableSlotNameProvider is not currently typed on Popover +const SlotNameProvider = Popover.__unstableSlotNameProvider; +export const WithSlotFillViaContext: StoryFn< typeof DropdownMenu > = ( + props +) => ( + + + { /* @ts-expect-error Slot is not currently typed on Popover */ } + + + Top level item + Open submenu + } + > + Nested item + + + + +); +WithSlotFillViaContext.args = { + ...Default.args, +}; diff --git a/packages/components/src/dropdown-menu-v2-ariakit/types.ts b/packages/components/src/dropdown-menu-v2-ariakit/types.ts index 27d3b1e8c4339..64c7134d62bff 100644 --- a/packages/components/src/dropdown-menu-v2-ariakit/types.ts +++ b/packages/components/src/dropdown-menu-v2-ariakit/types.ts @@ -79,6 +79,13 @@ export interface DropdownMenuProps { | ( ( event: KeyboardEvent | React.KeyboardEvent< Element > ) => boolean ); + /** + * The name of the Slot in which the popover should be rendered. It should + * be also passed to the corresponding `PopoverSlot` component. + * + * @default 'Popover' + */ + slotName?: string; } export interface DropdownMenuGroupProps { diff --git a/packages/components/src/dropdown-menu/stories/index.story.tsx b/packages/components/src/dropdown-menu/stories/index.story.tsx index d4b856380db92..e94b5199b2537 100644 --- a/packages/components/src/dropdown-menu/stories/index.story.tsx +++ b/packages/components/src/dropdown-menu/stories/index.story.tsx @@ -9,6 +9,8 @@ import type { Meta, StoryFn } from '@storybook/react'; import { DropdownMenu } from '..'; import MenuItem from '../../menu-item'; import MenuGroup from '../../menu-group'; +import Popover from '../../popover'; +import { Provider as SlotFillProvider } from '../../slot-fill'; /** * WordPress dependencies @@ -116,3 +118,53 @@ WithChildren.args = { ), }; + +export const WithDefaultSlotFill: StoryFn< typeof DropdownMenu > = ( + props +) => ( + +
+ { /* @ts-expect-error Slot is not currently typed on Popover */ } + + +
+
+); +WithDefaultSlotFill.args = { + ...Default.args, +}; + +export const WithNamedSlotFill: StoryFn< typeof DropdownMenu > = ( props ) => ( + +
+ { /* @ts-expect-error Slot is not currently typed on Popover */ } + + +
+
+); +WithNamedSlotFill.args = { + ...Default.args, + popoverProps: { + __unstableSlotName: 'dropdown-menu-slot-with-name', + }, +}; + +// @ts-expect-error __unstableSlotNameProvider is not currently typed on Popover +const SlotNameProvider = Popover.__unstableSlotNameProvider; +export const WithSlotFillViaContext: StoryFn< typeof DropdownMenu > = ( + props +) => ( + + + { /* @ts-expect-error Slot is not currently typed on Popover */ } + +
+ +
+
+
+); +WithSlotFillViaContext.args = { + ...Default.args, +}; diff --git a/packages/components/src/popover/index.tsx b/packages/components/src/popover/index.tsx index 709d4b9884b5e..ff67b65cf5b0d 100644 --- a/packages/components/src/popover/index.tsx +++ b/packages/components/src/popover/index.tsx @@ -97,7 +97,7 @@ const ArrowTriangle = () => ( ); -const slotNameContext = createContext< string | undefined >( undefined ); +export const slotNameContext = createContext< string | undefined >( undefined ); const fallbackContainerClassname = 'components-popover__fallback-container'; const getPopoverFallbackContainer = () => { From cc1870a49f57f89cb4c97b41782420a36f77e4da Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Thu, 23 Nov 2023 14:15:56 +0000 Subject: [PATCH 28/45] DataViews: Code Quality remove some unused props from action. (#56477) --- packages/edit-site/src/components/dataviews/item-actions.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/edit-site/src/components/dataviews/item-actions.js b/packages/edit-site/src/components/dataviews/item-actions.js index 777244e0396a7..2c3373c14bfdf 100644 --- a/packages/edit-site/src/components/dataviews/item-actions.js +++ b/packages/edit-site/src/components/dataviews/item-actions.js @@ -102,7 +102,6 @@ export default function ItemActions( { item, actions } ) { action.callback( item ) } /> ); @@ -128,7 +127,6 @@ export default function ItemActions( { item, actions } ) { action.callback( item ) } From 130a145c7b41a6629a340ba46c200517e4085bc9 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Thu, 23 Nov 2023 16:48:55 +0200 Subject: [PATCH 29/45] Dataviews: Add preview and grid view in templates list (#56382) * Dataviews: Add preview and grid view in templates list * Update preview design * Preview heights in grid view * fix linting issue * address feedback * minor tweak --------- Co-authored-by: James Koster --- .../src/components/dataviews/view-grid.js | 13 +++- .../src/components/dataviews/view-list.js | 10 ++- .../page-templates/dataviews-templates.js | 73 ++++++++++++++++++- .../src/components/page-templates/style.scss | 18 +++++ packages/edit-site/src/style.scss | 1 + 5 files changed, 107 insertions(+), 8 deletions(-) create mode 100644 packages/edit-site/src/components/page-templates/style.scss diff --git a/packages/edit-site/src/components/dataviews/view-grid.js b/packages/edit-site/src/components/dataviews/view-grid.js index b9d4bd78d96d6..d97a9db04200d 100644 --- a/packages/edit-site/src/components/dataviews/view-grid.js +++ b/packages/edit-site/src/components/dataviews/view-grid.js @@ -8,6 +8,7 @@ import { FlexBlock, Placeholder, } from '@wordpress/components'; +import { useAsyncList } from '@wordpress/compose'; /** * Internal dependencies @@ -23,9 +24,15 @@ export function ViewGrid( { data, fields, view, actions, getItemId } ) { ! view.hiddenFields.includes( field.id ) && field.id !== view.layout.mediaField ); + const shownData = useAsyncList( data, { step: 3 } ); return ( - - { data.map( ( item, index ) => { + + { shownData.map( ( item, index ) => { return (
@@ -50,7 +57,7 @@ export function ViewGrid( { data, fields, view, actions, getItemId } ) { ) ) } - +