From 758b750ee3347cba4f1d334d1ab378387657f837 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 27 Nov 2024 12:24:10 +0100 Subject: [PATCH 01/14] Site Editor: Unify layout with posts dataviews (#67162) Co-authored-by: youknowriad Co-authored-by: ntsekouras --- .../edit-site/src/components/app/index.js | 19 ++++--------------- .../edit-site/src/components/layout/index.js | 17 +++++++++++++++-- .../src/components/posts-app/index.js | 14 +++----------- 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/packages/edit-site/src/components/app/index.js b/packages/edit-site/src/components/app/index.js index 3588565fcb3c1..7e4c50d7d00f0 100644 --- a/packages/edit-site/src/components/app/index.js +++ b/packages/edit-site/src/components/app/index.js @@ -1,11 +1,6 @@ /** * WordPress dependencies */ -import { SlotFillProvider } from '@wordpress/components'; -import { - UnsavedChangesWarning, - privateApis as editorPrivateApis, -} from '@wordpress/editor'; import { store as noticesStore } from '@wordpress/notices'; import { useDispatch } from '@wordpress/data'; import { __, sprintf } from '@wordpress/i18n'; @@ -23,7 +18,6 @@ import useSetCommandContext from '../../hooks/commands/use-set-command-context'; import { useRegisterSiteEditorRoutes } from '../site-editor-routes'; const { RouterProvider } = unlock( routerPrivateApis ); -const { GlobalStylesProvider } = unlock( editorPrivateApis ); function AppLayout() { useCommonCommands(); @@ -50,14 +44,9 @@ export default function App() { } return ( - - - - - - - - - + + + + ); } diff --git a/packages/edit-site/src/components/layout/index.js b/packages/edit-site/src/components/layout/index.js index cbc0a4661bf3e..47ff65aa2ac67 100644 --- a/packages/edit-site/src/components/layout/index.js +++ b/packages/edit-site/src/components/layout/index.js @@ -10,6 +10,7 @@ import { __unstableMotion as motion, __unstableAnimatePresence as AnimatePresence, __unstableUseNavigateRegions as useNavigateRegions, + SlotFillProvider, } from '@wordpress/components'; import { useReducedMotion, @@ -23,6 +24,7 @@ import { CommandMenu } from '@wordpress/commands'; import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; import { EditorSnackbars, + UnsavedChangesWarning, privateApis as editorPrivateApis, } from '@wordpress/editor'; import { privateApis as coreCommandsPrivateApis } from '@wordpress/core-commands'; @@ -44,12 +46,12 @@ import SavePanel from '../save-panel'; const { useCommands } = unlock( coreCommandsPrivateApis ); const { useGlobalStyle } = unlock( blockEditorPrivateApis ); -const { NavigableRegion } = unlock( editorPrivateApis ); +const { NavigableRegion, GlobalStylesProvider } = unlock( editorPrivateApis ); const { useLocation } = unlock( routerPrivateApis ); const ANIMATION_DURATION = 0.3; -export default function Layout( { route } ) { +function Layout( { route } ) { const { params } = useLocation(); const { canvas = 'view' } = params; useCommands(); @@ -78,6 +80,7 @@ export default function Layout( { route } ) { return ( <> + { canvas === 'view' && }
); } + +export default function LayoutWithGlobalStylesProvider( props ) { + return ( + + + + + + ); +} diff --git a/packages/edit-site/src/components/posts-app/index.js b/packages/edit-site/src/components/posts-app/index.js index 72e5b1eb99749..e6eb90c168001 100644 --- a/packages/edit-site/src/components/posts-app/index.js +++ b/packages/edit-site/src/components/posts-app/index.js @@ -1,10 +1,6 @@ /** * WordPress dependencies */ -import { - UnsavedChangesWarning, - privateApis as editorPrivateApis, -} from '@wordpress/editor'; import { privateApis as routerPrivateApis } from '@wordpress/router'; /** @@ -16,7 +12,6 @@ import { unlock } from '../../lock-unlock'; import useActiveRoute from '../layout/router'; const { RouterProvider } = unlock( routerPrivateApis ); -const { GlobalStylesProvider } = unlock( editorPrivateApis ); function PostsLayout() { useRegisterPostsAppRoutes(); @@ -26,11 +21,8 @@ function PostsLayout() { export default function PostsApp() { return ( - - - - - - + + + ); } From 443ce894391a0e07738661c5b3d4af4e34c47616 Mon Sep 17 00:00:00 2001 From: Benazeer Hassan <66269472+benazeer-ben@users.noreply.github.com> Date: Wed, 27 Nov 2024 19:06:10 +0530 Subject: [PATCH 02/14] Site editor: style the selected template pattern (#65917) * Updated code to set active pattern and its styling * Fixes for linting issues on updated files * Updated code based on the first round feedback points * Modification to highlight active iitem on focus * Removed local/session storage * Changes applied from drafted PR * Changes applied from drafted PR * Updated with new style changes * Linting Fix * Updated code to set active pattern and its styling * Fixes for linting issues on updated files * Updated code based on the first round feedback points * Modification to highlight active iitem on focus * Removed local/session storage * Changes applied from drafted PR * Changes applied from drafted PR * Updated with new style changes * Linting Fix * Fix spacing --------- Co-authored-by: benazeer-ben Co-authored-by: ciampo Co-authored-by: ntsekouras Co-authored-by: t-hamano Co-authored-by: jasmussen Co-authored-by: patil-vipul Co-authored-by: juanfra --- .../components/block-patterns-list/index.js | 13 +++++++++++- .../components/block-patterns-list/style.scss | 21 ++++++++++++++----- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/components/block-patterns-list/index.js b/packages/block-editor/src/components/block-patterns-list/index.js index 8128e89418f45..0c7e54c3c62b2 100644 --- a/packages/block-editor/src/components/block-patterns-list/index.js +++ b/packages/block-editor/src/components/block-patterns-list/index.js @@ -41,6 +41,7 @@ function BlockPattern( { onHover, showTitlesAsTooltip, category, + isSelected, } ) { const [ isDragging, setIsDragging ] = useState( false ); const { blocks, viewportWidth } = pattern; @@ -114,6 +115,7 @@ function BlockPattern( { pattern.type === INSERTER_PATTERN_TYPES.user && ! pattern.syncStatus, + 'is-selected': isSelected, } ) } /> @@ -192,6 +194,7 @@ function BlockPatternsList( ref ) { const [ activeCompositeId, setActiveCompositeId ] = useState( undefined ); + const [ activePattern, setActivePattern ] = useState( null ); // State to track active pattern useEffect( () => { // Reset the active composite item whenever the available patterns change, @@ -201,6 +204,11 @@ function BlockPatternsList( setActiveCompositeId( firstCompositeItemId ); }, [ blockPatterns ] ); + const handleClickPattern = ( pattern, blocks ) => { + setActivePattern( pattern.name ); + onClickPattern( pattern, blocks ); + }; + return ( ) ) } { pagingProps && } diff --git a/packages/block-editor/src/components/block-patterns-list/style.scss b/packages/block-editor/src/components/block-patterns-list/style.scss index c46bb49b9a901..8b1b0b54c9b1a 100644 --- a/packages/block-editor/src/components/block-patterns-list/style.scss +++ b/packages/block-editor/src/components/block-patterns-list/style.scss @@ -44,19 +44,29 @@ outline: $border-width solid rgba($black, 0.1); outline-offset: -$border-width; border-radius: $radius-medium; + + transition: outline 0.1s linear; + @include reduce-motion("transition"); } } - &:hover:not(:focus) .block-editor-block-preview__container::after { + // Selected + &.is-selected .block-editor-block-preview__container::after { + outline-color: $gray-900; + outline-width: var(--wp-admin-border-width-focus); + outline-offset: calc(-1 * var(--wp-admin-border-width-focus)); + } + + // Hover state + &:hover .block-editor-block-preview__container::after { outline-color: rgba($black, 0.3); } - &:focus .block-editor-block-preview__container::after { + // Focused state + &[data-focus-visible] .block-editor-block-preview__container::after { outline-color: var(--wp-admin-theme-color); outline-width: var(--wp-admin-border-width-focus); - outline-offset: calc((-1 * var(--wp-admin-border-width-focus))); - transition: outline 0.1s linear; - @include reduce-motion("transition"); + outline-offset: calc(-1 * var(--wp-admin-border-width-focus)); } .block-editor-patterns__pattern-details:not(:empty) { @@ -68,6 +78,7 @@ .block-editor-patterns__pattern-icon-wrapper { min-width: 24px; height: 24px; + .block-editor-patterns__pattern-icon { fill: var(--wp-block-synced-color); } From 78fffa7ff0e2c19ac2891633f251f6470dae045b Mon Sep 17 00:00:00 2001 From: Andrei Draganescu Date: Wed, 27 Nov 2024 16:23:20 +0200 Subject: [PATCH 03/14] keep only copy, duplicate and delete in the more menu (#67279) Co-authored-by: draganescu Co-authored-by: getdave Co-authored-by: ellatrix Co-authored-by: richtabor Co-authored-by: annezazu --- .../block-settings-menu-controls/index.js | 3 ++- .../block-settings-dropdown.js | 7 ++++++- .../editor/src/components/provider/index.js | 20 ++++++++++++++++--- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/components/block-settings-menu-controls/index.js b/packages/block-editor/src/components/block-settings-menu-controls/index.js index 4ebce4172e9b3..b0755be4c2629 100644 --- a/packages/block-editor/src/components/block-settings-menu-controls/index.js +++ b/packages/block-editor/src/components/block-settings-menu-controls/index.js @@ -55,7 +55,8 @@ const BlockSettingsMenuControlsSlot = ( { fillProps, clientIds = null } ) => { const convertToGroupButtonProps = useConvertToGroupButtonProps( selectedClientIds ); const { isGroupable, isUngroupable } = convertToGroupButtonProps; - const showConvertToGroupButton = isGroupable || isUngroupable; + const showConvertToGroupButton = + ( isGroupable || isUngroupable ) && ! isContentOnly; return ( { const { @@ -74,6 +76,7 @@ export function BlockSettingsDropdown( { getBlockAttributes, getOpenedBlockSettingsMenu, getBlockEditingMode, + isZoomOut: _isZoomOut, } = unlock( select( blockEditorStore ) ); const { getActiveBlockVariation } = select( blocksStore ); @@ -98,10 +101,12 @@ export function BlockSettingsDropdown( { openedBlockSettingsMenu: getOpenedBlockSettingsMenu(), isContentOnly: getBlockEditingMode( firstBlockClientId ) === 'contentOnly', + isZoomOut: _isZoomOut(), }; }, [ firstBlockClientId ] ); + const { getBlockOrder, getSelectedBlockClientIds } = useSelect( blockEditorStore ); @@ -248,7 +253,7 @@ export function BlockSettingsDropdown( { clientId={ firstBlockClientId } /> ) } - { ! isContentOnly && ( + { ( ! isContentOnly || isZoomOut ) && ( { + const { isZoomOut: _isZoomOut } = unlock( + select( blockEditorStore ) + ); + + return _isZoomOut(); + } ); + const shouldRenderTemplate = !! template && mode !== 'post-only'; const rootLevelPost = shouldRenderTemplate ? template : post; const defaultBlockContext = useMemo( () => { @@ -357,9 +367,13 @@ export const ExperimentalEditorProvider = withRegistryProvider( { children } { ! settings.isPreviewMode && ( <> - - - + { ! isZoomOut && ( + <> + + + + + ) } { mode === 'template-locked' && ( ) } From f8140c4fcc8db2d6078ad76fd433c79df3543860 Mon Sep 17 00:00:00 2001 From: Ella <4710635+ellatrix@users.noreply.github.com> Date: Wed, 27 Nov 2024 15:58:58 +0100 Subject: [PATCH 04/14] Drag and drop: fix drop zones on block drag (#67317) Co-authored-by: ellatrix Co-authored-by: tellthemachines Co-authored-by: ramonjd --- .../inserter-draggable-blocks/index.js | 48 +++++++---------- .../src/components/media-placeholder/index.js | 53 +++++++++---------- packages/components/CHANGELOG.md | 1 + packages/components/src/drop-zone/index.tsx | 45 ++++++++-------- packages/components/src/drop-zone/types.ts | 5 ++ test/e2e/specs/editor/blocks/image.spec.js | 23 ++++---- 6 files changed, 84 insertions(+), 91 deletions(-) diff --git a/packages/block-editor/src/components/inserter-draggable-blocks/index.js b/packages/block-editor/src/components/inserter-draggable-blocks/index.js index 0e1aaadc72e67..ebef6304937aa 100644 --- a/packages/block-editor/src/components/inserter-draggable-blocks/index.js +++ b/packages/block-editor/src/components/inserter-draggable-blocks/index.js @@ -2,12 +2,9 @@ * WordPress dependencies */ import { Draggable } from '@wordpress/components'; -import { - createBlock, - serialize, - store as blocksStore, -} from '@wordpress/blocks'; +import { createBlock, store as blocksStore } from '@wordpress/blocks'; import { useDispatch, useSelect } from '@wordpress/data'; +import { useMemo } from '@wordpress/element'; /** * Internal dependencies @@ -24,20 +21,6 @@ const InserterDraggableBlocks = ( { children, pattern, } ) => { - const transferData = { - type: 'inserter', - blocks, - }; - - const blocksContainMedia = - blocks.filter( - ( block ) => - ( block.name === 'core/image' || - block.name === 'core/audio' || - block.name === 'core/video' ) && - ( block.attributes.url || block.attributes.src ) - ).length > 0; - const blockTypeIcon = useSelect( ( select ) => { const { getBlockType } = select( blocksStore ); @@ -52,6 +35,13 @@ const InserterDraggableBlocks = ( { useDispatch( blockEditorStore ) ); + const patternBlock = useMemo( () => { + return pattern?.type === INSERTER_PATTERN_TYPES.user && + pattern?.syncStatus !== 'unsynced' + ? [ createBlock( 'core/block', { ref: pattern.id } ) ] + : undefined; + }, [ pattern?.type, pattern?.syncStatus, pattern?.id ] ); + if ( ! isEnabled ) { return children( { draggable: false, @@ -60,21 +50,21 @@ const InserterDraggableBlocks = ( { } ); } + const draggableBlocks = patternBlock ?? blocks; return ( { startDragging(); - const parsedBlocks = - pattern?.type === INSERTER_PATTERN_TYPES.user && - pattern?.syncStatus !== 'unsynced' - ? [ createBlock( 'core/block', { ref: pattern.id } ) ] - : blocks; - event.dataTransfer.setData( - blocksContainMedia ? 'default' : 'text/html', - serialize( parsedBlocks ) - ); + for ( const block of draggableBlocks ) { + const type = `wp-block:${ block.name }`; + // This will fill in the dataTransfer.types array so that + // the drop zone can check if the draggable is eligible. + // Unfortuantely, on drag start, we don't have access to the + // actual data, only the data keys/types. + event.dataTransfer.items.add( '', type ); + } } } onDragEnd={ () => { stopDragging(); diff --git a/packages/block-editor/src/components/media-placeholder/index.js b/packages/block-editor/src/components/media-placeholder/index.js index e7b6c836468f0..0cbc6c8c26203 100644 --- a/packages/block-editor/src/components/media-placeholder/index.js +++ b/packages/block-editor/src/components/media-placeholder/index.js @@ -19,7 +19,6 @@ import { __ } from '@wordpress/i18n'; import { useState, useEffect } from '@wordpress/element'; import { useSelect } from '@wordpress/data'; import { keyboardReturn } from '@wordpress/icons'; -import { pasteHandler } from '@wordpress/blocks'; import deprecated from '@wordpress/deprecated'; /** @@ -29,6 +28,7 @@ import MediaUpload from '../media-upload'; import MediaUploadCheck from '../media-upload/check'; import URLPopover from '../url-popover'; import { store as blockEditorStore } from '../../store'; +import { parseDropEvent } from '../use-on-block-drop'; const noop = () => {}; @@ -229,30 +229,15 @@ export function MediaPlaceholder( { } ); }; - async function handleBlocksDrop( blocks ) { - if ( ! blocks || ! Array.isArray( blocks ) ) { - return; - } + async function handleBlocksDrop( event ) { + const { blocks } = parseDropEvent( event ); - function recursivelyFindMediaFromBlocks( _blocks ) { - return _blocks.flatMap( ( block ) => - ( block.name === 'core/image' || - block.name === 'core/audio' || - block.name === 'core/video' ) && - ( block.attributes.url || block.attributes.src ) - ? [ block ] - : recursivelyFindMediaFromBlocks( block.innerBlocks ) - ); - } - - const mediaBlocks = recursivelyFindMediaFromBlocks( blocks ); - - if ( ! mediaBlocks.length ) { + if ( ! blocks?.length ) { return; } const uploadedMediaList = await Promise.all( - mediaBlocks.map( ( block ) => { + blocks.map( ( block ) => { const blockType = block.name.split( '/' )[ 1 ]; if ( block.attributes.id ) { block.attributes.type = blockType; @@ -292,13 +277,6 @@ export function MediaPlaceholder( { } } - async function onDrop( event ) { - const blocks = pasteHandler( { - HTML: event.dataTransfer?.getData( 'default' ), - } ); - return await handleBlocksDrop( blocks ); - } - const onUpload = ( event ) => { onFilesUpload( event.target.files ); }; @@ -385,7 +363,26 @@ export function MediaPlaceholder( { return null; } - return ; + return ( + { + const prefix = 'wp-block:core/'; + const types = []; + for ( const type of dataTransfer.types ) { + if ( type.startsWith( prefix ) ) { + types.push( type.slice( prefix.length ) ); + } + } + return ( + types.every( ( type ) => + allowedTypes.includes( type ) + ) && ( multiple ? true : types.length === 1 ) + ); + } } + /> + ); }; const renderCancelLink = () => { diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index feff5ddc97535..a780f8f139d3e 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -32,6 +32,7 @@ - `ColorPicker`: Update sizes of color format select and copy button ([#67093](https://github.com/WordPress/gutenberg/pull/67093)). - `ComboboxControl`: Update reset button size ([#67215](https://github.com/WordPress/gutenberg/pull/67215)). - `Autocomplete`: Increase option height ([#67214](https://github.com/WordPress/gutenberg/pull/67214)). +- `DropZone`: Add `isEligible` prop to allow customizing whether the drop zone should activate ([#67317](https://github.com/WordPress/gutenberg/pull/67317)). - `CircularOptionPicker`: Update `Button` sizes to be ready for 40px default size ([#67285](https://github.com/WordPress/gutenberg/pull/67285)). ### Experimental diff --git a/packages/components/src/drop-zone/index.tsx b/packages/components/src/drop-zone/index.tsx index b1bd0199e877d..dd8b97149a059 100644 --- a/packages/components/src/drop-zone/index.tsx +++ b/packages/components/src/drop-zone/index.tsx @@ -15,7 +15,7 @@ import { __experimentalUseDropZone as useDropZone } from '@wordpress/compose'; /** * Internal dependencies */ -import type { DropType, DropZoneProps } from './types'; +import type { DropZoneProps } from './types'; import type { WordPressComponentProps } from '../context'; /** @@ -47,19 +47,22 @@ export function DropZoneComponent( { onFilesDrop, onHTMLDrop, onDrop, + isEligible = () => true, ...restProps }: WordPressComponentProps< DropZoneProps, 'div', false > ) { const [ isDraggingOverDocument, setIsDraggingOverDocument ] = useState< boolean >(); const [ isDraggingOverElement, setIsDraggingOverElement ] = useState< boolean >(); - const [ type, setType ] = useState< DropType >(); + const [ isActive, setIsActive ] = useState< boolean >(); const ref = useDropZone( { onDrop( event ) { - const files = event.dataTransfer - ? getFilesFromDataTransfer( event.dataTransfer ) - : []; - const html = event.dataTransfer?.getData( 'text/html' ); + if ( ! event.dataTransfer ) { + return; + } + + const files = getFilesFromDataTransfer( event.dataTransfer ); + const html = event.dataTransfer.getData( 'text/html' ); /** * From Windows Chrome 96, the `event.dataTransfer` returns both file object and HTML. @@ -76,32 +79,31 @@ export function DropZoneComponent( { onDragStart( event ) { setIsDraggingOverDocument( true ); - let _type: DropType = 'default'; + if ( ! event.dataTransfer ) { + return; + } /** * From Windows Chrome 96, the `event.dataTransfer` returns both file object and HTML. * The order of the checks is important to recognize the HTML drop. */ - if ( event.dataTransfer?.types.includes( 'text/html' ) ) { - _type = 'html'; + if ( event.dataTransfer.types.includes( 'text/html' ) ) { + setIsActive( !! onHTMLDrop ); } else if ( // Check for the types because sometimes the files themselves // are only available on drop. - event.dataTransfer?.types.includes( 'Files' ) || - ( event.dataTransfer - ? getFilesFromDataTransfer( event.dataTransfer ) - : [] - ).length > 0 + event.dataTransfer.types.includes( 'Files' ) || + getFilesFromDataTransfer( event.dataTransfer ).length > 0 ) { - _type = 'file'; + setIsActive( !! onFilesDrop ); + } else { + setIsActive( !! onDrop && isEligible( event.dataTransfer ) ); } - - setType( _type ); }, onDragEnd() { setIsDraggingOverElement( false ); setIsDraggingOverDocument( false ); - setType( undefined ); + setIsActive( undefined ); }, onDragEnter() { setIsDraggingOverElement( true ); @@ -112,14 +114,9 @@ export function DropZoneComponent( { } ); const classes = clsx( 'components-drop-zone', className, { - 'is-active': - ( isDraggingOverDocument || isDraggingOverElement ) && - ( ( type === 'file' && onFilesDrop ) || - ( type === 'html' && onHTMLDrop ) || - ( type === 'default' && onDrop ) ), + 'is-active': isActive, 'is-dragging-over-document': isDraggingOverDocument, 'is-dragging-over-element': isDraggingOverElement, - [ `is-dragging-${ type }` ]: !! type, } ); return ( diff --git a/packages/components/src/drop-zone/types.ts b/packages/components/src/drop-zone/types.ts index 3982889a4f3ea..503f400bc4be4 100644 --- a/packages/components/src/drop-zone/types.ts +++ b/packages/components/src/drop-zone/types.ts @@ -26,4 +26,9 @@ export type DropZoneProps = { * It receives the HTML being dropped as an argument. */ onHTMLDrop?: ( html: string ) => void; + /** + * A function to determine if the drop zone is eligible to handle the drop + * data transfer items. + */ + isEligible?: ( dataTransfer: DataTransfer ) => boolean; }; diff --git a/test/e2e/specs/editor/blocks/image.spec.js b/test/e2e/specs/editor/blocks/image.spec.js index b2195f2c67688..d3cddd9c3a51c 100644 --- a/test/e2e/specs/editor/blocks/image.spec.js +++ b/test/e2e/specs/editor/blocks/image.spec.js @@ -528,14 +528,13 @@ test.describe( 'Image', () => { name: 'Block: Image', } ); - const html = ` -
- Cat -
"Cat" by tomhouslay is licensed under CC BY-NC 2.0.
-
- `; - - await page.evaluate( ( _html ) => { + await page.evaluate( () => { + const { createBlock } = window.wp.blocks; + const block = createBlock( 'core/image', { + url: 'https://live.staticflickr.com/3894/14962688165_04759a8b03_b.jpg', + alt: 'Cat', + caption: `"Cat" by tomhouslay is licensed under CC BY-NC 2.0.`, + } ); const dummy = document.createElement( 'div' ); dummy.style.width = '10px'; dummy.style.height = '10px'; @@ -545,13 +544,17 @@ test.describe( 'Image', () => { dummy.style.left = 0; dummy.draggable = 'true'; dummy.addEventListener( 'dragstart', ( event ) => { - event.dataTransfer.setData( 'default', _html ); + event.dataTransfer.setData( + 'wp-blocks', + JSON.stringify( { blocks: [ block ] } ) + ); + event.dataTransfer.setData( 'wp-block:core/image', '' ); setTimeout( () => { dummy.remove(); }, 0 ); } ); document.body.appendChild( dummy ); - }, html ); + } ); await page.mouse.move( 0, 0 ); await page.mouse.down(); From 8dd99aaeba86ed65ab3e301a5179acd9d6ef8304 Mon Sep 17 00:00:00 2001 From: Mayank Tripathi <70465598+Mayank-Tripathi32@users.noreply.github.com> Date: Wed, 27 Nov 2024 22:14:18 +0530 Subject: [PATCH 05/14] Fix: Header layout spacing in Firefox (#67074) Co-authored-by: jorgefilipecosta Co-authored-by: Mayank-Tripathi32 Co-authored-by: SainathPoojary Co-authored-by: maddisondesigns --- packages/editor/src/components/header/style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/src/components/header/style.scss b/packages/editor/src/components/header/style.scss index d12c01506a052..4cbbe992e63fd 100644 --- a/packages/editor/src/components/header/style.scss +++ b/packages/editor/src/components/header/style.scss @@ -7,7 +7,7 @@ &:has(> .editor-header__center) { grid-template: auto / $header-height min-content 1fr min-content $header-height; @include break-medium { - grid-template: auto / $header-height minmax(min-content, 1fr) 2fr minmax(min-content, 1fr) $header-height; + grid-template: auto / $header-height minmax(min-content, 2fr) 2.5fr minmax(min-content, 2fr) $header-height; } } @include break-mobile { From 6781982c80cbc025308500a1f54ae31792ebdc24 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Thu, 28 Nov 2024 03:18:38 +0900 Subject: [PATCH 06/14] DuotonePicker: Simplify Button styles (#66641) * DuotonePicker: Simplify Button styles * Add changelog Co-authored-by: mirka <0mirka00@git.wordpress.org> Co-authored-by: tyxla --- packages/components/CHANGELOG.md | 1 + .../duotone-picker/color-list-picker/index.tsx | 16 ++++++++-------- .../duotone-picker/color-list-picker/style.scss | 6 ------ 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index a780f8f139d3e..be930515f1665 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -34,6 +34,7 @@ - `Autocomplete`: Increase option height ([#67214](https://github.com/WordPress/gutenberg/pull/67214)). - `DropZone`: Add `isEligible` prop to allow customizing whether the drop zone should activate ([#67317](https://github.com/WordPress/gutenberg/pull/67317)). - `CircularOptionPicker`: Update `Button` sizes to be ready for 40px default size ([#67285](https://github.com/WordPress/gutenberg/pull/67285)). +- `DuotonePicker`: Simplify Button styles ([#66641](https://github.com/WordPress/gutenberg/pull/66641)). ### Experimental diff --git a/packages/components/src/duotone-picker/color-list-picker/index.tsx b/packages/components/src/duotone-picker/color-list-picker/index.tsx index bd009c5db1d7d..e3925b7d064fd 100644 --- a/packages/components/src/duotone-picker/color-list-picker/index.tsx +++ b/packages/components/src/duotone-picker/color-list-picker/index.tsx @@ -12,7 +12,6 @@ import Button from '../../button'; import ColorPalette from '../../color-palette'; import ColorIndicator from '../../color-indicator'; import Icon from '../../icon'; -import { HStack } from '../../h-stack'; import type { ColorListPickerProps, ColorOptionProps } from './types'; import { useInstanceId } from '@wordpress/compose'; @@ -32,23 +31,24 @@ function ColorOption( { return ( <> + ) + } + text={ label } + />
Date: Wed, 27 Nov 2024 20:27:28 +0100 Subject: [PATCH 07/14] Remove fallback for `context.postType` (#67345) Co-authored-by: SantosGuillamot --- packages/editor/src/bindings/post-meta.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/editor/src/bindings/post-meta.js b/packages/editor/src/bindings/post-meta.js index a3602ce7d6207..fcd068ac21d8a 100644 --- a/packages/editor/src/bindings/post-meta.js +++ b/packages/editor/src/bindings/post-meta.js @@ -108,11 +108,8 @@ export default { return false; } - const postType = - context?.postType || select( editorStore ).getCurrentPostType(); - - // Check that editing is happening in the post editor and not a template. - if ( postType === 'wp_template' ) { + // Lock editing when `postType` is not defined. + if ( ! context?.postType ) { return false; } From d9eb6d9a6d64650f08ee68792b88f914de62cda1 Mon Sep 17 00:00:00 2001 From: Bernie Reiter <96308+ockham@users.noreply.github.com> Date: Wed, 27 Nov 2024 20:35:22 +0100 Subject: [PATCH 08/14] Navigation block: Remove more obsolete Block Hooks helpers (#67193) - `block_core_navigation_remove_serialized_parent_block` was `replaced by remove_serialized_parent_block`. - `apply_block_hooks_to_content` has been part of WP Core since 6.6, so we don't need to check for its existence anymore. Co-authored-by: ockham Co-authored-by: draganescu --- .../block-library/src/navigation/index.php | 31 ++----------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index ae3b9620a3358..68b23aceeced6 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -1436,20 +1436,6 @@ function block_core_navigation_get_most_recently_published_navigation() { return null; } -/** - * Accepts the serialized markup of a block and its inner blocks, and returns serialized markup of the inner blocks. - * - * @since 6.5.0 - * - * @param string $serialized_block The serialized markup of a block and its inner blocks. - * @return string - */ -function block_core_navigation_remove_serialized_parent_block( $serialized_block ) { - $start = strpos( $serialized_block, '-->' ) + strlen( '-->' ); - $end = strrpos( $serialized_block, ' +

Pattern Overrides

+ + +

Post Meta Binding

+ + +

No Overrides or Binding

+ + `; + + const { id } = await requestUtils.createBlock( { + title: 'Pattern', + content, + status: 'publish', + } ); + + await admin.visitSiteEditor( { + postId: 'emptytheme//index', + postType: 'wp_template', + canvas: 'edit', + } ); + + await editor.setContent( '' ); + + await editor.insertBlock( { + name: 'core/block', + attributes: { ref: id }, + } ); + + const patternBlock = editor.canvas.getByRole( 'document', { + name: 'Block: Pattern', + } ); + const paragraphs = editor.canvas.getByRole( 'document', { + name: 'Block: Paragraph', + } ); + const blockWithOverrides = paragraphs.filter( { + hasText: 'Pattern Overrides', + } ); + const blockWithBindings = paragraphs.filter( { + hasText: 'Post Meta Binding', + } ); + const blockWithoutOverridesOrBindings = paragraphs.filter( { + hasText: 'No Overrides or Binding', + } ); + + await test.step( 'Zoomed in / Design mode', async () => { + await editor.switchEditorTool( 'Design' ); + // In zoomed in and design mode the pattern block and child blocks + // with bindings are editable. + await expect( patternBlock ).not.toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithOverrides ).not.toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithBindings ).not.toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithoutOverridesOrBindings ).toHaveAttribute( + 'inert', + 'true' + ); + } ); + + await test.step( 'Zoomed in / Write mode - pattern as a section', async () => { + await editor.switchEditorTool( 'Write' ); + // The pattern block is still editable as a section. + await expect( patternBlock ).not.toHaveAttribute( + 'inert', + 'true' + ); + // Child blocks of the pattern with bindings are editable. + await expect( blockWithOverrides ).not.toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithBindings ).not.toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithoutOverridesOrBindings ).toHaveAttribute( + 'inert', + 'true' + ); + } ); + + await test.step( 'Zoomed out / Write mode - pattern as a section', async () => { + await page.getByLabel( 'Zoom Out' ).click(); + // In zoomed out only the pattern block is editable, as in this scenario it's a section. + await expect( patternBlock ).not.toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithOverrides ).toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithBindings ).toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithoutOverridesOrBindings ).toHaveAttribute( + 'inert', + 'true' + ); + } ); + + await test.step( 'Zoomed out / Design mode - pattern as a section', async () => { + await editor.switchEditorTool( 'Design' ); + // In zoomed out only the pattern block is editable, as in this scenario it's a section. + await expect( patternBlock ).not.toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithOverrides ).toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithBindings ).toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithoutOverridesOrBindings ).toHaveAttribute( + 'inert', + 'true' + ); + } ); + + // Zoom out and group the pattern. + await page.getByLabel( 'Zoom Out' ).click(); + await editor.selectBlocks( patternBlock ); + await editor.clickBlockOptionsMenuItem( 'Group' ); + + await test.step( 'Zoomed in / Write mode - pattern nested in a section', async () => { + await editor.switchEditorTool( 'Write' ); + // The pattern block is not inert as it has editable content, but it shouldn't be selectable. + // TODO: find a way to test that the block is not selectable. + await expect( patternBlock ).not.toHaveAttribute( + 'inert', + 'true' + ); + // Child blocks of the pattern are editable as normal. + await expect( blockWithOverrides ).not.toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithBindings ).not.toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithoutOverridesOrBindings ).toHaveAttribute( + 'inert', + 'true' + ); + } ); + + await test.step( 'Zoomed out / Write mode - pattern nested in a section', async () => { + await page.getByLabel( 'Zoom Out' ).click(); + // None of the pattern is editable in zoomed out when nested in a section. + await expect( patternBlock ).toHaveAttribute( 'inert', 'true' ); + await expect( blockWithOverrides ).toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithBindings ).toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithoutOverridesOrBindings ).toHaveAttribute( + 'inert', + 'true' + ); + } ); + + await test.step( 'Zoomed out / Design mode - pattern nested in a section', async () => { + await editor.switchEditorTool( 'Design' ); + // None of the pattern is editable in zoomed out when nested in a section. + await expect( patternBlock ).toHaveAttribute( 'inert', 'true' ); + await expect( blockWithOverrides ).toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithBindings ).toHaveAttribute( + 'inert', + 'true' + ); + await expect( blockWithoutOverridesOrBindings ).toHaveAttribute( + 'inert', + 'true' + ); + } ); + } ); + + test( 'disables editing of nested patterns', async ( { + page, + admin, + requestUtils, + editor, + } ) => { + const paragraphName = 'Editable paragraph'; + const headingName = 'Editable heading'; + const innerPattern = await requestUtils.createBlock( { + title: 'Inner Pattern', + content: ` +

Inner paragraph

+ `, + status: 'publish', + } ); + const outerPattern = await requestUtils.createBlock( { + title: 'Outer Pattern', + content: ` +

Outer heading

+ + `, + status: 'publish', + } ); + + await admin.createNewPost(); + + await editor.insertBlock( { + name: 'core/block', + attributes: { ref: outerPattern.id }, + } ); + + // Make an edit to the outer pattern heading. + await editor.canvas + .getByRole( 'document', { name: 'Block: Heading' } ) + .fill( 'Outer heading (edited)' ); + + const postId = await editor.publishPost(); + + // Check the pattern has the correct attributes. + await expect.poll( editor.getBlocks ).toMatchObject( [ + { + name: 'core/block', + attributes: { + ref: outerPattern.id, + content: { + [ headingName ]: { + content: 'Outer heading (edited)', + }, + }, + }, + innerBlocks: [], + }, + ] ); + // Check it renders correctly. + const headingBlock = editor.canvas.getByRole( 'document', { + name: 'Block: Heading', + } ); + const paragraphBlock = editor.canvas.getByRole( 'document', { + name: 'Block: Paragraph', + } ); + await expect( headingBlock ).toHaveText( 'Outer heading (edited)' ); + await expect( headingBlock ).not.toHaveAttribute( 'inert', 'true' ); + await expect( paragraphBlock ).toHaveText( + 'Inner paragraph (edited)' + ); + await expect( paragraphBlock ).toHaveAttribute( 'inert', 'true' ); + + // Edit the outer pattern. + await editor.selectBlocks( + editor.canvas + .getByRole( 'document', { name: 'Block: Pattern' } ) + .first() + ); + await editor.showBlockToolbar(); + await page + .getByRole( 'toolbar', { name: 'Block tools' } ) + .getByRole( 'button', { name: 'Edit original' } ) + .click(); + + // The inner paragraph should be editable in the pattern focus mode. + await editor.selectBlocks( + editor.canvas + .getByRole( 'document', { name: 'Block: Pattern' } ) + .first() + ); + await expect( + editor.canvas.getByRole( 'document', { + name: 'Block: Paragraph', + } ), + 'The inner paragraph should be editable' + ).not.toHaveAttribute( 'inert', 'true' ); + + // Visit the post on the frontend. + await page.goto( `/?p=${ postId }` ); + + await expect( + page.getByRole( 'heading', { level: 2 } ) + ).toHaveText( 'Outer heading (edited)' ); + await expect( + page.getByText( 'Inner paragraph (edited)' ) + ).toBeVisible(); + } ); + } ); + test( 'retains override values when converting a pattern block to regular blocks', async ( { page, admin, @@ -425,107 +740,6 @@ test.describe( 'Pattern Overrides', () => { await expect( buttonLink ).toHaveAttribute( 'rel', /^\s*nofollow\s*$/ ); } ); - test( 'disables editing of nested patterns', async ( { - page, - admin, - requestUtils, - editor, - } ) => { - const paragraphName = 'Editable paragraph'; - const headingName = 'Editable heading'; - const innerPattern = await requestUtils.createBlock( { - title: 'Inner Pattern', - content: ` -

Inner paragraph

-`, - status: 'publish', - } ); - const outerPattern = await requestUtils.createBlock( { - title: 'Outer Pattern', - content: ` -

Outer heading

- -`, - status: 'publish', - } ); - - await admin.createNewPost(); - - await editor.insertBlock( { - name: 'core/block', - attributes: { ref: outerPattern.id }, - } ); - - // Make an edit to the outer pattern heading. - await editor.canvas - .getByRole( 'document', { name: 'Block: Heading' } ) - .fill( 'Outer heading (edited)' ); - - const postId = await editor.publishPost(); - - // Check the pattern has the correct attributes. - await expect.poll( editor.getBlocks ).toMatchObject( [ - { - name: 'core/block', - attributes: { - ref: outerPattern.id, - content: { - [ headingName ]: { - content: 'Outer heading (edited)', - }, - }, - }, - innerBlocks: [], - }, - ] ); - // Check it renders correctly. - const headingBlock = editor.canvas.getByRole( 'document', { - name: 'Block: Heading', - } ); - const paragraphBlock = editor.canvas.getByRole( 'document', { - name: 'Block: Paragraph', - } ); - await expect( headingBlock ).toHaveText( 'Outer heading (edited)' ); - await expect( headingBlock ).not.toHaveAttribute( 'inert', 'true' ); - await expect( paragraphBlock ).toHaveText( 'Inner paragraph (edited)' ); - await expect( paragraphBlock ).toHaveAttribute( 'inert', 'true' ); - - // Edit the outer pattern. - await editor.selectBlocks( - editor.canvas - .getByRole( 'document', { name: 'Block: Pattern' } ) - .first() - ); - await editor.showBlockToolbar(); - await page - .getByRole( 'toolbar', { name: 'Block tools' } ) - .getByRole( 'button', { name: 'Edit original' } ) - .click(); - - // The inner paragraph should be editable in the pattern focus mode. - await editor.selectBlocks( - editor.canvas - .getByRole( 'document', { name: 'Block: Pattern' } ) - .first() - ); - await expect( - editor.canvas.getByRole( 'document', { - name: 'Block: Paragraph', - } ), - 'The inner paragraph should be editable' - ).not.toHaveAttribute( 'inert', 'true' ); - - // Visit the post on the frontend. - await page.goto( `/?p=${ postId }` ); - - await expect( page.getByRole( 'heading', { level: 2 } ) ).toHaveText( - 'Outer heading (edited)' - ); - await expect( - page.getByText( 'Inner paragraph (edited)' ) - ).toBeVisible(); - } ); - test( 'resets overrides after clicking the reset button', async ( { page, admin, From 2f6ef277f3c9f875f8294c387727249ecd0defa0 Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Thu, 28 Nov 2024 14:23:17 +0800 Subject: [PATCH 14/14] Remove use of `contentOnly` block editing mode for synced patterns (#67364) * Remove use of `contentOnly` block editing mode for synced patterns * Update unit tests ---- Co-authored-by: talldan --- packages/block-editor/src/store/reducer.js | 2 +- packages/block-editor/src/store/test/reducer.js | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index 1e09ec98f005a..edae9c392c37d 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -2355,7 +2355,7 @@ function getDerivedBlockEditingModesForTree( return; } - derivedBlockEditingModes.set( clientId, 'contentOnly' ); + // Else do nothing, use the default block editing mode. return; } diff --git a/packages/block-editor/src/store/test/reducer.js b/packages/block-editor/src/store/test/reducer.js index b539afde9e025..dd1665d6736ad 100644 --- a/packages/block-editor/src/store/test/reducer.js +++ b/packages/block-editor/src/store/test/reducer.js @@ -3828,7 +3828,6 @@ describe( 'state', () => { expect( initialState.derivedBlockEditingModes ).toEqual( new Map( Object.entries( { - 'root-pattern': 'contentOnly', 'pattern-paragraph': 'disabled', 'pattern-group': 'disabled', 'pattern-paragraph-with-overrides': 'contentOnly', @@ -3883,7 +3882,6 @@ describe( 'state', () => { expect( derivedBlockEditingModes ).toEqual( new Map( Object.entries( { - 'root-pattern': 'contentOnly', // Pattern and section. 'pattern-paragraph': 'disabled', 'pattern-group': 'disabled', 'pattern-paragraph-with-overrides': 'contentOnly', // Pattern child with bindings. @@ -3903,7 +3901,7 @@ describe( 'state', () => { 'paragraph-1': 'contentOnly', // Content block in section. 'group-2': 'disabled', 'paragraph-2': 'contentOnly', // Content block in section. - 'root-pattern': 'contentOnly', // Pattern and section. + 'root-pattern': 'contentOnly', // Section. 'pattern-paragraph': 'disabled', 'pattern-group': 'disabled', 'pattern-paragraph-with-overrides': 'contentOnly', // Pattern child with bindings.