From 20b773b7a47bc80aa7516a6955f23eb24782922f Mon Sep 17 00:00:00 2001 From: Hit Bhalodia <58802366+hbhalodia@users.noreply.github.com> Date: Thu, 7 Nov 2024 12:58:27 +0530 Subject: [PATCH 001/226] Feat: Storybook: Improve component organisation - Navigation Category - Issue #66275 (#66658) * Group the storybook components in Navigaiton category * Fix tabs to add inside containers and add experimental id for component * Fix the syntax style Co-authored-by: hbhalodia Co-authored-by: tyxla --- packages/components/src/external-link/stories/index.story.tsx | 3 ++- packages/components/src/navigator/stories/index.story.tsx | 3 ++- packages/components/src/tree-grid/stories/index.story.tsx | 3 ++- storybook/preview.js | 2 ++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/components/src/external-link/stories/index.story.tsx b/packages/components/src/external-link/stories/index.story.tsx index 91131e0c88aab0..eb70999413187f 100644 --- a/packages/components/src/external-link/stories/index.story.tsx +++ b/packages/components/src/external-link/stories/index.story.tsx @@ -10,7 +10,8 @@ import ExternalLink from '..'; const meta: Meta< typeof ExternalLink > = { component: ExternalLink, - title: 'Components/ExternalLink', + title: 'Components/Navigation/ExternalLink', + id: 'components-externallink', argTypes: { children: { control: { type: 'text' } }, }, diff --git a/packages/components/src/navigator/stories/index.story.tsx b/packages/components/src/navigator/stories/index.story.tsx index e9e342bb0d2eee..bd2cdc17a1263c 100644 --- a/packages/components/src/navigator/stories/index.story.tsx +++ b/packages/components/src/navigator/stories/index.story.tsx @@ -21,7 +21,8 @@ const meta: Meta< typeof Navigator > = { // @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170 BackButton: Navigator.BackButton, }, - title: 'Components/Navigator', + title: 'Components/Navigation/Navigator', + id: 'components-navigator', argTypes: { as: { control: { type: null } }, children: { control: { type: null } }, diff --git a/packages/components/src/tree-grid/stories/index.story.tsx b/packages/components/src/tree-grid/stories/index.story.tsx index 44af154c685b2f..5a1ed95e1fd627 100644 --- a/packages/components/src/tree-grid/stories/index.story.tsx +++ b/packages/components/src/tree-grid/stories/index.story.tsx @@ -16,7 +16,8 @@ import { Button } from '../../button'; import InputControl from '../../input-control'; const meta: Meta< typeof TreeGrid > = { - title: 'Components (Experimental)/TreeGrid', + title: 'Components (Experimental)/Navigation/TreeGrid', + id: 'components-experimental-treegrid', component: TreeGrid, // @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170 subcomponents: { TreeGridRow, TreeGridCell }, diff --git a/storybook/preview.js b/storybook/preview.js index 7672e7ebdcdff2..9e9dd587b39c4c 100644 --- a/storybook/preview.js +++ b/storybook/preview.js @@ -133,9 +133,11 @@ export const parameters = { 'Actions', 'Containers', 'Feedback', + 'Navigation', 'Utilities', ], 'Components (Experimental)', + [ 'Navigation' ], 'Icons', ], }, From b9b1a52d967db7a014100dd7d49a403ac26b7238 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Thu, 7 Nov 2024 09:35:45 +0200 Subject: [PATCH 002/226] =?UTF-8?q?Relocate=20=E2=80=9CView=E2=80=9D=20ext?= =?UTF-8?q?ernal=20link=20to=20end=20of=20editor=20header=20controls=20(#6?= =?UTF-8?q?6785)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: ntsekouras Co-authored-by: draganescu Co-authored-by: jasmussen Co-authored-by: richtabor --- packages/editor/src/components/header/index.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/editor/src/components/header/index.js b/packages/editor/src/components/header/index.js index 07a5e9ddee5911..5a9cc2f94a5951 100644 --- a/packages/editor/src/components/header/index.js +++ b/packages/editor/src/components/header/index.js @@ -156,19 +156,21 @@ function Header( { ) } - { canBeZoomedOut && isEditorIframed && isWideViewport && ( - - ) } + + - + + { canBeZoomedOut && isEditorIframed && isWideViewport && ( + + ) } { ( isWideViewport || ! showIconLabels ) && ( From 8be8e4675637726b0ff3194ccc547307c4a489bc Mon Sep 17 00:00:00 2001 From: Marin Atanasov <8436925+tyxla@users.noreply.github.com> Date: Thu, 7 Nov 2024 17:26:40 +0900 Subject: [PATCH 003/226] ESLint: Fix React Compiler violations in various commands (#66787) Co-authored-by: tyxla Co-authored-by: Mamaduka --- .../components/use-block-commands/index.js | 479 +++++++++-------- .../src/admin-navigation-commands.js | 129 ++--- .../src/site-editor-navigation-commands.js | 256 ++++----- .../src/hooks/commands/use-common-commands.js | 499 +++++++++--------- .../hooks/commands/use-edit-mode-commands.js | 259 ++++----- .../editor/src/components/commands/index.js | 472 +++++++++-------- 6 files changed, 1069 insertions(+), 1025 deletions(-) diff --git a/packages/block-editor/src/components/use-block-commands/index.js b/packages/block-editor/src/components/use-block-commands/index.js index e739729c8f9e84..ff919710a2284e 100644 --- a/packages/block-editor/src/components/use-block-commands/index.js +++ b/packages/block-editor/src/components/use-block-commands/index.js @@ -24,275 +24,286 @@ import { import BlockIcon from '../block-icon'; import { store as blockEditorStore } from '../../store'; -export const useTransformCommands = () => { - const { replaceBlocks, multiSelect } = useDispatch( blockEditorStore ); - const { - blocks, - clientIds, - canRemove, - possibleBlockTransformations, - invalidSelection, - } = useSelect( ( select ) => { +const getTransformCommands = () => + function useTransformCommands() { + const { replaceBlocks, multiSelect } = useDispatch( blockEditorStore ); const { - getBlockRootClientId, - getBlockTransformItems, - getSelectedBlockClientIds, - getBlocksByClientId, - canRemoveBlocks, - } = select( blockEditorStore ); + blocks, + clientIds, + canRemove, + possibleBlockTransformations, + invalidSelection, + } = useSelect( ( select ) => { + const { + getBlockRootClientId, + getBlockTransformItems, + getSelectedBlockClientIds, + getBlocksByClientId, + canRemoveBlocks, + } = select( blockEditorStore ); + + const selectedBlockClientIds = getSelectedBlockClientIds(); + const selectedBlocks = getBlocksByClientId( + selectedBlockClientIds + ); + + // selectedBlocks can have `null`s when something tries to call `selectBlock` with an inexistent clientId. + // These nulls will cause fatal errors down the line. + // In order to prevent discrepancies between selectedBlockClientIds and selectedBlocks, we effectively treat the entire selection as invalid. + // @see https://github.com/WordPress/gutenberg/pull/59410#issuecomment-2006304536 + if ( selectedBlocks.filter( ( block ) => ! block ).length > 0 ) { + return { + invalidSelection: true, + }; + } - const selectedBlockClientIds = getSelectedBlockClientIds(); - const selectedBlocks = getBlocksByClientId( selectedBlockClientIds ); + const rootClientId = getBlockRootClientId( + selectedBlockClientIds[ 0 ] + ); + return { + blocks: selectedBlocks, + clientIds: selectedBlockClientIds, + possibleBlockTransformations: getBlockTransformItems( + selectedBlocks, + rootClientId + ), + canRemove: canRemoveBlocks( selectedBlockClientIds ), + invalidSelection: false, + }; + }, [] ); - // selectedBlocks can have `null`s when something tries to call `selectBlock` with an inexistent clientId. - // These nulls will cause fatal errors down the line. - // In order to prevent discrepancies between selectedBlockClientIds and selectedBlocks, we effectively treat the entire selection as invalid. - // @see https://github.com/WordPress/gutenberg/pull/59410#issuecomment-2006304536 - if ( selectedBlocks.filter( ( block ) => ! block ).length > 0 ) { + if ( invalidSelection ) { return { - invalidSelection: true, + isLoading: false, + commands: [], }; } + const isTemplate = blocks.length === 1 && isTemplatePart( blocks[ 0 ] ); + + function selectForMultipleBlocks( insertedBlocks ) { + if ( insertedBlocks.length > 1 ) { + multiSelect( + insertedBlocks[ 0 ].clientId, + insertedBlocks[ insertedBlocks.length - 1 ].clientId + ); + } + } - const rootClientId = getBlockRootClientId( - selectedBlockClientIds[ 0 ] - ); - return { - blocks: selectedBlocks, - clientIds: selectedBlockClientIds, - possibleBlockTransformations: getBlockTransformItems( - selectedBlocks, - rootClientId - ), - canRemove: canRemoveBlocks( selectedBlockClientIds ), - invalidSelection: false, - }; - }, [] ); + // Simple block tranformation based on the `Block Transforms` API. + function onBlockTransform( name ) { + const newBlocks = switchToBlockType( blocks, name ); + replaceBlocks( clientIds, newBlocks ); + selectForMultipleBlocks( newBlocks ); + } - if ( invalidSelection ) { - return { - isLoading: false, - commands: [], - }; - } - const isTemplate = blocks.length === 1 && isTemplatePart( blocks[ 0 ] ); - - function selectForMultipleBlocks( insertedBlocks ) { - if ( insertedBlocks.length > 1 ) { - multiSelect( - insertedBlocks[ 0 ].clientId, - insertedBlocks[ insertedBlocks.length - 1 ].clientId - ); + /** + * The `isTemplate` check is a stopgap solution here. + * Ideally, the Transforms API should handle this + * by allowing to exclude blocks from wildcard transformations. + */ + const hasPossibleBlockTransformations = + !! possibleBlockTransformations.length && canRemove && ! isTemplate; + + if ( + ! clientIds || + clientIds.length < 1 || + ! hasPossibleBlockTransformations + ) { + return { isLoading: false, commands: [] }; } - } - - // Simple block tranformation based on the `Block Transforms` API. - function onBlockTransform( name ) { - const newBlocks = switchToBlockType( blocks, name ); - replaceBlocks( clientIds, newBlocks ); - selectForMultipleBlocks( newBlocks ); - } - - /** - * The `isTemplate` check is a stopgap solution here. - * Ideally, the Transforms API should handle this - * by allowing to exclude blocks from wildcard transformations. - */ - const hasPossibleBlockTransformations = - !! possibleBlockTransformations.length && canRemove && ! isTemplate; - - if ( - ! clientIds || - clientIds.length < 1 || - ! hasPossibleBlockTransformations - ) { - return { isLoading: false, commands: [] }; - } - - const commands = possibleBlockTransformations.map( ( transformation ) => { - const { name, title, icon } = transformation; - return { - name: 'core/block-editor/transform-to-' + name.replace( '/', '-' ), - /* translators: %s: Block or block variation name. */ - label: sprintf( __( 'Transform to %s' ), title ), - icon: , - callback: ( { close } ) => { - onBlockTransform( name ); - close(); + + const commands = possibleBlockTransformations.map( + ( transformation ) => { + const { name, title, icon } = transformation; + return { + name: + 'core/block-editor/transform-to-' + + name.replace( '/', '-' ), + /* translators: %s: Block or block variation name. */ + label: sprintf( __( 'Transform to %s' ), title ), + icon: , + callback: ( { close } ) => { + onBlockTransform( name ); + close(); + }, + }; + } + ); + + return { isLoading: false, commands }; + }; + +const getQuickActionsCommands = () => + function useQuickActionsCommands() { + const { clientIds, isUngroupable, isGroupable } = useSelect( + ( select ) => { + const { + getSelectedBlockClientIds, + isUngroupable: _isUngroupable, + isGroupable: _isGroupable, + } = select( blockEditorStore ); + const selectedBlockClientIds = getSelectedBlockClientIds(); + + return { + clientIds: selectedBlockClientIds, + isUngroupable: _isUngroupable(), + isGroupable: _isGroupable(), + }; }, - }; - } ); + [] + ); + const { + canInsertBlockType, + getBlockRootClientId, + getBlocksByClientId, + canRemoveBlocks, + } = useSelect( blockEditorStore ); + const { getDefaultBlockName, getGroupingBlockName } = + useSelect( blocksStore ); - return { isLoading: false, commands }; -}; + const blocks = getBlocksByClientId( clientIds ); -const useQuickActionsCommands = () => { - const { clientIds, isUngroupable, isGroupable } = useSelect( ( select ) => { const { - getSelectedBlockClientIds, - isUngroupable: _isUngroupable, - isGroupable: _isGroupable, - } = select( blockEditorStore ); - const selectedBlockClientIds = getSelectedBlockClientIds(); + removeBlocks, + replaceBlocks, + duplicateBlocks, + insertAfterBlock, + insertBeforeBlock, + } = useDispatch( blockEditorStore ); + + const onGroup = () => { + if ( ! blocks.length ) { + return; + } - return { - clientIds: selectedBlockClientIds, - isUngroupable: _isUngroupable(), - isGroupable: _isGroupable(), + const groupingBlockName = getGroupingBlockName(); + + // Activate the `transform` on `core/group` which does the conversion. + const newBlocks = switchToBlockType( blocks, groupingBlockName ); + + if ( ! newBlocks ) { + return; + } + replaceBlocks( clientIds, newBlocks ); }; - }, [] ); - const { - canInsertBlockType, - getBlockRootClientId, - getBlocksByClientId, - canRemoveBlocks, - } = useSelect( blockEditorStore ); - const { getDefaultBlockName, getGroupingBlockName } = - useSelect( blocksStore ); - - const blocks = getBlocksByClientId( clientIds ); - - const { - removeBlocks, - replaceBlocks, - duplicateBlocks, - insertAfterBlock, - insertBeforeBlock, - } = useDispatch( blockEditorStore ); - - const onGroup = () => { - if ( ! blocks.length ) { - return; - } + const onUngroup = () => { + if ( ! blocks.length ) { + return; + } - const groupingBlockName = getGroupingBlockName(); + const innerBlocks = blocks[ 0 ].innerBlocks; - // Activate the `transform` on `core/group` which does the conversion. - const newBlocks = switchToBlockType( blocks, groupingBlockName ); + if ( ! innerBlocks.length ) { + return; + } - if ( ! newBlocks ) { - return; - } - replaceBlocks( clientIds, newBlocks ); - }; - const onUngroup = () => { - if ( ! blocks.length ) { - return; + replaceBlocks( clientIds, innerBlocks ); + }; + + if ( ! clientIds || clientIds.length < 1 ) { + return { isLoading: false, commands: [] }; } - const innerBlocks = blocks[ 0 ].innerBlocks; + const rootClientId = getBlockRootClientId( clientIds[ 0 ] ); + const canInsertDefaultBlock = canInsertBlockType( + getDefaultBlockName(), + rootClientId + ); + const canDuplicate = blocks.every( ( block ) => { + return ( + !! block && + hasBlockSupport( block.name, 'multiple', true ) && + canInsertBlockType( block.name, rootClientId ) + ); + } ); + const canRemove = canRemoveBlocks( clientIds ); - if ( ! innerBlocks.length ) { - return; + const commands = []; + + if ( canDuplicate ) { + commands.push( { + name: 'duplicate', + label: __( 'Duplicate' ), + callback: () => duplicateBlocks( clientIds, true ), + icon: copy, + } ); } - replaceBlocks( clientIds, innerBlocks ); - }; + if ( canInsertDefaultBlock ) { + commands.push( + { + name: 'add-before', + label: __( 'Add before' ), + callback: () => { + const clientId = Array.isArray( clientIds ) + ? clientIds[ 0 ] + : clientId; + insertBeforeBlock( clientId ); + }, + icon: add, + }, + { + name: 'add-after', + label: __( 'Add after' ), + callback: () => { + const clientId = Array.isArray( clientIds ) + ? clientIds[ clientIds.length - 1 ] + : clientId; + insertAfterBlock( clientId ); + }, + icon: add, + } + ); + } - if ( ! clientIds || clientIds.length < 1 ) { - return { isLoading: false, commands: [] }; - } - - const rootClientId = getBlockRootClientId( clientIds[ 0 ] ); - const canInsertDefaultBlock = canInsertBlockType( - getDefaultBlockName(), - rootClientId - ); - const canDuplicate = blocks.every( ( block ) => { - return ( - !! block && - hasBlockSupport( block.name, 'multiple', true ) && - canInsertBlockType( block.name, rootClientId ) - ); - } ); - const canRemove = canRemoveBlocks( clientIds ); + if ( isGroupable ) { + commands.push( { + name: 'Group', + label: __( 'Group' ), + callback: onGroup, + icon: group, + } ); + } - const commands = []; + if ( isUngroupable ) { + commands.push( { + name: 'ungroup', + label: __( 'Ungroup' ), + callback: onUngroup, + icon: ungroup, + } ); + } - if ( canDuplicate ) { - commands.push( { - name: 'duplicate', - label: __( 'Duplicate' ), - callback: () => duplicateBlocks( clientIds, true ), - icon: copy, - } ); - } - - if ( canInsertDefaultBlock ) { - commands.push( - { - name: 'add-before', - label: __( 'Add before' ), - callback: () => { - const clientId = Array.isArray( clientIds ) - ? clientIds[ 0 ] - : clientId; - insertBeforeBlock( clientId ); - }, - icon: add, - }, - { - name: 'add-after', - label: __( 'Add after' ), - callback: () => { - const clientId = Array.isArray( clientIds ) - ? clientIds[ clientIds.length - 1 ] - : clientId; - insertAfterBlock( clientId ); + if ( canRemove ) { + commands.push( { + name: 'remove', + label: __( 'Delete' ), + callback: () => removeBlocks( clientIds, true ), + icon: remove, + } ); + } + + return { + isLoading: false, + commands: commands.map( ( command ) => ( { + ...command, + name: 'core/block-editor/action-' + command.name, + callback: ( { close } ) => { + command.callback(); + close(); }, - icon: add, - } - ); - } - - if ( isGroupable ) { - commands.push( { - name: 'Group', - label: __( 'Group' ), - callback: onGroup, - icon: group, - } ); - } - - if ( isUngroupable ) { - commands.push( { - name: 'ungroup', - label: __( 'Ungroup' ), - callback: onUngroup, - icon: ungroup, - } ); - } - - if ( canRemove ) { - commands.push( { - name: 'remove', - label: __( 'Delete' ), - callback: () => removeBlocks( clientIds, true ), - icon: remove, - } ); - } - - return { - isLoading: false, - commands: commands.map( ( command ) => ( { - ...command, - name: 'core/block-editor/action-' + command.name, - callback: ( { close } ) => { - command.callback(); - close(); - }, - } ) ), + } ) ), + }; }; -}; export const useBlockCommands = () => { useCommandLoader( { name: 'core/block-editor/blockTransforms', - hook: useTransformCommands, + hook: getTransformCommands(), } ); useCommandLoader( { name: 'core/block-editor/blockQuickActions', - hook: useQuickActionsCommands, + hook: getQuickActionsCommands(), context: 'block-selection-edit', } ); }; diff --git a/packages/core-commands/src/admin-navigation-commands.js b/packages/core-commands/src/admin-navigation-commands.js index c0d8bb084b46ad..9f0883faa3c17a 100644 --- a/packages/core-commands/src/admin-navigation-commands.js +++ b/packages/core-commands/src/admin-navigation-commands.js @@ -18,75 +18,78 @@ import { unlock } from './lock-unlock'; const { useHistory } = unlock( routerPrivateApis ); -function useAddNewPageCommand() { - const isSiteEditor = getPath( window.location.href )?.includes( - 'site-editor.php' - ); - const history = useHistory(); - const isBlockBasedTheme = useSelect( ( select ) => { - return select( coreStore ).getCurrentTheme()?.is_block_theme; - }, [] ); - const { saveEntityRecord } = useDispatch( coreStore ); - const { createErrorNotice } = useDispatch( noticesStore ); +const getAddNewPageCommand = () => + function useAddNewPageCommand() { + const isSiteEditor = getPath( window.location.href )?.includes( + 'site-editor.php' + ); + const history = useHistory(); + const isBlockBasedTheme = useSelect( ( select ) => { + return select( coreStore ).getCurrentTheme()?.is_block_theme; + }, [] ); + const { saveEntityRecord } = useDispatch( coreStore ); + const { createErrorNotice } = useDispatch( noticesStore ); - const createPageEntity = useCallback( - async ( { close } ) => { - try { - const page = await saveEntityRecord( - 'postType', - 'page', - { - status: 'draft', - }, - { - throwOnError: true, + const createPageEntity = useCallback( + async ( { close } ) => { + try { + const page = await saveEntityRecord( + 'postType', + 'page', + { + status: 'draft', + }, + { + throwOnError: true, + } + ); + if ( page?.id ) { + history.push( { + postId: page.id, + postType: 'page', + canvas: 'edit', + } ); } - ); - if ( page?.id ) { - history.push( { - postId: page.id, - postType: 'page', - canvas: 'edit', + } catch ( error ) { + const errorMessage = + error.message && error.code !== 'unknown_error' + ? error.message + : __( + 'An error occurred while creating the item.' + ); + + createErrorNotice( errorMessage, { + type: 'snackbar', } ); + } finally { + close(); } - } catch ( error ) { - const errorMessage = - error.message && error.code !== 'unknown_error' - ? error.message - : __( 'An error occurred while creating the item.' ); - - createErrorNotice( errorMessage, { - type: 'snackbar', - } ); - } finally { - close(); - } - }, - [ createErrorNotice, history, saveEntityRecord ] - ); - - const commands = useMemo( () => { - const addNewPage = - isSiteEditor && isBlockBasedTheme - ? createPageEntity - : () => - ( document.location.href = - 'post-new.php?post_type=page' ); - return [ - { - name: 'core/add-new-page', - label: __( 'Add new page' ), - icon: plus, - callback: addNewPage, }, - ]; - }, [ createPageEntity, isSiteEditor, isBlockBasedTheme ] ); + [ createErrorNotice, history, saveEntityRecord ] + ); + + const commands = useMemo( () => { + const addNewPage = + isSiteEditor && isBlockBasedTheme + ? createPageEntity + : () => + ( document.location.href = + 'post-new.php?post_type=page' ); + return [ + { + name: 'core/add-new-page', + label: __( 'Add new page' ), + icon: plus, + callback: addNewPage, + }, + ]; + }, [ createPageEntity, isSiteEditor, isBlockBasedTheme ] ); - return { - isLoading: false, - commands, + return { + isLoading: false, + commands, + }; }; -} export function useAdminNavigationCommands() { useCommand( { @@ -100,6 +103,6 @@ export function useAdminNavigationCommands() { useCommandLoader( { name: 'core/add-new-page', - hook: useAddNewPageCommand, + hook: getAddNewPageCommand(), } ); } diff --git a/packages/core-commands/src/site-editor-navigation-commands.js b/packages/core-commands/src/site-editor-navigation-commands.js index 4679d4d1523c89..2785d809d41e03 100644 --- a/packages/core-commands/src/site-editor-navigation-commands.js +++ b/packages/core-commands/src/site-editor-navigation-commands.js @@ -275,159 +275,169 @@ const getNavigationCommandLoaderPerTemplate = ( templateType ) => }; }; -const usePageNavigationCommandLoader = - getNavigationCommandLoaderPerPostType( 'page' ); -const usePostNavigationCommandLoader = - getNavigationCommandLoaderPerPostType( 'post' ); -const useTemplateNavigationCommandLoader = - getNavigationCommandLoaderPerTemplate( 'wp_template' ); -const useTemplatePartNavigationCommandLoader = - getNavigationCommandLoaderPerTemplate( 'wp_template_part' ); +const getSiteEditorBasicNavigationCommands = () => + function useSiteEditorBasicNavigationCommands() { + const history = useHistory(); + const isSiteEditor = getPath( window.location.href )?.includes( + 'site-editor.php' + ); + const { isBlockBasedTheme, canCreateTemplate } = useSelect( + ( select ) => { + return { + isBlockBasedTheme: + select( coreStore ).getCurrentTheme()?.is_block_theme, + canCreateTemplate: select( coreStore ).canUser( 'create', { + kind: 'postType', + name: 'wp_template', + } ), + }; + }, + [] + ); + const commands = useMemo( () => { + const result = []; -function useSiteEditorBasicNavigationCommands() { - const history = useHistory(); - const isSiteEditor = getPath( window.location.href )?.includes( - 'site-editor.php' - ); - const { isBlockBasedTheme, canCreateTemplate } = useSelect( ( select ) => { - return { - isBlockBasedTheme: - select( coreStore ).getCurrentTheme()?.is_block_theme, - canCreateTemplate: select( coreStore ).canUser( 'create', { - kind: 'postType', - name: 'wp_template', - } ), - }; - }, [] ); - const commands = useMemo( () => { - const result = []; + if ( canCreateTemplate && isBlockBasedTheme ) { + result.push( { + name: 'core/edit-site/open-navigation', + label: __( 'Navigation' ), + icon: navigation, + callback: ( { close } ) => { + const args = { + postType: 'wp_navigation', + }; + const targetUrl = addQueryArgs( + 'site-editor.php', + args + ); + if ( isSiteEditor ) { + history.push( args ); + } else { + document.location = targetUrl; + } + close(); + }, + } ); - if ( canCreateTemplate && isBlockBasedTheme ) { - result.push( { - name: 'core/edit-site/open-navigation', - label: __( 'Navigation' ), - icon: navigation, - callback: ( { close } ) => { - const args = { - postType: 'wp_navigation', - }; - const targetUrl = addQueryArgs( 'site-editor.php', args ); - if ( isSiteEditor ) { - history.push( args ); - } else { - document.location = targetUrl; - } - close(); - }, - } ); + result.push( { + name: 'core/edit-site/open-styles', + label: __( 'Styles' ), + icon: styles, + callback: ( { close } ) => { + const args = { + path: '/wp_global_styles', + }; + const targetUrl = addQueryArgs( + 'site-editor.php', + args + ); + if ( isSiteEditor ) { + history.push( args ); + } else { + document.location = targetUrl; + } + close(); + }, + } ); - result.push( { - name: 'core/edit-site/open-styles', - label: __( 'Styles' ), - icon: styles, - callback: ( { close } ) => { - const args = { - path: '/wp_global_styles', - }; - const targetUrl = addQueryArgs( 'site-editor.php', args ); - if ( isSiteEditor ) { - history.push( args ); - } else { - document.location = targetUrl; - } - close(); - }, - } ); + result.push( { + name: 'core/edit-site/open-pages', + label: __( 'Pages' ), + icon: page, + callback: ( { close } ) => { + const args = { + postType: 'page', + }; + const targetUrl = addQueryArgs( + 'site-editor.php', + args + ); + if ( isSiteEditor ) { + history.push( args ); + } else { + document.location = targetUrl; + } + close(); + }, + } ); - result.push( { - name: 'core/edit-site/open-pages', - label: __( 'Pages' ), - icon: page, - callback: ( { close } ) => { - const args = { - postType: 'page', - }; - const targetUrl = addQueryArgs( 'site-editor.php', args ); - if ( isSiteEditor ) { - history.push( args ); - } else { - document.location = targetUrl; - } - close(); - }, - } ); + result.push( { + name: 'core/edit-site/open-templates', + label: __( 'Templates' ), + icon: layout, + callback: ( { close } ) => { + const args = { + postType: 'wp_template', + }; + const targetUrl = addQueryArgs( + 'site-editor.php', + args + ); + if ( isSiteEditor ) { + history.push( args ); + } else { + document.location = targetUrl; + } + close(); + }, + } ); + } result.push( { - name: 'core/edit-site/open-templates', - label: __( 'Templates' ), - icon: layout, + name: 'core/edit-site/open-patterns', + label: __( 'Patterns' ), + icon: symbol, callback: ( { close } ) => { - const args = { - postType: 'wp_template', - }; - const targetUrl = addQueryArgs( 'site-editor.php', args ); - if ( isSiteEditor ) { - history.push( args ); + if ( canCreateTemplate ) { + const args = { + postType: 'wp_block', + }; + const targetUrl = addQueryArgs( + 'site-editor.php', + args + ); + if ( isSiteEditor ) { + history.push( args ); + } else { + document.location = targetUrl; + } + close(); } else { - document.location = targetUrl; + // If a user cannot access the site editor + document.location.href = 'edit.php?post_type=wp_block'; } - close(); }, } ); - } - - result.push( { - name: 'core/edit-site/open-patterns', - label: __( 'Patterns' ), - icon: symbol, - callback: ( { close } ) => { - if ( canCreateTemplate ) { - const args = { - postType: 'wp_block', - }; - const targetUrl = addQueryArgs( 'site-editor.php', args ); - if ( isSiteEditor ) { - history.push( args ); - } else { - document.location = targetUrl; - } - close(); - } else { - // If a user cannot access the site editor - document.location.href = 'edit.php?post_type=wp_block'; - } - }, - } ); - return result; - }, [ history, isSiteEditor, canCreateTemplate, isBlockBasedTheme ] ); + return result; + }, [ history, isSiteEditor, canCreateTemplate, isBlockBasedTheme ] ); - return { - commands, - isLoading: false, + return { + commands, + isLoading: false, + }; }; -} export function useSiteEditorNavigationCommands() { useCommandLoader( { name: 'core/edit-site/navigate-pages', - hook: usePageNavigationCommandLoader, + hook: getNavigationCommandLoaderPerPostType( 'page' ), } ); useCommandLoader( { name: 'core/edit-site/navigate-posts', - hook: usePostNavigationCommandLoader, + hook: getNavigationCommandLoaderPerPostType( 'post' ), } ); useCommandLoader( { name: 'core/edit-site/navigate-templates', - hook: useTemplateNavigationCommandLoader, + hook: getNavigationCommandLoaderPerTemplate( 'wp_template' ), } ); useCommandLoader( { name: 'core/edit-site/navigate-template-parts', - hook: useTemplatePartNavigationCommandLoader, + hook: getNavigationCommandLoaderPerTemplate( 'wp_template_part' ), } ); useCommandLoader( { name: 'core/edit-site/basic-navigation', - hook: useSiteEditorBasicNavigationCommands, + hook: getSiteEditorBasicNavigationCommands(), context: 'site-editor', } ); } diff --git a/packages/edit-site/src/hooks/commands/use-common-commands.js b/packages/edit-site/src/hooks/commands/use-common-commands.js index 536817e88d3a47..3e87f8721e116a 100644 --- a/packages/edit-site/src/hooks/commands/use-common-commands.js +++ b/packages/edit-site/src/hooks/commands/use-common-commands.js @@ -28,282 +28,289 @@ import { store as editSiteStore } from '../../store'; const { useGlobalStylesReset } = unlock( blockEditorPrivateApis ); const { useHistory, useLocation } = unlock( routerPrivateApis ); -function useGlobalStylesOpenStylesCommands() { - const { openGeneralSidebar } = unlock( useDispatch( editSiteStore ) ); - const { params } = useLocation(); - const { canvas = 'view' } = params; - const history = useHistory(); - const isBlockBasedTheme = useSelect( ( select ) => { - return select( coreStore ).getCurrentTheme().is_block_theme; - }, [] ); +const getGlobalStylesOpenStylesCommands = () => + function useGlobalStylesOpenStylesCommands() { + const { openGeneralSidebar } = unlock( useDispatch( editSiteStore ) ); + const { params } = useLocation(); + const { canvas = 'view' } = params; + const history = useHistory(); + const isBlockBasedTheme = useSelect( ( select ) => { + return select( coreStore ).getCurrentTheme().is_block_theme; + }, [] ); - const commands = useMemo( () => { - if ( ! isBlockBasedTheme ) { - return []; - } + const commands = useMemo( () => { + if ( ! isBlockBasedTheme ) { + return []; + } - return [ - { - name: 'core/edit-site/open-styles', - label: __( 'Open styles' ), - callback: ( { close } ) => { - close(); - if ( ! params.postId ) { - history.push( { - path: '/wp_global_styles', - canvas: 'edit', - } ); - } - if ( params.postId && canvas !== 'edit' ) { - history.push( - { ...params, canvas: 'edit' }, - undefined, - { - transition: 'canvas-mode-edit-transition', - } - ); - } - openGeneralSidebar( 'edit-site/global-styles' ); + return [ + { + name: 'core/edit-site/open-styles', + label: __( 'Open styles' ), + callback: ( { close } ) => { + close(); + if ( ! params.postId ) { + history.push( { + path: '/wp_global_styles', + canvas: 'edit', + } ); + } + if ( params.postId && canvas !== 'edit' ) { + history.push( + { ...params, canvas: 'edit' }, + undefined, + { + transition: 'canvas-mode-edit-transition', + } + ); + } + openGeneralSidebar( 'edit-site/global-styles' ); + }, + icon: styles, }, - icon: styles, - }, - ]; - }, [ history, openGeneralSidebar, params, canvas, isBlockBasedTheme ] ); + ]; + }, [ history, openGeneralSidebar, params, canvas, isBlockBasedTheme ] ); - return { - isLoading: false, - commands, + return { + isLoading: false, + commands, + }; }; -} -function useGlobalStylesToggleWelcomeGuideCommands() { - const { openGeneralSidebar } = unlock( useDispatch( editSiteStore ) ); - const { params } = useLocation(); - const { canvas = 'view' } = params; - const { set } = useDispatch( preferencesStore ); +const getGlobalStylesToggleWelcomeGuideCommands = () => + function useGlobalStylesToggleWelcomeGuideCommands() { + const { openGeneralSidebar } = unlock( useDispatch( editSiteStore ) ); + const { params } = useLocation(); + const { canvas = 'view' } = params; + const { set } = useDispatch( preferencesStore ); - const history = useHistory(); - const isBlockBasedTheme = useSelect( ( select ) => { - return select( coreStore ).getCurrentTheme().is_block_theme; - }, [] ); + const history = useHistory(); + const isBlockBasedTheme = useSelect( ( select ) => { + return select( coreStore ).getCurrentTheme().is_block_theme; + }, [] ); - const commands = useMemo( () => { - if ( ! isBlockBasedTheme ) { - return []; - } + const commands = useMemo( () => { + if ( ! isBlockBasedTheme ) { + return []; + } - return [ - { - name: 'core/edit-site/toggle-styles-welcome-guide', - label: __( 'Learn about styles' ), - callback: ( { close } ) => { - close(); - if ( ! params.postId ) { - history.push( { - path: '/wp_global_styles', - canvas: 'edit', - } ); - } - if ( params.postId && canvas !== 'edit' ) { - history.push( - { - ...params, + return [ + { + name: 'core/edit-site/toggle-styles-welcome-guide', + label: __( 'Learn about styles' ), + callback: ( { close } ) => { + close(); + if ( ! params.postId ) { + history.push( { + path: '/wp_global_styles', canvas: 'edit', - }, - undefined, - { - transition: 'canvas-mode-edit-transition', - } - ); - } - openGeneralSidebar( 'edit-site/global-styles' ); - set( 'core/edit-site', 'welcomeGuideStyles', true ); - // sometimes there's a focus loss that happens after some time - // that closes the modal, we need to force reopening it. - setTimeout( () => { + } ); + } + if ( params.postId && canvas !== 'edit' ) { + history.push( + { + ...params, + canvas: 'edit', + }, + undefined, + { + transition: 'canvas-mode-edit-transition', + } + ); + } + openGeneralSidebar( 'edit-site/global-styles' ); set( 'core/edit-site', 'welcomeGuideStyles', true ); - }, 500 ); + // sometimes there's a focus loss that happens after some time + // that closes the modal, we need to force reopening it. + setTimeout( () => { + set( 'core/edit-site', 'welcomeGuideStyles', true ); + }, 500 ); + }, + icon: help, }, - icon: help, - }, - ]; - }, [ - history, - openGeneralSidebar, - canvas, - isBlockBasedTheme, - set, - params, - ] ); + ]; + }, [ + history, + openGeneralSidebar, + canvas, + isBlockBasedTheme, + set, + params, + ] ); - return { - isLoading: false, - commands, + return { + isLoading: false, + commands, + }; }; -} -function useGlobalStylesResetCommands() { - const [ canReset, onReset ] = useGlobalStylesReset(); - const commands = useMemo( () => { - if ( ! canReset ) { - return []; - } +const getGlobalStylesResetCommands = () => + function useGlobalStylesResetCommands() { + const [ canReset, onReset ] = useGlobalStylesReset(); + const commands = useMemo( () => { + if ( ! canReset ) { + return []; + } - return [ - { - name: 'core/edit-site/reset-global-styles', - label: __( 'Reset styles' ), - icon: isRTL() ? rotateRight : rotateLeft, - callback: ( { close } ) => { - close(); - onReset(); + return [ + { + name: 'core/edit-site/reset-global-styles', + label: __( 'Reset styles' ), + icon: isRTL() ? rotateRight : rotateLeft, + callback: ( { close } ) => { + close(); + onReset(); + }, }, - }, - ]; - }, [ canReset, onReset ] ); + ]; + }, [ canReset, onReset ] ); - return { - isLoading: false, - commands, + return { + isLoading: false, + commands, + }; }; -} -function useGlobalStylesOpenCssCommands() { - const { openGeneralSidebar, setEditorCanvasContainerView } = unlock( - useDispatch( editSiteStore ) - ); - const { params } = useLocation(); - const { canvas = 'view' } = params; - const history = useHistory(); - const { canEditCSS } = useSelect( ( select ) => { - const { getEntityRecord, __experimentalGetCurrentGlobalStylesId } = - select( coreStore ); +const getGlobalStylesOpenCssCommands = () => + function useGlobalStylesOpenCssCommands() { + const { openGeneralSidebar, setEditorCanvasContainerView } = unlock( + useDispatch( editSiteStore ) + ); + const { params } = useLocation(); + const { canvas = 'view' } = params; + const history = useHistory(); + const { canEditCSS } = useSelect( ( select ) => { + const { getEntityRecord, __experimentalGetCurrentGlobalStylesId } = + select( coreStore ); - const globalStylesId = __experimentalGetCurrentGlobalStylesId(); - const globalStyles = globalStylesId - ? getEntityRecord( 'root', 'globalStyles', globalStylesId ) - : undefined; + const globalStylesId = __experimentalGetCurrentGlobalStylesId(); + const globalStyles = globalStylesId + ? getEntityRecord( 'root', 'globalStyles', globalStylesId ) + : undefined; - return { - canEditCSS: !! globalStyles?._links?.[ 'wp:action-edit-css' ], - }; - }, [] ); + return { + canEditCSS: !! globalStyles?._links?.[ 'wp:action-edit-css' ], + }; + }, [] ); - const commands = useMemo( () => { - if ( ! canEditCSS ) { - return []; - } + const commands = useMemo( () => { + if ( ! canEditCSS ) { + return []; + } - return [ - { - name: 'core/edit-site/open-styles-css', - label: __( 'Customize CSS' ), - icon: brush, - callback: ( { close } ) => { - close(); - if ( ! params.postId ) { - history.push( { - path: '/wp_global_styles', - canvas: 'edit', - } ); - } - if ( params.postId && canvas !== 'edit' ) { - history.push( - { - ...params, + return [ + { + name: 'core/edit-site/open-styles-css', + label: __( 'Customize CSS' ), + icon: brush, + callback: ( { close } ) => { + close(); + if ( ! params.postId ) { + history.push( { + path: '/wp_global_styles', canvas: 'edit', - }, - undefined, - { - transition: 'canvas-mode-edit-transition', - } - ); - } - openGeneralSidebar( 'edit-site/global-styles' ); - setEditorCanvasContainerView( 'global-styles-css' ); + } ); + } + if ( params.postId && canvas !== 'edit' ) { + history.push( + { + ...params, + canvas: 'edit', + }, + undefined, + { + transition: 'canvas-mode-edit-transition', + } + ); + } + openGeneralSidebar( 'edit-site/global-styles' ); + setEditorCanvasContainerView( 'global-styles-css' ); + }, }, - }, - ]; - }, [ - history, - openGeneralSidebar, - setEditorCanvasContainerView, - canEditCSS, - canvas, - params, - ] ); - return { - isLoading: false, - commands, + ]; + }, [ + history, + openGeneralSidebar, + setEditorCanvasContainerView, + canEditCSS, + canvas, + params, + ] ); + return { + isLoading: false, + commands, + }; }; -} -function useGlobalStylesOpenRevisionsCommands() { - const { openGeneralSidebar, setEditorCanvasContainerView } = unlock( - useDispatch( editSiteStore ) - ); - const { params } = useLocation(); - const { canvas = 'view' } = params; - const history = useHistory(); - const hasRevisions = useSelect( ( select ) => { - const { getEntityRecord, __experimentalGetCurrentGlobalStylesId } = - select( coreStore ); - const globalStylesId = __experimentalGetCurrentGlobalStylesId(); - const globalStyles = globalStylesId - ? getEntityRecord( 'root', 'globalStyles', globalStylesId ) - : undefined; - return !! globalStyles?._links?.[ 'version-history' ]?.[ 0 ]?.count; - }, [] ); +const getGlobalStylesOpenRevisionsCommands = () => + function useGlobalStylesOpenRevisionsCommands() { + const { openGeneralSidebar, setEditorCanvasContainerView } = unlock( + useDispatch( editSiteStore ) + ); + const { params } = useLocation(); + const { canvas = 'view' } = params; + const history = useHistory(); + const hasRevisions = useSelect( ( select ) => { + const { getEntityRecord, __experimentalGetCurrentGlobalStylesId } = + select( coreStore ); + const globalStylesId = __experimentalGetCurrentGlobalStylesId(); + const globalStyles = globalStylesId + ? getEntityRecord( 'root', 'globalStyles', globalStylesId ) + : undefined; + return !! globalStyles?._links?.[ 'version-history' ]?.[ 0 ]?.count; + }, [] ); - const commands = useMemo( () => { - if ( ! hasRevisions ) { - return []; - } + const commands = useMemo( () => { + if ( ! hasRevisions ) { + return []; + } - return [ - { - name: 'core/edit-site/open-global-styles-revisions', - label: __( 'Style revisions' ), - icon: backup, - callback: ( { close } ) => { - close(); - if ( ! params.postId ) { - history.push( { - path: '/wp_global_styles', - canvas: 'edit', - } ); - } - if ( params.postId && canvas !== 'edit' ) { - history.push( - { - ...params, + return [ + { + name: 'core/edit-site/open-global-styles-revisions', + label: __( 'Style revisions' ), + icon: backup, + callback: ( { close } ) => { + close(); + if ( ! params.postId ) { + history.push( { + path: '/wp_global_styles', canvas: 'edit', - }, - undefined, - { - transition: 'canvas-mode-edit-transition', - } + } ); + } + if ( params.postId && canvas !== 'edit' ) { + history.push( + { + ...params, + canvas: 'edit', + }, + undefined, + { + transition: 'canvas-mode-edit-transition', + } + ); + } + openGeneralSidebar( 'edit-site/global-styles' ); + setEditorCanvasContainerView( + 'global-styles-revisions' ); - } - openGeneralSidebar( 'edit-site/global-styles' ); - setEditorCanvasContainerView( 'global-styles-revisions' ); + }, }, - }, - ]; - }, [ - hasRevisions, - history, - openGeneralSidebar, - setEditorCanvasContainerView, - canvas, - params, - ] ); + ]; + }, [ + hasRevisions, + history, + openGeneralSidebar, + setEditorCanvasContainerView, + canvas, + params, + ] ); - return { - isLoading: false, - commands, + return { + isLoading: false, + commands, + }; }; -} export function useCommonCommands() { const homeUrl = useSelect( ( select ) => { @@ -324,26 +331,26 @@ export function useCommonCommands() { useCommandLoader( { name: 'core/edit-site/open-styles', - hook: useGlobalStylesOpenStylesCommands, + hook: getGlobalStylesOpenStylesCommands(), } ); useCommandLoader( { name: 'core/edit-site/toggle-styles-welcome-guide', - hook: useGlobalStylesToggleWelcomeGuideCommands, + hook: getGlobalStylesToggleWelcomeGuideCommands(), } ); useCommandLoader( { name: 'core/edit-site/reset-global-styles', - hook: useGlobalStylesResetCommands, + hook: getGlobalStylesResetCommands(), } ); useCommandLoader( { name: 'core/edit-site/open-styles-css', - hook: useGlobalStylesOpenCssCommands, + hook: getGlobalStylesOpenCssCommands(), } ); useCommandLoader( { name: 'core/edit-site/open-styles-revisions', - hook: useGlobalStylesOpenRevisionsCommands, + hook: getGlobalStylesOpenRevisionsCommands(), } ); } diff --git a/packages/edit-site/src/hooks/commands/use-edit-mode-commands.js b/packages/edit-site/src/hooks/commands/use-edit-mode-commands.js index 97283044193892..da36f32e6c0d51 100644 --- a/packages/edit-site/src/hooks/commands/use-edit-mode-commands.js +++ b/packages/edit-site/src/hooks/commands/use-edit-mode-commands.js @@ -22,147 +22,152 @@ import { useLink } from '../../components/routes/link'; const { useHistory, useLocation } = unlock( routerPrivateApis ); -function usePageContentFocusCommands() { - const { record: template } = useEditedEntityRecord(); - const { params } = useLocation(); - const { canvas = 'view' } = params; - const { isPage, templateId, currentPostType } = useSelect( ( select ) => { - const { isPage: _isPage } = unlock( select( editSiteStore ) ); - const { getCurrentPostType, getCurrentTemplateId } = - select( editorStore ); - return { - isPage: _isPage(), - templateId: getCurrentTemplateId(), - currentPostType: getCurrentPostType(), - }; - }, [] ); - - const { onClick: editTemplate } = useLink( { - postType: 'wp_template', - postId: templateId, - } ); - - const { setRenderingMode } = useDispatch( editorStore ); - - if ( ! isPage || canvas !== 'edit' ) { - return { isLoading: false, commands: [] }; - } - - const commands = []; - - if ( currentPostType !== 'wp_template' ) { - commands.push( { - name: 'core/switch-to-template-focus', - label: sprintf( - /* translators: %s: template title */ - __( 'Edit template: %s' ), - decodeEntities( template.title ) - ), - icon: layout, - callback: ( { close } ) => { - editTemplate(); - close(); - }, - } ); - } else { - commands.push( { - name: 'core/switch-to-page-focus', - label: __( 'Back to page' ), - icon: page, - callback: ( { close } ) => { - setRenderingMode( 'template-locked' ); - close(); +const getPageContentFocusCommands = () => + function usePageContentFocusCommands() { + const { record: template } = useEditedEntityRecord(); + const { params } = useLocation(); + const { canvas = 'view' } = params; + const { isPage, templateId, currentPostType } = useSelect( + ( select ) => { + const { isPage: _isPage } = unlock( select( editSiteStore ) ); + const { getCurrentPostType, getCurrentTemplateId } = + select( editorStore ); + return { + isPage: _isPage(), + templateId: getCurrentTemplateId(), + currentPostType: getCurrentPostType(), + }; }, + [] + ); + + const { onClick: editTemplate } = useLink( { + postType: 'wp_template', + postId: templateId, } ); - } - return { isLoading: false, commands }; -} + const { setRenderingMode } = useDispatch( editorStore ); + + if ( ! isPage || canvas !== 'edit' ) { + return { isLoading: false, commands: [] }; + } + + const commands = []; + + if ( currentPostType !== 'wp_template' ) { + commands.push( { + name: 'core/switch-to-template-focus', + label: sprintf( + /* translators: %s: template title */ + __( 'Edit template: %s' ), + decodeEntities( template.title ) + ), + icon: layout, + callback: ( { close } ) => { + editTemplate(); + close(); + }, + } ); + } else { + commands.push( { + name: 'core/switch-to-page-focus', + label: __( 'Back to page' ), + icon: page, + callback: ( { close } ) => { + setRenderingMode( 'template-locked' ); + close(); + }, + } ); + } + + return { isLoading: false, commands }; + }; -function useManipulateDocumentCommands() { - const { isLoaded, record: template } = useEditedEntityRecord(); - const { removeTemplate, revertTemplate } = useDispatch( editSiteStore ); - const history = useHistory(); - const isEditingPage = useSelect( - ( select ) => - select( editSiteStore ).isPage() && - select( editorStore ).getCurrentPostType() !== 'wp_template', - [] - ); - - if ( ! isLoaded ) { - return { isLoading: true, commands: [] }; - } - - const commands = []; - - if ( isTemplateRevertable( template ) && ! isEditingPage ) { - const label = - template.type === TEMPLATE_POST_TYPE - ? sprintf( - /* translators: %s: template title */ - __( 'Reset template: %s' ), - decodeEntities( template.title ) - ) - : sprintf( - /* translators: %s: template part title */ - __( 'Reset template part: %s' ), - decodeEntities( template.title ) - ); - commands.push( { - name: 'core/reset-template', - label, - icon: isRTL() ? rotateRight : rotateLeft, - callback: ( { close } ) => { - revertTemplate( template ); - close(); - }, - } ); - } - - if ( isTemplateRemovable( template ) && ! isEditingPage ) { - const label = - template.type === TEMPLATE_POST_TYPE - ? sprintf( - /* translators: %s: template title */ - __( 'Delete template: %s' ), - decodeEntities( template.title ) - ) - : sprintf( - /* translators: %s: template part title */ - __( 'Delete template part: %s' ), - decodeEntities( template.title ) - ); - commands.push( { - name: 'core/remove-template', - label, - icon: trash, - callback: ( { close } ) => { - removeTemplate( template ); - // Navigate to the template list - history.push( { - postType: template.type, - } ); - close(); - }, - } ); - } +const getManipulateDocumentCommands = () => + function useManipulateDocumentCommands() { + const { isLoaded, record: template } = useEditedEntityRecord(); + const { removeTemplate, revertTemplate } = useDispatch( editSiteStore ); + const history = useHistory(); + const isEditingPage = useSelect( + ( select ) => + select( editSiteStore ).isPage() && + select( editorStore ).getCurrentPostType() !== 'wp_template', + [] + ); + + if ( ! isLoaded ) { + return { isLoading: true, commands: [] }; + } + + const commands = []; + + if ( isTemplateRevertable( template ) && ! isEditingPage ) { + const label = + template.type === TEMPLATE_POST_TYPE + ? sprintf( + /* translators: %s: template title */ + __( 'Reset template: %s' ), + decodeEntities( template.title ) + ) + : sprintf( + /* translators: %s: template part title */ + __( 'Reset template part: %s' ), + decodeEntities( template.title ) + ); + commands.push( { + name: 'core/reset-template', + label, + icon: isRTL() ? rotateRight : rotateLeft, + callback: ( { close } ) => { + revertTemplate( template ); + close(); + }, + } ); + } + + if ( isTemplateRemovable( template ) && ! isEditingPage ) { + const label = + template.type === TEMPLATE_POST_TYPE + ? sprintf( + /* translators: %s: template title */ + __( 'Delete template: %s' ), + decodeEntities( template.title ) + ) + : sprintf( + /* translators: %s: template part title */ + __( 'Delete template part: %s' ), + decodeEntities( template.title ) + ); + commands.push( { + name: 'core/remove-template', + label, + icon: trash, + callback: ( { close } ) => { + removeTemplate( template ); + // Navigate to the template list + history.push( { + postType: template.type, + } ); + close(); + }, + } ); + } - return { - isLoading: ! isLoaded, - commands, + return { + isLoading: ! isLoaded, + commands, + }; }; -} export function useEditModeCommands() { useCommandLoader( { name: 'core/edit-site/page-content-focus', - hook: usePageContentFocusCommands, + hook: getPageContentFocusCommands(), context: 'entity-edit', } ); useCommandLoader( { name: 'core/edit-site/manipulate-document', - hook: useManipulateDocumentCommands, + hook: getManipulateDocumentCommands(), } ); } diff --git a/packages/editor/src/components/commands/index.js b/packages/editor/src/components/commands/index.js index b4b9c05db256d7..16260bed3978fd 100644 --- a/packages/editor/src/components/commands/index.js +++ b/packages/editor/src/components/commands/index.js @@ -30,279 +30,287 @@ import { PATTERN_POST_TYPE } from '../../store/constants'; import { modalName as patternRenameModalName } from '../pattern-rename-modal'; import { modalName as patternDuplicateModalName } from '../pattern-duplicate-modal'; -function useEditorCommandLoader() { - const { - editorMode, - isListViewOpen, - showBlockBreadcrumbs, - isDistractionFree, - isFocusMode, - isPreviewMode, - isViewable, - isCodeEditingEnabled, - isRichEditingEnabled, - isPublishSidebarEnabled, - } = useSelect( ( select ) => { - const { get } = select( preferencesStore ); - const { isListViewOpened, getCurrentPostType, getEditorSettings } = - select( editorStore ); - const { getSettings } = select( blockEditorStore ); - const { getPostType } = select( coreStore ); +const getEditorCommandLoader = () => + function useEditorCommandLoader() { + const { + editorMode, + isListViewOpen, + showBlockBreadcrumbs, + isDistractionFree, + isFocusMode, + isPreviewMode, + isViewable, + isCodeEditingEnabled, + isRichEditingEnabled, + isPublishSidebarEnabled, + } = useSelect( ( select ) => { + const { get } = select( preferencesStore ); + const { isListViewOpened, getCurrentPostType, getEditorSettings } = + select( editorStore ); + const { getSettings } = select( blockEditorStore ); + const { getPostType } = select( coreStore ); - return { - editorMode: get( 'core', 'editorMode' ) ?? 'visual', - isListViewOpen: isListViewOpened(), - showBlockBreadcrumbs: get( 'core', 'showBlockBreadcrumbs' ), - isDistractionFree: get( 'core', 'distractionFree' ), - isFocusMode: get( 'core', 'focusMode' ), - isPreviewMode: getSettings().isPreviewMode, - isViewable: getPostType( getCurrentPostType() )?.viewable ?? false, - isCodeEditingEnabled: getEditorSettings().codeEditingEnabled, - isRichEditingEnabled: getEditorSettings().richEditingEnabled, - isPublishSidebarEnabled: - select( editorStore ).isPublishSidebarEnabled(), - }; - }, [] ); - const { getActiveComplementaryArea } = useSelect( interfaceStore ); - const { toggle } = useDispatch( preferencesStore ); - const { createInfoNotice } = useDispatch( noticesStore ); - const { - __unstableSaveForPreview, - setIsListViewOpened, - switchEditorMode, - toggleDistractionFree, - toggleSpotlightMode, - toggleTopToolbar, - } = useDispatch( editorStore ); - const { openModal, enableComplementaryArea, disableComplementaryArea } = - useDispatch( interfaceStore ); - const { getCurrentPostId } = useSelect( editorStore ); - const allowSwitchEditorMode = isCodeEditingEnabled && isRichEditingEnabled; + return { + editorMode: get( 'core', 'editorMode' ) ?? 'visual', + isListViewOpen: isListViewOpened(), + showBlockBreadcrumbs: get( 'core', 'showBlockBreadcrumbs' ), + isDistractionFree: get( 'core', 'distractionFree' ), + isFocusMode: get( 'core', 'focusMode' ), + isPreviewMode: getSettings().isPreviewMode, + isViewable: + getPostType( getCurrentPostType() )?.viewable ?? false, + isCodeEditingEnabled: getEditorSettings().codeEditingEnabled, + isRichEditingEnabled: getEditorSettings().richEditingEnabled, + isPublishSidebarEnabled: + select( editorStore ).isPublishSidebarEnabled(), + }; + }, [] ); + const { getActiveComplementaryArea } = useSelect( interfaceStore ); + const { toggle } = useDispatch( preferencesStore ); + const { createInfoNotice } = useDispatch( noticesStore ); + const { + __unstableSaveForPreview, + setIsListViewOpened, + switchEditorMode, + toggleDistractionFree, + toggleSpotlightMode, + toggleTopToolbar, + } = useDispatch( editorStore ); + const { openModal, enableComplementaryArea, disableComplementaryArea } = + useDispatch( interfaceStore ); + const { getCurrentPostId } = useSelect( editorStore ); + const allowSwitchEditorMode = + isCodeEditingEnabled && isRichEditingEnabled; - if ( isPreviewMode ) { - return { commands: [], isLoading: false }; - } + if ( isPreviewMode ) { + return { commands: [], isLoading: false }; + } - const commands = []; + const commands = []; - commands.push( { - name: 'core/open-shortcut-help', - label: __( 'Keyboard shortcuts' ), - icon: keyboard, - callback: ( { close } ) => { - close(); - openModal( 'editor/keyboard-shortcut-help' ); - }, - } ); - - commands.push( { - name: 'core/toggle-distraction-free', - label: isDistractionFree - ? __( 'Exit Distraction free' ) - : __( 'Enter Distraction free' ), - callback: ( { close } ) => { - toggleDistractionFree(); - close(); - }, - } ); - - commands.push( { - name: 'core/open-preferences', - label: __( 'Editor preferences' ), - callback: ( { close } ) => { - close(); - openModal( 'editor/preferences' ); - }, - } ); - - commands.push( { - name: 'core/toggle-spotlight-mode', - label: isFocusMode - ? __( 'Exit Spotlight mode' ) - : __( 'Enter Spotlight mode' ), - callback: ( { close } ) => { - toggleSpotlightMode(); - close(); - }, - } ); - - commands.push( { - name: 'core/toggle-list-view', - label: isListViewOpen - ? __( 'Close List View' ) - : __( 'Open List View' ), - icon: listView, - callback: ( { close } ) => { - setIsListViewOpened( ! isListViewOpen ); - close(); - createInfoNotice( - isListViewOpen ? __( 'List View off.' ) : __( 'List View on.' ), - { - id: 'core/editor/toggle-list-view/notice', - type: 'snackbar', - } - ); - }, - } ); + commands.push( { + name: 'core/open-shortcut-help', + label: __( 'Keyboard shortcuts' ), + icon: keyboard, + callback: ( { close } ) => { + close(); + openModal( 'editor/keyboard-shortcut-help' ); + }, + } ); - commands.push( { - name: 'core/toggle-top-toolbar', - label: __( 'Top toolbar' ), - callback: ( { close } ) => { - toggleTopToolbar(); - close(); - }, - } ); + commands.push( { + name: 'core/toggle-distraction-free', + label: isDistractionFree + ? __( 'Exit Distraction free' ) + : __( 'Enter Distraction free' ), + callback: ( { close } ) => { + toggleDistractionFree(); + close(); + }, + } ); - if ( allowSwitchEditorMode ) { commands.push( { - name: 'core/toggle-code-editor', - label: - editorMode === 'visual' - ? __( 'Open code editor' ) - : __( 'Exit code editor' ), - icon: code, + name: 'core/open-preferences', + label: __( 'Editor preferences' ), callback: ( { close } ) => { - switchEditorMode( editorMode === 'visual' ? 'text' : 'visual' ); close(); + openModal( 'editor/preferences' ); }, } ); - } - commands.push( { - name: 'core/toggle-breadcrumbs', - label: showBlockBreadcrumbs - ? __( 'Hide block breadcrumbs' ) - : __( 'Show block breadcrumbs' ), - callback: ( { close } ) => { - toggle( 'core', 'showBlockBreadcrumbs' ); - close(); - createInfoNotice( - showBlockBreadcrumbs - ? __( 'Breadcrumbs hidden.' ) - : __( 'Breadcrumbs visible.' ), - { - id: 'core/editor/toggle-breadcrumbs/notice', - type: 'snackbar', - } - ); - }, - } ); + commands.push( { + name: 'core/toggle-spotlight-mode', + label: isFocusMode + ? __( 'Exit Spotlight mode' ) + : __( 'Enter Spotlight mode' ), + callback: ( { close } ) => { + toggleSpotlightMode(); + close(); + }, + } ); - commands.push( { - name: 'core/open-settings-sidebar', - label: __( 'Show or hide the Settings panel.' ), - icon: isRTL() ? drawerLeft : drawerRight, - callback: ( { close } ) => { - const activeSidebar = getActiveComplementaryArea( 'core' ); - close(); - if ( activeSidebar === 'edit-post/document' ) { - disableComplementaryArea( 'core' ); - } else { - enableComplementaryArea( 'core', 'edit-post/document' ); - } - }, - } ); + commands.push( { + name: 'core/toggle-list-view', + label: isListViewOpen + ? __( 'Close List View' ) + : __( 'Open List View' ), + icon: listView, + callback: ( { close } ) => { + setIsListViewOpened( ! isListViewOpen ); + close(); + createInfoNotice( + isListViewOpen + ? __( 'List View off.' ) + : __( 'List View on.' ), + { + id: 'core/editor/toggle-list-view/notice', + type: 'snackbar', + } + ); + }, + } ); - commands.push( { - name: 'core/open-block-inspector', - label: __( 'Show or hide the Block settings panel' ), - icon: blockDefault, - callback: ( { close } ) => { - const activeSidebar = getActiveComplementaryArea( 'core' ); - close(); - if ( activeSidebar === 'edit-post/block' ) { - disableComplementaryArea( 'core' ); - } else { - enableComplementaryArea( 'core', 'edit-post/block' ); - } - }, - } ); + commands.push( { + name: 'core/toggle-top-toolbar', + label: __( 'Top toolbar' ), + callback: ( { close } ) => { + toggleTopToolbar(); + close(); + }, + } ); - commands.push( { - name: 'core/toggle-publish-sidebar', - label: isPublishSidebarEnabled - ? __( 'Disable pre-publish checks' ) - : __( 'Enable pre-publish checks' ), - icon: formatListBullets, - callback: ( { close } ) => { - close(); - toggle( 'core', 'isPublishSidebarEnabled' ); - createInfoNotice( - isPublishSidebarEnabled - ? __( 'Pre-publish checks disabled.' ) - : __( 'Pre-publish checks enabled.' ), - { - id: 'core/editor/publish-sidebar/notice', - type: 'snackbar', - } - ); - }, - } ); + if ( allowSwitchEditorMode ) { + commands.push( { + name: 'core/toggle-code-editor', + label: + editorMode === 'visual' + ? __( 'Open code editor' ) + : __( 'Exit code editor' ), + icon: code, + callback: ( { close } ) => { + switchEditorMode( + editorMode === 'visual' ? 'text' : 'visual' + ); + close(); + }, + } ); + } - if ( isViewable ) { commands.push( { - name: 'core/preview-link', - label: __( 'Preview in a new tab' ), - icon: external, - callback: async ( { close } ) => { + name: 'core/toggle-breadcrumbs', + label: showBlockBreadcrumbs + ? __( 'Hide block breadcrumbs' ) + : __( 'Show block breadcrumbs' ), + callback: ( { close } ) => { + toggle( 'core', 'showBlockBreadcrumbs' ); close(); - const postId = getCurrentPostId(); - const link = await __unstableSaveForPreview(); - window.open( link, `wp-preview-${ postId }` ); + createInfoNotice( + showBlockBreadcrumbs + ? __( 'Breadcrumbs hidden.' ) + : __( 'Breadcrumbs visible.' ), + { + id: 'core/editor/toggle-breadcrumbs/notice', + type: 'snackbar', + } + ); }, } ); - } - - return { - commands, - isLoading: false, - }; -} -function useEditedEntityContextualCommands() { - const { postType } = useSelect( ( select ) => { - const { getCurrentPostType } = select( editorStore ); - return { - postType: getCurrentPostType(), - }; - }, [] ); - const { openModal } = useDispatch( interfaceStore ); - const commands = []; + commands.push( { + name: 'core/open-settings-sidebar', + label: __( 'Show or hide the Settings panel.' ), + icon: isRTL() ? drawerLeft : drawerRight, + callback: ( { close } ) => { + const activeSidebar = getActiveComplementaryArea( 'core' ); + close(); + if ( activeSidebar === 'edit-post/document' ) { + disableComplementaryArea( 'core' ); + } else { + enableComplementaryArea( 'core', 'edit-post/document' ); + } + }, + } ); - if ( postType === PATTERN_POST_TYPE ) { commands.push( { - name: 'core/rename-pattern', - label: __( 'Rename pattern' ), - icon: edit, + name: 'core/open-block-inspector', + label: __( 'Show or hide the Block settings panel' ), + icon: blockDefault, callback: ( { close } ) => { - openModal( patternRenameModalName ); + const activeSidebar = getActiveComplementaryArea( 'core' ); close(); + if ( activeSidebar === 'edit-post/block' ) { + disableComplementaryArea( 'core' ); + } else { + enableComplementaryArea( 'core', 'edit-post/block' ); + } }, } ); + commands.push( { - name: 'core/duplicate-pattern', - label: __( 'Duplicate pattern' ), - icon: symbol, + name: 'core/toggle-publish-sidebar', + label: isPublishSidebarEnabled + ? __( 'Disable pre-publish checks' ) + : __( 'Enable pre-publish checks' ), + icon: formatListBullets, callback: ( { close } ) => { - openModal( patternDuplicateModalName ); close(); + toggle( 'core', 'isPublishSidebarEnabled' ); + createInfoNotice( + isPublishSidebarEnabled + ? __( 'Pre-publish checks disabled.' ) + : __( 'Pre-publish checks enabled.' ), + { + id: 'core/editor/publish-sidebar/notice', + type: 'snackbar', + } + ); }, } ); - } - return { isLoading: false, commands }; -} + if ( isViewable ) { + commands.push( { + name: 'core/preview-link', + label: __( 'Preview in a new tab' ), + icon: external, + callback: async ( { close } ) => { + close(); + const postId = getCurrentPostId(); + const link = await __unstableSaveForPreview(); + window.open( link, `wp-preview-${ postId }` ); + }, + } ); + } + + return { + commands, + isLoading: false, + }; + }; + +const getEditedEntityContextualCommands = () => + function useEditedEntityContextualCommands() { + const { postType } = useSelect( ( select ) => { + const { getCurrentPostType } = select( editorStore ); + return { + postType: getCurrentPostType(), + }; + }, [] ); + const { openModal } = useDispatch( interfaceStore ); + const commands = []; + + if ( postType === PATTERN_POST_TYPE ) { + commands.push( { + name: 'core/rename-pattern', + label: __( 'Rename pattern' ), + icon: edit, + callback: ( { close } ) => { + openModal( patternRenameModalName ); + close(); + }, + } ); + commands.push( { + name: 'core/duplicate-pattern', + label: __( 'Duplicate pattern' ), + icon: symbol, + callback: ( { close } ) => { + openModal( patternDuplicateModalName ); + close(); + }, + } ); + } + + return { isLoading: false, commands }; + }; export default function useCommands() { useCommandLoader( { name: 'core/editor/edit-ui', - hook: useEditorCommandLoader, + hook: getEditorCommandLoader(), } ); useCommandLoader( { name: 'core/editor/contextual-commands', - hook: useEditedEntityContextualCommands, + hook: getEditedEntityContextualCommands(), context: 'entity-edit', } ); } From f15b4c19175da72843234cc6c862296ce9a4dcf8 Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Thu, 7 Nov 2024 09:55:42 +0100 Subject: [PATCH 004/226] Fix inconsistent sidebars close buttons sizes (#66756) * Increase complementary area and tabbed sidebar X close button size. * Adjust widgets header actions right padding and gap. * Adjust edit widgets list view X close button size. Co-authored-by: afercia Co-authored-by: mikachan Co-authored-by: richtabor Co-authored-by: t-hamano Co-authored-by: jameskoster --- .../block-editor/src/components/tabbed-sidebar/index.js | 2 +- .../block-editor/src/components/tabbed-sidebar/style.scss | 2 +- packages/edit-widgets/src/components/header/style.scss | 7 ++++--- .../src/components/secondary-sidebar/list-view-sidebar.js | 2 +- .../src/components/secondary-sidebar/style.scss | 2 +- packages/editor/src/components/sidebar/style.scss | 4 +--- .../src/components/complementary-area-header/style.scss | 4 ++-- .../interface/src/components/complementary-area/index.js | 2 +- 8 files changed, 12 insertions(+), 13 deletions(-) diff --git a/packages/block-editor/src/components/tabbed-sidebar/index.js b/packages/block-editor/src/components/tabbed-sidebar/index.js index a0cb510c720904..c9ff6bbf6555f0 100644 --- a/packages/block-editor/src/components/tabbed-sidebar/index.js +++ b/packages/block-editor/src/components/tabbed-sidebar/index.js @@ -33,7 +33,7 @@ function TabbedSidebar( icon={ closeSmall } label={ closeButtonLabel } onClick={ () => onClose() } - size="small" + size="compact" /> { __( 'List View' ) } + + ) + } +]; +``` #### `paginationInfo`: `Object` @@ -502,6 +533,164 @@ Parameters: Returns a boolean indicating if the item is valid (true) or not (false). +## Actions API + +### `id` + +The unique identifier of the action. + +- Type: `string` +- Required +- Example: `move-to-trash` + +### `label` + +The user facing description of the action. + +- Type: `string | function` +- Required +- Example: + +```js +{ + label: Move to Trash +} +``` + +or + +```js +{ + label: ( items ) => items.length > 1 ? 'Delete items' : 'Delete item' +} +``` + +### `isPrimary` + +Whether the action should be displayed inline (primary) or only displayed in the "More actions" menu (secondary). + +- Type: `boolean` +- Optional + +### `icon` + +Icon to show for primary actions. + +- Type: SVG element +- Required for primary actions, optional for secondary actions. + +### `isEligible` + +Function that determines whether the action can be performed for a given record. + +- Type: `function` +- Optional. If not present, action is considered eligible for all items. +- Example: + +```js +{ + isEligible: ( item ) => item.status === 'published' +} +``` + +### `isDestructive` + +Whether the action can delete data, in which case the UI communicates it via a red color. + +- Type: `boolean` +- Optional + +### `supportsBulk` + +Whether the action can operate over multiple items at once. + +- Type: `boolean` +- Optional +- Default: `false` + +### `disabled` + +Whether the action is disabled. + +- Type: `boolean` +- Optional +- Default: `false` + +### `context` + +Where this action would be visible. + +- Type: `string` +- Optional +- One of: `list`, `single` + +### `callback` + +Function that performs the required action. + +- Type: `function` +- Either `callback` or `RenderModal` must be provided. If `RenderModal` is provided, `callback` will be ignored +- Example: + +```js +{ + callback: ( items, { onActionPerformed } ) => { + // Perform action. + onActionPerformed?.( items ); + } +} +``` + +### `RenderModal` + +Component to render UI in a modal for the action. + +- Type: `ReactElement` +- Either `callback` or `RenderModal` must be provided. If `RenderModal` is provided, `callback` will be ignored. +- Example: + +```jsx +{ + RenderModal: ( { items, closeModal, onActionPerformed } ) => { + const onSubmit = ( event ) => { + event.preventDefault(); + // Perform action. + closeModal?.(); + onActionPerformed?.( items ); + }; + return ( +
+

