From c9ee64ad2e5e05ecbc40eb95faa3a0775ae674b1 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Fri, 7 Feb 2025 13:11:19 +0400 Subject: [PATCH 01/10] Exclude Iterator helpers from polyfills (#69070) * Exclude Iterator helpers from polyfills * Use assertEqualSets * Ignore bundled packages Co-authored-by: Mamaduka Co-authored-by: swissspidy --- .../polyfill-exclusions.js | 5 ++ phpunit/script-dependencies-test.php | 48 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 phpunit/script-dependencies-test.php diff --git a/packages/babel-preset-default/polyfill-exclusions.js b/packages/babel-preset-default/polyfill-exclusions.js index ca8c045d124146..9d0d18737540cb 100644 --- a/packages/babel-preset-default/polyfill-exclusions.js +++ b/packages/babel-preset-default/polyfill-exclusions.js @@ -28,4 +28,9 @@ module.exports = [ // // @see https://github.com/WordPress/gutenberg/pull/67230 /^es(next)?\.set\./, + // Remove Iterator feature polyfills. + // For the same reasoning as for Set exlusion above, we're excluding all iterator helper polyfills. + // + // @see https://github.com/WordPress/wordpress-develop/pull/8224#issuecomment-2636390007. + /^es(next)?\.iterator\./, ]; diff --git a/phpunit/script-dependencies-test.php b/phpunit/script-dependencies-test.php new file mode 100644 index 00000000000000..66f5c0a7e3dc57 --- /dev/null +++ b/phpunit/script-dependencies-test.php @@ -0,0 +1,48 @@ +registered; + $dependents = array(); + + // Iterate over all registered scripts, finding dependents of the `wp-polyfill` script. + // Based on private `WP_Scripts::get_dependents` method. + foreach ( $registered_scripts as $registered_handle => $args ) { + // Ignore bundled packages, they don't load separate polyfills. + if ( in_array( $registered_handle, $this->bundled_scripts, true ) ) { + continue; + } + + if ( in_array( 'wp-polyfill', $args->deps, true ) ) { + $dependents[] = $registered_handle; + } + } + + // This list should get smaller over time as we remove `wp-polyfill` dependencies. + // If the list update is intentional, please add a comment explaining why. + $expected = array( + 'react', + 'wp-blob', + 'wp-block-editor', + 'wp-block-library', + 'wp-blocks', + 'wp-edit-site', + 'wp-core-data', + 'wp-editor', + 'wp-router', + 'wp-url', + 'wp-widgets', + ); + + $this->assertEqualSets( $expected, $dependents ); + } +} From 194462f974732f18ee25bdacfc29455b969269cd Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Fri, 7 Feb 2025 14:17:09 +0400 Subject: [PATCH 02/10] Editor: Don't use selector shortcuts for the taxonomy queries (#68998) * Editor: Don't use selector shortcuts for the taxonomy queries * Update unit tests Co-authored-by: Mamaduka Co-authored-by: tyxla --- .../maybe-category-panel.js | 8 ++- .../post-publish-panel/maybe-tags-panel.js | 6 ++- .../src/components/post-taxonomies/check.js | 8 +-- .../post-taxonomies/flat-term-selector.js | 4 +- .../hierarchical-term-selector.js | 4 +- .../src/components/post-taxonomies/index.js | 6 ++- .../components/post-taxonomies/test/index.js | 50 ++++++++++++------- 7 files changed, 57 insertions(+), 29 deletions(-) diff --git a/packages/editor/src/components/post-publish-panel/maybe-category-panel.js b/packages/editor/src/components/post-publish-panel/maybe-category-panel.js index 66fdf985cc0d55..d3bca4417dbbf8 100644 --- a/packages/editor/src/components/post-publish-panel/maybe-category-panel.js +++ b/packages/editor/src/components/post-publish-panel/maybe-category-panel.js @@ -16,8 +16,12 @@ import { store as editorStore } from '../../store'; function MaybeCategoryPanel() { const hasNoCategory = useSelect( ( select ) => { const postType = select( editorStore ).getCurrentPostType(); - const { canUser, getEntityRecord, getTaxonomy } = select( coreStore ); - const categoriesTaxonomy = getTaxonomy( 'category' ); + const { canUser, getEntityRecord } = select( coreStore ); + const categoriesTaxonomy = getEntityRecord( + 'root', + 'taxonomy', + 'category' + ); const defaultCategoryId = canUser( 'read', { kind: 'root', name: 'site', diff --git a/packages/editor/src/components/post-publish-panel/maybe-tags-panel.js b/packages/editor/src/components/post-publish-panel/maybe-tags-panel.js index 537d62f382805e..4fa761ffbf71fa 100644 --- a/packages/editor/src/components/post-publish-panel/maybe-tags-panel.js +++ b/packages/editor/src/components/post-publish-panel/maybe-tags-panel.js @@ -36,7 +36,11 @@ const TagsPanel = () => { const MaybeTagsPanel = () => { const { hasTags, isPostTypeSupported } = useSelect( ( select ) => { const postType = select( editorStore ).getCurrentPostType(); - const tagsTaxonomy = select( coreStore ).getTaxonomy( 'post_tag' ); + const tagsTaxonomy = select( coreStore ).getEntityRecord( + 'root', + 'taxonomy', + 'post_tag' + ); const _isPostTypeSupported = tagsTaxonomy?.types?.includes( postType ); const areTagsFetched = tagsTaxonomy !== undefined; const tags = diff --git a/packages/editor/src/components/post-taxonomies/check.js b/packages/editor/src/components/post-taxonomies/check.js index b6b4d4f58e4e63..b89a89a54335d5 100644 --- a/packages/editor/src/components/post-taxonomies/check.js +++ b/packages/editor/src/components/post-taxonomies/check.js @@ -20,9 +20,11 @@ import { store as editorStore } from '../../store'; export default function PostTaxonomiesCheck( { children } ) { const hasTaxonomies = useSelect( ( select ) => { const postType = select( editorStore ).getCurrentPostType(); - const taxonomies = select( coreStore ).getTaxonomies( { - per_page: -1, - } ); + const taxonomies = select( coreStore ).getEntityRecords( + 'root', + 'taxonomy', + { per_page: -1 } + ); return taxonomies?.some( ( taxonomy ) => taxonomy.types.includes( postType ) ); diff --git a/packages/editor/src/components/post-taxonomies/flat-term-selector.js b/packages/editor/src/components/post-taxonomies/flat-term-selector.js index 890175534c8b4a..eb424e53c58de9 100644 --- a/packages/editor/src/components/post-taxonomies/flat-term-selector.js +++ b/packages/editor/src/components/post-taxonomies/flat-term-selector.js @@ -100,10 +100,10 @@ export function FlatTermSelector( { slug, __nextHasNoMarginBottom } ) { ( select ) => { const { getCurrentPost, getEditedPostAttribute } = select( editorStore ); - const { getEntityRecords, getTaxonomy, hasFinishedResolution } = + const { getEntityRecords, getEntityRecord, hasFinishedResolution } = select( coreStore ); const post = getCurrentPost(); - const _taxonomy = getTaxonomy( slug ); + const _taxonomy = getEntityRecord( 'root', 'taxonomy', slug ); const _termIds = _taxonomy ? getEditedPostAttribute( _taxonomy.rest_base ) : EMPTY_ARRAY; diff --git a/packages/editor/src/components/post-taxonomies/hierarchical-term-selector.js b/packages/editor/src/components/post-taxonomies/hierarchical-term-selector.js index ef2019ac3f0f44..0bc4b17ba1aa49 100644 --- a/packages/editor/src/components/post-taxonomies/hierarchical-term-selector.js +++ b/packages/editor/src/components/post-taxonomies/hierarchical-term-selector.js @@ -175,9 +175,9 @@ export function HierarchicalTermSelector( { slug } ) { ( select ) => { const { getCurrentPost, getEditedPostAttribute } = select( editorStore ); - const { getTaxonomy, getEntityRecords, isResolving } = + const { getEntityRecord, getEntityRecords, isResolving } = select( coreStore ); - const _taxonomy = getTaxonomy( slug ); + const _taxonomy = getEntityRecord( 'root', 'taxonomy', slug ); const post = getCurrentPost(); return { diff --git a/packages/editor/src/components/post-taxonomies/index.js b/packages/editor/src/components/post-taxonomies/index.js index dc2345fd6197f7..26ef06ee68ab3b 100644 --- a/packages/editor/src/components/post-taxonomies/index.js +++ b/packages/editor/src/components/post-taxonomies/index.js @@ -18,7 +18,11 @@ export function PostTaxonomies( { taxonomyWrapper = identity } ) { const { postType, taxonomies } = useSelect( ( select ) => { return { postType: select( editorStore ).getCurrentPostType(), - taxonomies: select( coreStore ).getTaxonomies( { per_page: -1 } ), + taxonomies: select( coreStore ).getEntityRecords( + 'root', + 'taxonomy', + { per_page: -1 } + ), }; }, [] ); const visibleTaxonomies = ( taxonomies ?? [] ).filter( diff --git a/packages/editor/src/components/post-taxonomies/test/index.js b/packages/editor/src/components/post-taxonomies/test/index.js index 1f386f4c2fab15..60f07c5aa417a6 100644 --- a/packages/editor/src/components/post-taxonomies/test/index.js +++ b/packages/editor/src/components/post-taxonomies/test/index.js @@ -44,6 +44,19 @@ describe( 'PostTaxonomies', () => { }, }; + const allTaxonomies = [ genresTaxonomy, categoriesTaxonomy ]; + + const hidesUI = [ + genresTaxonomy, + { + ...categoriesTaxonomy, + types: [ 'post', 'page', 'book' ], + visibility: { + show_ui: false, + }, + }, + ]; + beforeEach( () => { jest.spyOn( select( editorStore ), 'getCurrentPost' ).mockReturnValue( { _links: { @@ -70,8 +83,8 @@ describe( 'PostTaxonomies', () => { }, } ); - jest.spyOn( select( coreStore ), 'getTaxonomy' ).mockImplementation( - ( slug ) => { + jest.spyOn( select( coreStore ), 'getEntityRecord' ).mockImplementation( + ( kind, name, slug ) => { switch ( slug ) { case 'category': { return categoriesTaxonomy; @@ -91,8 +104,11 @@ describe( 'PostTaxonomies', () => { select( editorStore ), 'getCurrentPostType' ).mockReturnValue( 'page' ); - jest.spyOn( select( coreStore ), 'getTaxonomies' ).mockReturnValue( - taxonomies + jest.spyOn( + select( coreStore ), + 'getEntityRecords' + ).mockImplementation( ( kind, name ) => + kind === 'root' && name === 'taxonomy' ? taxonomies : null ); const { container } = render( ); @@ -105,10 +121,12 @@ describe( 'PostTaxonomies', () => { select( editorStore ), 'getCurrentPostType' ).mockReturnValue( 'book' ); - jest.spyOn( select( coreStore ), 'getTaxonomies' ).mockReturnValue( [ - genresTaxonomy, - categoriesTaxonomy, - ] ); + jest.spyOn( + select( coreStore ), + 'getEntityRecords' + ).mockImplementation( ( kind, name ) => + kind === 'root' && name === 'taxonomy' ? allTaxonomies : null + ); render( ); @@ -129,16 +147,12 @@ describe( 'PostTaxonomies', () => { select( editorStore ), 'getCurrentPostType' ).mockReturnValue( 'book' ); - jest.spyOn( select( coreStore ), 'getTaxonomies' ).mockReturnValue( [ - genresTaxonomy, - { - ...categoriesTaxonomy, - types: [ 'post', 'page', 'book' ], - visibility: { - show_ui: false, - }, - }, - ] ); + jest.spyOn( + select( coreStore ), + 'getEntityRecords' + ).mockImplementation( ( kind, name ) => + kind === 'root' && name === 'taxonomy' ? hidesUI : null + ); render( ); From d7e8549ac6c8d53552892f285813ca2fe3eb248f Mon Sep 17 00:00:00 2001 From: tomoki shimomura Date: Fri, 7 Feb 2025 19:52:19 +0900 Subject: [PATCH 03/10] Disable Clear button if there's no shadow. (#69092) Co-authored-by: shimotmk Co-authored-by: Mamaduka --- .../src/components/global-styles/shadow-panel-components.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/block-editor/src/components/global-styles/shadow-panel-components.js b/packages/block-editor/src/components/global-styles/shadow-panel-components.js index c335ef29384f4d..25da4150a090fa 100644 --- a/packages/block-editor/src/components/global-styles/shadow-panel-components.js +++ b/packages/block-editor/src/components/global-styles/shadow-panel-components.js @@ -46,6 +46,8 @@ export function ShadowPopoverContainer( { shadow, onShadowChange, settings } ) { __next40pxDefaultSize variant="tertiary" onClick={ () => onShadowChange( undefined ) } + disabled={ ! shadow } + accessibleWhenDisabled > { __( 'Clear' ) } From 177743059a87db2ba5f11f83dc8964e543bf3a03 Mon Sep 17 00:00:00 2001 From: Yogesh Bhutkar Date: Fri, 7 Feb 2025 16:51:30 +0530 Subject: [PATCH 04/10] Duotone Settings: Add `reset` button and improve toggle rendering in FiltersPanel (#68672) * Duotone Settings: Add reset button and improve toggle rendering in FiltersPanel * refactor: revert usage of `clearable` prop * refactor: hover on button to show `reset` * refactor: remove the usage of `ItemGroup` and add `css` for border * refactor: update button label to 'Reset' and adjust border color in filters panel Co-authored-by: yogeshbhutkar Co-authored-by: t-hamano --- .../components/global-styles/filters-panel.js | 69 +++++++++++++------ .../src/components/global-styles/style.scss | 27 ++++++++ 2 files changed, 75 insertions(+), 21 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/filters-panel.js b/packages/block-editor/src/components/global-styles/filters-panel.js index 64322d0fd5d5c9..3aed7255e411b4 100644 --- a/packages/block-editor/src/components/global-styles/filters-panel.js +++ b/packages/block-editor/src/components/global-styles/filters-panel.js @@ -9,8 +9,6 @@ import clsx from 'clsx'; import { __experimentalToolsPanel as ToolsPanel, __experimentalToolsPanelItem as ToolsPanelItem, - __experimentalItemGroup as ItemGroup, - __experimentalItem as Item, __experimentalHStack as HStack, __experimentalZStack as ZStack, __experimentalDropdownContentWrapper as DropdownContentWrapper, @@ -21,9 +19,11 @@ import { Dropdown, Flex, FlexItem, + Button, } from '@wordpress/components'; import { __, _x } from '@wordpress/i18n'; -import { useCallback, useMemo } from '@wordpress/element'; +import { useCallback, useMemo, useRef } from '@wordpress/element'; +import { reset as resetIcon } from '@wordpress/icons'; /** * Internal dependencies @@ -117,6 +117,50 @@ const LabeledColorIndicator = ( { indicator, label } ) => ( ); +const renderToggle = + ( duotone, resetDuotone ) => + ( { onToggle, isOpen } ) => { + const duotoneButtonRef = useRef( undefined ); + + const toggleProps = { + onClick: onToggle, + className: clsx( { 'is-open': isOpen } ), + 'aria-expanded': isOpen, + ref: duotoneButtonRef, + }; + + const removeButtonProps = { + onClick: () => { + if ( isOpen ) { + onToggle(); + } + resetDuotone(); + // Return focus to parent button. + duotoneButtonRef.current?.focus(); + }, + className: 'block-editor-panel-duotone-settings__reset', + label: __( 'Reset' ), + }; + + return ( + <> + + { duotone && ( +