From 16bc9a08e361c23c90a592898785725431e73cfd Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Tue, 19 Dec 2023 10:14:07 +0100 Subject: [PATCH 01/76] Site Editor: Add View Link (#57153) Co-authored-by: Aki Hamano <54422211+t-hamano@users.noreply.github.com> --- packages/edit-post/src/components/header/index.js | 5 ++--- .../src/components/header-edit-mode/index.js | 3 ++- .../src/components/post-view-link}/index.js | 12 +++++------- packages/editor/src/private-apis.js | 2 ++ 4 files changed, 11 insertions(+), 11 deletions(-) rename packages/{edit-post/src/components/view-link => editor/src/components/post-view-link}/index.js (73%) diff --git a/packages/edit-post/src/components/header/index.js b/packages/edit-post/src/components/header/index.js index d6871f95f036ac..67349bd6404038 100644 --- a/packages/edit-post/src/components/header/index.js +++ b/packages/edit-post/src/components/header/index.js @@ -37,12 +37,11 @@ import FullscreenModeClose from './fullscreen-mode-close'; import HeaderToolbar from './header-toolbar'; import MoreMenu from './more-menu'; import PostPublishButtonOrToggle from './post-publish-button-or-toggle'; -import ViewLink from '../view-link'; import MainDashboardButton from './main-dashboard-button'; import { store as editPostStore } from '../../store'; import { unlock } from '../../lock-unlock'; -const { PreviewDropdown } = unlock( editorPrivateApis ); +const { PostViewLink, PreviewDropdown } = unlock( editorPrivateApis ); const slideY = { hidden: { y: '-50px' }, @@ -189,7 +188,7 @@ function Header( { className="edit-post-header__post-preview-button" forceIsAutosaveable={ hasActiveMetaboxes } /> - + ) } + { ! isDistractionFree && ( diff --git a/packages/edit-post/src/components/view-link/index.js b/packages/editor/src/components/post-view-link/index.js similarity index 73% rename from packages/edit-post/src/components/view-link/index.js rename to packages/editor/src/components/post-view-link/index.js index 3ebf78b851e1f7..57866488ff103b 100644 --- a/packages/edit-post/src/components/view-link/index.js +++ b/packages/editor/src/components/post-view-link/index.js @@ -4,17 +4,16 @@ import { __ } from '@wordpress/i18n'; import { Button } from '@wordpress/components'; import { external } from '@wordpress/icons'; -import { store as editorStore } from '@wordpress/editor'; import { store as coreStore } from '@wordpress/core-data'; import { useSelect } from '@wordpress/data'; /** * Internal dependencies */ -import { store as editPostStore } from '../../store'; +import { store as editorStore } from '../../store'; -export default function ViewLink() { - const { permalink, isPublished, label, showIconLabels } = useSelect( +export default function PostViewLink( { showIconLabels } ) { + const { hasLoaded, permalink, isPublished, label } = useSelect( ( select ) => { // Grab post type to retrieve the view_item label. const postTypeSlug = select( editorStore ).getCurrentPostType(); @@ -24,15 +23,14 @@ export default function ViewLink() { permalink: select( editorStore ).getPermalink(), isPublished: select( editorStore ).isCurrentPostPublished(), label: postType?.labels.view_item, - showIconLabels: - select( editPostStore ).isFeatureActive( 'showIconLabels' ), + hasLoaded: !! postType, }; }, [] ); // Only render the view button if the post is published and has a permalink. - if ( ! isPublished || ! permalink ) { + if ( ! isPublished || ! permalink || ! hasLoaded ) { return null; } diff --git a/packages/editor/src/private-apis.js b/packages/editor/src/private-apis.js index da86d138bb2fd8..fab84cdd53946c 100644 --- a/packages/editor/src/private-apis.js +++ b/packages/editor/src/private-apis.js @@ -7,6 +7,7 @@ import { lock } from './lock-unlock'; import { EntitiesSavedStatesExtensible } from './components/entities-saved-states'; import useBlockEditorSettings from './components/provider/use-block-editor-settings'; import PostPanelRow from './components/post-panel-row'; +import PostViewLink from './components/post-view-link'; import PreviewDropdown from './components/preview-dropdown'; import PluginPostExcerpt from './components/post-excerpt/plugin'; @@ -16,6 +17,7 @@ lock( privateApis, { ExperimentalEditorProvider, EntitiesSavedStatesExtensible, PostPanelRow, + PostViewLink, PreviewDropdown, PluginPostExcerpt, From 3a0016bf17758ee16fb39c7bc88918eb02e73bee Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Tue, 19 Dec 2023 09:56:16 +0000 Subject: [PATCH 02/76] DataViews: Add "see revisions" action to templates. (#57175) --- .../src/components/page-templates/index.js | 2 ++ .../page-templates/template-actions.js | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/packages/edit-site/src/components/page-templates/index.js b/packages/edit-site/src/components/page-templates/index.js index f534768a237c42..a41f08e1754b8d 100644 --- a/packages/edit-site/src/components/page-templates/index.js +++ b/packages/edit-site/src/components/page-templates/index.js @@ -45,6 +45,7 @@ import { useResetTemplateAction, deleteTemplateAction, renameTemplateAction, + seeRevisionsAction, } from './template-actions'; import usePatternSettings from '../page-patterns/use-pattern-settings'; import { unlock } from '../../lock-unlock'; @@ -332,6 +333,7 @@ export default function DataviewsTemplates() { resetTemplateAction, deleteTemplateAction, renameTemplateAction, + seeRevisionsAction, ], [ resetTemplateAction ] ); diff --git a/packages/edit-site/src/components/page-templates/template-actions.js b/packages/edit-site/src/components/page-templates/template-actions.js index 9f5897e31fb93e..b9ea4474d34ef6 100644 --- a/packages/edit-site/src/components/page-templates/template-actions.js +++ b/packages/edit-site/src/components/page-templates/template-actions.js @@ -15,6 +15,7 @@ import { __experimentalHStack as HStack, __experimentalVStack as VStack, } from '@wordpress/components'; +import { addQueryArgs } from '@wordpress/url'; /** * Internal dependencies @@ -207,3 +208,23 @@ export const renameTemplateAction = { ); }, }; + +export const seeRevisionsAction = { + id: 'see-revisions', + label: __( 'See revisions' ), + isEligible: ( template ) => { + if ( template?._links && template?._links[ 'predecessor-version' ] ) { + const predecessorVersions = + template._links[ 'predecessor-version' ]; + return predecessorVersions.length > 0; + } + return false; + }, + callback( template ) { + const lastRevisionId = + template?._links[ 'predecessor-version' ][ 0 ].id; + document.location.href = addQueryArgs( 'revision.php', { + revision: lastRevisionId, + } ); + }, +}; From 9b800eb7a3967f563cb908d45800c3a7fa04167f Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Tue, 19 Dec 2023 09:58:52 +0000 Subject: [PATCH 03/76] DataViews: make secondary actions trigger always visible. (#57174) --- packages/dataviews/src/item-actions.js | 34 ++++++++++++-------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/packages/dataviews/src/item-actions.js b/packages/dataviews/src/item-actions.js index 1b0bd5f213ca8e..17690f0064112a 100644 --- a/packages/dataviews/src/item-actions.js +++ b/packages/dataviews/src/item-actions.js @@ -120,9 +120,6 @@ export default function ItemActions( { item, actions, isCompact } ) { { primaryActions: [], secondaryActions: [] } ); }, [ actions, item ] ); - if ( ! primaryActions.length && ! secondaryActions.length ) { - return null; - } if ( isCompact ) { return ( ); } ) } - { !! secondaryActions.length && ( - - } - placement="bottom-end" - > - - - ) } + } + placement="bottom-end" + > + + ); } From 7339ba620b32ac72aace92392a411c5fb2fe3b31 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Tue, 19 Dec 2023 12:05:10 +0200 Subject: [PATCH 04/76] Font size picker: Fix Reset button focus loss (#57196) --- packages/components/CHANGELOG.md | 8 +++----- packages/components/src/font-size-picker/index.tsx | 13 +++++++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 01a073567e2f22..9614494f0f0e07 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -4,18 +4,16 @@ ### Bug Fix +- `FontSizePicker`: Fix Reset button focus loss ([#57196](https://github.com/WordPress/gutenberg/pull/57196)). - `PaletteEdit`: Consider digits when generating kebab-cased slug ([#56713](https://github.com/WordPress/gutenberg/pull/56713)). +- `Button`: Fix logic of `has-text` class addition ([#56949](https://github.com/WordPress/gutenberg/pull/56949)). +- `FormTokenField`: Fix a regression where the suggestion list would re-open after clicking away from the input ([#57002](https://github.com/WordPress/gutenberg/pull/57002)). ### Experimental - `Tabs`: do not render hidden content ([#57046](https://github.com/WordPress/gutenberg/pull/57046)). - `Tabs`: make sure `Tab`s are associated to the right `TabPanel`s, regardless of the order they're rendered in ([#57033](https://github.com/WordPress/gutenberg/pull/57033)). -### Bug Fix - -- `Button`: Fix logic of `has-text` class addition ([#56949](https://github.com/WordPress/gutenberg/pull/56949)). -- `FormTokenField`: Fix a regression where the suggestion list would re-open after clicking away from the input ([#57002](https://github.com/WordPress/gutenberg/pull/57002)). - ## 25.14.0 (2023-12-13) ### Enhancements diff --git a/packages/components/src/font-size-picker/index.tsx b/packages/components/src/font-size-picker/index.tsx index d79bc870d33588..9d977f43db9597 100644 --- a/packages/components/src/font-size-picker/index.tsx +++ b/packages/components/src/font-size-picker/index.tsx @@ -123,6 +123,7 @@ const UnforwardedFontSizePicker = ( ); const isValueUnitRelative = !! valueUnit && [ 'em', 'rem' ].includes( valueUnit ); + const isDisabled = value === undefined; return ( @@ -276,10 +277,14 @@ const UnforwardedFontSizePicker = ( { withReset && ( + + + + ); + render( ); + + await user.tab(); + expect( screen.getByText( 'Before' ) ).toHaveFocus(); + await user.tab(); + expect( screen.getByText( 'Item 1' ) ).toHaveFocus(); + await user.tab(); + expect( screen.getByText( 'After' ) ).toHaveFocus(); + await user.tab( { shift: true } ); + expect( screen.getByText( 'Item 1' ) ).toHaveFocus(); + } ); + + test( 'Excludes disabled items', async () => { + const user = userEvent.setup(); + const Test = () => { + const props = useProps(); + return ( + + Item 1 + + Item 2 + + Item 3 + + ); + }; + render( ); + + const { item1, item2, item3 } = getOneDimensionalItems(); + + expect( item2 ).toBeDisabled(); + + await user.tab(); + expect( item1 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( item2 ).not.toHaveFocus(); + expect( item3 ).toHaveFocus(); + } ); + + test( 'Includes focusable disabled items', async () => { + const user = userEvent.setup(); + const Test = () => { + const props = useProps(); + return ( + + Item 1 + + Item 2 + + Item 3 + + ); + }; + render( ); + const { item1, item2, item3 } = getOneDimensionalItems(); + + expect( item2 ).toBeEnabled(); + expect( item2 ).toHaveAttribute( 'aria-disabled', 'true' ); + + await user.tab(); + expect( item1 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( item2 ).toHaveFocus(); + expect( item3 ).not.toHaveFocus(); + } ); + + test( 'Supports `baseId`', async () => { + const { item1, item2, item3 } = useOneDimensionalTest( { + baseId: 'test-id', + } ); + + expect( item1.id ).toMatch( 'test-id-1' ); + expect( item2.id ).toMatch( 'test-id-2' ); + expect( item3.id ).toMatch( 'test-id-3' ); + } ); + + test( 'Supports `currentId`', async () => { + const user = userEvent.setup(); + const { item2 } = useOneDimensionalTest( { + baseId: 'test-id', + currentId: 'test-id-2', + } ); + + await user.tab(); + expect( item2 ).toHaveFocus(); + } ); + } ); + + describe.each( [ + [ + 'When LTR', + false, + { previous: 'ArrowLeft', next: 'ArrowRight' }, + ], + [ 'When RTL', true, { previous: 'ArrowRight', next: 'ArrowLeft' } ], + ] )( '%s', ( _when, rtl, { previous, next } ) => { + function useOneDimensionalTest( initialState?: InitialState ) { + const Test = () => ( + + ); + render( ); + return getOneDimensionalItems(); + } + + function useTwoDimensionalTest( initialState?: InitialState ) { + const Test = () => ( + + ); + render( ); + return getTwoDimensionalItems(); + } + + function useShiftTest( shift: boolean ) { + const Test = () => ( + + ); + render( ); + return getShiftTestItems(); + } + + describe( 'In one dimension', () => { + test( 'All directions work with no orientation', async () => { + const user = userEvent.setup(); + const { item1, item2, item3 } = useOneDimensionalTest( { + rtl, + } ); + + await user.tab(); + expect( item1 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( item2 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( item3 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( item3 ).toHaveFocus(); + await user.keyboard( '[ArrowUp]' ); + expect( item2 ).toHaveFocus(); + await user.keyboard( '[ArrowUp]' ); + expect( item1 ).toHaveFocus(); + await user.keyboard( '[ArrowUp]' ); + expect( item1 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( item2 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( item3 ).toHaveFocus(); + await user.keyboard( `[${ previous }]` ); + expect( item2 ).toHaveFocus(); + await user.keyboard( `[${ previous }]` ); + expect( item1 ).toHaveFocus(); + await user.keyboard( '[End]' ); + expect( item3 ).toHaveFocus(); + await user.keyboard( '[Home]' ); + expect( item1 ).toHaveFocus(); + await user.keyboard( '[PageDown]' ); + expect( item3 ).toHaveFocus(); + await user.keyboard( '[PageUp]' ); + expect( item1 ).toHaveFocus(); + } ); + + test( 'Only left/right work with horizontal orientation', async () => { + const user = userEvent.setup(); + const { item1, item2, item3 } = useOneDimensionalTest( { + rtl, + orientation: 'horizontal', + } ); + + await user.tab(); + expect( item1 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( item1 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( item2 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( item3 ).toHaveFocus(); + await user.keyboard( '[ArrowUp]' ); + expect( item3 ).toHaveFocus(); + await user.keyboard( `[${ previous }]` ); + expect( item2 ).toHaveFocus(); + await user.keyboard( `[${ previous }]` ); + expect( item1 ).toHaveFocus(); + await user.keyboard( '[End]' ); + expect( item3 ).toHaveFocus(); + await user.keyboard( '[Home]' ); + expect( item1 ).toHaveFocus(); + await user.keyboard( '[PageDown]' ); + expect( item3 ).toHaveFocus(); + await user.keyboard( '[PageUp]' ); + expect( item1 ).toHaveFocus(); + } ); + + test( 'Only up/down work with vertical orientation', async () => { + const user = userEvent.setup(); + const { item1, item2, item3 } = useOneDimensionalTest( { + rtl, + orientation: 'vertical', + } ); + + await user.tab(); + expect( item1 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( item1 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( item2 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( item3 ).toHaveFocus(); + await user.keyboard( `[${ previous }]` ); + expect( item3 ).toHaveFocus(); + await user.keyboard( '[ArrowUp]' ); + expect( item2 ).toHaveFocus(); + await user.keyboard( '[ArrowUp]' ); + expect( item1 ).toHaveFocus(); + await user.keyboard( '[End]' ); + expect( item3 ).toHaveFocus(); + await user.keyboard( '[Home]' ); + expect( item1 ).toHaveFocus(); + await user.keyboard( '[PageDown]' ); + expect( item3 ).toHaveFocus(); + await user.keyboard( '[PageUp]' ); + expect( item1 ).toHaveFocus(); + } ); + + test( 'Focus wraps with loop enabled', async () => { + const user = userEvent.setup(); + const { item1, item2, item3 } = useOneDimensionalTest( { + rtl, + loop: true, + } ); + + await user.tab(); + expect( item1 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( item2 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( item3 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( item1 ).toHaveFocus(); + await user.keyboard( '[ArrowUp]' ); + expect( item3 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( item1 ).toHaveFocus(); + await user.keyboard( `[${ previous }]` ); + expect( item3 ).toHaveFocus(); + } ); + } ); + + describe( 'In two dimensions', () => { + test( 'All directions work as standard', async () => { + const user = userEvent.setup(); + const { + itemA1, + itemA2, + itemA3, + itemB1, + itemB2, + itemC1, + itemC3, + } = useTwoDimensionalTest( { rtl } ); + + await user.tab(); + expect( itemA1 ).toHaveFocus(); + await user.keyboard( '[ArrowUp]' ); + expect( itemA1 ).toHaveFocus(); + await user.keyboard( `[${ previous }]` ); + expect( itemA1 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( itemB1 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( itemB2 ).toHaveFocus(); + await user.keyboard( '[ArrowUp]' ); + expect( itemA2 ).toHaveFocus(); + await user.keyboard( `[${ previous }]` ); + expect( itemA1 ).toHaveFocus(); + await user.keyboard( '[End]' ); + expect( itemA3 ).toHaveFocus(); + await user.keyboard( '[PageDown]' ); + expect( itemC3 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( itemC3 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( itemC3 ).toHaveFocus(); + await user.keyboard( '[Home]' ); + expect( itemC1 ).toHaveFocus(); + await user.keyboard( '[PageUp]' ); + expect( itemA1 ).toHaveFocus(); + await user.keyboard( '{Control>}[End]{/Control}' ); + expect( itemC3 ).toHaveFocus(); + await user.keyboard( '{Control>}[Home]{/Control}' ); + expect( itemA1 ).toHaveFocus(); + } ); + + test( 'Focus wraps around rows/columns with loop enabled', async () => { + const user = userEvent.setup(); + const { itemA1, itemA2, itemA3, itemB1, itemC1, itemC3 } = + useTwoDimensionalTest( { rtl, loop: true } ); + + await user.tab(); + expect( itemA1 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( itemA2 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( itemA3 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( itemA1 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( itemB1 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( itemC1 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( itemA1 ).toHaveFocus(); + await user.keyboard( `[${ previous }]` ); + expect( itemA3 ).toHaveFocus(); + await user.keyboard( '[ArrowUp]' ); + expect( itemC3 ).toHaveFocus(); + } ); + + test( 'Focus moves between rows/columns with wrap enabled', async () => { + const user = userEvent.setup(); + const { itemA1, itemA2, itemA3, itemB1, itemC1, itemC3 } = + useTwoDimensionalTest( { rtl, wrap: true } ); + + await user.tab(); + expect( itemA1 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( itemA2 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( itemA3 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( itemB1 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( itemC1 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( itemA2 ).toHaveFocus(); + await user.keyboard( `[${ previous }]` ); + expect( itemA1 ).toHaveFocus(); + await user.keyboard( `[${ previous }]` ); + expect( itemA1 ).toHaveFocus(); + await user.keyboard( '[ArrowUp]' ); + expect( itemA1 ).toHaveFocus(); + await user.keyboard( '{Control>}[End]{/Control}' ); + expect( itemC3 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( itemC3 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( itemC3 ).toHaveFocus(); + } ); + + test( 'Focus wraps around start/end with loop and wrap enabled', async () => { + const user = userEvent.setup(); + const { itemA1, itemC3 } = useTwoDimensionalTest( { + rtl, + loop: true, + wrap: true, + } ); + + await user.tab(); + expect( itemA1 ).toHaveFocus(); + await user.keyboard( `[${ previous }]` ); + expect( itemC3 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( itemA1 ).toHaveFocus(); + await user.keyboard( '[ArrowUp]' ); + expect( itemC3 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( itemA1 ).toHaveFocus(); + } ); + + test( 'Focus shifts if vertical neighbour unavailable when shift enabled', async () => { + const user = userEvent.setup(); + const { itemA1, itemB1, itemB2, itemC1 } = + useShiftTest( true ); + + await user.tab(); + expect( itemA1 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( itemB1 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( itemB2 ).toHaveFocus(); + await user.keyboard( '[ArrowUp]' ); + // A2 doesn't exist + expect( itemA1 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( itemB1 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( itemB2 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + // C2 is disabled + expect( itemC1 ).toHaveFocus(); + } ); + + test( 'Focus does not shift if vertical neighbour unavailable when shift not enabled', async () => { + const user = userEvent.setup(); + const { itemA1, itemB1, itemB2 } = useShiftTest( false ); + + await user.tab(); + expect( itemA1 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + expect( itemB1 ).toHaveFocus(); + await user.keyboard( `[${ next }]` ); + expect( itemB2 ).toHaveFocus(); + await user.keyboard( '[ArrowUp]' ); + // A2 doesn't exist + expect( itemB2 ).toHaveFocus(); + await user.keyboard( '[ArrowDown]' ); + // C2 is disabled + expect( itemB2 ).toHaveFocus(); + } ); + } ); + } ); + } +); From 1dedeab82c51ccdd1062a29aeac248a9dcf02689 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 20 Dec 2023 01:37:04 +0900 Subject: [PATCH 25/76] Snackbar: Remove `__unstableHTML` prop from TS (#57218) * Snackbar: Remove `__unstableHTML` prop from TS * Add changelog --- packages/components/CHANGELOG.md | 1 + packages/components/src/snackbar/types.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index d0acdbd43c6e93..eccd9e639e5f20 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -9,6 +9,7 @@ - `PaletteEdit`: Consider digits when generating kebab-cased slug ([#56713](https://github.com/WordPress/gutenberg/pull/56713)). - `Button`: Fix logic of `has-text` class addition ([#56949](https://github.com/WordPress/gutenberg/pull/56949)). - `FormTokenField`: Fix a regression where the suggestion list would re-open after clicking away from the input ([#57002](https://github.com/WordPress/gutenberg/pull/57002)). +- `Snackbar`: Remove erroneous `__unstableHTML` prop from TypeScript definitions ([#57218](https://github.com/WordPress/gutenberg/pull/57218)). ### Enhancements diff --git a/packages/components/src/snackbar/types.ts b/packages/components/src/snackbar/types.ts index 71ded92e5b7d11..539c4c3ebdf65e 100644 --- a/packages/components/src/snackbar/types.ts +++ b/packages/components/src/snackbar/types.ts @@ -28,7 +28,8 @@ type SnackbarOnlyProps = { listRef?: MutableRefObject< HTMLDivElement | null >; }; -export type SnackbarProps = NoticeProps & SnackbarOnlyProps; +export type SnackbarProps = Omit< NoticeProps, '__unstableHTML' > & + SnackbarOnlyProps; export type SnackbarListProps = { notices: Array< From 85f8b264029ce8ed897af140770d885cd51a4709 Mon Sep 17 00:00:00 2001 From: Yuliyan Slavchev Date: Tue, 19 Dec 2023 19:11:41 +0200 Subject: [PATCH 26/76] Editor: Use visibility selector for PostTemplatePanel (#57224) --- packages/editor/src/components/post-template/panel.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/editor/src/components/post-template/panel.js b/packages/editor/src/components/post-template/panel.js index 8fcaeec8f3a3b2..bbad1cb135fd98 100644 --- a/packages/editor/src/components/post-template/panel.js +++ b/packages/editor/src/components/post-template/panel.js @@ -23,8 +23,7 @@ export default function PostTemplatePanel() { }; }, [] ); - const isVisible = true; - useSelect( ( select ) => { + const isVisible = useSelect( ( select ) => { const postTypeSlug = select( editorStore ).getCurrentPostType(); const postType = select( coreStore ).getPostType( postTypeSlug ); if ( ! postType?.viewable ) { From b13ae584892ff493c0aedc8c0218b7b62e534cf4 Mon Sep 17 00:00:00 2001 From: JuanMa Date: Tue, 19 Dec 2023 20:12:36 +0100 Subject: [PATCH 27/76] Add new section on markup representation of a block (#57230) --- docs/getting-started/fundamentals/README.md | 1 + .../markup-representation-block.md | 44 +++++++++++++++++++ docs/manifest.json | 6 +++ docs/toc.json | 3 ++ 4 files changed, 54 insertions(+) create mode 100644 docs/getting-started/fundamentals/markup-representation-block.md diff --git a/docs/getting-started/fundamentals/README.md b/docs/getting-started/fundamentals/README.md index 4fde0f3a0d1009..799ff89aa39419 100644 --- a/docs/getting-started/fundamentals/README.md +++ b/docs/getting-started/fundamentals/README.md @@ -9,4 +9,5 @@ In this section, you will learn: 1. [**Registration of a block**](https://developer.wordpress.org/block-editor/getting-started/fundamentals/registration-of-a-block) - How a block is registered in both the server and the client. 1. [**Block wrapper**](https://developer.wordpress.org/block-editor/getting-started/fundamentals/block-wrapper) - How to set proper attributes to the block's markup wrapper. 1. [**The block in the Editor**](https://developer.wordpress.org/block-editor/getting-started/fundamentals/block-in-the-editor) - The block as a React component loaded in the Block Editor and its possibilities. +1. [**Markup representation of a block**](https://developer.wordpress.org/block-editor/getting-started/fundamentals/markup-representation-block) - How blocks are represented in the DB or in templates. 1. [**Javascript in the Block Editor**](https://developer.wordpress.org/block-editor/getting-started/fundamentals/javascript-in-the-block-editor) - How to work with Javascript for the Block Editor. \ No newline at end of file diff --git a/docs/getting-started/fundamentals/markup-representation-block.md b/docs/getting-started/fundamentals/markup-representation-block.md new file mode 100644 index 00000000000000..20289f8f228ce8 --- /dev/null +++ b/docs/getting-started/fundamentals/markup-representation-block.md @@ -0,0 +1,44 @@ +# Markup representation of a block + +When stored, in the database (DB) or in templates as HTML files, blocks are represented using a [specific HTML grammar](https://developer.wordpress.org/block-editor/explanations/architecture/key-concepts/#data-and-attributes), which is technically valid HTML based on HTML comments that act as explicit block delimiters + +These are some of the rules for the markup used to represent a block: +- All core block comments start with a prefix and the block name: `wp:blockname` +- For custom blocks, `blockname` is `namespace/blockname` +- The comment can be a single line, self-closing, or wrapper for HTML content. +- Custom block settings and attributes are stored as a JSON object inside the block comment. + +_Example: Markup representation of an `image` core block_ + +``` + +
+ +``` + +The [markup representation of a block is parsed for the Block Editor](https://developer.wordpress.org/block-editor/explanations/architecture/data-flow/) and the block's output for the front end: +- In the editor, WordPress parses this block markup, captures its data and loads its `edit` version +- In the front end, WordPress parses this block markup, captures its data and generates its final HTML markup + +Whenever a block is saved, the `save` function, defined when the [block is registered in the client](https://developer.wordpress.org/block-editor/getting-started/fundamentals/registration-of-a-block/#registration-of-the-block-with-javascript-client-side), is called to return the markup that will be saved into the database within the block delimiter's comment. If `save` is `null` (common case for blocks with dynamic rendering), only a single line block delimiter's comment is stored, along with any attributes + +The Post Editor checks that the markup created by the `save` function is identical to the block's markup saved to the database: +- If there are any differences, the Post Editor trigger a **block validation error**. +- Block validation errors usually happen when a block’s `save` function is updated to change the markup produced by the block. +- A block developer can mitigate these issues by adding a [**block deprecation**](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-deprecation/) to register the change in the block. + +The markup of a **block with dynamic rendering** is expected to change so the markup of these blocks is not saved to the database. What is saved in the DB as representation of the block, for blocks with dynamic rendering, is a single line of HTML consisting on just the block delimiter's comment (including block attributes values). That HTML is not subject to the Post Editor’s validation. + +_Example: Markup representation of a block with dynamic rendering (`save` = `null`) and attributes_ + + +```html + +``` + +## Additional Resources + +- [Data Flow and Data Format](https://developer.wordpress.org/block-editor/explanations/architecture/data-flow/) +- [Static vs. dynamic blocks: What’s the difference?](https://developer.wordpress.org/news/2023/02/27/static-vs-dynamic-blocks-whats-the-difference/) +- [Block deprecation – a tutorial](https://developer.wordpress.org/news/2023/03/10/block-deprecation-a-tutorial/) +- [Introduction to Templates > Block markup](https://developer.wordpress.org/themes/templates/introduction-to-templates/#block-markup) | Theme Handbook \ No newline at end of file diff --git a/docs/manifest.json b/docs/manifest.json index fb6d8550fa7ec9..7bb1e847ce03fd 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -89,6 +89,12 @@ "markdown_source": "../docs/getting-started/fundamentals/block-in-the-editor.md", "parent": "fundamentals" }, + { + "title": "Markup representation of a block", + "slug": "markup-representation-block", + "markdown_source": "../docs/getting-started/fundamentals/markup-representation-block.md", + "parent": "fundamentals" + }, { "title": "Working with Javascript for the Block Editor", "slug": "javascript-in-the-block-editor", diff --git a/docs/toc.json b/docs/toc.json index 4b4f5bbd69a5f6..961fc88fae4f52 100644 --- a/docs/toc.json +++ b/docs/toc.json @@ -39,6 +39,9 @@ { "docs/getting-started/fundamentals/block-in-the-editor.md": [] }, + { + "docs/getting-started/fundamentals/markup-representation-block.md": [] + }, { "docs/getting-started/fundamentals/javascript-in-the-block-editor.md": [] } From c868408adeb8db7b440b8015fea674aa714bed5e Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Tue, 19 Dec 2023 14:14:26 -0600 Subject: [PATCH 28/76] Fix block lock toolbar item stealing focus when mounted with StrictMode (#57185) --- .../src/components/block-lock/toolbar.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/block-lock/toolbar.js b/packages/block-editor/src/components/block-lock/toolbar.js index 5ba08b08846a4a..14a941a9011b6d 100644 --- a/packages/block-editor/src/components/block-lock/toolbar.js +++ b/packages/block-editor/src/components/block-lock/toolbar.js @@ -23,6 +23,7 @@ export default function BlockLockToolbar( { clientId, wrapperRef } ) { const lockButtonRef = useRef( null ); const isFirstRender = useRef( true ); + const hasModalOpened = useRef( false ); const shouldHideBlockLockUI = ! canLock || ( canEdit && canMove && canRemove ); @@ -36,7 +37,19 @@ export default function BlockLockToolbar( { clientId, wrapperRef } ) { return; } - if ( ! isModalOpen && shouldHideBlockLockUI ) { + if ( isModalOpen && ! hasModalOpened.current ) { + hasModalOpened.current = true; + } + + // We only want to allow this effect to happen if the modal has been opened. + // The issue is when we're returning focus from the block lock modal to a toolbar, + // so it can only happen after a modal has been opened. Without this, the toolbar + // will steal focus on rerenders. + if ( + hasModalOpened.current && + ! isModalOpen && + shouldHideBlockLockUI + ) { focus.focusable .find( wrapperRef.current, { sequential: false, From 50f2ae28bcb095ce7e2fe0b81e09149666159292 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 20 Dec 2023 09:30:16 +1100 Subject: [PATCH 29/76] Allow default duotone styles in classic themes. (#57191) --- lib/class-wp-theme-json-resolver-gutenberg.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/class-wp-theme-json-resolver-gutenberg.php b/lib/class-wp-theme-json-resolver-gutenberg.php index 950d9e00e6243f..189d411db2257f 100644 --- a/lib/class-wp-theme-json-resolver-gutenberg.php +++ b/lib/class-wp-theme-json-resolver-gutenberg.php @@ -322,9 +322,6 @@ public static function get_theme_data( $deprecated = array(), $options = array() } $theme_support_data['settings']['color']['defaultGradients'] = $default_gradients; - // Classic themes without a theme.json don't support global duotone. - $theme_support_data['settings']['color']['defaultDuotone'] = false; - // Allow themes to enable all border settings via theme_support. if ( current_theme_supports( 'border' ) ) { $theme_support_data['settings']['border']['color'] = true; From c0f6e23f1c4cb49eb6fe49b810fdb824015a23ec Mon Sep 17 00:00:00 2001 From: Chad Chadbourne <13856531+chad1008@users.noreply.github.com> Date: Tue, 19 Dec 2023 17:40:54 -0500 Subject: [PATCH 30/76] Components: add unit test `__experimentalExpandOnFocus` unit tests for `FormTokenField` (#57122) * add unit test * add tests for suggestion visibility after selection --- .../src/form-token-field/test/index.tsx | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/packages/components/src/form-token-field/test/index.tsx b/packages/components/src/form-token-field/test/index.tsx index 76e308d5993beb..961214a574c90d 100644 --- a/packages/components/src/form-token-field/test/index.tsx +++ b/packages/components/src/form-token-field/test/index.tsx @@ -741,6 +741,103 @@ describe( 'FormTokenField', () => { ] ); } ); + it( 'should render suggestions after a selection is made when the `__experimentalExpandOnFocus` prop is set to `true`', async () => { + const user = userEvent.setup(); + + const onFocusSpy = jest.fn(); + + const suggestions = [ 'Green', 'Emerald', 'Seaweed' ]; + + render( + <> + + + ); + + const input = screen.getByRole( 'combobox' ); + + await user.type( input, 'ee' ); + + expectVisibleSuggestionsToBe( screen.getByRole( 'listbox' ), [ + 'Green', + 'Seaweed', + ] ); + + // Select the first suggestion ("Green") + await user.keyboard( '[ArrowDown][Enter]' ); + + expect( screen.getByRole( 'listbox' ) ).toBeVisible(); + } ); + + it( 'should not render suggestions after a selection is made when the `__experimentalExpandOnFocus` prop is set to `false` or not defined', async () => { + const user = userEvent.setup(); + + const onFocusSpy = jest.fn(); + + const suggestions = [ 'Green', 'Emerald', 'Seaweed' ]; + + render( + <> + + + ); + + const input = screen.getByRole( 'combobox' ); + + await user.type( input, 'ee' ); + + expectVisibleSuggestionsToBe( screen.getByRole( 'listbox' ), [ + 'Green', + 'Seaweed', + ] ); + + // Select the first suggestion ("Green") + await user.keyboard( '[ArrowDown][Enter]' ); + + expect( screen.queryByRole( 'listbox' ) ).not.toBeInTheDocument(); + } ); + + it( 'should not render suggestions after the input is blurred', async () => { + const user = userEvent.setup(); + + const onFocusSpy = jest.fn(); + + const suggestions = [ 'Green', 'Emerald', 'Seaweed' ]; + + render( + <> + + + ); + + const input = screen.getByRole( 'combobox' ); + + await user.type( input, 'ee' ); + + expectVisibleSuggestionsToBe( screen.getByRole( 'listbox' ), [ + 'Green', + 'Seaweed', + ] ); + + // Select the first suggestion ("Green") + await user.keyboard( '[ArrowDown][Enter]' ); + + // Click the body, blurring the input. + await user.click( document.body ); + + expect( screen.queryByRole( 'listbox' ) ).not.toBeInTheDocument(); + } ); + it( 'should not render suggestions if the text input is not matching any of the suggestions', async () => { const user = userEvent.setup(); From 6630e0a6721ce507e39bf8ee4696695be27b803a Mon Sep 17 00:00:00 2001 From: Chad Chadbourne <13856531+chad1008@users.noreply.github.com> Date: Tue, 19 Dec 2023 18:15:30 -0500 Subject: [PATCH 31/76] Components: replace `TabPanel` with `Tabs` in the Block Inspector (#56995) * implement `Tabs` * focusable false * add `show-icon-labels` support * address feedback --- .../inspector-controls-tabs/index.js | 67 +++++++++++-------- .../inspector-controls-tabs/style.scss | 2 +- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/packages/block-editor/src/components/inspector-controls-tabs/index.js b/packages/block-editor/src/components/inspector-controls-tabs/index.js index de192050d05cb2..944ce6f3220937 100644 --- a/packages/block-editor/src/components/inspector-controls-tabs/index.js +++ b/packages/block-editor/src/components/inspector-controls-tabs/index.js @@ -1,7 +1,10 @@ /** * WordPress dependencies */ -import { TabPanel } from '@wordpress/components'; +import { + Button, + privateApis as componentsPrivateApis, +} from '@wordpress/components'; /** * Internal dependencies @@ -11,6 +14,9 @@ import SettingsTab from './settings-tab'; import StylesTab from './styles-tab'; import InspectorControls from '../inspector-controls'; import useIsListViewTabDisabled from './use-is-list-view-tab-disabled'; +import { unlock } from '../../lock-unlock'; + +const { Tabs } = unlock( componentsPrivateApis ); export default function InspectorControlsTabs( { blockName, @@ -26,34 +32,39 @@ export default function InspectorControlsTabs( { const initialTabName = ! useIsListViewTabDisabled( blockName ) ? TAB_LIST_VIEW.name : undefined; - return ( - - { ( tab ) => { - if ( tab.name === TAB_SETTINGS.name ) { - return ( - - ); - } - if ( tab.name === TAB_STYLES.name ) { - return ( - + + + { tabs.map( ( tab ) => ( + + } /> - ); - } - - if ( tab.name === TAB_LIST_VIEW.name ) { - return ; - } - } } - + ) ) } + + + + + + + + + + + + ); } diff --git a/packages/block-editor/src/components/inspector-controls-tabs/style.scss b/packages/block-editor/src/components/inspector-controls-tabs/style.scss index da83073a45590a..6db9395af62ef6 100644 --- a/packages/block-editor/src/components/inspector-controls-tabs/style.scss +++ b/packages/block-editor/src/components/inspector-controls-tabs/style.scss @@ -1,5 +1,5 @@ .show-icon-labels { - .block-editor-block-inspector__tabs .components-tab-panel__tabs { + .block-editor-block-inspector__tabs [role="tablist"] { .components-button.has-icon { // Hide the button icons when labels are set to display... svg { From 6bbf33c1eeb634ed404ef8505318852308f0a627 Mon Sep 17 00:00:00 2001 From: Damon Cook Date: Tue, 19 Dec 2023 19:17:25 -0500 Subject: [PATCH 32/76] Fix vertical overflow when inserter is open in post and site editor (#57127) * Toggle classname for inserter * Adjust overflow when inserter is open * Revert "Toggle classname for inserter" This reverts commit 95f0a7264e179564a97f42fe8a7c8e1f56550793. * Revert "Adjust overflow when inserter is open" This reverts commit 40fba9e36cbc2f834d6850862fce6f1cd202b9d9. * Fix vertical overflow for inserter main area Co-authored-by: Aki Hamano <54422211+t-hamano@users.noreply.github.com> --------- Co-authored-by: Aki Hamano <54422211+t-hamano@users.noreply.github.com> --- packages/block-editor/src/components/inserter/style.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/block-editor/src/components/inserter/style.scss b/packages/block-editor/src/components/inserter/style.scss index 97a3d877b7e72a..dd0cc50e31fcb4 100644 --- a/packages/block-editor/src/components/inserter/style.scss +++ b/packages/block-editor/src/components/inserter/style.scss @@ -22,6 +22,8 @@ $block-inserter-tabs-height: 44px; flex-direction: column; height: 100%; gap: $grid-unit-20; + overflow-y: hidden; + &.show-as-tabs { gap: 0; } From b080c298ac6449b70ab469baa70dc327b71d6e2f Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 20 Dec 2023 14:51:29 +1300 Subject: [PATCH 33/76] Gallery block: combine useSelect calls (#57240) --- packages/block-library/src/gallery/edit.js | 50 +++++++++++----------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index e73e1e76b9c5f0..03fc15d19eedcd 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -74,6 +74,8 @@ const MOBILE_CONTROL_PROPS_RANGE_CONTROL = Platform.isNative ? { type: 'stepper' } : {}; +const EMPTY_ARRAY = []; + function GalleryEdit( props ) { const { setAttributes, @@ -97,33 +99,29 @@ function GalleryEdit( props ) { const { createSuccessNotice, createErrorNotice } = useDispatch( noticesStore ); - const { getBlock, getSettings, preferredStyle } = useSelect( ( select ) => { - const settings = select( blockEditorStore ).getSettings(); - const preferredStyleVariations = - settings.__experimentalPreferredStyleVariations; - return { - getBlock: select( blockEditorStore ).getBlock, - getSettings: select( blockEditorStore ).getSettings, - preferredStyle: preferredStyleVariations?.value?.[ 'core/image' ], - }; - }, [] ); - - const innerBlockImages = useSelect( - ( select ) => { - const innerBlocks = - select( blockEditorStore ).getBlock( clientId )?.innerBlocks ?? - []; - return innerBlocks; - }, - [ clientId ] - ); - - const wasBlockJustInserted = useSelect( + const { + getBlock, + getSettings, + preferredStyle, + innerBlockImages, + wasBlockJustInserted, + } = useSelect( ( select ) => { - return select( blockEditorStore ).wasBlockJustInserted( - clientId, - 'inserter_menu' - ); + const settings = select( blockEditorStore ).getSettings(); + const preferredStyleVariations = + settings.__experimentalPreferredStyleVariations; + return { + getBlock: select( blockEditorStore ).getBlock, + getSettings: select( blockEditorStore ).getSettings, + preferredStyle: + preferredStyleVariations?.value?.[ 'core/image' ], + innerBlockImages: + select( blockEditorStore ).getBlock( clientId ) + ?.innerBlocks ?? EMPTY_ARRAY, + wasBlockJustInserted: select( + blockEditorStore + ).wasBlockJustInserted( clientId, 'inserter_menu' ), + }; }, [ clientId ] ); From c86c37d692ccde93440d74cfe4bf433d63b52c5c Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 20 Dec 2023 13:35:25 +1100 Subject: [PATCH 34/76] Make sure theme color palette presets are output when appearance tools are enabled. (#57190) * Make sure theme color palette preset styles are output. * Check for color palette support * Also check for border support. --- lib/global-styles-and-settings.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/global-styles-and-settings.php b/lib/global-styles-and-settings.php index 03c8de10a89251..7a7a91e7368664 100644 --- a/lib/global-styles-and-settings.php +++ b/lib/global-styles-and-settings.php @@ -72,7 +72,13 @@ function gutenberg_get_global_stylesheet( $types = array() ) { * @see wp_add_global_styles_for_blocks */ $origins = array( 'default', 'theme', 'custom' ); - if ( ! $supports_theme_json ) { + /* + * If the theme doesn't have theme.json but supports both appearance tools and color palette, + * the 'theme' origin should be included so color palette presets are also output. + */ + if ( ! $supports_theme_json && ( current_theme_supports( 'appearance-tools' ) || current_theme_supports( 'border' ) ) && current_theme_supports( 'editor-color-palette' ) ) { + $origins = array( 'default', 'theme' ); + } elseif ( ! $supports_theme_json ) { $origins = array( 'default' ); } $styles_rest = $tree->get_stylesheet( $types, $origins ); From fda1efc7e733e4e2f0cdddb0ebb6843ac31db764 Mon Sep 17 00:00:00 2001 From: Mitchell Austin Date: Tue, 19 Dec 2023 22:28:45 -0800 Subject: [PATCH 35/76] `Modal`: Improve application of body class names (#55430) * Add unit tests for body class name effects * Fix and enhance body class attribute effect * Add changelog entry --- packages/components/CHANGELOG.md | 1 + packages/components/src/modal/index.tsx | 32 +++---- packages/components/src/modal/test/index.tsx | 91 +++++++++++++++++++- 3 files changed, 108 insertions(+), 16 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index eccd9e639e5f20..ecf4d3628c0839 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -14,6 +14,7 @@ ### Enhancements - `DateTimePicker`: Adjustment of the dot position on DayButton and expansion of the button area. ([#55502](https://github.com/WordPress/gutenberg/pull/55502)). +- `Modal`: Improve application of body class names ([#55430](https://github.com/WordPress/gutenberg/pull/55430)). ### Experimental diff --git a/packages/components/src/modal/index.tsx b/packages/components/src/modal/index.tsx index 041c592166ab73..b1bee51805f782 100644 --- a/packages/components/src/modal/index.tsx +++ b/packages/components/src/modal/index.tsx @@ -43,12 +43,12 @@ import StyleProvider from '../style-provider'; import type { ModalProps } from './types'; // Used to track and dismiss the prior modal when another opens unless nested. -const level0Dismissers: MutableRefObject< - ModalProps[ 'onRequestClose' ] | undefined ->[] = []; -const ModalContext = createContext( level0Dismissers ); +const ModalContext = createContext< + MutableRefObject< ModalProps[ 'onRequestClose' ] | undefined >[] +>( [] ); -let isBodyOpenClassActive = false; +// Used to track body class names applied while modals are open. +const bodyOpenClasses = new Map< string, number >(); function UnforwardedModal( props: ModalProps, @@ -146,7 +146,7 @@ function UnforwardedModal( // one should remain open at a time and the list enables closing prior ones. const dismissers = useContext( ModalContext ); // Used for the tracking and dismissing any nested modals. - const nestedDismissers = useRef< typeof level0Dismissers >( [] ); + const nestedDismissers = useRef< typeof dismissers >( [] ); // Updates the stack tracking open modals at this level and calls // onRequestClose for any prior and/or nested modals as applicable. @@ -162,20 +162,22 @@ function UnforwardedModal( }; }, [ dismissers ] ); - const isLevel0 = dismissers === level0Dismissers; // Adds/removes the value of bodyOpenClassName to body element. useEffect( () => { - if ( ! isBodyOpenClassActive ) { - isBodyOpenClassActive = true; - document.body.classList.add( bodyOpenClassName ); - } + const theClass = bodyOpenClassName; + const oneMore = 1 + ( bodyOpenClasses.get( theClass ) ?? 0 ); + bodyOpenClasses.set( theClass, oneMore ); + document.body.classList.add( bodyOpenClassName ); return () => { - if ( isLevel0 && dismissers.length === 0 ) { - document.body.classList.remove( bodyOpenClassName ); - isBodyOpenClassActive = false; + const oneLess = bodyOpenClasses.get( theClass )! - 1; + if ( oneLess === 0 ) { + document.body.classList.remove( theClass ); + bodyOpenClasses.delete( theClass ); + } else { + bodyOpenClasses.set( theClass, oneLess ); } }; - }, [ bodyOpenClassName, dismissers, isLevel0 ] ); + }, [ bodyOpenClassName ] ); // Calls the isContentScrollable callback when the Modal children container resizes. useLayoutEffect( () => { diff --git a/packages/components/src/modal/test/index.tsx b/packages/components/src/modal/test/index.tsx index 9073735e94dbe9..99f68345eec90c 100644 --- a/packages/components/src/modal/test/index.tsx +++ b/packages/components/src/modal/test/index.tsx @@ -7,7 +7,7 @@ import userEvent from '@testing-library/user-event'; /** * WordPress dependencies */ -import { useState } from '@wordpress/element'; +import { useEffect, useState } from '@wordpress/element'; /** * Internal dependencies @@ -388,4 +388,93 @@ describe( 'Modal', () => { expect( opener ).toHaveFocus(); } ); } ); + + describe( 'Body class name', () => { + const overrideClass = 'is-any-open'; + const BodyClassDemo = () => { + const [ isAShown, setIsAShown ] = useState( false ); + const [ isA1Shown, setIsA1Shown ] = useState( false ); + const [ isBShown, setIsBShown ] = useState( false ); + const [ isClassOverriden, setIsClassOverriden ] = useState( false ); + useEffect( () => { + const toggles: ( e: KeyboardEvent ) => void = ( { + key, + metaKey, + } ) => { + if ( key === 'a' ) { + if ( metaKey ) return setIsA1Shown( ( v ) => ! v ); + return setIsAShown( ( v ) => ! v ); + } + if ( key === 'b' ) return setIsBShown( ( v ) => ! v ); + if ( key === 'c' ) + return setIsClassOverriden( ( v ) => ! v ); + }; + document.addEventListener( 'keydown', toggles ); + return () => + void document.removeEventListener( 'keydown', toggles ); + }, [] ); + return ( + <> + { isAShown && ( + setIsAShown( false ) } + > +

Modal A contents

+ { isA1Shown && ( + + setIsA1Shown( false ) + } + > +

Modal A1 contents

+
+ ) } +
+ ) } + { isBShown && ( + setIsBShown( false ) } + > +

Modal B contents

+
+ ) } + + ); + }; + + it( 'is added and removed when modal opens and closes including when closed due to another modal opening', async () => { + const user = userEvent.setup(); + + const { baseElement } = render( ); + + await user.keyboard( 'a' ); // Opens modal A. + expect( baseElement ).toHaveClass( 'is-A-open' ); + + await user.keyboard( 'b' ); // Opens modal B > closes modal A. + expect( baseElement ).toHaveClass( 'is-B-open' ); + expect( baseElement ).not.toHaveClass( 'is-A-open' ); + + await user.keyboard( 'b' ); // Closes modal B. + expect( baseElement ).not.toHaveClass( 'is-B-open' ); + } ); + + it( 'is removed even when prop changes while nested modal is open', async () => { + const user = userEvent.setup(); + + const { baseElement } = render( ); + + await user.keyboard( 'a' ); // Opens modal A. + await user.keyboard( '{Meta>}a{/Meta}' ); // Opens nested modal. + await user.keyboard( 'c' ); // Changes `bodyOpenClassName`. + await user.keyboard( 'a' ); // Closes modal A. + expect( baseElement ).not.toHaveClass( 'is-A-open' ); + } ); + } ); } ); From 95e140e4ea7cf24f73d9aed9a8ef26cc85be7a79 Mon Sep 17 00:00:00 2001 From: Ella <4710635+ellatrix@users.noreply.github.com> Date: Wed, 20 Dec 2023 08:56:06 +0200 Subject: [PATCH 36/76] Rich text: avoid block editor subscription if not selected (#57226) --- .../src/components/rich-text/index.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js index a3b7b44e214a5b..ef21a8aa4ab239 100644 --- a/packages/block-editor/src/components/rich-text/index.js +++ b/packages/block-editor/src/components/rich-text/index.js @@ -113,8 +113,14 @@ export function RichTextWrapper( props = removeNativeProps( props ); const anchorRef = useRef(); - const { clientId } = useBlockEditContext(); + const { clientId, isSelected: isBlockSelected } = useBlockEditContext(); const selector = ( select ) => { + // Avoid subscribing to the block editor store if the block is not + // selected. + if ( ! isBlockSelected ) { + return { isSelected: false }; + } + const { getSelectionStart, getSelectionEnd } = select( blockEditorStore ); const selectionStart = getSelectionStart(); @@ -137,10 +143,12 @@ export function RichTextWrapper( isSelected, }; }; - // This selector must run on every render so the right selection state is - // retrieved from the store on merge. - // To do: fix this somehow. - const { selectionStart, selectionEnd, isSelected } = useSelect( selector ); + const { selectionStart, selectionEnd, isSelected } = useSelect( selector, [ + clientId, + identifier, + originalIsSelected, + isBlockSelected, + ] ); const { getSelectionStart, getSelectionEnd, getBlockRootClientId } = useSelect( blockEditorStore ); const { selectionChange } = useDispatch( blockEditorStore ); From b924779de8a91231f8109a4eaa0dd620d4182727 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 20 Dec 2023 08:20:34 +0100 Subject: [PATCH 37/76] Override all the labels of the pattern categories taxonomy (#57094) Co-authored-by: Nik Tsekouras --- lib/compat/wordpress-6.4/block-patterns.php | 36 ----------------- lib/compat/wordpress-6.5/block-patterns.php | 45 +++++++++++++++++++++ lib/load.php | 1 - 3 files changed, 45 insertions(+), 37 deletions(-) delete mode 100644 lib/compat/wordpress-6.4/block-patterns.php diff --git a/lib/compat/wordpress-6.4/block-patterns.php b/lib/compat/wordpress-6.4/block-patterns.php deleted file mode 100644 index 65c31fb7a22af4..00000000000000 --- a/lib/compat/wordpress-6.4/block-patterns.php +++ /dev/null @@ -1,36 +0,0 @@ -= 6.4. - * - * @see https://github.com/WordPress/gutenberg/pull/53163 - * - * @return void - */ -function gutenberg_register_taxonomy_patterns() { - $args = array( - 'public' => false, - 'publicly_queryable' => false, - 'hierarchical' => false, - 'labels' => array( - 'name' => _x( 'Pattern Categories', 'taxonomy general name' ), - 'singular_name' => _x( 'Pattern Category', 'taxonomy singular name' ), - ), - 'query_var' => false, - 'rewrite' => false, - 'show_ui' => true, - '_builtin' => true, - 'show_in_nav_menus' => false, - 'show_in_rest' => true, - 'show_admin_column' => true, - ); - register_taxonomy( 'wp_pattern_category', array( 'wp_block' ), $args ); -} -add_action( 'init', 'gutenberg_register_taxonomy_patterns' ); diff --git a/lib/compat/wordpress-6.5/block-patterns.php b/lib/compat/wordpress-6.5/block-patterns.php index 4521d5e4e578f3..87756ea45c7d00 100644 --- a/lib/compat/wordpress-6.5/block-patterns.php +++ b/lib/compat/wordpress-6.5/block-patterns.php @@ -31,3 +31,48 @@ function gutenberg_register_media_pattern_categories() { ); } add_action( 'init', 'gutenberg_register_media_pattern_categories' ); + +/** + * Adds a new taxonomy for organizing user created patterns. + * + * @see https://github.com/WordPress/gutenberg/pull/53163 + * + * @return void + */ +function gutenberg_register_taxonomy_patterns() { + $args = array( + 'public' => false, + 'publicly_queryable' => false, + 'hierarchical' => false, + 'labels' => array( + 'name' => _x( 'Pattern Categories', 'taxonomy general name' ), + 'singular_name' => _x( 'Pattern Category', 'taxonomy singular name' ), + 'add_new_item' => __( 'Add New Category' ), + 'add_or_remove_items' => __( 'Add or remove pattern categories' ), + 'back_to_items' => __( '← Go to pattern categories' ), + 'choose_from_most_used' => __( 'Choose from the most used pattern categories' ), + 'edit_item' => __( 'Edit Pattern Category' ), + 'item_link' => __( 'Pattern Category Link' ), + 'item_link_description' => __( 'A link to a pattern category.' ), + 'items_list' => __( 'Pattern Categories list' ), + 'items_list_navigation' => __( 'Pattern Categories list navigation' ), + 'new_item_name' => __( 'New Pattern Category Name' ), + 'no_terms' => __( 'No pattern categories' ), + 'not_found' => __( 'No pattern categories found.' ), + 'popular_items' => __( 'Popular Pattern Categories' ), + 'search_items' => __( 'Search Pattern Categories' ), + 'separate_items_with_commas' => __( 'Separate pattern categories with commas' ), + 'update_item' => __( 'Update Pattern Category' ), + 'view_item' => __( 'View Pattern Category' ), + ), + 'query_var' => false, + 'rewrite' => false, + 'show_ui' => true, + '_builtin' => true, + 'show_in_nav_menus' => false, + 'show_in_rest' => true, + 'show_admin_column' => true, + ); + register_taxonomy( 'wp_pattern_category', array( 'wp_block' ), $args ); +} +add_action( 'init', 'gutenberg_register_taxonomy_patterns' ); diff --git a/lib/load.php b/lib/load.php index 59fb75541ac41e..ed108f764ada19 100644 --- a/lib/load.php +++ b/lib/load.php @@ -97,7 +97,6 @@ function gutenberg_is_experiment_enabled( $name ) { // WordPress 6.4 compat. require __DIR__ . '/compat/wordpress-6.4/blocks.php'; require __DIR__ . '/compat/wordpress-6.4/block-hooks.php'; -require __DIR__ . '/compat/wordpress-6.4/block-patterns.php'; require __DIR__ . '/compat/wordpress-6.4/script-loader.php'; require __DIR__ . '/compat/wordpress-6.4/kses.php'; From 6bf61f9127c299afcdf5a65ab5e45203432861c7 Mon Sep 17 00:00:00 2001 From: Brian Coords Date: Wed, 20 Dec 2023 00:01:52 -0800 Subject: [PATCH 38/76] Fixes heading hierarchy in block filters (#57239) --- docs/reference-guides/filters/block-filters.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference-guides/filters/block-filters.md b/docs/reference-guides/filters/block-filters.md index e269ba9ef19917..4c7e3df7cec128 100644 --- a/docs/reference-guides/filters/block-filters.md +++ b/docs/reference-guides/filters/block-filters.md @@ -116,7 +116,7 @@ wp.hooks.addFilter( ); ``` -#### `blocks.getSaveContent.extraProps` +### `blocks.getSaveContent.extraProps` A filter that applies to all blocks returning a WP Element in the `save` function. This filter is used to add extra props to the root element of the `save` function. For example: to add a className, an id, or any valid prop for this element. @@ -229,7 +229,7 @@ const withMyPluginControls = createHigherOrderComponent( ( BlockEdit ) => { }, 'withMyPluginControls' ); ``` -#### `editor.BlockListBlock` +### `editor.BlockListBlock` Used to modify the block's wrapper component containing the block's `edit` component and all toolbars. It receives the original `BlockListBlock` component and returns a new wrapped component. From 54e8aee4cdc090b4754a7895e94fb94082b29051 Mon Sep 17 00:00:00 2001 From: Mitchell Austin Date: Wed, 20 Dec 2023 00:42:04 -0800 Subject: [PATCH 39/76] Remove cruft in Button block editor styles (#30950) * Remove cruft in Button block editor styles * Remove unused z-index rule --- packages/base-styles/_z-index.scss | 1 - packages/block-library/src/button/editor.scss | 43 ------------------- 2 files changed, 44 deletions(-) diff --git a/packages/base-styles/_z-index.scss b/packages/base-styles/_z-index.scss index 7d1fd0796f109b..36d01c843c1c73 100644 --- a/packages/base-styles/_z-index.scss +++ b/packages/base-styles/_z-index.scss @@ -32,7 +32,6 @@ $z-layers: ( ".interface-interface-skeleton__header": 30, ".interface-interface-skeleton__content": 20, ".edit-widgets-header": 30, - ".block-library-button__inline-link .block-editor-url-input__suggestions": 6, // URL suggestions for button block above sibling inserter ".wp-block-cover__inner-container": 1, // InnerBlocks area inside cover image block. ".wp-block-cover.is-placeholder .components-placeholder.is-large": 1, // Cover block resizer component inside a large placeholder. ".wp-block-cover.has-background-dim::before": 1, // Overlay area inside block cover need to be higher than the video background. diff --git a/packages/block-library/src/button/editor.scss b/packages/block-library/src/button/editor.scss index 3c36586bbfabdf..c24021d17e38ec 100644 --- a/packages/block-library/src/button/editor.scss +++ b/packages/block-library/src/button/editor.scss @@ -28,49 +28,6 @@ } } -.wp-block-button__inline-link { - color: $gray-700; - height: 0; - overflow: hidden; - max-width: 290px; - - &-input__suggestions { - max-width: 290px; - } - - @include break-medium() { - max-width: 260px; - - &-input__suggestions { - max-width: 260px; - } - - } - @include break-large() { - max-width: 290px; - - &-input__suggestions { - max-width: 290px; - } - - } - - .is-selected & { - height: auto; - overflow: visible; - } -} - -.wp-button-label__width { - .components-button-group { - display: block; - } - - .components-base-control__field { - margin-bottom: 12px; - } -} - // Display "table" is used because the button container should only wrap the content and not takes the full width. div[data-type="core/button"] { display: table; From a312c1b49c5c286c527f1efe68b8451054736e8f Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Wed, 20 Dec 2023 17:45:30 +0900 Subject: [PATCH 40/76] Pattern Category: change show_tagcloud to false (#57212) --- lib/compat/wordpress-6.5/block-patterns.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/compat/wordpress-6.5/block-patterns.php b/lib/compat/wordpress-6.5/block-patterns.php index 87756ea45c7d00..f43acda2a1035c 100644 --- a/lib/compat/wordpress-6.5/block-patterns.php +++ b/lib/compat/wordpress-6.5/block-patterns.php @@ -72,6 +72,7 @@ function gutenberg_register_taxonomy_patterns() { 'show_in_nav_menus' => false, 'show_in_rest' => true, 'show_admin_column' => true, + 'show_tagcloud' => false, ); register_taxonomy( 'wp_pattern_category', array( 'wp_block' ), $args ); } From cf2950eef1b74c41af59283b3e7390711256a67c Mon Sep 17 00:00:00 2001 From: Marco Ciampini Date: Wed, 20 Dec 2023 11:39:56 +0100 Subject: [PATCH 41/76] DropdownMenuV2: do not collapse suffix width (#57238) * DropdownMenuV2: do not collapse suffix width * CHANGELOG --- packages/components/CHANGELOG.md | 1 + packages/components/src/dropdown-menu-v2-ariakit/styles.ts | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index ecf4d3628c0839..19feebd911b456 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -13,6 +13,7 @@ ### Enhancements +- `DropdownMenuV2`: do not collapse suffix width ([#57238](https://github.com/WordPress/gutenberg/pull/57238)). - `DateTimePicker`: Adjustment of the dot position on DayButton and expansion of the button area. ([#55502](https://github.com/WordPress/gutenberg/pull/55502)). - `Modal`: Improve application of body class names ([#55430](https://github.com/WordPress/gutenberg/pull/55430)). diff --git a/packages/components/src/dropdown-menu-v2-ariakit/styles.ts b/packages/components/src/dropdown-menu-v2-ariakit/styles.ts index eaa249ae86b78c..ec6b2cb74d2172 100644 --- a/packages/components/src/dropdown-menu-v2-ariakit/styles.ts +++ b/packages/components/src/dropdown-menu-v2-ariakit/styles.ts @@ -269,8 +269,9 @@ export const DropdownMenuItemChildrenWrapper = styled.div` `; export const ItemSuffixWrapper = styled.span` - flex: 0; - width: max-content; + flex: 0 1 fit-content; + min-width: 0; + width: fit-content; display: flex; align-items: center; From d4886839847dbe1e7b25639a5dbbb6c8f1bc78ea Mon Sep 17 00:00:00 2001 From: Akira Tachibana Date: Wed, 20 Dec 2023 20:01:27 +0900 Subject: [PATCH 42/76] Fix raw html tag is not shown. (#56906) --- docs/getting-started/fundamentals/block-wrapper.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/getting-started/fundamentals/block-wrapper.md b/docs/getting-started/fundamentals/block-wrapper.md index 6ecebbe8303864..1f2404eca9b031 100644 --- a/docs/getting-started/fundamentals/block-wrapper.md +++ b/docs/getting-started/fundamentals/block-wrapper.md @@ -5,7 +5,7 @@ Each block's markup is wrapped by a container HTML tag that needs to have the pr Ensuring proper attributes to the block wrapper is especially important when using custom styling or features like `supports`.
-The use of supports generates a set of properties that need to be manually added to the wrapping element of the block so they're properly stored as part of the block data +The use of supports generates a set of properties that need to be manually added to the wrapping element of the block so they're properly stored as part of the block data.
A block can have three sets of markup defined, each one of them with a specific target and purpose: @@ -16,7 +16,7 @@ A block can have three sets of markup defined, each one of them with a specific - The one used to **dynamically render the markup of the block** returned to the front end on request, defined through the `render_callback` on [`register_block_type`](https://developer.wordpress.org/reference/functions/register_block_type/) or the [`render`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#render) PHP file in `block.json` - If defined, this server-side generated markup will be returned to the front end, ignoring the markup stored in DB. -For the [`edit` React component and the `save` function](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/), the block wrapper element should be a native DOM element (like `
`) or a React component that forwards any additional props to native DOM elements. Using a or component, for instance, would be invalid. +For the [`edit` React component and the `save` function](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/), the block wrapper element should be a native DOM element (like `
`) or a React component that forwards any additional props to native DOM elements. Using a `` or `` component, for instance, would be invalid. ## The Edit component's markup @@ -60,7 +60,7 @@ _(see the [code above](https://github.com/WordPress/block-development-examples/b >Hello World - Block Editor

``` -Any additional classes and attributes for the `Edit` component of the block should be passed as an argument of `useBlockProps` (see [example](https://github.com/WordPress/block-development-examples/blob/trunk/plugins/stylesheets-79a4c3/src/edit.js)). When you add `support` for any feature, they get added to the object returned by the `useBlockProps` hook. +Any additional classes and attributes for the `Edit` component of the block should be passed as an argument of `useBlockProps` (see [example](https://github.com/WordPress/block-development-examples/blob/trunk/plugins/stylesheets-79a4c3/src/edit.js)). When you add `supports` for any feature, they get added to the object returned by the `useBlockProps` hook. ## The Save component's markup @@ -89,7 +89,7 @@ _(see the [code above](https://github.com/WordPress/block-development-examples/b Any additional classes and attributes for the `save` function of the block should be passed as an argument of `useBlockProps.save()` (see [example](https://github.com/WordPress/block-development-examples/blob/trunk/plugins/stylesheets-79a4c3/src/save.js)). -When you add `support` for any feature, the proper classes get added to the object returned by the `useBlockProps.save()` hook. +When you add `supports` for any feature, the proper classes get added to the object returned by the `useBlockProps.save()` hook. ```html

+

{ + const { keyCode } = event; + if ( keyCode === ENTER || keyCode === SPACE ) { + history.push( { + postId: pageId, + postType, + canvas: 'edit', + } ); + } + } } + onClick={ () => + history.push( { + postId: pageId, + postType, + canvas: 'edit', + } ) + } + > { pageId !== null ? ( setTemplateId( items?.length === 1 ? items[ 0 ].id : null ); @@ -390,7 +394,28 @@ export default function DataviewsTemplates() { { view.type === LAYOUT_LIST && ( -
+
{ + const { keyCode } = event; + if ( keyCode === ENTER || keyCode === SPACE ) { + history.push( { + postId: templateId, + postType: TEMPLATE_POST_TYPE, + canvas: 'edit', + } ); + } + } } + onClick={ () => + history.push( { + postId: templateId, + postType: TEMPLATE_POST_TYPE, + canvas: 'edit', + } ) + } + > { templateId !== null ? ( ; + return ; } From 45c9d1ab830ab083b7f07685084504c677b62bf2 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 20 Dec 2023 12:21:56 +0100 Subject: [PATCH 44/76] Editor: Unify the list view shortcut registration and definition (#57200) --- .../components/header/header-toolbar/index.js | 2 +- .../test/__snapshots__/index.js.snap | 929 ------------------ .../test/index.js | 15 - .../components/keyboard-shortcuts/index.js | 20 - .../secondary-sidebar/list-view-sidebar.js | 5 +- .../edit-site/src/components/editor/index.js | 10 +- .../header-edit-mode/document-tools/index.js | 2 +- .../keyboard-shortcuts/edit-mode.js | 26 - .../components/keyboard-shortcuts/register.js | 43 - .../secondary-sidebar/list-view-sidebar.js | 5 +- .../global-keyboard-shortcuts/index.js | 14 +- .../register-shortcuts.js | 10 + 12 files changed, 35 insertions(+), 1046 deletions(-) delete mode 100644 packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap diff --git a/packages/edit-post/src/components/header/header-toolbar/index.js b/packages/edit-post/src/components/header/header-toolbar/index.js index e1d059578809e0..e8786900e4f257 100644 --- a/packages/edit-post/src/components/header/header-toolbar/index.js +++ b/packages/edit-post/src/components/header/header-toolbar/index.js @@ -65,7 +65,7 @@ function HeaderToolbar( { hasFixedToolbar } ) { showIconLabels: isFeatureActive( 'showIconLabels' ), isListViewOpen: isListViewOpened(), listViewShortcut: getShortcutRepresentation( - 'core/edit-post/toggle-list-view' + 'core/editor/toggle-list-view' ), listViewToggleRef: getListViewToggleRef(), }; diff --git a/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap b/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap deleted file mode 100644 index 79990664a2427b..00000000000000 --- a/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap +++ /dev/null @@ -1,929 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`KeyboardShortcutHelpModal should match snapshot when the modal is active 1`] = ` - -`; diff --git a/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/index.js b/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/index.js index 0380e648a17331..9ba2ebdf82597f 100644 --- a/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/index.js +++ b/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/index.js @@ -16,21 +16,6 @@ import { KeyboardShortcutHelpModal } from '../index'; const noop = () => {}; describe( 'KeyboardShortcutHelpModal', () => { - it( 'should match snapshot when the modal is active', () => { - render( - <> - - - - ); - - expect( - screen.getByRole( 'dialog', { - name: 'Keyboard shortcuts', - } ) - ).toMatchSnapshot(); - } ); - it( 'should not render the modal when inactive', () => { render( <> diff --git a/packages/edit-post/src/components/keyboard-shortcuts/index.js b/packages/edit-post/src/components/keyboard-shortcuts/index.js index c808d65ae5b165..0bdcd5613599a3 100644 --- a/packages/edit-post/src/components/keyboard-shortcuts/index.js +++ b/packages/edit-post/src/components/keyboard-shortcuts/index.js @@ -24,7 +24,6 @@ function KeyboardShortcuts() { select( editorStore ).getEditorSettings(); return ! richEditingEnabled || ! codeEditingEnabled; }, [] ); - const { isListViewOpened } = useSelect( editorStore ); const { switchEditorMode, openGeneralSidebar, @@ -33,7 +32,6 @@ function KeyboardShortcuts() { toggleDistractionFree, } = useDispatch( editPostStore ); const { registerShortcut } = useDispatch( keyboardShortcutsStore ); - const { setIsListViewOpened } = useDispatch( editorStore ); const { replaceBlocks } = useDispatch( blockEditorStore ); const { getBlockName, @@ -101,16 +99,6 @@ function KeyboardShortcuts() { }, } ); - registerShortcut( { - name: 'core/edit-post/toggle-list-view', - category: 'global', - description: __( 'Open the block list view.' ), - keyCombination: { - modifier: 'access', - character: 'o', - }, - } ); - registerShortcut( { name: 'core/edit-post/toggle-sidebar', category: 'global', @@ -225,14 +213,6 @@ function KeyboardShortcuts() { } } ); - // Only opens the list view. Other functionality for this shortcut happens in the rendered sidebar. - useShortcut( 'core/edit-post/toggle-list-view', ( event ) => { - if ( ! isListViewOpened() ) { - event.preventDefault(); - setIsListViewOpened( true ); - } - } ); - useShortcut( 'core/edit-post/transform-heading-to-paragraph', ( event ) => handleTextLevelShortcut( event, 0 ) ); diff --git a/packages/edit-post/src/components/secondary-sidebar/list-view-sidebar.js b/packages/edit-post/src/components/secondary-sidebar/list-view-sidebar.js index 02690d9115d7ab..c1b4512454b150 100644 --- a/packages/edit-post/src/components/secondary-sidebar/list-view-sidebar.js +++ b/packages/edit-post/src/components/secondary-sidebar/list-view-sidebar.js @@ -106,10 +106,7 @@ export default function ListViewSidebar() { // This only fires when the sidebar is open because of the conditional rendering. // It is the same shortcut to open but that is defined as a global shortcut and only fires when the sidebar is closed. - useShortcut( - 'core/edit-post/toggle-list-view', - handleToggleListViewShortcut - ); + useShortcut( 'core/editor/toggle-list-view', handleToggleListViewShortcut ); /** * Render tab content for a given tab name. diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 9a1931b2ede398..6718fc705b50b9 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -23,6 +23,8 @@ import { store as interfaceStore, } from '@wordpress/interface'; import { + EditorKeyboardShortcutsRegister, + EditorKeyboardShortcuts, EditorNotices, EditorSnackbars, privateApis as editorPrivateApis, @@ -245,7 +247,13 @@ export default function Editor( { isLoading } ) { { editorMode === 'text' && isEditMode && ( ) } - { isEditMode && } + { isEditMode && ( + <> + + + + + ) } } secondarySidebar={ diff --git a/packages/edit-site/src/components/header-edit-mode/document-tools/index.js b/packages/edit-site/src/components/header-edit-mode/document-tools/index.js index 837c825b2060a9..ec37cadfbc0de0 100644 --- a/packages/edit-site/src/components/header-edit-mode/document-tools/index.js +++ b/packages/edit-site/src/components/header-edit-mode/document-tools/index.js @@ -53,7 +53,7 @@ export default function DocumentTools( { isInserterOpen: isInserterOpened(), isListViewOpen: isListViewOpened(), listViewShortcut: getShortcutRepresentation( - 'core/edit-site/toggle-list-view' + 'core/editor/toggle-list-view' ), isVisualMode: getEditorMode() === 'visual', listViewToggleRef: getListViewToggleRef(), 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 8bc6497967902e..07e017349a0c61 100644 --- a/packages/edit-site/src/components/keyboard-shortcuts/edit-mode.js +++ b/packages/edit-site/src/components/keyboard-shortcuts/edit-mode.js @@ -3,10 +3,8 @@ */ import { useShortcut } from '@wordpress/keyboard-shortcuts'; import { useDispatch, useSelect } from '@wordpress/data'; -import { store as coreStore } from '@wordpress/core-data'; import { store as blockEditorStore } from '@wordpress/block-editor'; import { store as interfaceStore } from '@wordpress/interface'; -import { store as editorStore } from '@wordpress/editor'; import { createBlock } from '@wordpress/blocks'; /** @@ -18,10 +16,6 @@ import { STORE_NAME } from '../../store/constants'; function KeyboardShortcutsEditMode() { const { getEditorMode } = useSelect( editSiteStore ); - const isListViewOpen = useSelect( - ( select ) => select( editorStore ).isListViewOpened(), - [] - ); const isBlockInspectorOpen = useSelect( ( select ) => select( interfaceStore ).getActiveComplementaryArea( @@ -29,12 +23,10 @@ function KeyboardShortcutsEditMode() { ) === SIDEBAR_BLOCK, [] ); - const { redo, undo } = useDispatch( coreStore ); const { switchEditorMode, toggleDistractionFree } = useDispatch( editSiteStore ); const { enableComplementaryArea, disableComplementaryArea } = useDispatch( interfaceStore ); - const { setIsListViewOpened } = useDispatch( editorStore ); const { replaceBlocks } = useDispatch( blockEditorStore ); const { getBlockName, getSelectedBlockClientId, getBlockAttributes } = useSelect( blockEditorStore ); @@ -67,24 +59,6 @@ function KeyboardShortcutsEditMode() { ); }; - useShortcut( 'core/edit-site/undo', ( event ) => { - undo(); - event.preventDefault(); - } ); - - useShortcut( 'core/edit-site/redo', ( event ) => { - redo(); - event.preventDefault(); - } ); - - // Only opens the list view. Other functionality for this shortcut happens in the rendered sidebar. - useShortcut( 'core/edit-site/toggle-list-view', () => { - if ( isListViewOpen ) { - return; - } - setIsListViewOpened( true ); - } ); - useShortcut( 'core/edit-site/toggle-block-settings-sidebar', ( event ) => { // This shortcut has no known clashes, but use preventDefault to prevent any // obscure shortcuts from triggering. diff --git a/packages/edit-site/src/components/keyboard-shortcuts/register.js b/packages/edit-site/src/components/keyboard-shortcuts/register.js index 8dfd1e3e2a45bf..ef32cd920b6711 100644 --- a/packages/edit-site/src/components/keyboard-shortcuts/register.js +++ b/packages/edit-site/src/components/keyboard-shortcuts/register.js @@ -3,7 +3,6 @@ */ import { useEffect } from '@wordpress/element'; import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; -import { isAppleOS } from '@wordpress/keycodes'; import { useDispatch } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; @@ -21,48 +20,6 @@ function KeyboardShortcutsRegister() { }, } ); - registerShortcut( { - name: 'core/edit-site/undo', - category: 'global', - description: __( 'Undo your last changes.' ), - keyCombination: { - modifier: 'primary', - character: 'z', - }, - } ); - - registerShortcut( { - name: 'core/edit-site/redo', - category: 'global', - description: __( 'Redo your last undo.' ), - keyCombination: { - modifier: 'primaryShift', - character: 'z', - }, - // Disable on Apple OS because it conflicts with the browser's - // history shortcut. It's a fine alias for both Windows and Linux. - // Since there's no conflict for Ctrl+Shift+Z on both Windows and - // Linux, we keep it as the default for consistency. - aliases: isAppleOS() - ? [] - : [ - { - modifier: 'primary', - character: 'y', - }, - ], - } ); - - registerShortcut( { - name: 'core/edit-site/toggle-list-view', - category: 'global', - description: __( 'Open the block list view.' ), - keyCombination: { - modifier: 'access', - character: 'o', - }, - } ); - registerShortcut( { name: 'core/edit-site/toggle-block-settings-sidebar', category: 'global', diff --git a/packages/edit-site/src/components/secondary-sidebar/list-view-sidebar.js b/packages/edit-site/src/components/secondary-sidebar/list-view-sidebar.js index 3b837ba6a91713..d18abd0083f07b 100644 --- a/packages/edit-site/src/components/secondary-sidebar/list-view-sidebar.js +++ b/packages/edit-site/src/components/secondary-sidebar/list-view-sidebar.js @@ -88,10 +88,7 @@ export default function ListViewSidebar() { // This only fires when the sidebar is open because of the conditional rendering. // It is the same shortcut to open but that is defined as a global shortcut and only fires when the sidebar is closed. - useShortcut( - 'core/edit-site/toggle-list-view', - handleToggleListViewShortcut - ); + useShortcut( 'core/editor/toggle-list-view', handleToggleListViewShortcut ); return ( // eslint-disable-next-line jsx-a11y/no-static-element-interactions diff --git a/packages/editor/src/components/global-keyboard-shortcuts/index.js b/packages/editor/src/components/global-keyboard-shortcuts/index.js index 4b45fe449123f4..a62f542ff9974d 100644 --- a/packages/editor/src/components/global-keyboard-shortcuts/index.js +++ b/packages/editor/src/components/global-keyboard-shortcuts/index.js @@ -10,8 +10,10 @@ import { useDispatch, useSelect } from '@wordpress/data'; import { store as editorStore } from '../../store'; export default function EditorKeyboardShortcuts() { - const { redo, undo, savePost } = useDispatch( editorStore ); - const { isEditedPostDirty, isPostSavingLocked } = useSelect( editorStore ); + const { redo, undo, savePost, setIsListViewOpened } = + useDispatch( editorStore ); + const { isEditedPostDirty, isPostSavingLocked, isListViewOpened } = + useSelect( editorStore ); useShortcut( 'core/editor/undo', ( event ) => { undo(); @@ -45,5 +47,13 @@ export default function EditorKeyboardShortcuts() { savePost(); } ); + // Only opens the list view. Other functionality for this shortcut happens in the rendered sidebar. + useShortcut( 'core/editor/toggle-list-view', ( event ) => { + if ( ! isListViewOpened() ) { + event.preventDefault(); + setIsListViewOpened( true ); + } + } ); + return null; } diff --git a/packages/editor/src/components/global-keyboard-shortcuts/register-shortcuts.js b/packages/editor/src/components/global-keyboard-shortcuts/register-shortcuts.js index 8e8f4c42ca6dd6..b1ed83bd33e4e0 100644 --- a/packages/editor/src/components/global-keyboard-shortcuts/register-shortcuts.js +++ b/packages/editor/src/components/global-keyboard-shortcuts/register-shortcuts.js @@ -53,6 +53,16 @@ function EditorKeyboardShortcutsRegister() { }, ], } ); + + registerShortcut( { + name: 'core/editor/toggle-list-view', + category: 'global', + description: __( 'Open the block list view.' ), + keyCombination: { + modifier: 'access', + character: 'o', + }, + } ); }, [ registerShortcut ] ); return ; From 1f6136d92914eef8e160231867714404b9557c2a Mon Sep 17 00:00:00 2001 From: Joen A <1204802+jasmussen@users.noreply.github.com> Date: Wed, 20 Dec 2023 12:35:08 +0100 Subject: [PATCH 45/76] More settings tip: add explicit font size. (#55835) --- .../src/components/inspector-controls-tabs/style.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/inspector-controls-tabs/style.scss b/packages/block-editor/src/components/inspector-controls-tabs/style.scss index 6db9395af62ef6..f25e89903a6efd 100644 --- a/packages/block-editor/src/components/inspector-controls-tabs/style.scss +++ b/packages/block-editor/src/components/inspector-controls-tabs/style.scss @@ -15,13 +15,14 @@ } .block-editor-inspector-controls-tabs__hint { - align-items: top; + align-items: flex-start; background: $gray-100; border-radius: $radius-block-ui; color: $gray-900; display: flex; flex-direction: row; margin: $grid-unit-20; + font-size: $default-font-size; } .block-editor-inspector-controls-tabs__hint-content { From 07e99ceafda38272ac66b74a5890276b620322a5 Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Wed, 20 Dec 2023 13:13:16 +0000 Subject: [PATCH 46/76] Bump plugin version to 17.3.0 --- 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 20c51fdb6ead2a..69d5a6732a7e37 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.3 * Requires PHP: 7.0 - * Version: 17.3.0-rc.1 + * Version: 17.3.0 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/package-lock.json b/package-lock.json index 7425d75403ad10..478570140e51aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gutenberg", - "version": "17.3.0-rc.1", + "version": "17.3.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "gutenberg", - "version": "17.3.0-rc.1", + "version": "17.3.0", "hasInstallScript": true, "license": "GPL-2.0-or-later", "dependencies": { diff --git a/package.json b/package.json index cab3288450cd75..e1dd7fba270773 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "17.3.0-rc.1", + "version": "17.3.0", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", From 7ecbbe82f6d192cd30257966af74e59582193dd2 Mon Sep 17 00:00:00 2001 From: Koen <77921155+koen12344@users.noreply.github.com> Date: Wed, 20 Dec 2023 14:20:49 +0100 Subject: [PATCH 47/76] Button: Restore descriptions for isPrimary, isSecondary, isTertiary, isLink but mark them as deprecated (#37690) --- packages/components/src/button/README.md | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/packages/components/src/button/README.md b/packages/components/src/button/README.md index cf2748d3846f73..3f577991dc44be 100644 --- a/packages/components/src/button/README.md +++ b/packages/components/src/button/README.md @@ -176,6 +176,14 @@ Renders a red text-based button style to indicate destructive behavior. - Required: No +#### `isLink`: `boolean` + +Deprecated: Renders a button with an anchor style. +Use `variant` prop with `link` value instead. + +- Required: No +- Default: `false` + #### `isPressed`: `boolean` Renders a pressed button style. @@ -184,6 +192,22 @@ If the native `aria-pressed` attribute is also set, it will take precedence. - Required: No +#### `isPrimary`: `boolean` + +Deprecated: Renders a primary button style. +Use `variant` prop with `primary` value instead. + +- Required: No +- Default: `false` + +#### `isSecondary`: `boolean` + +Deprecated: Renders a default button style. +Use `variant` prop with `secondary` value instead. + +- Required: No +- Default: `false` + #### `isSmall`: `boolean` Decreases the size of the button. @@ -192,6 +216,14 @@ Deprecated in favor of the `size` prop. If both props are defined, the `size` pr - Required: No +#### `isTertiary`: `boolean` + +Deprecated: Renders a text-based button style. +Use `variant` prop with `tertiary` value instead. + +- Required: No +- Default: `false` + #### `label`: `string` Sets the `aria-label` of the component, if none is provided. Sets the Tooltip content if `showTooltip` is provided. From 353b73264e9764b3291c753cc5eeb71f21a7e4dd Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Wed, 20 Dec 2023 13:27:07 +0000 Subject: [PATCH 48/76] Update Changelog for 17.3.0 --- changelog.txt | 337 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 337 insertions(+) diff --git a/changelog.txt b/changelog.txt index c8aa6254923aab..0b70b68c9377ee 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,342 @@ == Changelog == += 17.3.0 = + + + +## Changelog + +### Bug Fixes + +- (edit-site)(use-init-edited-entity-from-url) Safely access `toString()` on `siteData`'s `page_on_front`. ([57035](https://github.com/WordPress/gutenberg/pull/57035)) + +#### Components +- Fix form token field suggestion list reopening after blurring the input. ([57002](https://github.com/WordPress/gutenberg/pull/57002)) + + + + +## Contributors + +The following contributors merged PRs in this release: + +@fullofcaffeine @talldan + += 17.3.0-rc.1 = + + +## Changelog + +### Enhancements + +- Components: Replace `TabPanel` with `Tabs` in the editor's `ColorPanel`. ([56878](https://github.com/WordPress/gutenberg/pull/56878)) +- Editor: Move the edit template blocks notification to editor package. ([56901](https://github.com/WordPress/gutenberg/pull/56901)) +- Editor: Unify the preview dropdown between post and site editors. ([56921](https://github.com/WordPress/gutenberg/pull/56921)) +- Editor: Use the same PostTemplatePanel between post and site editors. ([56817](https://github.com/WordPress/gutenberg/pull/56817)) +- Tabs: Replace `id` with new `tabId` prop. ([56883](https://github.com/WordPress/gutenberg/pull/56883)) +- Update main toolbar buttons to all be compact. ([56635](https://github.com/WordPress/gutenberg/pull/56635), [56729](https://github.com/WordPress/gutenberg/pull/56729)) +- Update preferences organization. ([56481](https://github.com/WordPress/gutenberg/pull/56481)) + +#### Components +- FocalPointPicker with __next40pxDefaultSize. ([56021](https://github.com/WordPress/gutenberg/pull/56021)) +- Font Library: Improve usability of font variant selection. ([56158](https://github.com/WordPress/gutenberg/pull/56158)) +- Tabs: Sync browser focus to selected tab in controlled mode. ([56658](https://github.com/WordPress/gutenberg/pull/56658)) +- Use consistent styling for duotone panels. ([56801](https://github.com/WordPress/gutenberg/pull/56801)) +- `BorderControl`: Fix button styles. ([56730](https://github.com/WordPress/gutenberg/pull/56730)) +- `DimensionControl`: Add __next40pxDefaultSize prop. ([56805](https://github.com/WordPress/gutenberg/pull/56805)) +- `FontSizePicker`: Add opt-in prop for 40px default size. ([56804](https://github.com/WordPress/gutenberg/pull/56804)) +- `QueryControls`: Add opt-in prop for 40px default size. ([56576](https://github.com/WordPress/gutenberg/pull/56576)) + +#### Block Library +- Control dimensions (margin and padding) of the list-item block. ([55874](https://github.com/WordPress/gutenberg/pull/55874)) +- Consistent default typography controls across blocks. ([55208](https://github.com/WordPress/gutenberg/pull/55208)) +- Social Icons: Add Gravatar service. ([56544](https://github.com/WordPress/gutenberg/pull/56544)) +- Tweak table block placeholder with __next40pxDefaultSize props. ([56935](https://github.com/WordPress/gutenberg/pull/56935)) + +#### Site Editor +- Merge the post only mode and the post editor. ([56671](https://github.com/WordPress/gutenberg/pull/56671)) +- Site Editor Sidebar: Add "Areas" details panel to all templates and update icon. ([55677](https://github.com/WordPress/gutenberg/pull/55677)) + +#### Block Editor +- Allow dragging between adjacent container blocks based on a threshold. ([56466](https://github.com/WordPress/gutenberg/pull/56466)) +- Components: Replace `TabPanel` with `Tabs` in the editor's `ColorGradientControl`. ([56351](https://github.com/WordPress/gutenberg/pull/56351)) + +#### Data Views +- Update data view layout. ([56786](https://github.com/WordPress/gutenberg/pull/56786)) + +#### Layout +- Match the front end layout classname in the editor. ([56774](https://github.com/WordPress/gutenberg/pull/56774)) + +#### Global Styles +- Global style revisions: Show change summary on selected item. ([56577](https://github.com/WordPress/gutenberg/pull/56577)) + +#### Icons +- Another round of HiDPI icon tweaks. ([56532](https://github.com/WordPress/gutenberg/pull/56532)) + +#### Media +- Update external images panel in post publish sidebar. ([55524](https://github.com/WordPress/gutenberg/pull/55524)) + +#### Post Editor +- Implement `Tabs` in editor settings. ([55360](https://github.com/WordPress/gutenberg/pull/55360)) + + +### Bug Fixes + +- Create-block-interactive-template: Add all files to the generated plugin zip. ([56943](https://github.com/WordPress/gutenberg/pull/56943)) +- Create-block-interactive-template: Prevent crash when Gutenberg plugin is not installed. ([56941](https://github.com/WordPress/gutenberg/pull/56941)) +- Fix end-to-end test: Update how we find the template title to match markup changes. ([56992](https://github.com/WordPress/gutenberg/pull/56992)) +- Fix: Fatal php error if a template was created by an author that was deleted. ([56990](https://github.com/WordPress/gutenberg/pull/56990)) +- Fix: PHP 8.1 deprecated warning strpos(). ([56171](https://github.com/WordPress/gutenberg/pull/56171)) +- Fix: Use span on template list titles. ([56955](https://github.com/WordPress/gutenberg/pull/56955)) +- Font Library: Add font family and font face preview keys to schema. ([56793](https://github.com/WordPress/gutenberg/pull/56793)) +- Remove unnecessary CSS for shrinking central header area. ([56220](https://github.com/WordPress/gutenberg/pull/56220)) +- Revert format types hook refactor. ([56859](https://github.com/WordPress/gutenberg/pull/56859)) +- Show template center UI when no block is selected. ([56217](https://github.com/WordPress/gutenberg/pull/56217)) +- setImmutably: Don't clone all objects. ([56612](https://github.com/WordPress/gutenberg/pull/56612)) + +#### Block Library +- Fix error when using a navigation block that returns an empty fallback result. ([56629](https://github.com/WordPress/gutenberg/pull/56629)) +- Fixture Tests: Correctly generate fixture files for form-related blocks. ([56719](https://github.com/WordPress/gutenberg/pull/56719)) +- Image: Fix resetting behaviour for alt image text. ([56809](https://github.com/WordPress/gutenberg/pull/56809)) +- Social Links Block: Prevent Theme Styles Distorting Size. ([56301](https://github.com/WordPress/gutenberg/pull/56301)) +- Update image block save to only save align none class. ([56449](https://github.com/WordPress/gutenberg/pull/56449)) + +#### Components +- DropdownMenuV2Ariakit: Prevent prefix collapsing if all radios or checkboxes are unselected. ([56720](https://github.com/WordPress/gutenberg/pull/56720)) +- FormToggle: Do not use "/" math operator. ([56672](https://github.com/WordPress/gutenberg/pull/56672)) +- PaletteEdit: Temporary custom gradient not saving. ([56896](https://github.com/WordPress/gutenberg/pull/56896)) +- `ToggleGroupControl`: React correctly to external controlled updates. ([56678](https://github.com/WordPress/gutenberg/pull/56678)) + +#### Block Editor +- Apply __next40pxDefaultSize to TextControl and Button component in renaming UIs. ([56933](https://github.com/WordPress/gutenberg/pull/56933)) +- Pattern inserter: Fix Broken preview layout. ([56814](https://github.com/WordPress/gutenberg/pull/56814)) +- Patterns: Keep synced pattern when added via drag and drop. ([56924](https://github.com/WordPress/gutenberg/pull/56924)) + +#### Design Tools +- Background image support: Fix duplicate output of styling rules. ([56997](https://github.com/WordPress/gutenberg/pull/56997)) +- Fix sticky position in classic themes with appearance tools support. ([56743](https://github.com/WordPress/gutenberg/pull/56743)) + +#### Post Editor +- Editor Canvas: Fix animation when device type changes. ([56970](https://github.com/WordPress/gutenberg/pull/56970)) +- Editor: Fix display of edit template blocks notification. ([56978](https://github.com/WordPress/gutenberg/pull/56978)) + +#### Site Editor +- Fix active edited post. ([56863](https://github.com/WordPress/gutenberg/pull/56863)) +- Show back button when editing navigation and template area in-place with no URL params. ([56741](https://github.com/WordPress/gutenberg/pull/56741)) + +#### Typography +- Fix order of typography sizes and families. ([56659](https://github.com/WordPress/gutenberg/pull/56659)) +- Font Library: Fix font uninstallation. ([56762](https://github.com/WordPress/gutenberg/pull/56762)) + +#### Navigation in Site View +- Navigation editor: Fix content mode. ([56856](https://github.com/WordPress/gutenberg/pull/56856)) + +#### Patterns +- Fix top position and height of Pattern Modal Sidebar. ([56787](https://github.com/WordPress/gutenberg/pull/56787)) + +#### Interactivity API +- Start using modules in the interactive create-block template. ([56694](https://github.com/WordPress/gutenberg/pull/56694)) + +#### Layout +- Fix input not showing when switching to "Fixed" width. ([56660](https://github.com/WordPress/gutenberg/pull/56660)) + +#### Data Views +- Align data view icon usage. ([56602](https://github.com/WordPress/gutenberg/pull/56602)) + +#### Block Styles +- Consolidate and resolve display issues between InserterPreviewPanel and BlockStylesPreviewPanel. ([56011](https://github.com/WordPress/gutenberg/pull/56011)) + +#### Inspector Controls +- Decode some characters if used in taxonomy name so it's displayed correctly in Query Loop filters. ([50376](https://github.com/WordPress/gutenberg/pull/50376)) + + +### Accessibility + +#### Data Views +- Add scroll padding to dataviews container. ([56946](https://github.com/WordPress/gutenberg/pull/56946)) +- Adding `aria-sort` to table view headers. ([56860](https://github.com/WordPress/gutenberg/pull/56860)) +- Fix: Use span instead of heading for the template titles. ([56785](https://github.com/WordPress/gutenberg/pull/56785)) + +#### Post Editor +- Avoid to show unnecessary Tooltip for the Post Schedule button. ([56759](https://github.com/WordPress/gutenberg/pull/56759)) + +#### Block Editor +- Increase right padding of URL field to take the Submit button into account. ([56685](https://github.com/WordPress/gutenberg/pull/56685)) + +#### Site Editor +- Shorter screen reader announcement after changing pages. ([56339](https://github.com/WordPress/gutenberg/pull/56339)) + +#### Components +- Use tooltip for the Timezone only when necessary. ([56214](https://github.com/WordPress/gutenberg/pull/56214)) + + +### Performance + +- Block editor: Make all BlockEdit hooks pure. ([56813](https://github.com/WordPress/gutenberg/pull/56813)) +- Block editor: Remove 4 useSelect in favour of context. ([56915](https://github.com/WordPress/gutenberg/pull/56915)) +- Block editor: hooks: Avoid BlockEdit filter for content locking UI. ([56957](https://github.com/WordPress/gutenberg/pull/56957)) +- Block editor: hooks: Share block settings. ([56852](https://github.com/WordPress/gutenberg/pull/56852)) +- Keycodes: Avoid regex for capital case. ([56822](https://github.com/WordPress/gutenberg/pull/56822)) +- Measure typing without inspector. ([56753](https://github.com/WordPress/gutenberg/pull/56753)) +- Media upload component: Lazy mount. ([56958](https://github.com/WordPress/gutenberg/pull/56958)) +- Paragraph: Store subscription for selected block only. ([56967](https://github.com/WordPress/gutenberg/pull/56967)) +- Perf: Reopen inspector for remaining tests. ([56780](https://github.com/WordPress/gutenberg/pull/56780)) +- useBlockProps: Combine store subscriptions. ([56847](https://github.com/WordPress/gutenberg/pull/56847)) + +#### Block Editor +- Improve opening inserter in post editor. ([57006](https://github.com/WordPress/gutenberg/pull/57006)) +- hooks: Subscribe only to relevant attributes. ([56783](https://github.com/WordPress/gutenberg/pull/56783)) + +#### Site Editor +- Fix typing performance by not rendering sidebar. ([56927](https://github.com/WordPress/gutenberg/pull/56927)) + +#### Components +- ToolsPanel: Fix deregister/register on type. ([56770](https://github.com/WordPress/gutenberg/pull/56770)) + +#### Modules API +- Load the import map polyfill only when there is an import map. ([56699](https://github.com/WordPress/gutenberg/pull/56699)) + +#### Post Editor +- Editor: Avoid double parsing content in 'getSuggestedPostFormat' selelector. ([56679](https://github.com/WordPress/gutenberg/pull/56679)) + + +### Experiments + +#### Data Views +- DataViews: Add story. ([56761](https://github.com/WordPress/gutenberg/pull/56761)) +- DataViews: Add support for `NOT IN` operator in filter. ([56479](https://github.com/WordPress/gutenberg/pull/56479)) +- DataViews: Centralize the view definition and rename `list` to `table`. ([56693](https://github.com/WordPress/gutenberg/pull/56693)) +- DataViews: Do not export strings constants. ([56754](https://github.com/WordPress/gutenberg/pull/56754)) +- DataViews: Export the view components as defaults. ([56677](https://github.com/WordPress/gutenberg/pull/56677)) +- DataViews: Fix dropdown menu actions with modal. ([56760](https://github.com/WordPress/gutenberg/pull/56760)) +- DataViews: Hide pagination if we have only one page. ([56948](https://github.com/WordPress/gutenberg/pull/56948)) +- DataViews: Implement `NOT IN` operator for author filter in templates. ([56777](https://github.com/WordPress/gutenberg/pull/56777)) +- DataViews: Iterate on list view. ([56746](https://github.com/WordPress/gutenberg/pull/56746)) +- DataViews: Make `Actions` styles the same as any other column header. ([56654](https://github.com/WordPress/gutenberg/pull/56654)) +- DataViews: Make `mediaField` not hidable. ([56643](https://github.com/WordPress/gutenberg/pull/56643)) +- DataViews: Rename view components. ([56709](https://github.com/WordPress/gutenberg/pull/56709)) +- DataViews: Render data async conditionally. ([56851](https://github.com/WordPress/gutenberg/pull/56851)) +- DataViews: Set proper role for AddFilter's items. ([56714](https://github.com/WordPress/gutenberg/pull/56714)) +- DataViews: Set proper semantics for dropdown items. ([56676](https://github.com/WordPress/gutenberg/pull/56676)) +- DataViews: Update sorting semantics. ([56717](https://github.com/WordPress/gutenberg/pull/56717)) +- Dataviews: Extract to dedicated bundled package. ([56721](https://github.com/WordPress/gutenberg/pull/56721)) + +#### Block Validation/Deprecation +- Input Field Block: Use `useblockProps` hook in save function. ([56507](https://github.com/WordPress/gutenberg/pull/56507)) + +#### Patterns +- Implement partially synced patterns behind an experimental flag. ([56235](https://github.com/WordPress/gutenberg/pull/56235)) + + +### Documentation + +- Add the nested blocks chapter to the platform documentation. ([56689](https://github.com/WordPress/gutenberg/pull/56689)) +- Components: Update CHANGELOG.md. ([56960](https://github.com/WordPress/gutenberg/pull/56960)) +- Doc: Search Control - add Storybook link. ([56815](https://github.com/WordPress/gutenberg/pull/56815)) +- Doc: Spinner - add Storybook link. ([56818](https://github.com/WordPress/gutenberg/pull/56818)) +- Docs: Add storybook link for spinner component. ([56953](https://github.com/WordPress/gutenberg/pull/56953)) +- Docs: Fix {% end %} tab position to show the text. ([56735](https://github.com/WordPress/gutenberg/pull/56735)) +- Docs: Fundamentals of Block Development - Minor fixes - registration-of-a-block. ([56731](https://github.com/WordPress/gutenberg/pull/56731)) +- Docs: Fundamentals of Block Development - add links. ([56700](https://github.com/WordPress/gutenberg/pull/56700)) +- Docs: Fundamentals of Block Development ---- Small fixes for "Block wrapper". ([56651](https://github.com/WordPress/gutenberg/pull/56651)) +- Link to Dashicons. ([56872](https://github.com/WordPress/gutenberg/pull/56872)) +- Platform Docs: Add trusted by section. ([56749](https://github.com/WordPress/gutenberg/pull/56749)) +- Revert "Doc: Spinner - add Storybook link". ([56913](https://github.com/WordPress/gutenberg/pull/56913)) +- Update Getting Started Guide for Gutenberg 17.2. ([56674](https://github.com/WordPress/gutenberg/pull/56674)) +- Update InnerBlocks defaultblock doc usage. ([56728](https://github.com/WordPress/gutenberg/pull/56728)) +- Update formatting and fix grammar in the Block Editor Handbook readme. ([56798](https://github.com/WordPress/gutenberg/pull/56798)) + + +### Code Quality + +- Block editor: hooks: Avoid getEditWrapperProps. ([56912](https://github.com/WordPress/gutenberg/pull/56912)) +- Block lib: Use RichText.isEmpty where forgotten. ([56726](https://github.com/WordPress/gutenberg/pull/56726)) +- Block library: Reusable caption component util. ([56606](https://github.com/WordPress/gutenberg/pull/56606)) +- Core data revisions: Remove hardcoded supports constant. ([56701](https://github.com/WordPress/gutenberg/pull/56701)) +- Editor: Cleanup default editor mode handling. ([56819](https://github.com/WordPress/gutenberg/pull/56819)) +- Editor: Move the BlockCanvas component within the EditorCanvas component. ([56850](https://github.com/WordPress/gutenberg/pull/56850)) +- Editor: Move the device type state to the editor package. ([56866](https://github.com/WordPress/gutenberg/pull/56866)) +- Editor: Unify device preview styles. ([56904](https://github.com/WordPress/gutenberg/pull/56904)) +- Fix PHP linter failing. ([56905](https://github.com/WordPress/gutenberg/pull/56905)) +- Framework: Bundle the BlockTools component within BlockCanvas. ([56996](https://github.com/WordPress/gutenberg/pull/56996)) +- Move `useDebouncedInput` hook to @wordpress/compose package. ([56744](https://github.com/WordPress/gutenberg/pull/56744)) +- Post Editor: Rely on the editor store for the template mode state. ([56716](https://github.com/WordPress/gutenberg/pull/56716)) +- Refactor . ([56335](https://github.com/WordPress/gutenberg/pull/56335)) +- Remove Block Tools BackCompat. ([56874](https://github.com/WordPress/gutenberg/pull/56874)) +- Site and Post Editor: Unify the DocumentBar component. ([56778](https://github.com/WordPress/gutenberg/pull/56778)) +- getValueFromObjectPath: Remove memize. ([56711](https://github.com/WordPress/gutenberg/pull/56711)) + +#### Block Editor +- Don't render undefined classname in useBlockProps hook. ([56923](https://github.com/WordPress/gutenberg/pull/56923)) +- One hook to rule them all: Preparation for a block supports API. ([56862](https://github.com/WordPress/gutenberg/pull/56862)) +- RichText: Pass value to store. ([43204](https://github.com/WordPress/gutenberg/pull/43204)) +- hooks: Manage BlockListBlock filters in one place. ([56875](https://github.com/WordPress/gutenberg/pull/56875)) + +#### Global Styles +- Command Palette: Use getRevisions instead of deprecated selector. ([56738](https://github.com/WordPress/gutenberg/pull/56738)) +- Global styles revisions: Remove PHP unit tests that are running in Core. ([56492](https://github.com/WordPress/gutenberg/pull/56492)) + +#### Components +- Site editor: Do not use navigator's internal classname. ([56911](https://github.com/WordPress/gutenberg/pull/56911)) + +#### Data Views +- DataViews: Remove TanStack. ([56873](https://github.com/WordPress/gutenberg/pull/56873)) + + +### Tools + +- Env: Migrate to Compose V2. ([51339](https://github.com/WordPress/gutenberg/pull/51339)) +- Scripts: Fix CSS imports not minified. ([56516](https://github.com/WordPress/gutenberg/pull/56516)) +- wp-env: Make env-cwd option work on Windows. ([56265](https://github.com/WordPress/gutenberg/pull/56265)) + +#### Testing +- Migrate 'editor multi entity saving' end-to-end tests to Playwright. ([56670](https://github.com/WordPress/gutenberg/pull/56670)) +- Migrate 'inner-blocks-locking-all-embed' end-to-end tests to Playwright. ([56673](https://github.com/WordPress/gutenberg/pull/56673)) +- Migrate 'site editor export' end-to-end tests to Playwright. ([56675](https://github.com/WordPress/gutenberg/pull/56675)) +- RN: Add watch mode for native tests. ([56788](https://github.com/WordPress/gutenberg/pull/56788)) +- Scripts: Enable skipping Playwright browser installation. ([56594](https://github.com/WordPress/gutenberg/pull/56594)) +- Tabs: Implement `ariakit/test` in unit tests. ([56835](https://github.com/WordPress/gutenberg/pull/56835)) +- `CustomSelectControl`: Add additional unit tests. ([56575](https://github.com/WordPress/gutenberg/pull/56575)) + + +### Copy + +- Copy/fix capitalization of WordPress. ([56834](https://github.com/WordPress/gutenberg/pull/56834)) + +#### Site Editor +- Improve text and design of the block removal warnings. ([56869](https://github.com/WordPress/gutenberg/pull/56869)) + +#### Global Styles +- Global styles welcome guide: Add a space between translated strings. ([56839](https://github.com/WordPress/gutenberg/pull/56839)) + +#### Block Library +- Simplify page list edit warning. ([56829](https://github.com/WordPress/gutenberg/pull/56829)) + +#### Patterns +- End pattern page descriptions with a period. ([56828](https://github.com/WordPress/gutenberg/pull/56828)) + + +## First time contributors + +The following PRs were merged by first time contributors: + +- @benoitchantre: Scripts: Fix CSS imports not minified. ([56516](https://github.com/WordPress/gutenberg/pull/56516)) +- @kmanijak: Decode some characters if used in taxonomy name so it's displayed correctly in Query Loop filters. ([50376](https://github.com/WordPress/gutenberg/pull/50376)) +- @lithrel: Env: Migrate to Compose V2. ([51339](https://github.com/WordPress/gutenberg/pull/51339)) +- @nk-o: Fix: PHP 8.1 deprecated warning strpos(). ([56171](https://github.com/WordPress/gutenberg/pull/56171)) +- @taylorgorman: Link to Dashicons. ([56872](https://github.com/WordPress/gutenberg/pull/56872)) +- @valerogarte: #55702 - Control dimensions (margin and padding) of the list-item block. ([55874](https://github.com/WordPress/gutenberg/pull/55874)) + + +## Contributors + +The following contributors merged PRs in this release: + +@afercia @ajlende @alexstine @andrewhayward @andrewserong @apeatling @atachibana @Aurorum @benoitchantre @bph @brookewp @chad1008 @ciampo @colorful-tones @dcalhoun @derekblank @draganescu @ellatrix @fluiddot @geriux @getdave @jameskoster @jasmussen @jeherve @jeryj @jffng @jonathanbossenger @jorgefilipecosta @jsnajdr @juanmaguitar @kevin940726 @kmanijak @lithrel @luisherranz @Mamaduka @matiasbenedetto @mikachan @miminari @mtias @ndiego @nk-o @ntsekouras @oandregal @ramonjd @richtabor @scruffian @SiobhyB @t-hamano @talldan @taylorgorman @tellthemachines @tyxla @valerogarte @WunderBart @youknowriad + + + + = 17.2.3 = ## Changelog From 79cca7e6a4b223bfbdefcd5df5937c6cf5274d00 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Wed, 20 Dec 2023 15:58:07 +0100 Subject: [PATCH 49/76] Modules API: Refactor, tests, and final dependencies array structure (#57231) * WIP * Remove the scripts code and improve the tests * Add missing comments * Add tests for get_version_query_string * Refactor and finish tests * Remove unnecessary array check * Remove HTML from comments * Escape tag attributes * Rename module preloads method * Fix typo * Rename module preloads method in tests --- .../modules/class-gutenberg-modules.php | 185 +++++++---- .../modules/class-gutenberg-modules-test.php | 299 +++++++++++++++--- 2 files changed, 380 insertions(+), 104 deletions(-) diff --git a/lib/experimental/modules/class-gutenberg-modules.php b/lib/experimental/modules/class-gutenberg-modules.php index 5f847fa8c897ad..bbe51f1376a7db 100644 --- a/lib/experimental/modules/class-gutenberg-modules.php +++ b/lib/experimental/modules/class-gutenberg-modules.php @@ -20,64 +20,90 @@ class Gutenberg_Modules { private static $registered = array(); /** - * An array of queued modules. + * An array of module identifiers that were enqueued before registered. * - * @var string[] + * @var array */ - private static $enqueued = array(); + private static $enqueued_modules_before_register = array(); /** - * Registers the module if no module with that module identifier already - * exists. + * Registers the module if no module with that module identifier has already + * been registered. * - * @param string $module_identifier The identifier of the module. Should be unique. It will be used in the final import map. - * @param string $src Full URL of the module, or path of the script relative to the WordPress root directory. - * @param array $dependencies Optional. An array of module identifiers of the static and dynamic dependencies of this module. It can be an indexed array, in which case all the dependencies are static, or it can be an associative array, in which case it has to contain the keys `static` and `dynamic`. - * @param string|bool|null $version Optional. String specifying module version number. It is added to the URL as a query string for cache busting purposes. If SCRIPT_DEBUG is true, a timestamp is used. If it is set to false, a version number is automatically added equal to current installed WordPress version. If set to null, no version is added. + * @param string $module_identifier The identifier of the module. Should be unique. It will be used in the final import map. + * @param string $src Full URL of the module, or path of the script relative to the WordPress root directory. + * @param array $dependencies Optional. An array of module identifiers of the dependencies of this module. The dependencies can be strings or arrays. If they are arrays, they need an `id` key with the module identifier, and can contain a `type` key with either `static` or `dynamic`. By default, dependencies that don't contain a type are considered static. + * @param string|false|null $version Optional. String specifying module version number. Defaults to false. It is added to the URL as a query string for cache busting purposes. If SCRIPT_DEBUG is true, the version is the current timestamp. If $version is set to false, the version number is the currently installed WordPress version. If $version is set to null, no version is added. */ public static function register( $module_identifier, $src, $dependencies = array(), $version = false ) { - // Register the module if it's not already registered. if ( ! isset( self::$registered[ $module_identifier ] ) ) { - $deps = array( - 'static' => isset( $dependencies['static'] ) || isset( $dependencies['dynamic'] ) ? $dependencies['static'] ?? array() : $dependencies, - 'dynamic' => isset( $dependencies['dynamic'] ) ? $dependencies['dynamic'] : array(), - ); + $deps = array(); + foreach ( $dependencies as $dependency ) { + if ( isset( $dependency['id'] ) ) { + $deps[] = array( + 'id' => $dependency['id'], + 'type' => isset( $dependency['type'] ) && 'dynamic' === $dependency['type'] ? 'dynamic' : 'static', + ); + } elseif ( is_string( $dependency ) ) { + $deps[] = array( + 'id' => $dependency, + 'type' => 'static', + ); + } + } self::$registered[ $module_identifier ] = array( 'src' => $src, 'version' => $version, + 'enqueued' => in_array( $module_identifier, self::$enqueued_modules_before_register, true ), 'dependencies' => $deps, ); } } /** - * Enqueues a module in the page. + * Marks the module to be enqueued in the page. * * @param string $module_identifier The identifier of the module. */ public static function enqueue( $module_identifier ) { - // Add the module to the queue if it's not already there. - if ( ! in_array( $module_identifier, self::$enqueued, true ) ) { - self::$enqueued[] = $module_identifier; + if ( isset( self::$registered[ $module_identifier ] ) ) { + self::$registered[ $module_identifier ]['enqueued'] = true; + } elseif ( ! in_array( $module_identifier, self::$enqueued_modules_before_register, true ) ) { + self::$enqueued_modules_before_register[] = $module_identifier; + } + } + + /** + * Unmarks the module so it is no longer enqueued in the page. + * + * @param string $module_identifier The identifier of the module. + */ + public static function dequeue( $module_identifier ) { + if ( isset( self::$registered[ $module_identifier ] ) ) { + self::$registered[ $module_identifier ]['enqueued'] = false; + } + $key = array_search( $module_identifier, self::$enqueued_modules_before_register, true ); + if ( false !== $key ) { + array_splice( self::$enqueued_modules_before_register, $key, 1 ); } } /** * Returns the import map array. * - * @return array Associative array with 'imports' key mapping to an array of module identifiers and their respective source strings. + * @return array Array with an 'imports' key mapping to an array of module identifiers and their respective source URLs, including the version query. */ public static function get_import_map() { $imports = array(); - foreach ( self::get_dependencies( self::$enqueued, array( 'static', 'dynamic' ) ) as $module_identifier => $module ) { + foreach ( self::get_dependencies( array_keys( self::get_enqueued() ) ) as $module_identifier => $module ) { $imports[ $module_identifier ] = $module['src'] . self::get_version_query_string( $module['version'] ); } return array( 'imports' => $imports ); } /** - * Prints the import map. + * Prints the import map using a script tag with an type="importmap" attribute. */ public static function print_import_map() { $import_map = self::get_import_map(); @@ -90,27 +116,30 @@ public static function print_import_map() { * Prints all the enqueued modules using