Modal UI

+ + + + +
+ ); + } +} +``` + +### `hideModalHeader` + +Controls visibility of the modal's header when using `RenderModal`. + +- Type: `boolean` +- Optional +- When false and using `RenderModal`, the action's label is used in modal header + +### `modalHeader` + +The header text to show in the modal. + +- Type: `string` +- Optional + + ## Fields API ### `id` From ebf1149eec2db05127bfe307974b0c409bf892ec Mon Sep 17 00:00:00 2001 From: Carlos Bravo <37012961+cbravobernal@users.noreply.github.com> Date: Wed, 20 Nov 2024 14:11:12 +0100 Subject: [PATCH 145/226] `FormFileUpload`: Prevent HEIC and HEIF files from being uploaded on Safari (#67139) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Revert "Ensure HEIC files selectable from “Upload” button (#66292)" This reverts commit c5921d766c143ef6774c827c8c2f6322b2b26b6b. * Update changelog * Make it Safari conditional * Remove extra whitespaces * Update changelog * Use globalthis * Forgot a # * Make it safer Co-authored-by: cbravobernal Co-authored-by: mirka <0mirka00@git.wordpress.org> Co-authored-by: azaozz Co-authored-by: desrosj Co-authored-by: Mamaduka Co-authored-by: jsnajdr --- packages/components/CHANGELOG.md | 4 ++++ packages/components/src/form-file-upload/index.tsx | 12 +++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 0638842814a7d3..b84b720e35c900 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Bug Fixes + +- `FormFileUpload`: Prevent HEIC and HEIF files from being uploaded on Safari ([#67139](https://github.com/WordPress/gutenberg/pull/67139)). + ### Deprecations - `DimensionControl`: Deprecate 36px default size ([#66705](https://github.com/WordPress/gutenberg/pull/66705)). diff --git a/packages/components/src/form-file-upload/index.tsx b/packages/components/src/form-file-upload/index.tsx index 66f0b2ea6d6480..83d563f2074764 100644 --- a/packages/components/src/form-file-upload/index.tsx +++ b/packages/components/src/form-file-upload/index.tsx @@ -50,9 +50,15 @@ export function FormFileUpload( { // @todo: Temporary fix a bug that prevents Chromium browsers from selecting ".heic" files // from the file upload. See https://core.trac.wordpress.org/ticket/62268#comment:4. // This can be removed once the Chromium fix is in the stable channel. - const compatAccept = !! accept?.includes( 'image/*' ) - ? `${ accept }, image/heic, image/heif` - : accept; + // Prevent Safari from adding "image/heic" and "image/heif" to the accept attribute. + const isSafari = + globalThis.window?.navigator.userAgent.includes( 'Safari' ) && + ! globalThis.window?.navigator.userAgent.includes( 'Chrome' ) && + ! globalThis.window?.navigator.userAgent.includes( 'Chromium' ); + const compatAccept = + ! isSafari && !! accept?.includes( 'image/*' ) + ? `${ accept }, image/heic, image/heif` + : accept; return (
From 944e6b8c04a017c50af3f8862c9120bd7c383d4e Mon Sep 17 00:00:00 2001 From: Jarda Snajdr Date: Wed, 20 Nov 2024 14:34:54 +0100 Subject: [PATCH 146/226] SlotFill: rewrite base Slot to functional, unify rerenderable refs (#67153) * SlotFill: rewrite base Slot to functional, unify rerenderable refs * Add changelog entry * Implement rerender with useReducer Co-authored-by: jsnajdr Co-authored-by: Mamaduka Co-authored-by: tyxla --- packages/components/CHANGELOG.md | 1 + .../src/slot-fill/bubbles-virtually/fill.tsx | 27 +--- .../bubbles-virtually/slot-fill-provider.tsx | 2 +- packages/components/src/slot-fill/fill.ts | 2 +- .../components/src/slot-fill/provider.tsx | 25 ++-- packages/components/src/slot-fill/slot.tsx | 133 +++++++----------- packages/components/src/slot-fill/types.ts | 69 ++------- 7 files changed, 78 insertions(+), 181 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index b84b720e35c900..e5d467f22d30c8 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -33,6 +33,7 @@ ### Internal - `SlotFill`: fix dependencies of `Fill` registration effects ([#67071](https://github.com/WordPress/gutenberg/pull/67071)). +- `SlotFill`: rewrite the `Slot` component from class component to functional ([#67153](https://github.com/WordPress/gutenberg/pull/67153)). ## 28.12.0 (2024-11-16) diff --git a/packages/components/src/slot-fill/bubbles-virtually/fill.tsx b/packages/components/src/slot-fill/bubbles-virtually/fill.tsx index b1b82aac5c0567..d5287adfab4178 100644 --- a/packages/components/src/slot-fill/bubbles-virtually/fill.tsx +++ b/packages/components/src/slot-fill/bubbles-virtually/fill.tsx @@ -4,8 +4,8 @@ import { useObservableValue } from '@wordpress/compose'; import { useContext, + useReducer, useRef, - useState, useEffect, createPortal, } from '@wordpress/element'; @@ -17,37 +17,20 @@ import SlotFillContext from './slot-fill-context'; import StyleProvider from '../../style-provider'; import type { FillComponentProps } from '../types'; -function useForceUpdate() { - const [ , setState ] = useState( {} ); - const mountedRef = useRef( true ); - - useEffect( () => { - mountedRef.current = true; - return () => { - mountedRef.current = false; - }; - }, [] ); - - return () => { - if ( mountedRef.current ) { - setState( {} ); - } - }; -} - export default function Fill( { name, children }: FillComponentProps ) { const registry = useContext( SlotFillContext ); const slot = useObservableValue( registry.slots, name ); - const rerender = useForceUpdate(); + const [ , rerender ] = useReducer( () => [], [] ); const ref = useRef( { rerender } ); useEffect( () => { // We register fills so we can keep track of their existence. // Some Slot implementations need to know if there're already fills // registered so they can choose to render themselves or not. - registry.registerFill( name, ref ); + const refValue = ref.current; + registry.registerFill( name, refValue ); return () => { - registry.unregisterFill( name, ref ); + registry.unregisterFill( name, refValue ); }; }, [ registry, name ] ); diff --git a/packages/components/src/slot-fill/bubbles-virtually/slot-fill-provider.tsx b/packages/components/src/slot-fill/bubbles-virtually/slot-fill-provider.tsx index 16a19c6569fda6..1dc5ef35ceccfe 100644 --- a/packages/components/src/slot-fill/bubbles-virtually/slot-fill-provider.tsx +++ b/packages/components/src/slot-fill/bubbles-virtually/slot-fill-provider.tsx @@ -70,7 +70,7 @@ function createSlotRegistry(): SlotFillBubblesVirtuallyContext { const slotFills = fills.get( name ); if ( slotFills ) { // Force update fills. - slotFills.forEach( ( fill ) => fill.current.rerender() ); + slotFills.forEach( ( fill ) => fill.rerender() ); } }; diff --git a/packages/components/src/slot-fill/fill.ts b/packages/components/src/slot-fill/fill.ts index b11b7af09b82f0..0a31c8276b3f10 100644 --- a/packages/components/src/slot-fill/fill.ts +++ b/packages/components/src/slot-fill/fill.ts @@ -29,7 +29,7 @@ export default function Fill( { name, children }: FillComponentProps ) { useLayoutEffect( () => { ref.current.children = children; if ( slot ) { - slot.forceUpdate(); + slot.rerender(); } }, [ slot, children ] ); diff --git a/packages/components/src/slot-fill/provider.tsx b/packages/components/src/slot-fill/provider.tsx index 6ed624bab67a3c..e2b98e73e1b707 100644 --- a/packages/components/src/slot-fill/provider.tsx +++ b/packages/components/src/slot-fill/provider.tsx @@ -1,7 +1,6 @@ /** * WordPress dependencies */ -import type { Component } from '@wordpress/element'; import { useState } from '@wordpress/element'; /** @@ -11,20 +10,17 @@ import SlotFillContext from './context'; import type { FillComponentProps, BaseSlotFillContext, - BaseSlotComponentProps, SlotFillProviderProps, SlotKey, + Rerenderable, } from './types'; function createSlotRegistry(): BaseSlotFillContext { - const slots: Record< SlotKey, Component< BaseSlotComponentProps > > = {}; + const slots: Record< SlotKey, Rerenderable > = {}; const fills: Record< SlotKey, FillComponentProps[] > = {}; let listeners: Array< () => void > = []; - function registerSlot( - name: SlotKey, - slot: Component< BaseSlotComponentProps > - ) { + function registerSlot( name: SlotKey, slot: Rerenderable ) { const previousSlot = slots[ name ]; slots[ name ] = slot; triggerListeners(); @@ -38,7 +34,7 @@ function createSlotRegistry(): BaseSlotFillContext { // assigned into the instance, such that its own rendering of children // will be empty (the new Slot will subsume all fills for this name). if ( previousSlot ) { - previousSlot.forceUpdate(); + previousSlot.rerender(); } } @@ -47,10 +43,7 @@ function createSlotRegistry(): BaseSlotFillContext { forceUpdateSlot( name ); } - function unregisterSlot( - name: SlotKey, - instance: Component< BaseSlotComponentProps > - ) { + function unregisterSlot( name: SlotKey, instance: Rerenderable ) { // If a previous instance of a Slot by this name unmounts, do nothing, // as the slot and its fills should only be removed for the current // known instance. @@ -68,15 +61,13 @@ function createSlotRegistry(): BaseSlotFillContext { forceUpdateSlot( name ); } - function getSlot( - name: SlotKey - ): Component< BaseSlotComponentProps > | undefined { + function getSlot( name: SlotKey ): Rerenderable | undefined { return slots[ name ]; } function getFills( name: SlotKey, - slotInstance: Component< BaseSlotComponentProps > + slotInstance: Rerenderable ): FillComponentProps[] { // Fills should only be returned for the current instance of the slot // in which they occupy. @@ -90,7 +81,7 @@ function createSlotRegistry(): BaseSlotFillContext { const slot = getSlot( name ); if ( slot ) { - slot.forceUpdate(); + slot.rerender(); } } diff --git a/packages/components/src/slot-fill/slot.tsx b/packages/components/src/slot-fill/slot.tsx index 3fe2a549359260..fe4a741ddbfbad 100644 --- a/packages/components/src/slot-fill/slot.tsx +++ b/packages/components/src/slot-fill/slot.tsx @@ -7,8 +7,11 @@ import type { ReactElement, ReactNode, Key } from 'react'; * WordPress dependencies */ import { + useContext, + useEffect, + useReducer, + useRef, Children, - Component, cloneElement, isEmptyElement, } from '@wordpress/element'; @@ -17,7 +20,7 @@ import { * Internal dependencies */ import SlotFillContext from './context'; -import type { BaseSlotComponentProps, SlotComponentProps } from './types'; +import type { SlotComponentProps } from './types'; /** * Whether the argument is a function. @@ -29,90 +32,50 @@ function isFunction( maybeFunc: any ): maybeFunc is Function { return typeof maybeFunc === 'function'; } -class SlotComponent extends Component< BaseSlotComponentProps > { - private isUnmounted: boolean; - - constructor( props: BaseSlotComponentProps ) { - super( props ); - - this.isUnmounted = false; - } - - componentDidMount() { - const { registerSlot } = this.props; - this.isUnmounted = false; - registerSlot( this.props.name, this ); - } - - componentWillUnmount() { - const { unregisterSlot } = this.props; - this.isUnmounted = true; - unregisterSlot( this.props.name, this ); - } - - componentDidUpdate( prevProps: BaseSlotComponentProps ) { - const { name, unregisterSlot, registerSlot } = this.props; - - if ( prevProps.name !== name ) { - unregisterSlot( prevProps.name, this ); - registerSlot( name, this ); - } - } - - forceUpdate() { - if ( this.isUnmounted ) { - return; - } - super.forceUpdate(); - } - - render() { - const { children, name, fillProps = {}, getFills } = this.props; - const fills: ReactNode[] = ( getFills( name, this ) ?? [] ) - .map( ( fill ) => { - const fillChildren = isFunction( fill.children ) - ? fill.children( fillProps ) - : fill.children; - return Children.map( fillChildren, ( child, childIndex ) => { - if ( ! child || typeof child === 'string' ) { - return child; - } - let childKey: Key = childIndex; - if ( - typeof child === 'object' && - 'key' in child && - child?.key - ) { - childKey = child.key; - } - - return cloneElement( child as ReactElement, { - key: childKey, - } ); +function Slot( props: Omit< SlotComponentProps, 'bubblesVirtually' > ) { + const registry = useContext( SlotFillContext ); + const [ , rerender ] = useReducer( () => [], [] ); + const ref = useRef( { rerender } ); + + const { name, children, fillProps = {} } = props; + + useEffect( () => { + const refValue = ref.current; + registry.registerSlot( name, refValue ); + return () => registry.unregisterSlot( name, refValue ); + }, [ registry, name ] ); + + const fills: ReactNode[] = ( registry.getFills( name, ref.current ) ?? [] ) + .map( ( fill ) => { + const fillChildren = isFunction( fill.children ) + ? fill.children( fillProps ) + : fill.children; + return Children.map( fillChildren, ( child, childIndex ) => { + if ( ! child || typeof child === 'string' ) { + return child; + } + let childKey: Key = childIndex; + if ( + typeof child === 'object' && + 'key' in child && + child?.key + ) { + childKey = child.key; + } + + return cloneElement( child as ReactElement, { + key: childKey, } ); - } ) - .filter( - // In some cases fills are rendered only when some conditions apply. - // This ensures that we only use non-empty fills when rendering, i.e., - // it allows us to render wrappers only when the fills are actually present. - ( element ) => ! isEmptyElement( element ) - ); - - return <>{ isFunction( children ) ? children( fills ) : fills }; - } + } ); + } ) + .filter( + // In some cases fills are rendered only when some conditions apply. + // This ensures that we only use non-empty fills when rendering, i.e., + // it allows us to render wrappers only when the fills are actually present. + ( element ) => ! isEmptyElement( element ) + ); + + return <>{ isFunction( children ) ? children( fills ) : fills }; } -const Slot = ( props: Omit< SlotComponentProps, 'bubblesVirtually' > ) => ( - - { ( { registerSlot, unregisterSlot, getFills } ) => ( - - ) } - -); - export default Slot; diff --git a/packages/components/src/slot-fill/types.ts b/packages/components/src/slot-fill/types.ts index 7e1b8b7e1f3f9f..15f082cf3f7552 100644 --- a/packages/components/src/slot-fill/types.ts +++ b/packages/components/src/slot-fill/types.ts @@ -1,7 +1,7 @@ /** * External dependencies */ -import type { Component, MutableRefObject, ReactNode, RefObject } from 'react'; +import type { ReactNode, RefObject } from 'react'; /** * WordPress dependencies @@ -108,42 +108,17 @@ export type SlotFillProviderProps = { passthrough?: boolean; }; -export type SlotFillBubblesVirtuallySlotRef = RefObject< HTMLElement >; -export type SlotFillBubblesVirtuallyFillRef = MutableRefObject< { - rerender: () => void; -} >; +export type SlotRef = RefObject< HTMLElement >; +export type Rerenderable = { rerender: () => void }; export type SlotFillBubblesVirtuallyContext = { - slots: ObservableMap< - SlotKey, - { - ref: SlotFillBubblesVirtuallySlotRef; - fillProps: FillProps; - } - >; - fills: ObservableMap< SlotKey, SlotFillBubblesVirtuallyFillRef[] >; - registerSlot: ( - name: SlotKey, - ref: SlotFillBubblesVirtuallySlotRef, - fillProps: FillProps - ) => void; - unregisterSlot: ( - name: SlotKey, - ref: SlotFillBubblesVirtuallySlotRef - ) => void; - updateSlot: ( - name: SlotKey, - ref: SlotFillBubblesVirtuallySlotRef, - fillProps: FillProps - ) => void; - registerFill: ( - name: SlotKey, - ref: SlotFillBubblesVirtuallyFillRef - ) => void; - unregisterFill: ( - name: SlotKey, - ref: SlotFillBubblesVirtuallyFillRef - ) => void; + slots: ObservableMap< SlotKey, { ref: SlotRef; fillProps: FillProps } >; + fills: ObservableMap< SlotKey, Rerenderable[] >; + registerSlot: ( name: SlotKey, ref: SlotRef, fillProps: FillProps ) => void; + unregisterSlot: ( name: SlotKey, ref: SlotRef ) => void; + updateSlot: ( name: SlotKey, ref: SlotRef, fillProps: FillProps ) => void; + registerFill: ( name: SlotKey, ref: Rerenderable ) => void; + unregisterFill: ( name: SlotKey, ref: Rerenderable ) => void; /** * This helps the provider know if it's using the default context value or not. @@ -152,30 +127,14 @@ export type SlotFillBubblesVirtuallyContext = { }; export type BaseSlotFillContext = { - registerSlot: ( - name: SlotKey, - slot: Component< BaseSlotComponentProps > - ) => void; - unregisterSlot: ( - name: SlotKey, - slot: Component< BaseSlotComponentProps > - ) => void; + registerSlot: ( name: SlotKey, slot: Rerenderable ) => void; + unregisterSlot: ( name: SlotKey, slot: Rerenderable ) => void; registerFill: ( name: SlotKey, instance: FillComponentProps ) => void; unregisterFill: ( name: SlotKey, instance: FillComponentProps ) => void; - getSlot: ( - name: SlotKey - ) => Component< BaseSlotComponentProps > | undefined; + getSlot: ( name: SlotKey ) => Rerenderable | undefined; getFills: ( name: SlotKey, - slotInstance: Component< BaseSlotComponentProps > + slotInstance: Rerenderable ) => FillComponentProps[]; subscribe: ( listener: () => void ) => () => void; }; - -export type BaseSlotComponentProps = Pick< - BaseSlotFillContext, - 'registerSlot' | 'unregisterSlot' | 'getFills' -> & - Omit< SlotComponentProps, 'bubblesVirtually' > & { - children?: ( fills: ReactNode ) => ReactNode; - }; From c38610ae21d5aad266aff9a08fc49e80cd38f0e6 Mon Sep 17 00:00:00 2001 From: louwie17 Date: Wed, 20 Nov 2024 11:42:10 -0400 Subject: [PATCH 147/226] DataForm: enable fields to declare a different layout (#66531) Co-authored-by: louwie17 Co-authored-by: oandregal Co-authored-by: gigitux Co-authored-by: youknowriad --- .../dataform-combined-edit/index.tsx | 69 ----- .../dataform-combined-edit/style.scss | 16 - .../src/components/dataform-context/index.tsx | 30 ++ .../src/components/dataform/index.tsx | 27 +- .../dataform/stories/index.story.tsx | 137 +++++--- .../dataforms-layouts/data-form-layout.tsx | 87 ++++++ .../dataforms-layouts/get-visible-fields.ts | 29 -- .../dataviews/src/dataforms-layouts/index.tsx | 14 +- .../dataforms-layouts/is-combined-field.ts | 10 + .../src/dataforms-layouts/panel/index.tsx | 293 ++++++++++++------ .../src/dataforms-layouts/regular/index.tsx | 138 ++++++--- .../src/dataforms-layouts/regular/style.scss | 30 ++ packages/dataviews/src/normalize-fields.ts | 34 +- .../dataviews/src/normalize-form-fields.ts | 42 +++ packages/dataviews/src/style.scss | 2 +- packages/dataviews/src/types.ts | 44 +-- packages/dataviews/src/validation.ts | 2 +- .../src/components/post-edit/index.js | 20 +- 18 files changed, 645 insertions(+), 379 deletions(-) delete mode 100644 packages/dataviews/src/components/dataform-combined-edit/index.tsx delete mode 100644 packages/dataviews/src/components/dataform-combined-edit/style.scss create mode 100644 packages/dataviews/src/components/dataform-context/index.tsx create mode 100644 packages/dataviews/src/dataforms-layouts/data-form-layout.tsx delete mode 100644 packages/dataviews/src/dataforms-layouts/get-visible-fields.ts create mode 100644 packages/dataviews/src/dataforms-layouts/is-combined-field.ts create mode 100644 packages/dataviews/src/dataforms-layouts/regular/style.scss create mode 100644 packages/dataviews/src/normalize-form-fields.ts diff --git a/packages/dataviews/src/components/dataform-combined-edit/index.tsx b/packages/dataviews/src/components/dataform-combined-edit/index.tsx deleted file mode 100644 index 90a92ac861bdd1..00000000000000 --- a/packages/dataviews/src/components/dataform-combined-edit/index.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/** - * WordPress dependencies - */ -import { - __experimentalHStack as HStack, - __experimentalVStack as VStack, - __experimentalHeading as Heading, - __experimentalSpacer as Spacer, -} from '@wordpress/components'; - -/** - * Internal dependencies - */ -import type { DataFormCombinedEditProps, NormalizedField } from '../../types'; -import FormFieldVisibility from '../form-field-visibility'; - -function Header( { title }: { title: string } ) { - return ( - - - - { title } - - - - - ); -} - -function DataFormCombinedEdit< Item >( { - field, - data, - onChange, - hideLabelFromVision, -}: DataFormCombinedEditProps< Item > ) { - const className = 'dataforms-combined-edit'; - const visibleChildren = ( field.children ?? [] ) - .map( ( fieldId ) => field.fields.find( ( { id } ) => id === fieldId ) ) - .filter( - ( childField ): childField is NormalizedField< Item > => - !! childField - ); - const children = visibleChildren.map( ( child ) => { - return ( - -
- -
-
- ); - } ); - - const Stack = field.direction === 'horizontal' ? HStack : VStack; - - return ( - <> - { ! hideLabelFromVision &&
} - - { children } - - - ); -} - -export default DataFormCombinedEdit; diff --git a/packages/dataviews/src/components/dataform-combined-edit/style.scss b/packages/dataviews/src/components/dataform-combined-edit/style.scss deleted file mode 100644 index 97e052ed897989..00000000000000 --- a/packages/dataviews/src/components/dataform-combined-edit/style.scss +++ /dev/null @@ -1,16 +0,0 @@ -.dataforms-layouts-panel__field-dropdown { - .dataforms-combined-edit { - border: none; - padding: 0; - } -} - -.dataforms-combined-edit { - &__field { - flex: 1 1 auto; - } - - p.components-base-control__help:has(.components-checkbox-control__help) { - margin-top: $grid-unit-05; - } -} diff --git a/packages/dataviews/src/components/dataform-context/index.tsx b/packages/dataviews/src/components/dataform-context/index.tsx new file mode 100644 index 00000000000000..72fbf7e0f42ab6 --- /dev/null +++ b/packages/dataviews/src/components/dataform-context/index.tsx @@ -0,0 +1,30 @@ +/** + * WordPress dependencies + */ +import { createContext } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import type { NormalizedField } from '../../types'; + +type DataFormContextType< Item > = { + fields: NormalizedField< Item >[]; +}; + +const DataFormContext = createContext< DataFormContextType< any > >( { + fields: [], +} ); + +export function DataFormProvider< Item >( { + fields, + children, +}: React.PropsWithChildren< { fields: NormalizedField< Item >[] } > ) { + return ( + + { children } + + ); +} + +export default DataFormContext; diff --git a/packages/dataviews/src/components/dataform/index.tsx b/packages/dataviews/src/components/dataform/index.tsx index 58f0bf06afb414..b359ddba74381e 100644 --- a/packages/dataviews/src/components/dataform/index.tsx +++ b/packages/dataviews/src/components/dataform/index.tsx @@ -1,17 +1,34 @@ +/** + * WordPress dependencies + */ +import { useMemo } from '@wordpress/element'; + /** * Internal dependencies */ import type { DataFormProps } from '../../types'; -import { getFormLayout } from '../../dataforms-layouts'; +import { DataFormProvider } from '../dataform-context'; +import { normalizeFields } from '../../normalize-fields'; +import { DataFormLayout } from '../../dataforms-layouts/data-form-layout'; export default function DataForm< Item >( { + data, form, - ...props + fields, + onChange, }: DataFormProps< Item > ) { - const layout = getFormLayout( form.type ?? 'regular' ); - if ( ! layout ) { + const normalizedFields = useMemo( + () => normalizeFields( fields ), + [ fields ] + ); + + if ( ! form.fields ) { return null; } - return ; + return ( + + + + ); } diff --git a/packages/dataviews/src/components/dataform/stories/index.story.tsx b/packages/dataviews/src/components/dataform/stories/index.story.tsx index b59d79063200bf..ecad2af43fb84b 100644 --- a/packages/dataviews/src/components/dataform/stories/index.story.tsx +++ b/packages/dataviews/src/components/dataform/stories/index.story.tsx @@ -1,13 +1,14 @@ /** * WordPress dependencies */ -import { useState } from '@wordpress/element'; +import { useMemo, useState } from '@wordpress/element'; +import { ToggleControl } from '@wordpress/components'; /** * Internal dependencies */ import DataForm from '../index'; -import type { CombinedFormField, Field } from '../../../types'; +import type { Field, Form } from '../../../types'; type SamplePost = { title: string; @@ -27,8 +28,13 @@ const meta = { type: { control: { type: 'select' }, description: - 'Chooses the layout of the form. "regular" is the default layout.', - options: [ 'regular', 'panel' ], + 'Chooses the default layout of each field. "regular" is the default layout.', + options: [ 'default', 'regular', 'panel' ], + }, + labelPosition: { + control: { type: 'select' }, + description: 'Chooses the label position of the layout.', + options: [ 'default', 'top', 'side', 'none' ], }, }, }; @@ -97,9 +103,33 @@ const fields = [ return item.status !== 'private'; }, }, + { + id: 'sticky', + label: 'Sticky', + type: 'integer', + Edit: ( { field, onChange, data, hideLabelFromVision } ) => { + const { id, getValue } = field; + return ( + + onChange( { [ id ]: ! getValue( { item: data } ) } ) + } + /> + ); + }, + }, ] as Field< SamplePost >[]; -export const Default = ( { type }: { type: 'panel' | 'regular' } ) => { +export const Default = ( { + type, + labelPosition, +}: { + type: 'default' | 'regular' | 'panel'; + labelPosition: 'default' | 'top' | 'side' | 'none'; +} ) => { const [ post, setPost ] = useState( { title: 'Hello, World!', order: 2, @@ -108,29 +138,36 @@ export const Default = ( { type }: { type: 'panel' | 'regular' } ) => { reviewer: 'fulano', date: '2021-01-01T12:00:00', birthdate: '1950-02-23T12:00:00', + sticky: false, } ); - const form = { - fields: [ - 'title', - 'order', - 'author', - 'reviewer', - 'status', - 'password', - 'date', - 'birthdate', - ], - }; + const form = useMemo( + () => ( { + type, + labelPosition, + fields: [ + 'title', + 'order', + { + id: 'sticky', + layout: 'regular', + labelPosition: 'side', + }, + 'author', + 'reviewer', + 'password', + 'date', + 'birthdate', + ], + } ), + [ type, labelPosition ] + ) as Form; return ( data={ post } fields={ fields } - form={ { - ...form, - type, - } } + form={ form } onChange={ ( edits ) => setPost( ( prev ) => ( { ...prev, @@ -142,40 +179,45 @@ export const Default = ( { type }: { type: 'panel' | 'regular' } ) => { }; const CombinedFieldsComponent = ( { - type = 'regular', - combinedFieldDirection = 'vertical', + type, + labelPosition, }: { - type: 'panel' | 'regular'; - combinedFieldDirection: 'vertical' | 'horizontal'; + type: 'default' | 'regular' | 'panel'; + labelPosition: 'default' | 'top' | 'side' | 'none'; } ) => { - const [ post, setPost ] = useState( { + const [ post, setPost ] = useState< SamplePost >( { title: 'Hello, World!', order: 2, author: 1, status: 'draft', + reviewer: 'fulano', + date: '2021-01-01T12:00:00', + birthdate: '1950-02-23T12:00:00', } ); - const form = { - fields: [ 'title', 'status_and_visibility', 'order', 'author' ], - combinedFields: [ - { - id: 'status_and_visibility', - label: 'Status & Visibility', - children: [ 'status', 'password' ], - direction: combinedFieldDirection, - render: ( { item } ) => item.status, - }, - ] as CombinedFormField< any >[], - }; + const form = useMemo( + () => ( { + type, + labelPosition, + fields: [ + 'title', + { + id: 'status', + label: 'Status & Visibility', + children: [ 'status', 'password' ], + }, + 'order', + 'author', + ], + } ), + [ type, labelPosition ] + ) as Form; return ( - data={ post } fields={ fields } - form={ { - ...form, - type, - } } + form={ form } onChange={ ( edits ) => setPost( ( prev ) => ( { ...prev, @@ -191,11 +233,8 @@ export const CombinedFields = { render: CombinedFieldsComponent, argTypes: { ...meta.argTypes, - combinedFieldDirection: { - control: { type: 'select' }, - description: - 'Chooses the direction of the combined field. "vertical" is the default layout.', - options: [ 'vertical', 'horizontal' ], - }, + }, + args: { + type: 'panel', }, }; diff --git a/packages/dataviews/src/dataforms-layouts/data-form-layout.tsx b/packages/dataviews/src/dataforms-layouts/data-form-layout.tsx new file mode 100644 index 00000000000000..08cc47f569eafe --- /dev/null +++ b/packages/dataviews/src/dataforms-layouts/data-form-layout.tsx @@ -0,0 +1,87 @@ +/** + * WordPress dependencies + */ +import { __experimentalVStack as VStack } from '@wordpress/components'; +import { useContext, useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import type { Form, FormField, SimpleFormField } from '../types'; +import { getFormFieldLayout } from './index'; +import DataFormContext from '../components/dataform-context'; +import { isCombinedField } from './is-combined-field'; +import normalizeFormFields from '../normalize-form-fields'; + +export function DataFormLayout< Item >( { + data, + form, + onChange, + children, +}: { + data: Item; + form: Form; + onChange: ( value: any ) => void; + children?: ( + FieldLayout: ( props: { + data: Item; + field: FormField; + onChange: ( value: any ) => void; + hideLabelFromVision?: boolean; + } ) => React.JSX.Element | null, + field: FormField + ) => React.JSX.Element; +} ) { + const { fields: fieldDefinitions } = useContext( DataFormContext ); + + function getFieldDefinition( field: SimpleFormField | string ) { + const fieldId = typeof field === 'string' ? field : field.id; + + return fieldDefinitions.find( + ( fieldDefinition ) => fieldDefinition.id === fieldId + ); + } + + const normalizedFormFields = useMemo( + () => normalizeFormFields( form ), + [ form ] + ); + + return ( + + { normalizedFormFields.map( ( formField ) => { + const FieldLayout = getFormFieldLayout( formField.layout ) + ?.component; + + if ( ! FieldLayout ) { + return null; + } + + const fieldDefinition = ! isCombinedField( formField ) + ? getFieldDefinition( formField ) + : undefined; + + if ( + fieldDefinition && + fieldDefinition.isVisible && + ! fieldDefinition.isVisible( data ) + ) { + return null; + } + + if ( children ) { + return children( FieldLayout, formField ); + } + + return ( + + ); + } ) } + + ); +} diff --git a/packages/dataviews/src/dataforms-layouts/get-visible-fields.ts b/packages/dataviews/src/dataforms-layouts/get-visible-fields.ts deleted file mode 100644 index d95d59a88394e4..00000000000000 --- a/packages/dataviews/src/dataforms-layouts/get-visible-fields.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Internal dependencies - */ -import { normalizeCombinedFields } from '../normalize-fields'; -import type { - Field, - CombinedFormField, - NormalizedCombinedFormField, -} from '../types'; - -export function getVisibleFields< Item >( - fields: Field< Item >[], - formFields: string[] = [], - combinedFields?: CombinedFormField< Item >[] -): Field< Item >[] { - const visibleFields: Array< - Field< Item > | NormalizedCombinedFormField< Item > - > = [ ...fields ]; - if ( combinedFields ) { - visibleFields.push( - ...normalizeCombinedFields( combinedFields, fields ) - ); - } - return formFields - .map( ( fieldId ) => - visibleFields.find( ( { id } ) => id === fieldId ) - ) - .filter( ( field ): field is Field< Item > => !! field ); -} diff --git a/packages/dataviews/src/dataforms-layouts/index.tsx b/packages/dataviews/src/dataforms-layouts/index.tsx index 9434ea724ed4ca..5e4f3617d9c7dd 100644 --- a/packages/dataviews/src/dataforms-layouts/index.tsx +++ b/packages/dataviews/src/dataforms-layouts/index.tsx @@ -1,20 +1,20 @@ /** * Internal dependencies */ -import FormRegular from './regular'; -import FormPanel from './panel'; +import FormRegularField from './regular'; +import FormPanelField from './panel'; -const FORM_LAYOUTS = [ +const FORM_FIELD_LAYOUTS = [ { type: 'regular', - component: FormRegular, + component: FormRegularField, }, { type: 'panel', - component: FormPanel, + component: FormPanelField, }, ]; -export function getFormLayout( type: string ) { - return FORM_LAYOUTS.find( ( layout ) => layout.type === type ); +export function getFormFieldLayout( type: string ) { + return FORM_FIELD_LAYOUTS.find( ( layout ) => layout.type === type ); } diff --git a/packages/dataviews/src/dataforms-layouts/is-combined-field.ts b/packages/dataviews/src/dataforms-layouts/is-combined-field.ts new file mode 100644 index 00000000000000..3df6fdc60f906e --- /dev/null +++ b/packages/dataviews/src/dataforms-layouts/is-combined-field.ts @@ -0,0 +1,10 @@ +/** + * Internal dependencies + */ +import type { FormField, CombinedFormField } from '../types'; + +export function isCombinedField( + field: FormField +): field is CombinedFormField { + return ( field as CombinedFormField ).children !== undefined; +} diff --git a/packages/dataviews/src/dataforms-layouts/panel/index.tsx b/packages/dataviews/src/dataforms-layouts/panel/index.tsx index b74e5e4667d4b1..269b2bb418a856 100644 --- a/packages/dataviews/src/dataforms-layouts/panel/index.tsx +++ b/packages/dataviews/src/dataforms-layouts/panel/index.tsx @@ -9,29 +9,29 @@ import { Dropdown, Button, } from '@wordpress/components'; -import { useState, useMemo } from '@wordpress/element'; import { sprintf, __, _x } from '@wordpress/i18n'; +import { useState, useMemo, useContext } from '@wordpress/element'; import { closeSmall } from '@wordpress/icons'; /** * Internal dependencies */ -import { normalizeFields } from '../../normalize-fields'; -import { getVisibleFields } from '../get-visible-fields'; -import type { DataFormProps, NormalizedField } from '../../types'; -import FormFieldVisibility from '../../components/form-field-visibility'; - -interface FormFieldProps< Item > { - data: Item; - field: NormalizedField< Item >; - onChange: ( value: any ) => void; -} +import type { + Form, + FormField, + FieldLayoutProps, + NormalizedField, + SimpleFormField, +} from '../../types'; +import DataFormContext from '../../components/dataform-context'; +import { DataFormLayout } from '../data-form-layout'; +import { isCombinedField } from '../is-combined-field'; function DropdownHeader( { title, onClose, }: { - title: string; + title?: string; onClose: () => void; } ) { return ( @@ -40,9 +40,11 @@ function DropdownHeader( { spacing={ 4 } > - - { title } - + { title && ( + + { title } + + ) } { onClose && ( + ( + + ) } + renderContent={ ( { onClose } ) => ( + <> + + + { ( FieldLayout, nestedField ) => ( + - - ) } - /> -
- + ) } + + + ) } + /> ); } -export default function FormPanel< Item >( { +export default function FormPanelField< Item >( { data, - fields, - form, + field, onChange, -}: DataFormProps< Item > ) { - const visibleFields = useMemo( - () => - normalizeFields( - getVisibleFields< Item >( - fields, - form.fields, - form.combinedFields - ) - ), - [ fields, form.fields, form.combinedFields ] +}: FieldLayoutProps< Item > ) { + const { fields } = useContext( DataFormContext ); + const fieldDefinition = fields.find( ( fieldDef ) => { + // Default to the first child if it is a combined field. + if ( isCombinedField( field ) ) { + const children = field.children.filter( + ( child ): child is string | SimpleFormField => + typeof child === 'string' || ! isCombinedField( child ) + ); + const firstChildFieldId = + typeof children[ 0 ] === 'string' + ? children[ 0 ] + : children[ 0 ].id; + return fieldDef.id === firstChildFieldId; + } + return fieldDef.id === field.id; + } ); + const labelPosition = field.labelPosition ?? 'side'; + + // Use internal state instead of a ref to make sure that the component + // re-renders when the popover's anchor updates. + const [ popoverAnchor, setPopoverAnchor ] = useState< HTMLElement | null >( + null ); - return ( - - { visibleFields.map( ( field ) => { - return ( - +
+ { fieldLabel } +
+
+ - - - ); - } ) } - + popoverAnchor={ popoverAnchor } + fieldDefinition={ fieldDefinition } + data={ data } + onChange={ onChange } + labelPosition={ labelPosition } + /> +
+
+ ); + } + + if ( labelPosition === 'none' ) { + return ( +
+ +
+ ); + } + + // Defaults to label position side. + return ( + +
+ { fieldLabel } +
+
+ +
+
); } diff --git a/packages/dataviews/src/dataforms-layouts/regular/index.tsx b/packages/dataviews/src/dataforms-layouts/regular/index.tsx index 6a340a50584df4..a3d90b807b5cd4 100644 --- a/packages/dataviews/src/dataforms-layouts/regular/index.tsx +++ b/packages/dataviews/src/dataforms-layouts/regular/index.tsx @@ -1,52 +1,116 @@ /** * WordPress dependencies */ -import { __experimentalVStack as VStack } from '@wordpress/components'; -import { useMemo } from '@wordpress/element'; +import { useContext, useMemo } from '@wordpress/element'; +import { + __experimentalHStack as HStack, + __experimentalVStack as VStack, + __experimentalHeading as Heading, + __experimentalSpacer as Spacer, +} from '@wordpress/components'; /** * Internal dependencies */ -import { normalizeFields } from '../../normalize-fields'; -import { getVisibleFields } from '../get-visible-fields'; -import type { DataFormProps } from '../../types'; -import FormFieldVisibility from '../../components/form-field-visibility'; +import type { Form, FieldLayoutProps } from '../../types'; +import DataFormContext from '../../components/dataform-context'; +import { DataFormLayout } from '../data-form-layout'; +import { isCombinedField } from '../is-combined-field'; -export default function FormRegular< Item >( { +function Header( { title }: { title: string } ) { + return ( + + + + { title } + + + + + ); +} + +export default function FormRegularField< Item >( { data, - fields, - form, + field, onChange, -}: DataFormProps< Item > ) { - const visibleFields = useMemo( - () => - normalizeFields( - getVisibleFields< Item >( - fields, - form.fields, - form.combinedFields - ) - ), - [ fields, form.fields, form.combinedFields ] + hideLabelFromVision, +}: FieldLayoutProps< Item > ) { + const { fields } = useContext( DataFormContext ); + + const form = useMemo( () => { + if ( isCombinedField( field ) ) { + return { + fields: field.children.map( ( child ) => { + if ( typeof child === 'string' ) { + return { + id: child, + }; + } + return child; + } ), + type: 'regular' as const, + }; + } + + return { + type: 'regular' as const, + fields: [], + }; + }, [ field ] ); + + if ( isCombinedField( field ) ) { + return ( + <> + { ! hideLabelFromVision && field.label && ( +
+ ) } + + + ); + } + + const labelPosition = field.labelPosition ?? 'top'; + const fieldDefinition = fields.find( + ( fieldDef ) => fieldDef.id === field.id ); - return ( - - { visibleFields.map( ( field ) => { - return ( - +
+ { fieldDefinition.label } +
+
+ - - - ); - } ) } - + field={ fieldDefinition } + onChange={ onChange } + hideLabelFromVision + /> +
+ + ); + } + + return ( +
+ +
); } diff --git a/packages/dataviews/src/dataforms-layouts/regular/style.scss b/packages/dataviews/src/dataforms-layouts/regular/style.scss new file mode 100644 index 00000000000000..d94b804fdf1fe5 --- /dev/null +++ b/packages/dataviews/src/dataforms-layouts/regular/style.scss @@ -0,0 +1,30 @@ +.dataforms-layouts-regular__field { + width: 100%; + min-height: $grid-unit-40; + justify-content: flex-start !important; + align-items: flex-start !important; +} + +.dataforms-layouts-regular__field .components-base-control__label { + font-size: inherit; + font-weight: normal; + text-transform: none; +} + +.dataforms-layouts-regular__field-label { + width: 38%; + flex-shrink: 0; + min-height: $grid-unit-40; + display: flex; + align-items: center; + padding: 6px 0; // Matches button to ensure alignment + line-height: $grid-unit-05 * 5; + hyphens: auto; +} + +.dataforms-layouts-regular__field-control { + flex-grow: 1; + min-height: $grid-unit-40; + display: flex; + align-items: center; +} diff --git a/packages/dataviews/src/normalize-fields.ts b/packages/dataviews/src/normalize-fields.ts index 562f29fcce84fe..2ed87cbe112229 100644 --- a/packages/dataviews/src/normalize-fields.ts +++ b/packages/dataviews/src/normalize-fields.ts @@ -2,14 +2,8 @@ * Internal dependencies */ import getFieldTypeDefinition from './field-types'; -import type { - CombinedFormField, - Field, - NormalizedField, - NormalizedCombinedFormField, -} from './types'; +import type { Field, NormalizedField } from './types'; import { getControl } from './dataform-controls'; -import DataFormCombinedEdit from './components/dataform-combined-edit'; const getValueFromId = ( id: string ) => @@ -87,29 +81,3 @@ export function normalizeFields< Item >( }; } ); } - -/** - * Apply default values and normalize the fields config. - * - * @param combinedFields combined field list. - * @param fields Fields config. - * @return Normalized fields config. - */ -export function normalizeCombinedFields< Item >( - combinedFields: CombinedFormField< Item >[], - fields: Field< Item >[] -): NormalizedCombinedFormField< Item >[] { - return combinedFields.map( ( combinedField ) => { - return { - ...combinedField, - Edit: DataFormCombinedEdit, - fields: normalizeFields( - combinedField.children - .map( ( fieldId ) => - fields.find( ( { id } ) => id === fieldId ) - ) - .filter( ( field ): field is Field< Item > => !! field ) - ), - }; - } ); -} diff --git a/packages/dataviews/src/normalize-form-fields.ts b/packages/dataviews/src/normalize-form-fields.ts new file mode 100644 index 00000000000000..3cd5f67564d7ce --- /dev/null +++ b/packages/dataviews/src/normalize-form-fields.ts @@ -0,0 +1,42 @@ +/** + * Internal dependencies + */ +import type { Form } from './types'; + +interface NormalizedFormField { + id: string; + layout: 'regular' | 'panel'; + labelPosition: 'side' | 'top' | 'none'; +} + +export default function normalizeFormFields( + form: Form +): NormalizedFormField[] { + let layout: 'regular' | 'panel' = 'regular'; + if ( [ 'regular', 'panel' ].includes( form.type ?? '' ) ) { + layout = form.type as 'regular' | 'panel'; + } + + const labelPosition = + form.labelPosition ?? ( layout === 'regular' ? 'top' : 'side' ); + + return ( form.fields ?? [] ).map( ( field ) => { + if ( typeof field === 'string' ) { + return { + id: field, + layout, + labelPosition, + }; + } + + const fieldLayout = field.layout ?? layout; + const fieldLabelPosition = + field.labelPosition ?? + ( fieldLayout === 'regular' ? 'top' : 'side' ); + return { + ...field, + layout: fieldLayout, + labelPosition: fieldLabelPosition, + }; + } ); +} diff --git a/packages/dataviews/src/style.scss b/packages/dataviews/src/style.scss index 26c6ecea645f43..5639f3cac0da51 100644 --- a/packages/dataviews/src/style.scss +++ b/packages/dataviews/src/style.scss @@ -6,7 +6,6 @@ @import "./components/dataviews-item-actions/style.scss"; @import "./components/dataviews-selection-checkbox/style.scss"; @import "./components/dataviews-view-config/style.scss"; -@import "./components/dataform-combined-edit/style.scss"; @import "./dataviews-layouts/grid/style.scss"; @import "./dataviews-layouts/list/style.scss"; @@ -14,3 +13,4 @@ @import "./dataform-controls/style.scss"; @import "./dataforms-layouts/panel/style.scss"; +@import "./dataforms-layouts/regular/style.scss"; diff --git a/packages/dataviews/src/types.ts b/packages/dataviews/src/types.ts index 71990f72d4eecd..8c4276f2541ecc 100644 --- a/packages/dataviews/src/types.ts +++ b/packages/dataviews/src/types.ts @@ -527,37 +527,41 @@ export interface SupportedLayouts { table?: Omit< ViewTable, 'type' >; } -export interface CombinedFormField< Item > extends CombinedField { - render?: ComponentType< { item: Item } >; -} - -export interface DataFormCombinedEditProps< Item > { - field: NormalizedCombinedFormField< Item >; - data: Item; - onChange: ( value: Record< string, any > ) => void; - hideLabelFromVision?: boolean; -} +export type SimpleFormField = { + id: string; + layout?: 'regular' | 'panel'; + labelPosition?: 'side' | 'top' | 'none'; +}; -export type NormalizedCombinedFormField< Item > = CombinedFormField< Item > & { - fields: NormalizedField< Item >[]; - Edit?: ComponentType< DataFormCombinedEditProps< Item > >; +export type CombinedFormField = { + id: string; + label?: string; + layout?: 'regular' | 'panel'; + labelPosition?: 'side' | 'top' | 'none'; + children: Array< FormField | string >; }; +export type FormField = SimpleFormField | CombinedFormField; + /** * The form configuration. */ -export type Form< Item > = { +export type Form = { type?: 'regular' | 'panel'; - fields?: string[]; - /** - * The fields to combine. - */ - combinedFields?: CombinedFormField< Item >[]; + fields?: Array< FormField | string >; + labelPosition?: 'side' | 'top' | 'none'; }; export interface DataFormProps< Item > { data: Item; fields: Field< Item >[]; - form: Form< Item >; + form: Form; onChange: ( value: Record< string, any > ) => void; } + +export interface FieldLayoutProps< Item > { + data: Item; + field: FormField; + onChange: ( value: any ) => void; + hideLabelFromVision?: boolean; +} diff --git a/packages/dataviews/src/validation.ts b/packages/dataviews/src/validation.ts index 0a6542da4e8d40..bcc9a15908ff59 100644 --- a/packages/dataviews/src/validation.ts +++ b/packages/dataviews/src/validation.ts @@ -16,7 +16,7 @@ import type { Field, Form } from './types'; export function isItemValid< Item >( item: Item, fields: Field< Item >[], - form: Form< Item > + form: Form ): boolean { const _fields = normalizeFields( fields.filter( ( { id } ) => !! form.fields?.includes( id ) ) diff --git a/packages/edit-site/src/components/post-edit/index.js b/packages/edit-site/src/components/post-edit/index.js index a535eef4ce7878..a7842f0feb3c2f 100644 --- a/packages/edit-site/src/components/post-edit/index.js +++ b/packages/edit-site/src/components/post-edit/index.js @@ -70,9 +70,16 @@ function PostEditForm( { postType, postId } ) { () => ( { type: 'panel', fields: [ - 'featured_media', + { + id: 'featured_media', + layout: 'regular', + }, 'title', - 'status_and_visibility', + { + id: 'status', + label: __( 'Status & Visibility' ), + children: [ 'status', 'password' ], + }, 'author', 'date', 'slug', @@ -83,15 +90,6 @@ function PostEditForm( { postType, postId } ) { ids.length === 1 || fieldsWithBulkEditSupport.includes( field ) ), - combinedFields: [ - { - id: 'status_and_visibility', - label: __( 'Status & Visibility' ), - children: [ 'status', 'password' ], - direction: 'vertical', - render: ( { item } ) => item.status, - }, - ], } ), [ ids ] ); From 776b9e0da9709e360a2cd95112a811ccefbfa818 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Wed, 20 Nov 2024 10:01:14 -0600 Subject: [PATCH 148/226] Preserve footer template bar in zoom out (#67135) --- .../editor/src/components/editor-interface/index.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/editor/src/components/editor-interface/index.js b/packages/editor/src/components/editor-interface/index.js index 3692a5ed797f5e..6f6ffbec7b9c32 100644 --- a/packages/editor/src/components/editor-interface/index.js +++ b/packages/editor/src/components/editor-interface/index.js @@ -10,11 +10,7 @@ import { InterfaceSkeleton, ComplementaryArea } from '@wordpress/interface'; import { useSelect } from '@wordpress/data'; import { __, _x } from '@wordpress/i18n'; import { store as preferencesStore } from '@wordpress/preferences'; -import { - store as blockEditorStore, - BlockBreadcrumb, - BlockToolbar, -} from '@wordpress/block-editor'; +import { BlockBreadcrumb, BlockToolbar } from '@wordpress/block-editor'; import { useViewportMatch } from '@wordpress/compose'; import { useState, useCallback } from '@wordpress/element'; @@ -31,8 +27,6 @@ import TextEditor from '../text-editor'; import VisualEditor from '../visual-editor'; import EditorContentSlotFill from './content-slot-fill'; -import { unlock } from '../../lock-unlock'; - const interfaceLabels = { /* translators: accessibility text for the editor top bar landmark region. */ header: __( 'Editor top bar' ), @@ -69,13 +63,11 @@ export default function EditorInterface( { isPreviewMode, showBlockBreadcrumbs, documentLabel, - isZoomOut, } = useSelect( ( select ) => { const { get } = select( preferencesStore ); const { getEditorSettings, getPostTypeLabel } = select( editorStore ); const editorSettings = getEditorSettings(); const postTypeLabel = getPostTypeLabel(); - const { isZoomOut: _isZoomOut } = unlock( select( blockEditorStore ) ); return { mode: select( editorStore ).getEditorMode(), @@ -88,7 +80,6 @@ export default function EditorInterface( { documentLabel: // translators: Default label for the Document in the Block Breadcrumb. postTypeLabel || _x( 'Document', 'noun, breadcrumb' ), - isZoomOut: _isZoomOut(), }; }, [] ); const isLargeViewport = useViewportMatch( 'medium' ); @@ -197,7 +188,6 @@ export default function EditorInterface( { isLargeViewport && showBlockBreadcrumbs && isRichEditingEnabled && - ! isZoomOut && mode === 'visual' && ( ) From fa675a794311e9c4d27cbb9d51ac95dcac08b1cc Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Wed, 20 Nov 2024 10:02:18 -0600 Subject: [PATCH 149/226] Leave help text in patterns flyout regardless of zoom state (#67132) --- .../pattern-category-previews.js | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js b/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js index a19a579ae5c0cf..c6ce9ba97d2501 100644 --- a/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js +++ b/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js @@ -17,7 +17,6 @@ import { __experimentalText as Text, FlexBlock, } from '@wordpress/components'; -import { useSelect } from '@wordpress/data'; /** * Internal dependencies @@ -34,8 +33,6 @@ import { starterPatternsCategory, INSERTER_PATTERN_TYPES, } from './utils'; -import { store as blockEditorStore } from '../../../store'; -import { unlock } from '../../../lock-unlock'; const noop = () => {}; @@ -46,10 +43,6 @@ export function PatternCategoryPreviews( { category, showTitlesAsTooltip, } ) { - const isZoomOutMode = useSelect( - ( select ) => unlock( select( blockEditorStore ) ).isZoomOut(), - [] - ); const [ allPatterns, , onClickPattern ] = usePatternsState( onInsert, rootClientId, @@ -179,15 +172,13 @@ export function PatternCategoryPreviews( {
{ currentCategoryPatterns.length > 0 && ( <> - { isZoomOutMode && ( - - { __( 'Drag and drop patterns into the canvas.' ) } - - ) } + + { __( 'Drag and drop patterns into the canvas.' ) } + Date: Wed, 20 Nov 2024 17:16:49 +0000 Subject: [PATCH 150/226] Bump plugin version to 19.7.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 738fe1a3bd5268..3e4d6941b5a0f3 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.6 * Requires PHP: 7.2 - * Version: 19.7.0-rc.2 + * Version: 19.7.0 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/package-lock.json b/package-lock.json index 376cd0b9e6edf6..04a8d2021f12a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gutenberg", - "version": "19.7.0-rc.2", + "version": "19.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "gutenberg", - "version": "19.7.0-rc.2", + "version": "19.7.0", "hasInstallScript": true, "license": "GPL-2.0-or-later", "workspaces": [ diff --git a/package.json b/package.json index a7470a1333ffad..52668f667c71cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "19.7.0-rc.2", + "version": "19.7.0", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", From e4a716eb524458e2c567c5fd5f92d1985d7ea779 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Wed, 20 Nov 2024 12:27:06 -0500 Subject: [PATCH 151/226] Add documentation about required Core changes when updating minimum WordPress version (#67167) * Add a note about required Core SVN changes. * A few refinements. --------- Co-authored-by: desrosj Co-authored-by: ndiego Co-authored-by: Mamaduka --- docs/explanations/architecture/performance.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/explanations/architecture/performance.md b/docs/explanations/architecture/performance.md index 4c8b6386b9263b..8c1034ad9de331 100644 --- a/docs/explanations/architecture/performance.md +++ b/docs/explanations/architecture/performance.md @@ -84,6 +84,12 @@ The new reference commit hash that is chosen needs to meet the following require - Be compatible with the new WP version used in the "Tested up to" flag. - Is already tracked on "codevitals.run" for all existing metrics. +When releasing a plugin update with changes to the minimum WordPress version requirements, the end-to-end test GitHub Action workflow in Core SVN will need to be updated for any branch losing support. Otherwise the first run of that workflow on that branch following the release will fail. + +The version of the plugin used in the workflow can be pinned by adding the `gutenberg-version` input to the test matrix. [Core-59221](https://core.trac.wordpress.org/changeset/59221) is an example of this change for the 6.4 branch. + +**Note:** Always use the final release including bug fixes (ie. `x.y.2` or `x.y.3`). If the final release is not yet known, create a [Trac ticket](https://core.trac.wordpress.org/ticket/62488) so it's not forgotten. + **A simple way to choose commit is to pick a very recent commit on trunk with a passing performance job.** ## Going further From e79c46950cd58f1588dbef531c143186e0666110 Mon Sep 17 00:00:00 2001 From: Vipul Gupta <55375170+vipul0425@users.noreply.github.com> Date: Wed, 20 Nov 2024 23:06:38 +0530 Subject: [PATCH 152/226] ToggleGroupControl : Deprecate 36px default size (#66747) * feat: Adds deprecation warning in toggleGroupControl Block. * feat: Adds the test case and story book modification. * docs: Adds changelog. * Add prop to suppress redundant warning * Updates the changelog and ToolsPanel Story. * Updates the snapshots. * Add prop to all instances in the ToolsPanel stories * Rebase changelog again --------- Co-authored-by: vipul0425 Co-authored-by: mirka <0mirka00@git.wordpress.org> --- packages/components/CHANGELOG.md | 1 + .../font-size-picker-toggle-group.tsx | 1 + .../stories/index.story.tsx | 1 + .../test/__snapshots__/index.tsx.snap | 24 +++++++++---------- .../src/toggle-group-control/test/index.tsx | 8 ++++++- .../README.md | 2 +- .../component.tsx | 2 +- .../toggle-group-control-option/README.md | 2 +- .../toggle-group-control-option/component.tsx | 1 + .../toggle-group-control/README.md | 3 ++- .../toggle-group-control/component.tsx | 10 ++++++++ .../src/toggle-group-control/types.ts | 7 ++++++ .../src/tools-panel/stories/index.story.tsx | 3 +++ .../src/utils/deprecated-36px-size.ts | 3 +++ 14 files changed, 51 insertions(+), 17 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index e5d467f22d30c8..ff4a8b714c9a52 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -12,6 +12,7 @@ - `TextControl`: Deprecate 36px default size ([#66745](https://github.com/WordPress/gutenberg/pull/66745). - `FontSizePicker`: Deprecate 36px default size ([#66920](https://github.com/WordPress/gutenberg/pull/66920)). - `ComboboxControl`: Deprecate 36px default size ([#66900](https://github.com/WordPress/gutenberg/pull/66900)). +- `ToggleGroupControl`: Deprecate 36px default size ([#66747](https://github.com/WordPress/gutenberg/pull/66747)). ### Bug Fixes diff --git a/packages/components/src/font-size-picker/font-size-picker-toggle-group.tsx b/packages/components/src/font-size-picker/font-size-picker-toggle-group.tsx index 1e4cbcd1b72660..1b3619c800e453 100644 --- a/packages/components/src/font-size-picker/font-size-picker-toggle-group.tsx +++ b/packages/components/src/font-size-picker/font-size-picker-toggle-group.tsx @@ -19,6 +19,7 @@ const FontSizePickerToggleGroup = ( props: FontSizePickerToggleGroupProps ) => { = ( { return ( { setValue( ...changeArgs ); diff --git a/packages/components/src/toggle-group-control/test/__snapshots__/index.tsx.snap b/packages/components/src/toggle-group-control/test/__snapshots__/index.tsx.snap index 832c6d7cb7a8c8..f344cd6ba16528 100644 --- a/packages/components/src/toggle-group-control/test/__snapshots__/index.tsx.snap +++ b/packages/components/src/toggle-group-control/test/__snapshots__/index.tsx.snap @@ -44,8 +44,8 @@ exports[`ToggleGroupControl controlled should render correctly with icons 1`] = display: inline-flex; min-width: 0; position: relative; - min-height: 36px; - padding: 2px; + min-height: 40px; + padding: 3px; } .emotion-8:hover { @@ -159,7 +159,7 @@ exports[`ToggleGroupControl controlled should render correctly with icons 1`] = width: 100%; z-index: 2; color: #1e1e1e; - height: 30px; + height: 32px; aspect-ratio: 1; padding-left: 0; padding-right: 0; @@ -236,7 +236,7 @@ exports[`ToggleGroupControl controlled should render correctly with icons 1`] = width: 100%; z-index: 2; color: #1e1e1e; - height: 30px; + height: 32px; aspect-ratio: 1; padding-left: 0; padding-right: 0; @@ -409,8 +409,8 @@ exports[`ToggleGroupControl controlled should render correctly with text options display: inline-flex; min-width: 0; position: relative; - min-height: 36px; - padding: 2px; + min-height: 40px; + padding: 3px; } .emotion-8:hover { @@ -678,8 +678,8 @@ exports[`ToggleGroupControl uncontrolled should render correctly with icons 1`] display: inline-flex; min-width: 0; position: relative; - min-height: 36px; - padding: 2px; + min-height: 40px; + padding: 3px; } .emotion-8:hover { @@ -793,7 +793,7 @@ exports[`ToggleGroupControl uncontrolled should render correctly with icons 1`] width: 100%; z-index: 2; color: #1e1e1e; - height: 30px; + height: 32px; aspect-ratio: 1; padding-left: 0; padding-right: 0; @@ -870,7 +870,7 @@ exports[`ToggleGroupControl uncontrolled should render correctly with icons 1`] width: 100%; z-index: 2; color: #1e1e1e; - height: 30px; + height: 32px; aspect-ratio: 1; padding-left: 0; padding-right: 0; @@ -1037,8 +1037,8 @@ exports[`ToggleGroupControl uncontrolled should render correctly with text optio display: inline-flex; min-width: 0; position: relative; - min-height: 36px; - padding: 2px; + min-height: 40px; + padding: 3px; } .emotion-8:hover { diff --git a/packages/components/src/toggle-group-control/test/index.tsx b/packages/components/src/toggle-group-control/test/index.tsx index 168e8f498958b5..44cfda69c423cf 100644 --- a/packages/components/src/toggle-group-control/test/index.tsx +++ b/packages/components/src/toggle-group-control/test/index.tsx @@ -28,7 +28,13 @@ const hoverOutside = async () => { }; const ToggleGroupControl = ( props: ToggleGroupControlProps ) => { - return <_ToggleGroupControl { ...props } __nextHasNoMarginBottom />; + return ( + <_ToggleGroupControl + { ...props } + __nextHasNoMarginBottom + __next40pxDefaultSize + /> + ); }; const ControlledToggleGroupControl = ( { diff --git a/packages/components/src/toggle-group-control/toggle-group-control-option-icon/README.md b/packages/components/src/toggle-group-control/toggle-group-control-option-icon/README.md index a0e3a44cf74607..1ee82b26a91998 100644 --- a/packages/components/src/toggle-group-control/toggle-group-control-option-icon/README.md +++ b/packages/components/src/toggle-group-control/toggle-group-control-option-icon/README.md @@ -17,7 +17,7 @@ import { formatLowercase, formatUppercase } from '@wordpress/icons'; function Example() { return ( - + + * * * * diff --git a/packages/components/src/toggle-group-control/toggle-group-control/README.md b/packages/components/src/toggle-group-control/toggle-group-control/README.md index ca5c5d14eb6b5a..841d474c148d45 100644 --- a/packages/components/src/toggle-group-control/toggle-group-control/README.md +++ b/packages/components/src/toggle-group-control/toggle-group-control/README.md @@ -25,6 +25,7 @@ function Example() { value="vertical" isBlock __nextHasNoMarginBottom + __next40pxDefaultSize > @@ -100,4 +101,4 @@ Start opting into the larger default height that will become the default size in Start opting into the new margin-free styles that will become the default in a future version. - Required: No -- Default: `false` \ No newline at end of file +- Default: `false` diff --git a/packages/components/src/toggle-group-control/toggle-group-control/component.tsx b/packages/components/src/toggle-group-control/toggle-group-control/component.tsx index 0c3cadf210d84a..9f3427e95a6017 100644 --- a/packages/components/src/toggle-group-control/toggle-group-control/component.tsx +++ b/packages/components/src/toggle-group-control/toggle-group-control/component.tsx @@ -23,6 +23,7 @@ import { ToggleGroupControlAsButtonGroup } from './as-button-group'; import { useTrackElementOffsetRect } from '../../utils/element-rect'; import { useMergeRefs } from '@wordpress/compose'; import { useAnimatedOffsetRect } from '../../utils/hooks/use-animated-offset-rect'; +import { maybeWarnDeprecated36pxSize } from '../../utils/deprecated-36px-size'; function UnconnectedToggleGroupControl( props: WordPressComponentProps< ToggleGroupControlProps, 'div', false >, @@ -31,6 +32,7 @@ function UnconnectedToggleGroupControl( const { __nextHasNoMarginBottom = false, __next40pxDefaultSize = false, + __shouldNotWarnDeprecated36pxSize, className, isAdaptiveWidth = false, isBlock = false, @@ -81,6 +83,13 @@ function UnconnectedToggleGroupControl( ? ToggleGroupControlAsButtonGroup : ToggleGroupControlAsRadioGroup; + maybeWarnDeprecated36pxSize( { + componentName: 'ToggleGroupControl', + size, + __next40pxDefaultSize, + __shouldNotWarnDeprecated36pxSize, + } ); + return ( * * diff --git a/packages/components/src/toggle-group-control/types.ts b/packages/components/src/toggle-group-control/types.ts index 463d8d26e64410..cfa9d00080467c 100644 --- a/packages/components/src/toggle-group-control/types.ts +++ b/packages/components/src/toggle-group-control/types.ts @@ -128,6 +128,13 @@ export type ToggleGroupControlProps = Pick< * @default false */ __next40pxDefaultSize?: boolean; + /** + * Do not throw a warning for the deprecated 36px default size. + * For internal components of other components that already throw the warning. + * + * @ignore + */ + __shouldNotWarnDeprecated36pxSize?: boolean; }; export type ToggleGroupControlContextProps = { diff --git a/packages/components/src/tools-panel/stories/index.story.tsx b/packages/components/src/tools-panel/stories/index.story.tsx index 459932c9d22d7a..787585ac716b51 100644 --- a/packages/components/src/tools-panel/stories/index.story.tsx +++ b/packages/components/src/tools-panel/stories/index.story.tsx @@ -110,6 +110,7 @@ export const Default: StoryFn< typeof ToolsPanel > = ( { > setScale( next ) } @@ -457,6 +458,7 @@ export const WithConditionalDefaultControl: StoryFn< typeof ToolsPanel > = ( { > @@ -559,6 +561,7 @@ export const WithConditionallyRenderedControl: StoryFn< > diff --git a/packages/components/src/utils/deprecated-36px-size.ts b/packages/components/src/utils/deprecated-36px-size.ts index be5baa2515637c..0f87c2cd270c73 100644 --- a/packages/components/src/utils/deprecated-36px-size.ts +++ b/packages/components/src/utils/deprecated-36px-size.ts @@ -7,12 +7,15 @@ export function maybeWarnDeprecated36pxSize( { componentName, __next40pxDefaultSize, size, + __shouldNotWarnDeprecated36pxSize, }: { componentName: string; __next40pxDefaultSize: boolean | undefined; size: string | undefined; + __shouldNotWarnDeprecated36pxSize?: boolean; } ) { if ( + __shouldNotWarnDeprecated36pxSize || __next40pxDefaultSize || ( size !== undefined && size !== 'default' ) ) { From 603e5c0e44cf6e231ffbc40d00c2bb851b49b9ef Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Wed, 20 Nov 2024 17:51:45 +0000 Subject: [PATCH 153/226] Update Changelog for 19.7.0 --- changelog.txt | 291 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) diff --git a/changelog.txt b/changelog.txt index d9236e513469af..1a6b45a37fc7cf 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,296 @@ == Changelog == += 19.7.0 = + +## Changelog + +### Enhancements + +- Add "show template" to preview dropdown. ([66514](https://github.com/WordPress/gutenberg/pull/66514)) +- Iframe: Always enable for block themes, in core too. ([66800](https://github.com/WordPress/gutenberg/pull/66800)) +- Media Utils: Add experimental `sideloadMedia`. ([66378](https://github.com/WordPress/gutenberg/pull/66378)) +- Post fields: Clean up. ([66941](https://github.com/WordPress/gutenberg/pull/66941)) +- Post fields: Extract `title` from `edit-site` to `fields` package. ([66940](https://github.com/WordPress/gutenberg/pull/66940)) +- Post fields: Move `comment_status` from edit-site to fields package. ([66934](https://github.com/WordPress/gutenberg/pull/66934)) +- Post fields: Move `date` fields from `edit-site` to `fields` package. ([66938](https://github.com/WordPress/gutenberg/pull/66938)) +- Post fields: Move `status` from `edit-site` to `fields`. ([66937](https://github.com/WordPress/gutenberg/pull/66937)) +- Relocate “View” external link to end of editor header controls. ([66785](https://github.com/WordPress/gutenberg/pull/66785)) + +#### Block Library +- Added toggle control to set any image as feature image if no feature image is set for post. ([65896](https://github.com/WordPress/gutenberg/pull/65896)) +- Improve cover z-index solution. ([66249](https://github.com/WordPress/gutenberg/pull/66249)) +- Post Content: Add border and spacing support. ([66366](https://github.com/WordPress/gutenberg/pull/66366)) +- Query Loop: Use templateSlug and postType for more context. ([65820](https://github.com/WordPress/gutenberg/pull/65820)) +- Update text case of "Starter Content". ([66954](https://github.com/WordPress/gutenberg/pull/66954)) +- [Details Block]: Adds anchor support in details block. ([66734](https://github.com/WordPress/gutenberg/pull/66734)) + +#### Components +- Guide: Use small size button for page controls. ([66607](https://github.com/WordPress/gutenberg/pull/66607)) +- MenuItem: Add 40px size prop on Button. ([66596](https://github.com/WordPress/gutenberg/pull/66596)) +- Notice: Add appropriate size props to Buttons. ([66593](https://github.com/WordPress/gutenberg/pull/66593)) +- PaletteEdit: Add appropriate size props to Buttons. ([66590](https://github.com/WordPress/gutenberg/pull/66590)) +- Popover: Add small size prop to close button. ([66587](https://github.com/WordPress/gutenberg/pull/66587)) + +#### Global Styles +- Global styles revisions: Move focus and active state to list item. ([66780](https://github.com/WordPress/gutenberg/pull/66780)) +- Site editor: Integrate global styles controls and style book preview into the styles panel. ([65619](https://github.com/WordPress/gutenberg/pull/65619)) + +#### DataViews +- DataViews Fields API: Default getValueFromId supports nested objects. ([66890](https://github.com/WordPress/gutenberg/pull/66890)) + +#### Block Editor +- Inserter: Add 'Starter Content' category to the inserter. ([66819](https://github.com/WordPress/gutenberg/pull/66819)) + +#### Zoom Out +- Enable zoom out mode for non-iframe editor. ([66789](https://github.com/WordPress/gutenberg/pull/66789)) + +#### Themes +- Theme JSON Resolver: Remove theme json merge in resolve_theme_file_uris. ([66662](https://github.com/WordPress/gutenberg/pull/66662)) + +#### Edit Mode +- Image block: Add support for "more" dropdown for additional tools in Write mode. ([66605](https://github.com/WordPress/gutenberg/pull/66605)) + +#### Style Book +- Add a landing section to stylebook tabs. ([66545](https://github.com/WordPress/gutenberg/pull/66545)) + +#### Media +- Media Library: Expose filters dropdown for individual images, such as with the Image block. ([65965](https://github.com/WordPress/gutenberg/pull/65965)) + + +### Bug Fixes + +- Block toolbar: Restrict visible child calculation to known blocks. ([66702](https://github.com/WordPress/gutenberg/pull/66702)) +- ComplementaryArea: Fix button position. ([66677](https://github.com/WordPress/gutenberg/pull/66677)) +- Fix Paragraph appender layout shift (building on 66061). ([66779](https://github.com/WordPress/gutenberg/pull/66779)) +- Fix: Set the `fit-content` width for images that are not `.svg`. ([66643](https://github.com/WordPress/gutenberg/pull/66643)) +- Preference modal: Avoid fetching all reusable blocks when the site editor loads. ([66621](https://github.com/WordPress/gutenberg/pull/66621)) +- Revert "Set image width to `fit-content` to solve aspect ratio problems in Firefox. (#66217)". ([66804](https://github.com/WordPress/gutenberg/pull/66804)) +- Safari: Fix site editor template error. ([66647](https://github.com/WordPress/gutenberg/pull/66647)) +- Safari: Prevent focus capturing caused by flex display. ([66402](https://github.com/WordPress/gutenberg/pull/66402)) +- Select Mode: Hide tool selector in the post editor and force design mode. ([66784](https://github.com/WordPress/gutenberg/pull/66784)) +- Shadow panel: Make the delete modal text translatable. ([66712](https://github.com/WordPress/gutenberg/pull/66712)) +- Site Editor: Fix template for page-on-front option. ([66739](https://github.com/WordPress/gutenberg/pull/66739)) +- WP Scripts: Make watch mode more resilient for developer errors. ([66752](https://github.com/WordPress/gutenberg/pull/66752)) +- getDefaultTemplateId: Ensure entity configuration is loaded. ([66650](https://github.com/WordPress/gutenberg/pull/66650)) +- Comments controller: fix issue where comments are allowed when closed (https://github.com/WordPress/gutenberg/pull/66976) + +#### Block Library +- Cover: Fix media library image selection. ([66782](https://github.com/WordPress/gutenberg/pull/66782)) +- Cover: Show DropZone only when dragging withing the block. ([66912](https://github.com/WordPress/gutenberg/pull/66912)) +- Media & Text: Set `.wp-block-media-text__media a` display to block. ([66915](https://github.com/WordPress/gutenberg/pull/66915)) +- Prevent duplicate post format taxonomy queries. ([66627](https://github.com/WordPress/gutenberg/pull/66627)) +- Query Loop: Check for postTypeFromContext before using it. ([66655](https://github.com/WordPress/gutenberg/pull/66655)) +- Query Loop: Remove postTypeFromContext. ([66681](https://github.com/WordPress/gutenberg/pull/66681)) + +#### Block Editor +- Appender: Fix initial position. ([66711](https://github.com/WordPress/gutenberg/pull/66711)) +- Appender: Fix outside canvas styles. ([66630](https://github.com/WordPress/gutenberg/pull/66630)) +- Block Inspector: Restore bottom margin for RadioControl. ([66688](https://github.com/WordPress/gutenberg/pull/66688)) +- Iframed editor: Fix relative wp-content URLs. ([66751](https://github.com/WordPress/gutenberg/pull/66751)) + +#### Global Styles +- Section Styles: Fix insecure properties removal for inner block types and elements. ([66896](https://github.com/WordPress/gutenberg/pull/66896)) +- Style book: Reduce margin selector specificity so that it doesn't override global block styles. ([66895](https://github.com/WordPress/gutenberg/pull/66895)) +- Theme JSON: Replace top-level background style objects on merge. ([66656](https://github.com/WordPress/gutenberg/pull/66656)) + +#### Components +- FormTokenField: Fix token styles. ([66640](https://github.com/WordPress/gutenberg/pull/66640)) +- Storybook: Fix DataViews action modals. ([66727](https://github.com/WordPress/gutenberg/pull/66727)) +- ToggleGroupControl: Fix active background for `zero` value. ([66855](https://github.com/WordPress/gutenberg/pull/66855)) + +#### Post Editor +- Disable device preview button in pattern/template part/navitation editor. ([65970](https://github.com/WordPress/gutenberg/pull/65970)) +- PostTaxonomiesFlatTermSelector: Abstract wrapper component. ([66625](https://github.com/WordPress/gutenberg/pull/66625)) +- VisualEditor: Always output has-global-padding classname when in post only mode. ([66626](https://github.com/WordPress/gutenberg/pull/66626)) + +#### DataViews +- Fix TypeError when duplicating uncategorized theme patterns. ([66889](https://github.com/WordPress/gutenberg/pull/66889)) +- Tweak primary field in patterns grid layout. ([66733](https://github.com/WordPress/gutenberg/pull/66733)) + +#### Meta Boxes +- Fix: Show Meta Boxes at the bottom of the screen regardless of the current rendering mode. ([66508](https://github.com/WordPress/gutenberg/pull/66508)) +- Hide metaboxes in Zoom Out. ([66886](https://github.com/WordPress/gutenberg/pull/66886)) + +#### Site Editor +- DataViews: Fix 'aria-label' for pattern preview element. ([66601](https://github.com/WordPress/gutenberg/pull/66601)) +- Site Hub: Fixed navigation redirect on mobile devices for classic themes. ([66867](https://github.com/WordPress/gutenberg/pull/66867)) + +#### Media +- Add `x-wav` mime type for wav files in Firefox. ([66850](https://github.com/WordPress/gutenberg/pull/66850)) +- Ensure HEIC files selectable from “Upload” button. ([66292](https://github.com/WordPress/gutenberg/pull/66292)) + +#### Patterns +- Fix uncategorized pattern browsing when pattern has no categories. ([66945](https://github.com/WordPress/gutenberg/pull/66945)) + +#### Interactivity API +- Fix property modification from inherited context two or more levels above. ([66872](https://github.com/WordPress/gutenberg/pull/66872)) + +#### Block API +- Process Block Type: Copy deprecation to a new object instead of mutating when stabilizing supports. ([66849](https://github.com/WordPress/gutenberg/pull/66849)) + +#### Design Tools +- Block Gap: Fix block spacing control for axial gap supported blocks. ([66783](https://github.com/WordPress/gutenberg/pull/66783)) + +#### Document Settings +- Editor: Restore the 'PluginPostStatusInfo' slot position. ([66665](https://github.com/WordPress/gutenberg/pull/66665)) + +#### Templates API +- Fix flash when clicking template name in the editor when a plugin registered template matches a default WP theme template. ([66359](https://github.com/WordPress/gutenberg/pull/66359)) + +#### Block bindings +- Fix unset array key warning in block-bindings.php. ([66337](https://github.com/WordPress/gutenberg/pull/66337)) + + +### Accessibility + +- Fix : Snackbar Notice Inconsistency. ([66405](https://github.com/WordPress/gutenberg/pull/66405)) +- Image: Add `aria-haspopup` prop write mode `more` tools menu items. ([66815](https://github.com/WordPress/gutenberg/pull/66815)) +- Site Icon Focus fix. ([66952](https://github.com/WordPress/gutenberg/pull/66952)) + +#### Components +- Popover: Fix missing label of the headerTitle Close button. ([66813](https://github.com/WordPress/gutenberg/pull/66813)) + +#### Post Editor +- Fix inconsistent sidebars close buttons sizes. ([66756](https://github.com/WordPress/gutenberg/pull/66756)) + +#### Block Library +- Remove unnecessary tooltip from Video block Text tracks button. ([66716](https://github.com/WordPress/gutenberg/pull/66716)) + +#### Block Editor +- Speak 'Block moved up/down' after using keyboard actions to move up/down. ([64966](https://github.com/WordPress/gutenberg/pull/64966)) + +#### Patterns +- Block Patterns List: Fix visual title and tooltip inconsistencies. ([64815](https://github.com/WordPress/gutenberg/pull/64815)) + + +### Performance + +- Inline Commenting: Avoid querying comments on editor load. ([66670](https://github.com/WordPress/gutenberg/pull/66670)) +- Patterns: Receive intermediate responses while unbound request is resolving. ([66713](https://github.com/WordPress/gutenberg/pull/66713)) +- Perf metrics: Update select and other metrics to use non-empty paragraphs. ([66762](https://github.com/WordPress/gutenberg/pull/66762)) +- Site Editor: Preload settings requests. ([66488](https://github.com/WordPress/gutenberg/pull/66488)) +- Site Editor: Speed up load by preloading home and front-page templates. ([66579](https://github.com/WordPress/gutenberg/pull/66579)) +- Site editor: Preload post if needed. ([66631](https://github.com/WordPress/gutenberg/pull/66631)) + +#### Global Styles +- Preload user global styles based on user caps. ([66541](https://github.com/WordPress/gutenberg/pull/66541)) + + +### Experiments + +- Add `isVisible` option to fields within DataForm. ([65826](https://github.com/WordPress/gutenberg/pull/65826)) +- DataViews: Implement `isItemClickable` and `onClickItem` props. ([66365](https://github.com/WordPress/gutenberg/pull/66365)) + +#### DataViews +- Quick Edit - Slug Field: Improve slug preview. ([66559](https://github.com/WordPress/gutenberg/pull/66559)) +- QuickEdit: Add password field data to the pages quick edit. ([66567](https://github.com/WordPress/gutenberg/pull/66567)) + + +### Documentation + +- Add 6.6.2 to Version in WordPress. ([66870](https://github.com/WordPress/gutenberg/pull/66870)) +- Add missing properties for DataViews/DataForm components. ([66749](https://github.com/WordPress/gutenberg/pull/66749)) +- Add section about the Fields API. ([66761](https://github.com/WordPress/gutenberg/pull/66761)) +- Block Bindings: Documentation API reference. ([66251](https://github.com/WordPress/gutenberg/pull/66251)) +- Docs: Include a note about supported licenses in WordPress packages. ([66562](https://github.com/WordPress/gutenberg/pull/66562)) +- Document `filterSortAndPaginate` & `isItemValid` utilities. ([66738](https://github.com/WordPress/gutenberg/pull/66738)) +- Feat: Storybook: Improve component organisation - Navigation Category - Issue #66275. ([66658](https://github.com/WordPress/gutenberg/pull/66658)) +- Feat: Storybook: Improve component organisation - Overlays Category - Issue #66275. ([66657](https://github.com/WordPress/gutenberg/pull/66657)) +- Feat: Storybook: Improve component organisation - Selection & Input Category - Issue #66275. ([66660](https://github.com/WordPress/gutenberg/pull/66660)) +- Feat: Storybook: Improve component organisation - Typography - Issue #66275. ([66633](https://github.com/WordPress/gutenberg/pull/66633)) +- Improve readability of DataViews documentation. ([66766](https://github.com/WordPress/gutenberg/pull/66766)) +- Move documentation for filter operators to proper place. ([66743](https://github.com/WordPress/gutenberg/pull/66743)) +- Reorganize to bootstrap DataForm API section. ([66729](https://github.com/WordPress/gutenberg/pull/66729)) +- Storybook: Improve component organisation - Actions. ([66680](https://github.com/WordPress/gutenberg/pull/66680)) +- Storybook: Log `warning()` when in dev mode. ([66568](https://github.com/WordPress/gutenberg/pull/66568)) +- Update Commands documentation with the existing contexts. ([66860](https://github.com/WordPress/gutenberg/pull/66860)) + + +### Code Quality + +- BlockPatternsList: Use the Async component. ([66744](https://github.com/WordPress/gutenberg/pull/66744)) +- Core Commands: Fix add new post URL assignment. ([66830](https://github.com/WordPress/gutenberg/pull/66830)) +- Inline Commenting: Optimize store selector and misc changes. ([66592](https://github.com/WordPress/gutenberg/pull/66592)) +- Remove unnecessary boolean assignments. ([66857](https://github.com/WordPress/gutenberg/pull/66857)) +- TypeScript: Fix and improve types for private-apis. ([66667](https://github.com/WordPress/gutenberg/pull/66667)) + +#### Block Editor +- Fix 'useSelect' dependencies for the 'RichText' component. ([66964](https://github.com/WordPress/gutenberg/pull/66964)) +- Fix ESLint warning for 'useBlockTypesState' hook. ([66757](https://github.com/WordPress/gutenberg/pull/66757)) +- Fix React Compiler error for 'BlockProps' util component. ([66809](https://github.com/WordPress/gutenberg/pull/66809)) +- Optimize `getVisibleElementBounds` in scrollable cases. ([66546](https://github.com/WordPress/gutenberg/pull/66546)) +- Revert: Fix unable to remove empty blocks on merge (#65262) + alternative. ([66564](https://github.com/WordPress/gutenberg/pull/66564)) +- URLInput: Fix incorrect classname for suggestions. ([66714](https://github.com/WordPress/gutenberg/pull/66714)) + +#### Site Editor +- Avoid using edited entity state in site editor loading hook. ([66924](https://github.com/WordPress/gutenberg/pull/66924)) +- Avoid using edited post selectors in welcome guide. ([66926](https://github.com/WordPress/gutenberg/pull/66926)) +- Edit Site: Refactor to remove usage of edited entity state. ([66922](https://github.com/WordPress/gutenberg/pull/66922)) +- Edit Site: Remove leftover 'priority-queue' dependency. ([66773](https://github.com/WordPress/gutenberg/pull/66773)) +- Remove useEditedEntityRecord hook. ([66955](https://github.com/WordPress/gutenberg/pull/66955)) + +#### Components +- Fix React Compiler error for 'useScrollRectIntoView'. ([66498](https://github.com/WordPress/gutenberg/pull/66498)) +- Panel: Add 40px size prop to Button. ([66589](https://github.com/WordPress/gutenberg/pull/66589)) +- Radio: Deprecate 36px default size. ([66572](https://github.com/WordPress/gutenberg/pull/66572)) +- Snackbar: Use `link` variant for action Button. ([66560](https://github.com/WordPress/gutenberg/pull/66560)) + +#### Data Layer +- Convert the emitter module in data package to TS. ([66669](https://github.com/WordPress/gutenberg/pull/66669)) +- Data: Rename useSelect internals to fix React Compiler violations. ([66807](https://github.com/WordPress/gutenberg/pull/66807)) +- Data: Upgrade Redux to v5.0.1. ([66966](https://github.com/WordPress/gutenberg/pull/66966)) + +#### Post Editor +- ESLint: Fix React Compiler violations in various commands. ([66787](https://github.com/WordPress/gutenberg/pull/66787)) +- Fix TS types for editor package. ([66754](https://github.com/WordPress/gutenberg/pull/66754)) + +#### Zoom Out +- Zoom-out: Move default background to the iframe component. ([66284](https://github.com/WordPress/gutenberg/pull/66284)) + +#### Design Tools +- Typography: Stabilize typography block supports within block processing. ([63401](https://github.com/WordPress/gutenberg/pull/63401)) + + +### Tools + +#### Testing +- Media: Check for `wav` mime type using isset. ([66947](https://github.com/WordPress/gutenberg/pull/66947)) + +#### Build Tooling +- Enforce the same order of fields in `package.json` files. ([66239](https://github.com/WordPress/gutenberg/pull/66239)) +- Introduce React Scanner for component usage stats. ([65463](https://github.com/WordPress/gutenberg/pull/65463)) + + +### Various + +- Style engine: Wrap array_merge in conditionals to prevent unnecessary merging. ([66661](https://github.com/WordPress/gutenberg/pull/66661)) + +#### Block Library +- Update placeholder text for blocks that support drag and drop. ([66842](https://github.com/WordPress/gutenberg/pull/66842)) +- update: Add Media to Add media in cover block. ([66835](https://github.com/WordPress/gutenberg/pull/66835)) + + +## First-time contributors + +The following PRs were merged by first-time contributors: + +- @benharri: Fix unset array key warning in block-bindings.php. ([66337](https://github.com/WordPress/gutenberg/pull/66337)) +- @benniledl: Add 6.6.2 to Version in WordPress. ([66870](https://github.com/WordPress/gutenberg/pull/66870)) +- @Infinite-Null: Media & Text: Set `.wp-block-media-text__media a` display to block. ([66915](https://github.com/WordPress/gutenberg/pull/66915)) +- @karthick-murugan: Site Icon Focus fix. ([66952](https://github.com/WordPress/gutenberg/pull/66952)) +- @rinkalpagdar: Post Content: Add border and spacing support. ([66366](https://github.com/WordPress/gutenberg/pull/66366)) +- @yogeshbhutkar: Site Hub: Fixed navigation redirect on mobile devices for classic themes. ([66867](https://github.com/WordPress/gutenberg/pull/66867)) + + +## Contributors + +The following contributors merged PRs in this release: + +@aaronrobertshaw @adamsilverstein @afercia @Aljullu @amitraj2203 @andrewserong @benharri @benniledl @carolinan @cbravobernal @DAreRodz @dcalhoun @ellatrix @fabiankaegy @gigitux @gziolo @hbhalodia @Infinite-Null @jasmussen @jorgefilipecosta @jsnajdr @juanfra @karthick-murugan @kevin940726 @louwie17 @Mamaduka @manzoorwanijk @matiasbenedetto @mikachan @mirka @n2erjo00 @ntsekouras @oandregal @ramonjd @renatho @rinkalpagdar @Soean @stokesman @swissspidy @t-hamano @tellthemachines @tyxla @up1512001 @Vrishabhsk @yogeshbhutkar @youknowriad + + + + = 19.6.4 = - PostTaxonomiesFlatTermSelector: abstract wrapper component (#66625) From d57502ee6bad7bd6bf352a73700ba2e61d79c3ef Mon Sep 17 00:00:00 2001 From: Bernie Reiter <96308+ockham@users.noreply.github.com> Date: Wed, 20 Nov 2024 19:57:53 +0100 Subject: [PATCH 154/226] Navigation Block: Remove obsolete Block Hooks filters (#64676) --- .../block-library/src/navigation/index.php | 150 ------------------ .../block-navigation-block-hooks-test.php | 148 ----------------- 2 files changed, 298 deletions(-) delete mode 100644 phpunit/blocks/block-navigation-block-hooks-test.php diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index dd300eb12c6feb..ae3b9620a33584 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -1520,153 +1520,3 @@ function block_core_navigation_insert_hooked_blocks( $inner_blocks, $post ) { return traverse_and_serialize_block( $mock_navigation_block, $before_block_visitor, $after_block_visitor ); } - -/** - * Insert ignoredHookedBlocks meta into the Navigation block and its inner blocks. - * - * Given a Navigation block's inner blocks and its corresponding `wp_navigation` post object, - * this function inserts ignoredHookedBlocks meta into it, and returns the serialized inner blocks in a - * mock Navigation block wrapper. - * - * @since 6.5.0 - * - * @param array $inner_blocks Parsed inner blocks of a Navigation block. - * @param WP_Post $post `wp_navigation` post object corresponding to the block. - * @return string Serialized inner blocks in mock Navigation block wrapper, with hooked blocks inserted, if any. - */ -function block_core_navigation_set_ignored_hooked_blocks_metadata( $inner_blocks, $post ) { - $mock_navigation_block = block_core_navigation_mock_parsed_block( $inner_blocks, $post ); - $hooked_blocks = get_hooked_blocks(); - $before_block_visitor = null; - $after_block_visitor = null; - - if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) { - $before_block_visitor = make_before_block_visitor( $hooked_blocks, $post, 'set_ignored_hooked_blocks_metadata' ); - $after_block_visitor = make_after_block_visitor( $hooked_blocks, $post, 'set_ignored_hooked_blocks_metadata' ); - } - - return traverse_and_serialize_block( $mock_navigation_block, $before_block_visitor, $after_block_visitor ); -} - -/** - * Updates the post meta with the list of ignored hooked blocks when the navigation is created or updated via the REST API. - * - * @access private - * @since 6.5.0 - * - * @param stdClass $post Post object. - * @return stdClass The updated post object. - */ -function block_core_navigation_update_ignore_hooked_blocks_meta( $post ) { - /* - * In this scenario the user has likely tried to create a navigation via the REST API. - * In which case we won't have a post ID to work with and store meta against. - */ - if ( empty( $post->ID ) ) { - return $post; - } - - /** - * Skip meta generation when consumers intentionally update specific Navigation fields - * and omit the content update. - */ - if ( ! isset( $post->post_content ) ) { - return $post; - } - - /* - * We run the Block Hooks mechanism to inject the `metadata.ignoredHookedBlocks` attribute into - * all anchor blocks. For the root level, we create a mock Navigation and extract them from there. - */ - $blocks = parse_blocks( $post->post_content ); - - /* - * Block Hooks logic requires a `WP_Post` object (rather than the `stdClass` with the updates that - * we're getting from the `rest_pre_insert_wp_navigation` filter) as its second argument (to be - * used as context for hooked blocks insertion). - * We thus have to look it up from the DB,based on `$post->ID`. - */ - $markup = block_core_navigation_set_ignored_hooked_blocks_metadata( $blocks, get_post( $post->ID ) ); - - $root_nav_block = parse_blocks( $markup )[0]; - $ignored_hooked_blocks = isset( $root_nav_block['attrs']['metadata']['ignoredHookedBlocks'] ) - ? $root_nav_block['attrs']['metadata']['ignoredHookedBlocks'] - : array(); - - if ( ! empty( $ignored_hooked_blocks ) ) { - $existing_ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true ); - if ( ! empty( $existing_ignored_hooked_blocks ) ) { - $existing_ignored_hooked_blocks = json_decode( $existing_ignored_hooked_blocks, true ); - $ignored_hooked_blocks = array_unique( array_merge( $ignored_hooked_blocks, $existing_ignored_hooked_blocks ) ); - } - update_post_meta( $post->ID, '_wp_ignored_hooked_blocks', json_encode( $ignored_hooked_blocks ) ); - } - - $post->post_content = block_core_navigation_remove_serialized_parent_block( $markup ); - return $post; -} - -/* - * Before adding our filter, we verify if it's already added in Core. - * However, during the build process, Gutenberg automatically prefixes our functions with "gutenberg_". - * Therefore, we concatenate the Core's function name to circumvent this prefix for our check. - */ -$rest_insert_wp_navigation_core_callback = 'block_core_navigation_' . 'update_ignore_hooked_blocks_meta'; // phpcs:ignore Generic.Strings.UnnecessaryStringConcat.Found - -/* - * Do not add the `block_core_navigation_update_ignore_hooked_blocks_meta` filter in the following cases: - * - If Core has added the `update_ignored_hooked_blocks_postmeta` filter already (WP >= 6.6); - * - or if the `$rest_insert_wp_navigation_core_callback` filter has already been added. - */ -if ( - ! has_filter( 'rest_pre_insert_wp_navigation', 'update_ignored_hooked_blocks_postmeta' ) && - ! has_filter( 'rest_pre_insert_wp_navigation', $rest_insert_wp_navigation_core_callback ) -) { - add_filter( 'rest_pre_insert_wp_navigation', 'block_core_navigation_update_ignore_hooked_blocks_meta' ); -} - -/** - * Hooks into the REST API response for the core/navigation block and adds the first and last inner blocks. - * - * @since 6.5.0 - * - * @param WP_REST_Response $response The response object. - * @param WP_Post $post Post object. - * @return WP_REST_Response The response object. - */ -function block_core_navigation_insert_hooked_blocks_into_rest_response( $response, $post ) { - if ( ! isset( $response->data['content']['raw'] ) || ! isset( $response->data['content']['rendered'] ) ) { - return $response; - } - $parsed_blocks = parse_blocks( $response->data['content']['raw'] ); - $content = block_core_navigation_insert_hooked_blocks( $parsed_blocks, $post ); - - // Remove mock Navigation block wrapper. - $content = block_core_navigation_remove_serialized_parent_block( $content ); - - $response->data['content']['raw'] = $content; - - /** This filter is documented in wp-includes/post-template.php */ - $response->data['content']['rendered'] = apply_filters( 'the_content', $content ); - - return $response; -} - -/* - * Before adding our filter, we verify if it's already added in Core. - * However, during the build process, Gutenberg automatically prefixes our functions with "gutenberg_". - * Therefore, we concatenate the Core's function name to circumvent this prefix for our check. - */ -$rest_prepare_wp_navigation_core_callback = 'block_core_navigation_' . 'insert_hooked_blocks_into_rest_response'; - -/* - * Do not add the `block_core_navigation_insert_hooked_blocks_into_rest_response` filter in the following cases: - * - If Core has added the `insert_hooked_blocks_into_rest_response` filter already (WP >= 6.6); - * - or if the `$rest_prepare_wp_navigation_core_callback` filter has already been added. - */ -if ( - ! has_filter( 'rest_prepare_wp_navigation', 'insert_hooked_blocks_into_rest_response' ) && - ! has_filter( 'rest_prepare_wp_navigation', $rest_prepare_wp_navigation_core_callback ) -) { - add_filter( 'rest_prepare_wp_navigation', 'block_core_navigation_insert_hooked_blocks_into_rest_response', 10, 3 ); -} diff --git a/phpunit/blocks/block-navigation-block-hooks-test.php b/phpunit/blocks/block-navigation-block-hooks-test.php deleted file mode 100644 index 1d3c86bf4bca4b..00000000000000 --- a/phpunit/blocks/block-navigation-block-hooks-test.php +++ /dev/null @@ -1,148 +0,0 @@ -'; - - self::$navigation_post = self::factory()->post->create_and_get( - array( - 'post_type' => 'wp_navigation', - 'post_title' => 'Navigation Menu', - 'post_content' => 'Original content', - ) - ); - } - - /** - * Tear down each test method. - */ - public function tear_down() { - $registry = WP_Block_Type_Registry::get_instance(); - - if ( $registry->is_registered( 'tests/my-block' ) ) { - $registry->unregister( 'tests/my-block' ); - } - - parent::tear_down(); - } - - /** - * @covers ::gutenberg_block_core_navigation_update_ignore_hooked_blocks_meta - */ - public function test_block_core_navigation_update_ignore_hooked_blocks_meta_preserves_entities() { - register_block_type( - 'tests/my-block', - array( - 'block_hooks' => array( - 'core/navigation' => 'last_child', - ), - ) - ); - - $original_markup = ''; - $post = new stdClass(); - $post->ID = self::$navigation_post->ID; - $post->post_content = $original_markup; - - $post = gutenberg_block_core_navigation_update_ignore_hooked_blocks_meta( $post ); - - // We expect the '&' character to be replaced with its unicode representation. - $expected_markup = str_replace( '&', '\u0026', $original_markup ); - - $this->assertSame( - $expected_markup, - $post->post_content, - 'Post content did not match expected markup with entities escaped.' - ); - $this->assertSame( - array( 'tests/my-block' ), - json_decode( get_post_meta( self::$navigation_post->ID, '_wp_ignored_hooked_blocks', true ), true ), - 'Block was not added to ignored hooked blocks metadata.' - ); - } - - /** - * @covers ::gutenberg_block_core_navigation_update_ignore_hooked_blocks_meta - */ - public function test_block_core_navigation_dont_modify_no_post_id() { - register_block_type( - 'tests/my-block', - array( - 'block_hooks' => array( - 'core/navigation' => 'last_child', - ), - ) - ); - - $original_markup = ''; - $post = new stdClass(); - $post->post_content = $original_markup; - - $post = gutenberg_block_core_navigation_update_ignore_hooked_blocks_meta( $post ); - - $this->assertSame( - $original_markup, - $post->post_content, - 'Post content did not match the original markup.' - ); - } - - /** - * @covers ::gutenberg_block_core_navigation_update_ignore_hooked_blocks_meta - */ - public function test_block_core_navigation_retains_content_if_not_set() { - register_block_type( - 'tests/my-block', - array( - 'block_hooks' => array( - 'core/navigation' => 'last_child', - ), - ) - ); - - $post = new stdClass(); - $post->ID = self::$navigation_post->ID; - $post->post_title = 'Navigation Menu with changes'; - - $post = gutenberg_block_core_navigation_update_ignore_hooked_blocks_meta( $post ); - - $this->assertSame( - 'Navigation Menu with changes', - $post->post_title, - 'Post title was changed.' - ); - - $this->assertFalse( - isset( $post->post_content ), - 'Post content should not be set.' - ); - } -} From b7d989e0dafb23866f65295a851e6b8734c3b693 Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Thu, 21 Nov 2024 13:58:58 +0800 Subject: [PATCH 155/226] Fix typo in use-block-sync tests (#67145) Co-authored-by: talldan Co-authored-by: ramonjd --- .../src/components/provider/test/use-block-sync.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/provider/test/use-block-sync.js b/packages/block-editor/src/components/provider/test/use-block-sync.js index aae5e517c63029..b2afdb942e66fa 100644 --- a/packages/block-editor/src/components/provider/test/use-block-sync.js +++ b/packages/block-editor/src/components/provider/test/use-block-sync.js @@ -22,7 +22,9 @@ jest.mock( '../../../store/actions', () => { ...actions, resetBlocks: jest.fn( actions.resetBlocks ), replaceInnerBlocks: jest.fn( actions.replaceInnerBlocks ), - setHasControlledInnerBlocks: jest.fn( actions.replaceInnerBlocks ), + setHasControlledInnerBlocks: jest.fn( + actions.setHasControlledInnerBlocks + ), }; } ); From afb05e8b9c2dbdc43c119f2c756f57620a4febfc Mon Sep 17 00:00:00 2001 From: Miguel Fonseca <150562+mcsf@users.noreply.github.com> Date: Thu, 21 Nov 2024 10:41:53 +0000 Subject: [PATCH 156/226] useBlockNameForPatterns: Refactor as a single useSelect call (#67171) --- packages/block-library/src/query/utils.js | 29 +++++++++++------------ 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/packages/block-library/src/query/utils.js b/packages/block-library/src/query/utils.js index fc22ca46d471c0..e12fdc8d8a7e89 100644 --- a/packages/block-library/src/query/utils.js +++ b/packages/block-library/src/query/utils.js @@ -272,32 +272,31 @@ export const getTransformedBlocksFromPattern = ( * @return {string} The block name to be used in the patterns suggestions. */ export function useBlockNameForPatterns( clientId, attributes ) { - const activeVariationName = useSelect( - ( select ) => - select( blocksStore ).getActiveBlockVariation( - 'core/query', - attributes - )?.name, - [ attributes ] - ); - const blockName = `core/query/${ activeVariationName }`; - const hasActiveVariationPatterns = useSelect( + return useSelect( ( select ) => { + const activeVariationName = select( + blocksStore + ).getActiveBlockVariation( 'core/query', attributes )?.name; + if ( ! activeVariationName ) { - return false; + return 'core/query'; } + const { getBlockRootClientId, getPatternsByBlockTypes } = select( blockEditorStore ); + const rootClientId = getBlockRootClientId( clientId ); const activePatterns = getPatternsByBlockTypes( - blockName, + `core/query/${ activeVariationName }`, rootClientId ); - return activePatterns.length > 0; + + return activePatterns.length > 0 + ? `core/query/${ activeVariationName }` + : 'core/query'; }, - [ clientId, activeVariationName, blockName ] + [ clientId, attributes ] ); - return hasActiveVariationPatterns ? blockName : 'core/query'; } /** From b5732a58e930f28cb8aa34d2d1d2ca741e2abd93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Thu, 21 Nov 2024 12:15:26 +0100 Subject: [PATCH 157/226] DataViews: fix action visibility logic (#67197) Co-authored-by: oandregal Co-authored-by: ntsekouras --- .../dataviews/src/components/dataviews-item-actions/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dataviews/src/components/dataviews-item-actions/index.tsx b/packages/dataviews/src/components/dataviews-item-actions/index.tsx index 47e65bc81cb171..787cef4420acc0 100644 --- a/packages/dataviews/src/components/dataviews-item-actions/index.tsx +++ b/packages/dataviews/src/components/dataviews-item-actions/index.tsx @@ -190,7 +190,7 @@ function hasOnlyOneActionAndIsPrimary< Item >( primaryActions: Action< Item >[], actions: Action< Item >[] ) { - return primaryActions.length === 1 && actions.length; + return primaryActions.length === 1 && actions.length === 1; } export default function ItemActions< Item >( { From ec4b881cf89a426772b10f265b400f701751ffd5 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Thu, 21 Nov 2024 15:10:24 +0200 Subject: [PATCH 158/226] Place "Write mode" functionality behind a Gutenberg experiment (#67008) Co-authored-by: ntsekouras Co-authored-by: mcsf Co-authored-by: carolinan Co-authored-by: youknowriad Co-authored-by: richtabor Co-authored-by: annezazu --- lib/experimental/editor-settings.php | 3 + lib/experiments-page.php | 12 ++ packages/block-editor/src/store/selectors.js | 3 + .../block-editor/src/store/test/selectors.js | 145 +++++++++++------- .../src/components/document-tools/index.js | 5 +- .../editor/various/write-design-mode.spec.js | 8 +- test/e2e/specs/site-editor/style-book.spec.js | 3 + 7 files changed, 115 insertions(+), 64 deletions(-) diff --git a/lib/experimental/editor-settings.php b/lib/experimental/editor-settings.php index afc6d7e220f676..5b36c32b3c8296 100644 --- a/lib/experimental/editor-settings.php +++ b/lib/experimental/editor-settings.php @@ -37,6 +37,9 @@ function gutenberg_enable_experiments() { if ( $gutenberg_experiments && array_key_exists( 'gutenberg-media-processing', $gutenberg_experiments ) ) { wp_add_inline_script( 'wp-block-editor', 'window.__experimentalMediaProcessing = true', 'before' ); } + if ( $gutenberg_experiments && array_key_exists( 'gutenberg-editor-write-mode', $gutenberg_experiments ) ) { + wp_add_inline_script( 'wp-block-editor', 'window.__experimentalEditorWriteMode = true', 'before' ); + } } add_action( 'admin_init', 'gutenberg_enable_experiments' ); diff --git a/lib/experiments-page.php b/lib/experiments-page.php index 946b68283a3e0b..9033e3c2d0c1fb 100644 --- a/lib/experiments-page.php +++ b/lib/experiments-page.php @@ -187,6 +187,18 @@ function gutenberg_initialize_experiments_settings() { ) ); + add_settings_field( + 'gutenberg-editor-write-mode', + __( 'Editor write mode', 'gutenberg' ), + 'gutenberg_display_experiment_field', + 'gutenberg-experiments', + 'gutenberg_experiments_section', + array( + 'label' => __( 'Enable write mode in editor.', 'gutenberg' ), + 'id' => 'gutenberg-editor-write-mode', + ) + ); + register_setting( 'gutenberg-experiments', 'gutenberg-experiments' diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 598b6b4ea480de..ac1d178f43de7c 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -2774,6 +2774,9 @@ export function isNavigationMode( state ) { */ export const __unstableGetEditorMode = createRegistrySelector( ( select ) => ( state ) => { + if ( ! window?.__experimentalEditorWriteMode ) { + return 'edit'; + } return ( state.settings.editorTool ?? select( preferencesStore ).get( 'core', 'editorTool' ) diff --git a/packages/block-editor/src/store/test/selectors.js b/packages/block-editor/src/store/test/selectors.js index 00aa085f667093..7c0361449c5fca 100644 --- a/packages/block-editor/src/store/test/selectors.js +++ b/packages/block-editor/src/store/test/selectors.js @@ -4615,68 +4615,97 @@ describe( 'getBlockEditingMode', () => { ).toBe( 'contentOnly' ); } ); - it( 'in navigation mode, the root section container is default', () => { - dispatch( preferencesStore ).set( 'core', 'editorTool', 'navigation' ); - expect( - getBlockEditingMode( - navigationModeStateWithRootSection, - 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337' - ) - ).toBe( 'default' ); - } ); + describe( 'navigation mode', () => { + const writeModeExperiment = window.__experimentalEditorWriteMode; + beforeAll( () => { + window.__experimentalEditorWriteMode = true; + } ); + afterAll( () => { + window.__experimentalEditorWriteMode = writeModeExperiment; + } ); + it( 'in navigation mode, the root section container is default', () => { + dispatch( preferencesStore ).set( + 'core', + 'editorTool', + 'navigation' + ); + expect( + getBlockEditingMode( + navigationModeStateWithRootSection, + 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337' + ) + ).toBe( 'default' ); + } ); - it( 'in navigation mode, anything outside the section container is disabled', () => { - dispatch( preferencesStore ).set( 'core', 'editorTool', 'navigation' ); - expect( - getBlockEditingMode( - navigationModeStateWithRootSection, - '6cf70164-9097-4460-bcbf-200560546988' - ) - ).toBe( 'disabled' ); - } ); + it( 'in navigation mode, anything outside the section container is disabled', () => { + dispatch( preferencesStore ).set( + 'core', + 'editorTool', + 'navigation' + ); + expect( + getBlockEditingMode( + navigationModeStateWithRootSection, + '6cf70164-9097-4460-bcbf-200560546988' + ) + ).toBe( 'disabled' ); + } ); - it( 'in navigation mode, sections are contentOnly', () => { - dispatch( preferencesStore ).set( 'core', 'editorTool', 'navigation' ); - expect( - getBlockEditingMode( - navigationModeStateWithRootSection, - 'b26fc763-417d-4f01-b81c-2ec61e14a972' - ) - ).toBe( 'contentOnly' ); - expect( - getBlockEditingMode( - navigationModeStateWithRootSection, - '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f' - ) - ).toBe( 'contentOnly' ); - } ); + it( 'in navigation mode, sections are contentOnly', () => { + dispatch( preferencesStore ).set( + 'core', + 'editorTool', + 'navigation' + ); + expect( + getBlockEditingMode( + navigationModeStateWithRootSection, + 'b26fc763-417d-4f01-b81c-2ec61e14a972' + ) + ).toBe( 'contentOnly' ); + expect( + getBlockEditingMode( + navigationModeStateWithRootSection, + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f' + ) + ).toBe( 'contentOnly' ); + } ); - it( 'in navigation mode, blocks with content attributes within sections are contentOnly', () => { - dispatch( preferencesStore ).set( 'core', 'editorTool', 'navigation' ); - hasContentRoleAttribute.mockReturnValueOnce( true ); - expect( - getBlockEditingMode( - navigationModeStateWithRootSection, - 'b3247f75-fd94-4fef-97f9-5bfd162cc416' - ) - ).toBe( 'contentOnly' ); + it( 'in navigation mode, blocks with content attributes within sections are contentOnly', () => { + dispatch( preferencesStore ).set( + 'core', + 'editorTool', + 'navigation' + ); + hasContentRoleAttribute.mockReturnValueOnce( true ); + expect( + getBlockEditingMode( + navigationModeStateWithRootSection, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'contentOnly' ); - hasContentRoleAttribute.mockReturnValueOnce( true ); - expect( - getBlockEditingMode( - navigationModeStateWithRootSection, - 'e178812d-ce5e-48c7-a945-8ae4ffcbbb7c' - ) - ).toBe( 'contentOnly' ); - } ); + hasContentRoleAttribute.mockReturnValueOnce( true ); + expect( + getBlockEditingMode( + navigationModeStateWithRootSection, + 'e178812d-ce5e-48c7-a945-8ae4ffcbbb7c' + ) + ).toBe( 'contentOnly' ); + } ); - it( 'in navigation mode, blocks without content attributes within sections are disabled', () => { - dispatch( preferencesStore ).set( 'core', 'editorTool', 'navigation' ); - expect( - getBlockEditingMode( - navigationModeStateWithRootSection, - '9b9c5c3f-2e46-4f02-9e14-9fed515b958s' - ) - ).toBe( 'disabled' ); + it( 'in navigation mode, blocks without content attributes within sections are disabled', () => { + dispatch( preferencesStore ).set( + 'core', + 'editorTool', + 'navigation' + ); + expect( + getBlockEditingMode( + navigationModeStateWithRootSection, + '9b9c5c3f-2e46-4f02-9e14-9fed515b958s' + ) + ).toBe( 'disabled' ); + } ); } ); } ); diff --git a/packages/editor/src/components/document-tools/index.js b/packages/editor/src/components/document-tools/index.js index 74118caaf5849c..a98def685e93a6 100644 --- a/packages/editor/src/components/document-tools/index.js +++ b/packages/editor/src/components/document-tools/index.js @@ -60,8 +60,9 @@ function DocumentTools( { className, disableBlockTools = false } ) { isDistractionFree: get( 'core', 'distractionFree' ), isVisualMode: getEditorMode() === 'visual', showTools: - getRenderingMode() !== 'post-only' || - getCurrentPostType() === 'wp_template', + !! window?.__experimentalEditorWriteMode && + ( getRenderingMode() !== 'post-only' || + getCurrentPostType() === 'wp_template' ), }; }, [] ); diff --git a/test/e2e/specs/editor/various/write-design-mode.spec.js b/test/e2e/specs/editor/various/write-design-mode.spec.js index 2116f9042685af..053f4cb8ff092a 100644 --- a/test/e2e/specs/editor/various/write-design-mode.spec.js +++ b/test/e2e/specs/editor/various/write-design-mode.spec.js @@ -7,19 +7,19 @@ test.describe( 'Write/Design mode', () => { test.beforeAll( async ( { requestUtils } ) => { await requestUtils.activateTheme( 'emptytheme' ); } ); - - test.beforeEach( async ( { admin } ) => { + test.beforeEach( async ( { admin, page } ) => { + await page.addInitScript( () => { + window.__experimentalEditorWriteMode = true; + } ); await admin.visitSiteEditor( { postId: 'emptytheme//index', postType: 'wp_template', canvas: 'edit', } ); } ); - test.afterAll( async ( { requestUtils } ) => { await requestUtils.activateTheme( 'twentytwentyone' ); } ); - test( 'Should prevent selecting intermediary blocks', async ( { editor, page, diff --git a/test/e2e/specs/site-editor/style-book.spec.js b/test/e2e/specs/site-editor/style-book.spec.js index d860b05bc8f06d..38030892826ec7 100644 --- a/test/e2e/specs/site-editor/style-book.spec.js +++ b/test/e2e/specs/site-editor/style-book.spec.js @@ -19,6 +19,9 @@ test.describe( 'Style Book', () => { } ); test.beforeEach( async ( { admin, editor, styleBook, page } ) => { + await page.addInitScript( () => { + window.__experimentalEditorWriteMode = true; + } ); await admin.visitSiteEditor(); await editor.canvas.locator( 'body' ).click(); await styleBook.open(); From 0c32e9e88c7e2fdd837c6de3a7055267af3af0e6 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 21 Nov 2024 15:35:45 +0100 Subject: [PATCH 159/226] Posts DataViews: Refactor the router to use route registration (#67160) Co-authored-by: youknowriad Co-authored-by: ntsekouras --- .../src/components/posts-app-routes/home.js | 36 ++++++++++ .../src/components/posts-app-routes/index.js | 36 ++++++++++ .../components/posts-app-routes/posts-edit.js | 31 +++++++++ .../posts-list-view-quick-edit.js | 52 ++++++++++++++ .../posts-app-routes/posts-list-view.js | 40 +++++++++++ .../posts-app-routes/posts-view-quick-edit.js | 49 +++++++++++++ .../components/posts-app-routes/posts-view.js | 35 ++++++++++ .../src/components/posts-app/index.js | 4 +- .../src/components/posts-app/router.js | 69 ------------------- 9 files changed, 282 insertions(+), 70 deletions(-) create mode 100644 packages/edit-site/src/components/posts-app-routes/home.js create mode 100644 packages/edit-site/src/components/posts-app-routes/index.js create mode 100644 packages/edit-site/src/components/posts-app-routes/posts-edit.js create mode 100644 packages/edit-site/src/components/posts-app-routes/posts-list-view-quick-edit.js create mode 100644 packages/edit-site/src/components/posts-app-routes/posts-list-view.js create mode 100644 packages/edit-site/src/components/posts-app-routes/posts-view-quick-edit.js create mode 100644 packages/edit-site/src/components/posts-app-routes/posts-view.js delete mode 100644 packages/edit-site/src/components/posts-app/router.js diff --git a/packages/edit-site/src/components/posts-app-routes/home.js b/packages/edit-site/src/components/posts-app-routes/home.js new file mode 100644 index 00000000000000..ec99cbd8899f1d --- /dev/null +++ b/packages/edit-site/src/components/posts-app-routes/home.js @@ -0,0 +1,36 @@ +/** + * WordPress dependencies + */ +import { privateApis as routerPrivateApis } from '@wordpress/router'; + +/** + * Internal dependencies + */ +import Editor from '../editor'; +import SidebarNavigationScreenMain from '../sidebar-navigation-screen-main'; +import { unlock } from '../../lock-unlock'; + +const { useLocation } = unlock( routerPrivateApis ); + +function HomeMobileView() { + const { params = {} } = useLocation(); + const { canvas = 'view' } = params; + + return canvas === 'edit' ? ( + + ) : ( + + ); +} + +export const homeRoute = { + name: 'home', + match: () => { + return true; + }, + areas: { + sidebar: , + preview: , + mobile: HomeMobileView, + }, +}; diff --git a/packages/edit-site/src/components/posts-app-routes/index.js b/packages/edit-site/src/components/posts-app-routes/index.js new file mode 100644 index 00000000000000..e850bbd382200d --- /dev/null +++ b/packages/edit-site/src/components/posts-app-routes/index.js @@ -0,0 +1,36 @@ +/** + * WordPress dependencies + */ +import { useRegistry, useDispatch } from '@wordpress/data'; +import { useEffect } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { unlock } from '../../lock-unlock'; +import { store as siteEditorStore } from '../../store'; +import { homeRoute } from './home'; +import { postsListViewQuickEditRoute } from './posts-list-view-quick-edit'; +import { postsListViewRoute } from './posts-list-view'; +import { postsViewQuickEditRoute } from './posts-view-quick-edit'; +import { postsViewRoute } from './posts-view'; +import { postsEditRoute } from './posts-edit'; + +const routes = [ + postsListViewQuickEditRoute, + postsListViewRoute, + postsViewQuickEditRoute, + postsViewRoute, + postsEditRoute, + homeRoute, +]; + +export function useRegisterPostsAppRoutes() { + const registry = useRegistry(); + const { registerRoute } = unlock( useDispatch( siteEditorStore ) ); + useEffect( () => { + registry.batch( () => { + routes.forEach( registerRoute ); + } ); + }, [ registry, registerRoute ] ); +} diff --git a/packages/edit-site/src/components/posts-app-routes/posts-edit.js b/packages/edit-site/src/components/posts-app-routes/posts-edit.js new file mode 100644 index 00000000000000..d3958245595416 --- /dev/null +++ b/packages/edit-site/src/components/posts-app-routes/posts-edit.js @@ -0,0 +1,31 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import PostList from '../post-list'; +import DataViewsSidebarContent from '../sidebar-dataviews'; +import SidebarNavigationScreen from '../sidebar-navigation-screen'; +import Editor from '../editor'; + +export const postsEditRoute = { + name: 'posts-edit', + match: ( params ) => { + return params.postType === 'post' && params.canvas === 'edit'; + }, + areas: { + sidebar: ( + } + /> + ), + content: , + mobile: , + preview: , + }, +}; diff --git a/packages/edit-site/src/components/posts-app-routes/posts-list-view-quick-edit.js b/packages/edit-site/src/components/posts-app-routes/posts-list-view-quick-edit.js new file mode 100644 index 00000000000000..d2434b390ffd9f --- /dev/null +++ b/packages/edit-site/src/components/posts-app-routes/posts-list-view-quick-edit.js @@ -0,0 +1,52 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; + +/** + * Internal dependencies + */ +import PostList from '../post-list'; +import DataViewsSidebarContent from '../sidebar-dataviews'; +import SidebarNavigationScreen from '../sidebar-navigation-screen'; +import { unlock } from '../../lock-unlock'; +import { PostEdit } from '../post-edit'; +import Editor from '../editor'; + +const { useLocation } = unlock( routerPrivateApis ); + +function PostQuickEdit() { + const { params } = useLocation(); + return ; +} + +export const postsListViewQuickEditRoute = { + name: 'posts-list-view-quick-edit', + match: ( params ) => { + return ( + params.isCustom !== 'true' && + ( params.layout ?? 'list' ) === 'list' && + !! params.quickEdit && + params.postType === 'post' && + params.canvas !== 'edit' + ); + }, + areas: { + sidebar: ( + } + /> + ), + content: , + mobile: , + preview: , + edit: , + }, + widths: { + content: 380, + edit: 380, + }, +}; diff --git a/packages/edit-site/src/components/posts-app-routes/posts-list-view.js b/packages/edit-site/src/components/posts-app-routes/posts-list-view.js new file mode 100644 index 00000000000000..68aa86c7fb2392 --- /dev/null +++ b/packages/edit-site/src/components/posts-app-routes/posts-list-view.js @@ -0,0 +1,40 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import PostList from '../post-list'; +import DataViewsSidebarContent from '../sidebar-dataviews'; +import SidebarNavigationScreen from '../sidebar-navigation-screen'; +import Editor from '../editor'; + +export const postsListViewRoute = { + name: 'posts-list-view', + match: ( params ) => { + return ( + params.isCustom !== 'true' && + ( params.layout ?? 'list' ) === 'list' && + ! params.quickEdit && + params.postType === 'post' && + params.canvas !== 'edit' + ); + }, + areas: { + sidebar: ( + } + /> + ), + content: , + preview: , + mobile: , + }, + widths: { + content: 380, + }, +}; diff --git a/packages/edit-site/src/components/posts-app-routes/posts-view-quick-edit.js b/packages/edit-site/src/components/posts-app-routes/posts-view-quick-edit.js new file mode 100644 index 00000000000000..52e6f9a2d26ef6 --- /dev/null +++ b/packages/edit-site/src/components/posts-app-routes/posts-view-quick-edit.js @@ -0,0 +1,49 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; + +/** + * Internal dependencies + */ +import PostList from '../post-list'; +import DataViewsSidebarContent from '../sidebar-dataviews'; +import SidebarNavigationScreen from '../sidebar-navigation-screen'; +import { unlock } from '../../lock-unlock'; +import { PostEdit } from '../post-edit'; + +const { useLocation } = unlock( routerPrivateApis ); + +function PostQuickEdit() { + const { params } = useLocation(); + return ; +} + +export const postsViewQuickEditRoute = { + name: 'posts-view-quick-edit', + match: ( params ) => { + return ( + ( params.isCustom === 'true' || + ( params.layout ?? 'list' ) !== 'list' ) && + !! params.quickEdit && + params.postType === 'post' && + params.canvas !== 'edit' + ); + }, + areas: { + sidebar: ( + } + /> + ), + content: , + mobile: , + edit: , + }, + widths: { + edit: 380, + }, +}; diff --git a/packages/edit-site/src/components/posts-app-routes/posts-view.js b/packages/edit-site/src/components/posts-app-routes/posts-view.js new file mode 100644 index 00000000000000..6559991475d278 --- /dev/null +++ b/packages/edit-site/src/components/posts-app-routes/posts-view.js @@ -0,0 +1,35 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import PostList from '../post-list'; +import DataViewsSidebarContent from '../sidebar-dataviews'; +import SidebarNavigationScreen from '../sidebar-navigation-screen'; + +export const postsViewRoute = { + name: 'posts-view', + match: ( params ) => { + return ( + ( params.isCustom === 'true' || + ( params.layout ?? 'list' ) !== 'list' ) && + ! params.quickEdit && + params.postType === 'post' && + params.canvas !== 'edit' + ); + }, + areas: { + sidebar: ( + } + /> + ), + content: , + mobile: , + }, +}; diff --git a/packages/edit-site/src/components/posts-app/index.js b/packages/edit-site/src/components/posts-app/index.js index 80d2c1c7eba86f..72e5b1eb997498 100644 --- a/packages/edit-site/src/components/posts-app/index.js +++ b/packages/edit-site/src/components/posts-app/index.js @@ -11,13 +11,15 @@ import { privateApis as routerPrivateApis } from '@wordpress/router'; * Internal dependencies */ import Layout from '../layout'; -import useActiveRoute from './router'; +import { useRegisterPostsAppRoutes } from '../posts-app-routes'; import { unlock } from '../../lock-unlock'; +import useActiveRoute from '../layout/router'; const { RouterProvider } = unlock( routerPrivateApis ); const { GlobalStylesProvider } = unlock( editorPrivateApis ); function PostsLayout() { + useRegisterPostsAppRoutes(); const route = useActiveRoute(); return ; } diff --git a/packages/edit-site/src/components/posts-app/router.js b/packages/edit-site/src/components/posts-app/router.js deleted file mode 100644 index de89567b262094..00000000000000 --- a/packages/edit-site/src/components/posts-app/router.js +++ /dev/null @@ -1,69 +0,0 @@ -/** - * WordPress dependencies - */ -import { privateApis as routerPrivateApis } from '@wordpress/router'; -import { useSelect } from '@wordpress/data'; -import { store as coreStore } from '@wordpress/core-data'; - -/** - * Internal dependencies - */ -import { unlock } from '../../lock-unlock'; -import Editor from '../editor'; -import SidebarNavigationScreen from '../sidebar-navigation-screen'; -import SidebarNavigationScreenMain from '../sidebar-navigation-screen-main'; -import DataViewsSidebarContent from '../sidebar-dataviews'; -import PostList from '../post-list'; - -const { useLocation } = unlock( routerPrivateApis ); - -export default function useActiveRoute() { - const { params = {} } = useLocation(); - const { postType, layout, canvas } = params; - const labels = useSelect( - ( select ) => { - return select( coreStore ).getPostType( postType )?.labels; - }, - [ postType ] - ); - - // Posts list. - if ( [ 'post' ].includes( postType ) ) { - const isListLayout = layout === 'list' || ! layout; - return { - name: 'posts-list', - areas: { - sidebar: ( - } - /> - ), - content: , - preview: ( isListLayout || canvas === 'edit' ) && ( - - ), - mobile: - canvas === 'edit' ? ( - - ) : ( - - ), - }, - widths: { - content: isListLayout ? 380 : undefined, - }, - }; - } - - // Fallback shows the home page preview - return { - name: 'default', - areas: { - sidebar: , - preview: , - mobile: canvas === 'edit' && , - }, - }; -} From e0d5ee65919d8e187509f7a78b9b77255e63ddac Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Thu, 21 Nov 2024 12:31:20 -0500 Subject: [PATCH 160/226] Migrate Gradle wrapper validation action. (#66602) * Migrate Gradel wrapper validation action. The `gradle/wrapper-validation-action` has been migrated to `gradle/actions/wrapper-validation`. Read more: https://github.com/gradle/actions/blob/main/docs/deprecation-upgrade-guide.md#the-action-gradlewrapper-validation-action-has-been-replaced-by-gradleactionswrapper-validation. * FIx botched merge. * Update gradle/actions version. --------- Co-authored-by: desrosj --- .github/workflows/gradle-wrapper-validation.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index 54378765bd26ff..2bb5676ae9ed66 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -6,7 +6,9 @@ jobs: name: 'Validation' runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - - uses: gradle/wrapper-validation-action@v3 + - name: Validate checksums + uses: gradle/actions/wrapper-validation@cc4fc85e6b35bafd578d5ffbc76a5518407e1af0 # v4.2.1 From 9a6f48b8337e598076503b7ad36e10e52e666f94 Mon Sep 17 00:00:00 2001 From: Himanshu Pathak Date: Thu, 21 Nov 2024 23:37:13 +0530 Subject: [PATCH 161/226] Menu.ItemHelpText: better line breaking (#67011) * Fix: Use break-word instead of break-all in attribute description Changed break-all to use word-break for better readability. * CSS: Replace deprecated word-break with overflow-wrap Replace deprecated `word-break: break-word` with the modern equivalent `overflow-wrap: anywhere` to handle text wrapping. This change maintains the same text wrapping behavior while using the current standard CSS property. * Docs: Add changelog entry for MenuItemHelpText text wrapping fix * Docs: Update changelog entry for Menu.ItemHelpText to internal section Co-authored-by: himanshupathak95 Co-authored-by: juanfra Co-authored-by: mirka <0mirka00@git.wordpress.org> Co-authored-by: ciampo Co-authored-by: im3dabasia Co-authored-by: jasmussen --- packages/components/CHANGELOG.md | 1 + packages/components/src/menu/styles.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index ff4a8b714c9a52..d7741f4caa9886 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -35,6 +35,7 @@ - `SlotFill`: fix dependencies of `Fill` registration effects ([#67071](https://github.com/WordPress/gutenberg/pull/67071)). - `SlotFill`: rewrite the `Slot` component from class component to functional ([#67153](https://github.com/WordPress/gutenberg/pull/67153)). +- `Menu.ItemHelpText`: Fix text wrapping to prevent unintended word breaks ([#67011](https://github.com/WordPress/gutenberg/pull/67011)). ## 28.12.0 (2024-11-16) diff --git a/packages/components/src/menu/styles.ts b/packages/components/src/menu/styles.ts index 3312c8cb2de161..0e0752bf24cd10 100644 --- a/packages/components/src/menu/styles.ts +++ b/packages/components/src/menu/styles.ts @@ -380,7 +380,7 @@ export const MenuItemHelpText = styled( Truncate )` font-size: ${ font( 'helpText.fontSize' ) }; line-height: 16px; color: ${ LIGHTER_TEXT_COLOR }; - word-break: break-all; + overflow-wrap: anywhere; [data-active-item]:not( [data-focus-visible] ) *:not( ${ MenuPopoverInnerWrapper } ) From 98a7d5d10e86fdbca135f46233a08d6cf9acfcc8 Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Nov 2024 19:49:08 -0500 Subject: [PATCH 162/226] Update the enhanced pagination help text (#67173) --- .../inspector-controls/enhanced-pagination-control.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/block-library/src/query/edit/inspector-controls/enhanced-pagination-control.js b/packages/block-library/src/query/edit/inspector-controls/enhanced-pagination-control.js index 9d47d67e61d781..4d0b1a9fd9da37 100644 --- a/packages/block-library/src/query/edit/inspector-controls/enhanced-pagination-control.js +++ b/packages/block-library/src/query/edit/inspector-controls/enhanced-pagination-control.js @@ -18,15 +18,13 @@ export default function EnhancedPaginationControl( { const fullPageClientSideNavigation = window.__experimentalFullPageClientSideNavigation; - let help = __( 'Browsing between pages requires a full page reload.' ); + let help = __( + 'Reload the full page—instead of just the posts list—when visitors navigate between pages.' + ); if ( fullPageClientSideNavigation ) { help = __( 'Experimental full-page client-side navigation setting enabled.' ); - } else if ( enhancedPagination ) { - help = __( - 'Reload the full page—instead of just the posts list—when visitors navigate between pages.' - ); } else if ( hasUnsupportedBlocks ) { help = __( 'Enhancement disabled because there are non-compatible blocks inside the Query block.' From a7c373f7acf212ec7999db53ddb17108f1f684df Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Fri, 22 Nov 2024 09:48:38 +0800 Subject: [PATCH 163/226] Avoid zooming out when browsing styles if the preview mode is active (#67190) Co-authored-by: talldan Co-authored-by: tellthemachines Co-authored-by: ramonjd Co-authored-by: draganescu Co-authored-by: yogeshbhutkar Co-authored-by: jameskoster --- .../global-styles/screen-style-variations.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/screen-style-variations.js b/packages/edit-site/src/components/global-styles/screen-style-variations.js index 76d13023ff09a8..f6036aaace4358 100644 --- a/packages/edit-site/src/components/global-styles/screen-style-variations.js +++ b/packages/edit-site/src/components/global-styles/screen-style-variations.js @@ -1,10 +1,13 @@ /** * WordPress dependencies */ +import { + privateApis as blockEditorPrivateApis, + store as blockEditorStore, +} from '@wordpress/block-editor'; import { Card, CardBody } from '@wordpress/components'; +import { useSelect, useDispatch } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; -import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; -import { useDispatch } from '@wordpress/data'; import { store as editorStore } from '@wordpress/editor'; import { useEffect } from '@wordpress/element'; @@ -19,10 +22,13 @@ const { useZoomOut } = unlock( blockEditorPrivateApis ); function ScreenStyleVariations() { // Style Variations should only be previewed in with - // - a "zoomed out" editor + // - a "zoomed out" editor (but not when in preview mode) // - "Desktop" device preview + const isPreviewMode = useSelect( ( select ) => { + return select( blockEditorStore ).getSettings().isPreviewMode; + }, [] ); const { setDeviceType } = useDispatch( editorStore ); - useZoomOut(); + useZoomOut( ! isPreviewMode ); useEffect( () => { setDeviceType( 'desktop' ); }, [ setDeviceType ] ); From 92254bf3677d7c561d36ab47ec0344e18f71fa2b Mon Sep 17 00:00:00 2001 From: Doug Wollison Date: Thu, 21 Nov 2024 21:40:17 -0500 Subject: [PATCH 164/226] Details block: use summary content as default label (#67217) Co-authored-by: dougwollison Co-authored-by: talldan --- packages/block-library/src/details/index.js | 24 ++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/details/index.js b/packages/block-library/src/details/index.js index 3ba5efb04e27d2..31ee2e0e00f139 100644 --- a/packages/block-library/src/details/index.js +++ b/packages/block-library/src/details/index.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { details as icon } from '@wordpress/icons'; -import { __ } from '@wordpress/i18n'; +import { __, sprintf } from '@wordpress/i18n'; /** * Internal dependencies @@ -34,6 +34,28 @@ export const settings = { }, ], }, + __experimentalLabel( attributes, { context } ) { + const { summary } = attributes; + + const customName = attributes?.metadata?.name; + const hasSummary = summary?.trim().length > 0; + + // In the list view, use the block's summary as the label. + // If the summary is empty, fall back to the default label. + if ( context === 'list-view' && ( customName || hasSummary ) ) { + return customName || summary; + } + + if ( context === 'accessibility' ) { + return ! hasSummary + ? __( 'Details. Empty.' ) + : sprintf( + /* translators: accessibility text; summary title. */ + __( 'Details. %s' ), + summary + ); + } + }, save, edit, transforms, From b58cce696977b0f8850a39bfaf895a426a59c619 Mon Sep 17 00:00:00 2001 From: Manzoor Wani Date: Fri, 22 Nov 2024 00:30:15 -0800 Subject: [PATCH 165/226] Fix ESLint Jest reporting entire body of the test function rather than the identifier (#67222) Co-authored-by: manzoorwanijk Co-authored-by: Mamaduka Co-authored-by: talldan --- package-lock.json | 11 ++++++----- package.json | 2 +- packages/eslint-plugin/package.json | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 04a8d2021f12a0..1fc9131a33c8c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -88,7 +88,7 @@ "eslint-import-resolver-node": "0.3.4", "eslint-plugin-eslint-comments": "3.1.2", "eslint-plugin-import": "2.25.2", - "eslint-plugin-jest": "27.2.3", + "eslint-plugin-jest": "27.4.3", "eslint-plugin-jest-dom": "5.0.2", "eslint-plugin-prettier": "5.0.0", "eslint-plugin-react-compiler": "19.0.0-beta-0dec889-20241115", @@ -25190,9 +25190,10 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/eslint-plugin-jest": { - "version": "27.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.3.tgz", - "integrity": "sha512-sRLlSCpICzWuje66Gl9zvdF6mwD5X86I4u55hJyFBsxYOsBCmT5+kSUjf+fkFWVMMgpzNEupjW8WzUqi83hJAQ==", + "version": "27.4.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.4.3.tgz", + "integrity": "sha512-7S6SmmsHsgIm06BAGCAxL+ABd9/IB3MWkz2pudj6Qqor2y1qQpWPfuFU4SG9pWj4xDjF0e+D7Llh5useuSzAZw==", + "license": "MIT", "dependencies": { "@typescript-eslint/utils": "^5.10.0" }, @@ -54649,7 +54650,7 @@ "cosmiconfig": "^7.0.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-import": "^2.25.2", - "eslint-plugin-jest": "^27.2.3", + "eslint-plugin-jest": "^27.4.3", "eslint-plugin-jsdoc": "^46.4.6", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-playwright": "^0.15.3", diff --git a/package.json b/package.json index 52668f667c71cd..41102f867f0e22 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "eslint-import-resolver-node": "0.3.4", "eslint-plugin-eslint-comments": "3.1.2", "eslint-plugin-import": "2.25.2", - "eslint-plugin-jest": "27.2.3", + "eslint-plugin-jest": "27.4.3", "eslint-plugin-jest-dom": "5.0.2", "eslint-plugin-prettier": "5.0.0", "eslint-plugin-react-compiler": "19.0.0-beta-0dec889-20241115", diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index c3521692d7fd12..0e8880f0941234 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -39,7 +39,7 @@ "cosmiconfig": "^7.0.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-import": "^2.25.2", - "eslint-plugin-jest": "^27.2.3", + "eslint-plugin-jest": "^27.4.3", "eslint-plugin-jsdoc": "^46.4.6", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-playwright": "^0.15.3", From 58ae911e10abe260a20514c2249ff50b8e46dcac Mon Sep 17 00:00:00 2001 From: Sainath Poojary <53347682+SainathPoojary@users.noreply.github.com> Date: Fri, 22 Nov 2024 14:22:22 +0530 Subject: [PATCH 166/226] Social Links: Fix font family and weight inconsistency in editor (#67204) Added font-weight: inherit; and font-family: inherit; to the .wp-block-social-link-anchor class in the editor to ensure consistent font styling with the frontend. Unlinked contributors: bgardner. Co-authored-by: SainathPoojary Co-authored-by: akasunil Co-authored-by: Mamaduka Co-authored-by: jordesign Co-authored-by: himanshupathak95 --- packages/block-library/src/social-link/editor.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/block-library/src/social-link/editor.scss b/packages/block-library/src/social-link/editor.scss index 2f5714f5d2ed9f..2e93c9447cca8d 100644 --- a/packages/block-library/src/social-link/editor.scss +++ b/packages/block-library/src/social-link/editor.scss @@ -14,6 +14,8 @@ font-size: inherit; color: currentColor; height: auto; + font-weight: inherit; + font-family: inherit; // This rule ensures social link buttons display correctly in template parts. opacity: 1; From 81d2ee840c21bf7818ef0b3ec0a6297ace43d973 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 22 Nov 2024 09:17:00 +0000 Subject: [PATCH 167/226] Use rems for Nav overlay left padding (#67168) Co-authored-by: getdave Co-authored-by: MaggieCabrera Co-authored-by: tysonlmao --- packages/block-library/src/navigation/style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation/style.scss b/packages/block-library/src/navigation/style.scss index 3d7a8810ae9b71..5f49eba466a5fd 100644 --- a/packages/block-library/src/navigation/style.scss +++ b/packages/block-library/src/navigation/style.scss @@ -510,7 +510,7 @@ button.wp-block-navigation-item__content { padding-top: clamp(1rem, var(--wp--style--root--padding-top), 20rem); padding-right: clamp(1rem, var(--wp--style--root--padding-right), 20rem); padding-bottom: clamp(1rem, var(--wp--style--root--padding-bottom), 20rem); - padding-left: clamp(1rem, var(--wp--style--root--padding-left), 20em); + padding-left: clamp(1rem, var(--wp--style--root--padding-left), 20rem); // Allow modal to scroll. overflow: auto; From 2919c5c4c6ee20740faa7bd7ffd9b360120e6a38 Mon Sep 17 00:00:00 2001 From: Jarda Snajdr Date: Fri, 22 Nov 2024 10:47:03 +0100 Subject: [PATCH 168/226] Fix fatal error in in_array call in post_type_default_rendering_mode (#67225) Co-authored-by: jsnajdr Co-authored-by: fabiankaegy --- lib/compat/wordpress-6.8/post.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compat/wordpress-6.8/post.php b/lib/compat/wordpress-6.8/post.php index 26e6c3adc07a3d..639e33b4e5ca51 100644 --- a/lib/compat/wordpress-6.8/post.php +++ b/lib/compat/wordpress-6.8/post.php @@ -39,7 +39,7 @@ function gutenberg_post_type_default_rendering_mode( $args, $post_type ) { if ( wp_is_block_theme() && ( isset( $args['show_in_rest'] ) && $args['show_in_rest'] ) && - ( isset( $args['supports'] ) && in_array( 'editor', $args['supports'], true ) ) + ( ! empty( $args['supports'] ) && in_array( 'editor', $args['supports'], true ) ) ) { // Validate the supplied rendering mode. if ( From 4d2fb64425d7653315997d9c4003f1fa6a4f912a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Fri, 22 Nov 2024 11:24:12 +0100 Subject: [PATCH 169/226] DataViews: fix spacing when combining combined fields (#67226) Co-authored-by: oandregal Co-authored-by: youknowriad --- .../components/dataviews/stories/fixtures.tsx | 1 + .../dataviews/stories/index.story.tsx | 18 +++++++++++++++--- .../src/dataviews-layouts/table/index.tsx | 6 +++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/dataviews/src/components/dataviews/stories/fixtures.tsx b/packages/dataviews/src/components/dataviews/stories/fixtures.tsx index ff098209b34684..6c74c516853c5b 100644 --- a/packages/dataviews/src/components/dataviews/stories/fixtures.tsx +++ b/packages/dataviews/src/components/dataviews/stories/fixtures.tsx @@ -558,6 +558,7 @@ export const themeFields: Field< Theme >[] = [ }, { id: 'requires', label: 'Requires at least' }, { id: 'tested', label: 'Tested up to' }, + { id: 'icon', label: 'Icon', render: () => }, { id: 'tags', label: 'Tags', diff --git a/packages/dataviews/src/components/dataviews/stories/index.story.tsx b/packages/dataviews/src/components/dataviews/stories/index.story.tsx index 878677d2eb30c6..6161af125b5ca4 100644 --- a/packages/dataviews/src/components/dataviews/stories/index.story.tsx +++ b/packages/dataviews/src/components/dataviews/stories/index.story.tsx @@ -137,16 +137,28 @@ export const FieldsNoSortableNoHidable = () => { export const CombinedFields = () => { const defaultLayoutsThemes = { table: { - fields: [ 'theme', 'requires', 'tested' ], + fields: [ 'theme_with_combined', 'theme_with_simple' ], layout: { primaryField: 'name', combinedFields: [ { - id: 'theme', + id: 'name_tested', label: 'Theme', - children: [ 'name', 'description' ], + children: [ 'name', 'tested' ], direction: 'vertical', }, + { + id: 'theme_with_combined', + label: 'Combine combined fields', + children: [ 'icon', 'name_tested' ], + direction: 'horizontal', + }, + { + id: 'theme_with_simple', + label: 'Combine simple fields', + children: [ 'icon', 'name' ], + direction: 'horizontal', + }, ] as CombinedField[], styles: { theme: { diff --git a/packages/dataviews/src/dataviews-layouts/table/index.tsx b/packages/dataviews/src/dataviews-layouts/table/index.tsx index 8ef41db1c38798..db76d24b53bfa3 100644 --- a/packages/dataviews/src/dataviews-layouts/table/index.tsx +++ b/packages/dataviews/src/dataviews-layouts/table/index.tsx @@ -147,7 +147,11 @@ function TableColumnCombined< Item >( { ) ); if ( field.direction === 'horizontal' ) { - return { children }; + return ( + + { children } + + ); } return { children }; } From 452de1b775ea28e4d13f94db6117b99e36d56e0e Mon Sep 17 00:00:00 2001 From: Akshat Kakkad <87222220+AKSHAT2802@users.noreply.github.com> Date: Fri, 22 Nov 2024 17:09:41 +0530 Subject: [PATCH 170/226] Add all color palettes to select from editor panel (#65148) * Add all the colors in with-color-context so that they all are listed in block editor * Remove default colour pallete * Remove extra space * Update packages/block-editor/src/components/color-palette/with-color-context.js re-add default colours Co-authored-by: Aki Hamano <54422211+t-hamano@users.noreply.github.com> * Add default colours if enabled * Update packages/block-editor/src/components/color-palette/with-color-context.js Co-authored-by: Aki Hamano <54422211+t-hamano@users.noreply.github.com> * update test --------- Unlinked contributors: EddyBoels, burnuser. Co-authored-by: AKSHAT2802 Co-authored-by: richtabor Co-authored-by: t-hamano Co-authored-by: ndiego Co-authored-by: rohitmathur-7 Co-authored-by: javiercasares --- .../color-palette/with-color-context.js | 32 +++++++++++++++---- packages/block-library/src/cover/test/edit.js | 4 +-- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/packages/block-editor/src/components/color-palette/with-color-context.js b/packages/block-editor/src/components/color-palette/with-color-context.js index 62b8c1bc4b6181..38c90531edaac1 100644 --- a/packages/block-editor/src/components/color-palette/with-color-context.js +++ b/packages/block-editor/src/components/color-palette/with-color-context.js @@ -10,14 +10,32 @@ import { useSettings } from '../use-settings'; export default createHigherOrderComponent( ( WrappedComponent ) => { return ( props ) => { - const [ colorsFeature, enableCustomColors ] = useSettings( - 'color.palette', - 'color.custom' + // Get the default colors, theme colors, and custom colors + const [ + defaultColors, + themeColors, + customColors, + enableCustomColors, + enableDefaultColors, + ] = useSettings( + 'color.palette.default', + 'color.palette.theme', + 'color.palette.custom', + 'color.custom', + 'color.defaultPalette' ); - const { - colors = colorsFeature, - disableCustomColors = ! enableCustomColors, - } = props; + + const _colors = enableDefaultColors + ? [ + ...( themeColors || [] ), + ...( defaultColors || [] ), + ...( customColors || [] ), + ] + : [ ...( themeColors || [] ), ...( customColors || [] ) ]; + + const { colors = _colors, disableCustomColors = ! enableCustomColors } = + props; + const hasColorsToChoose = ( colors && colors.length > 0 ) || ! disableCustomColors; return ( diff --git a/packages/block-library/src/cover/test/edit.js b/packages/block-library/src/cover/test/edit.js index 5c1a5b5e13e67d..f5d6a5301ef6d2 100644 --- a/packages/block-library/src/cover/test/edit.js +++ b/packages/block-library/src/cover/test/edit.js @@ -337,7 +337,7 @@ describe( 'Cover block', () => { describe( 'when colors are disabled', () => { test( 'does not render overlay control', async () => { await setup( undefined, true, disabledColorSettings ); - await createAndSelectBlock(); + await selectBlock( 'Block: Cover' ); await userEvent.click( screen.getByRole( 'tab', { name: 'Styles' } ) ); @@ -350,7 +350,7 @@ describe( 'Cover block', () => { } ); test( 'does not render opacity control', async () => { await setup( undefined, true, disabledColorSettings ); - await createAndSelectBlock(); + await selectBlock( 'Block: Cover' ); await userEvent.click( screen.getByRole( 'tab', { name: 'Styles' } ) ); From 455bb5d93408c45622d747a547088cd77e0d0511 Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Fri, 22 Nov 2024 12:47:04 +0100 Subject: [PATCH 171/226] Modal: Increase size of the Close button (#66792) * Make the modal component close button use the compact size. * Make spacing consistent. * Add changelog entry. Co-authored-by: afercia Co-authored-by: mirka <0mirka00@git.wordpress.org> Co-authored-by: jameskoster --- packages/block-library/src/freeform/modal.js | 2 +- packages/components/CHANGELOG.md | 1 + packages/components/src/modal/index.tsx | 4 ++-- packages/components/src/modal/stories/index.story.tsx | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/block-library/src/freeform/modal.js b/packages/block-library/src/freeform/modal.js index 4ed4ef4d3a07ca..35652eb29948a3 100644 --- a/packages/block-library/src/freeform/modal.js +++ b/packages/block-library/src/freeform/modal.js @@ -25,7 +25,7 @@ function ModalAuxiliaryActions( { onClick, isModalFullScreen } ) { return (