From c7722262e65a3f4d0f1a2d1ad29eccb2069509e4 Mon Sep 17 00:00:00 2001 From: Yogesh Bhutkar Date: Tue, 19 Nov 2024 15:33:23 +0530 Subject: [PATCH 01/20] Zoom Out: Disable zooming out when Distraction Free mode is activated (#67028) Co-authored-by: yogeshbhutkar Co-authored-by: Mamaduka Co-authored-by: t-hamano Co-authored-by: draganescu --- .../editor/src/components/header/style.scss | 3 +- .../src/components/zoom-out-toggle/index.js | 39 ++++++++++++------- packages/editor/src/store/actions.js | 3 ++ 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/packages/editor/src/components/header/style.scss b/packages/editor/src/components/header/style.scss index 4259ef4b8a208..d12c01506a052 100644 --- a/packages/editor/src/components/header/style.scss +++ b/packages/editor/src/components/header/style.scss @@ -256,7 +256,8 @@ & > .editor-header__toolbar .editor-document-tools__document-overview-toggle, & > .editor-header__settings > .editor-preview-dropdown, - & > .editor-header__settings > .interface-pinned-items { + & > .editor-header__settings > .interface-pinned-items, + & > .editor-header__settings > .editor-zoom-out-toggle { display: none; } diff --git a/packages/editor/src/components/zoom-out-toggle/index.js b/packages/editor/src/components/zoom-out-toggle/index.js index 080a4c5857806..2646898a066fb 100644 --- a/packages/editor/src/components/zoom-out-toggle/index.js +++ b/packages/editor/src/components/zoom-out-toggle/index.js @@ -20,13 +20,19 @@ import { isAppleOS } from '@wordpress/keycodes'; import { unlock } from '../../lock-unlock'; const ZoomOutToggle = ( { disabled } ) => { - const { isZoomOut, showIconLabels } = useSelect( ( select ) => ( { - isZoomOut: unlock( select( blockEditorStore ) ).isZoomOut(), - showIconLabels: select( preferencesStore ).get( - 'core', - 'showIconLabels' - ), - } ) ); + const { isZoomOut, showIconLabels, isDistractionFree } = useSelect( + ( select ) => ( { + isZoomOut: unlock( select( blockEditorStore ) ).isZoomOut(), + showIconLabels: select( preferencesStore ).get( + 'core', + 'showIconLabels' + ), + isDistractionFree: select( preferencesStore ).get( + 'core', + 'distractionFree' + ), + } ) + ); const { resetZoomLevel, setZoomLevel } = unlock( useDispatch( blockEditorStore ) @@ -52,13 +58,19 @@ const ZoomOutToggle = ( { disabled } ) => { }; }, [ registerShortcut, unregisterShortcut ] ); - useShortcut( 'core/editor/zoom', () => { - if ( isZoomOut ) { - resetZoomLevel(); - } else { - setZoomLevel( 'auto-scaled' ); + useShortcut( + 'core/editor/zoom', + () => { + if ( isZoomOut ) { + resetZoomLevel(); + } else { + setZoomLevel( 'auto-scaled' ); + } + }, + { + isDisabled: isDistractionFree, } - } ); + ); const handleZoomOut = () => { if ( isZoomOut ) { @@ -78,6 +90,7 @@ const ZoomOutToggle = ( { disabled } ) => { isPressed={ isZoomOut } size="compact" showTooltip={ ! showIconLabels } + className="editor-zoom-out-toggle" /> ); }; diff --git a/packages/editor/src/store/actions.js b/packages/editor/src/store/actions.js index 7ff23cb49f498..4942e50322e06 100644 --- a/packages/editor/src/store/actions.js +++ b/packages/editor/src/store/actions.js @@ -834,6 +834,9 @@ export const toggleDistractionFree = .set( 'core', 'fixedToolbar', true ); dispatch.setIsInserterOpened( false ); dispatch.setIsListViewOpened( false ); + unlock( + registry.dispatch( blockEditorStore ) + ).resetZoomLevel(); } ); } registry.batch( () => { From 89b47b41bd5e4cb7d746917e03a5c0ee01725d98 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Tue, 19 Nov 2024 15:14:25 +0400 Subject: [PATCH 02/20] Editor: Correctly select post title support in 'DocumentOutline' (#67109) Co-authored-by: Mamaduka --- packages/editor/README.md | 3 +-- packages/editor/src/components/document-outline/check.js | 2 +- packages/editor/src/components/document-outline/index.js | 6 ++---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/editor/README.md b/packages/editor/README.md index e0b53362089f1..07405d0d51c3d 100644 --- a/packages/editor/README.md +++ b/packages/editor/README.md @@ -279,8 +279,7 @@ Renders a document outline component. _Parameters_ - _props_ `Object`: Props. -- _props.onSelect_ `Function`: Function to be called when an outline item is selected. -- _props.isTitleSupported_ `boolean`: Indicates whether the title is supported. +- _props.onSelect_ `Function`: Function to be called when an outline item is selected - _props.hasOutlineItemsDisabled_ `boolean`: Indicates whether the outline items are disabled. _Returns_ diff --git a/packages/editor/src/components/document-outline/check.js b/packages/editor/src/components/document-outline/check.js index 7e396f45c82f1..d0676aa9037ff 100644 --- a/packages/editor/src/components/document-outline/check.js +++ b/packages/editor/src/components/document-outline/check.js @@ -19,7 +19,7 @@ export default function DocumentOutlineCheck( { children } ) { return getGlobalBlockCount( 'core/heading' ) > 0; } ); - if ( hasHeadings ) { + if ( ! hasHeadings ) { return null; } diff --git a/packages/editor/src/components/document-outline/index.js b/packages/editor/src/components/document-outline/index.js index 2ed53f771b67b..ab5caa8cf0f8a 100644 --- a/packages/editor/src/components/document-outline/index.js +++ b/packages/editor/src/components/document-outline/index.js @@ -102,19 +102,17 @@ const isEmptyHeading = ( heading ) => * Renders a document outline component. * * @param {Object} props Props. - * @param {Function} props.onSelect Function to be called when an outline item is selected. - * @param {boolean} props.isTitleSupported Indicates whether the title is supported. + * @param {Function} props.onSelect Function to be called when an outline item is selected * @param {boolean} props.hasOutlineItemsDisabled Indicates whether the outline items are disabled. * * @return {Component} The component to be rendered. */ export default function DocumentOutline( { onSelect, - isTitleSupported, hasOutlineItemsDisabled, } ) { const { selectBlock } = useDispatch( blockEditorStore ); - const { blocks, title } = useSelect( ( select ) => { + const { blocks, title, isTitleSupported } = useSelect( ( select ) => { const { getBlocks } = select( blockEditorStore ); const { getEditedPostAttribute } = select( editorStore ); const { getPostType } = select( coreStore ); From 68d77765aa2d4fc6e23e3ea561ee2b94bd51ce46 Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Tue, 19 Nov 2024 21:30:34 +0900 Subject: [PATCH 03/20] Site Hub: Fix height in mobile layout (#67110) Co-authored-by: t-hamano Co-authored-by: jasmussen --- packages/edit-site/src/components/site-hub/style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/site-hub/style.scss b/packages/edit-site/src/components/site-hub/style.scss index b1c1a3a41cc53..39f44d2bef7bb 100644 --- a/packages/edit-site/src/components/site-hub/style.scss +++ b/packages/edit-site/src/components/site-hub/style.scss @@ -4,7 +4,7 @@ justify-content: space-between; gap: $grid-unit-10; margin-right: $grid-unit-15; - height: $grid-unit-70; + height: $header-height; } .edit-site-site-hub__actions { From 6b42879ad0391dbe7e7dd352de2bc00cc4c152e7 Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Tue, 19 Nov 2024 21:31:23 +0900 Subject: [PATCH 04/20] DataViews: Reduce the size of action button in Grid layout (#67032) Co-authored-by: t-hamano Co-authored-by: jasmussen --- .../src/components/dataviews-item-actions/index.tsx | 12 ++++++++++-- .../dataviews/src/dataviews-layouts/grid/style.scss | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/dataviews/src/components/dataviews-item-actions/index.tsx b/packages/dataviews/src/components/dataviews-item-actions/index.tsx index c1a1f84b99e62..47e65bc81cb17 100644 --- a/packages/dataviews/src/components/dataviews-item-actions/index.tsx +++ b/packages/dataviews/src/components/dataviews-item-actions/index.tsx @@ -57,6 +57,7 @@ interface ItemActionsProps< Item > { interface CompactItemActionsProps< Item > { item: Item; actions: Action< Item >[]; + isSmall?: boolean; } interface PrimaryActionsProps< Item > { @@ -214,7 +215,13 @@ export default function ItemActions< Item >( { }, [ actions, item ] ); if ( isCompact ) { - return ; + return ( + + ); } if ( hasOnlyOneActionAndIsPrimary( primaryActions, actions ) ) { @@ -250,12 +257,13 @@ export default function ItemActions< Item >( { function CompactItemActions< Item >( { item, actions, + isSmall, }: CompactItemActionsProps< Item > ) { return ( Date: Tue, 19 Nov 2024 22:23:27 +0900 Subject: [PATCH 05/20] Make `BlockManager` component reusable (#67052) * Make `BlockManager` component reusable * Convert a prop to an array * Revert "Convert a prop to an array" This reverts commit 242ba0e3a9008d9e896aeeb7208622650a58dbcb. Co-authored-by: t-hamano Co-authored-by: ramonjd Co-authored-by: youknowriad --- .../src/components/block-manager/category.js | 82 ++++++++-------- .../src/components/block-manager/checklist.js | 2 +- .../src/components/block-manager/index.js | 72 ++++++-------- .../preferences-modal/block-visibility.js | 94 +++++++++++++++++++ .../src/components/preferences-modal/index.js | 4 +- 5 files changed, 168 insertions(+), 86 deletions(-) create mode 100644 packages/editor/src/components/preferences-modal/block-visibility.js diff --git a/packages/editor/src/components/block-manager/category.js b/packages/editor/src/components/block-manager/category.js index e7125fa151f72..341584fee03b9 100644 --- a/packages/editor/src/components/block-manager/category.js +++ b/packages/editor/src/components/block-manager/category.js @@ -1,73 +1,79 @@ /** * WordPress dependencies */ -import { useMemo, useCallback } from '@wordpress/element'; -import { useDispatch, useSelect } from '@wordpress/data'; +import { useCallback } from '@wordpress/element'; import { useInstanceId } from '@wordpress/compose'; import { CheckboxControl } from '@wordpress/components'; -import { store as preferencesStore } from '@wordpress/preferences'; /** * Internal dependencies */ import BlockTypesChecklist from './checklist'; -import { store as editorStore } from '../../store'; -import { unlock } from '../../lock-unlock'; -function BlockManagerCategory( { title, blockTypes } ) { +function BlockManagerCategory( { + title, + blockTypes, + selectedBlockTypes, + onChange, +} ) { const instanceId = useInstanceId( BlockManagerCategory ); - const { allowedBlockTypes, hiddenBlockTypes } = useSelect( ( select ) => { - const { getEditorSettings } = select( editorStore ); - const { get } = select( preferencesStore ); - return { - allowedBlockTypes: getEditorSettings().allowedBlockTypes, - hiddenBlockTypes: get( 'core', 'hiddenBlockTypes' ), - }; - }, [] ); - const filteredBlockTypes = useMemo( () => { - if ( allowedBlockTypes === true ) { - return blockTypes; - } - return blockTypes.filter( ( { name } ) => { - return allowedBlockTypes?.includes( name ); - } ); - }, [ allowedBlockTypes, blockTypes ] ); - const { showBlockTypes, hideBlockTypes } = unlock( - useDispatch( editorStore ) - ); + const toggleVisible = useCallback( - ( blockName, nextIsChecked ) => { + ( blockType, nextIsChecked ) => { if ( nextIsChecked ) { - showBlockTypes( blockName ); + onChange( [ ...selectedBlockTypes, blockType ] ); } else { - hideBlockTypes( blockName ); + onChange( + selectedBlockTypes.filter( + ( { name } ) => name !== blockType.name + ) + ); } }, - [ showBlockTypes, hideBlockTypes ] + [ selectedBlockTypes, onChange ] ); + const toggleAllVisible = useCallback( ( nextIsChecked ) => { - const blockNames = blockTypes.map( ( { name } ) => name ); if ( nextIsChecked ) { - showBlockTypes( blockNames ); + onChange( [ + ...selectedBlockTypes, + ...blockTypes.filter( + ( blockType ) => + ! selectedBlockTypes.find( + ( { name } ) => name === blockType.name + ) + ), + ] ); } else { - hideBlockTypes( blockNames ); + onChange( + selectedBlockTypes.filter( + ( selectedBlockType ) => + ! blockTypes.find( + ( { name } ) => name === selectedBlockType.name + ) + ) + ); } }, - [ blockTypes, showBlockTypes, hideBlockTypes ] + [ blockTypes, selectedBlockTypes, onChange ] ); - if ( ! filteredBlockTypes.length ) { + if ( ! blockTypes.length ) { return null; } - const checkedBlockNames = filteredBlockTypes + const checkedBlockNames = blockTypes .map( ( { name } ) => name ) - .filter( ( type ) => ! ( hiddenBlockTypes ?? [] ).includes( type ) ); + .filter( ( type ) => + ( selectedBlockTypes ?? [] ).some( + ( selectedBlockType ) => selectedBlockType.name === type + ) + ); const titleId = 'editor-block-manager__category-title-' + instanceId; - const isAllChecked = checkedBlockNames.length === filteredBlockTypes.length; + const isAllChecked = checkedBlockNames.length === blockTypes.length; const isIndeterminate = ! isAllChecked && checkedBlockNames.length > 0; return ( @@ -85,7 +91,7 @@ function BlockManagerCategory( { title, blockTypes } ) { label={ { title } } /> diff --git a/packages/editor/src/components/block-manager/checklist.js b/packages/editor/src/components/block-manager/checklist.js index 01bd06abdeba8..2839e2c9e14c1 100644 --- a/packages/editor/src/components/block-manager/checklist.js +++ b/packages/editor/src/components/block-manager/checklist.js @@ -17,7 +17,7 @@ function BlockTypesChecklist( { blockTypes, value, onItemChange } ) { label={ blockType.title } checked={ value.includes( blockType.name ) } onChange={ ( ...args ) => - onItemChange( blockType.name, ...args ) + onItemChange( blockType, ...args ) } /> diff --git a/packages/editor/src/components/block-manager/index.js b/packages/editor/src/components/block-manager/index.js index 4a1145839976f..5c719c62a5a0b 100644 --- a/packages/editor/src/components/block-manager/index.js +++ b/packages/editor/src/components/block-manager/index.js @@ -2,69 +2,49 @@ * WordPress dependencies */ import { store as blocksStore } from '@wordpress/blocks'; -import { useDispatch, useSelect } from '@wordpress/data'; +import { useSelect } from '@wordpress/data'; import { SearchControl, Button } from '@wordpress/components'; import { __, _n, sprintf } from '@wordpress/i18n'; import { useEffect, useState } from '@wordpress/element'; import { useDebounce } from '@wordpress/compose'; import { speak } from '@wordpress/a11y'; -import { store as preferencesStore } from '@wordpress/preferences'; /** * Internal dependencies */ -import { unlock } from '../../lock-unlock'; -import { store as editorStore } from '../../store'; import BlockManagerCategory from './category'; -export default function BlockManager() { +/** + * Provides a list of blocks with checkboxes. + * + * @param {Object} props Props. + * @param {Array} props.blockTypes An array of blocks. + * @param {Array} props.selectedBlockTypes An array of selected blocks. + * @param {Function} props.onChange Function to be called when the selected blocks change. + */ +export default function BlockManager( { + blockTypes, + selectedBlockTypes, + onChange, +} ) { const debouncedSpeak = useDebounce( speak, 500 ); const [ search, setSearch ] = useState( '' ); - const { showBlockTypes } = unlock( useDispatch( editorStore ) ); - - const { - blockTypes, - categories, - hasBlockSupport, - isMatchingSearchTerm, - numberOfHiddenBlocks, - } = useSelect( ( select ) => { - // Some hidden blocks become unregistered - // by removing for instance the plugin that registered them, yet - // they're still remain as hidden by the user's action. - // We consider "hidden", blocks which were hidden and - // are still registered. - const _blockTypes = select( blocksStore ).getBlockTypes(); - const hiddenBlockTypes = ( - select( preferencesStore ).get( 'core', 'hiddenBlockTypes' ) ?? [] - ).filter( ( hiddenBlock ) => { - return _blockTypes.some( - ( registeredBlock ) => registeredBlock.name === hiddenBlock - ); - } ); - + const { categories, isMatchingSearchTerm } = useSelect( ( select ) => { return { - blockTypes: _blockTypes, categories: select( blocksStore ).getCategories(), - hasBlockSupport: select( blocksStore ).hasBlockSupport, isMatchingSearchTerm: select( blocksStore ).isMatchingSearchTerm, - numberOfHiddenBlocks: - Array.isArray( hiddenBlockTypes ) && hiddenBlockTypes.length, }; }, [] ); - function enableAllBlockTypes( newBlockTypes ) { - const blockNames = newBlockTypes.map( ( { name } ) => name ); - showBlockTypes( blockNames ); + function enableAllBlockTypes() { + onChange( blockTypes ); } - const filteredBlockTypes = blockTypes.filter( - ( blockType ) => - hasBlockSupport( blockType, 'inserter', true ) && - ( ! search || isMatchingSearchTerm( blockType, search ) ) && - ( ! blockType.parent || - blockType.parent.includes( 'core/post-content' ) ) - ); + const filteredBlockTypes = blockTypes.filter( ( blockType ) => { + return ! search || isMatchingSearchTerm( blockType, search ); + } ); + + const numberOfHiddenBlocks = blockTypes.length - selectedBlockTypes.length; // Announce search results on change useEffect( () => { @@ -96,9 +76,7 @@ export default function BlockManager() { @@ -131,6 +109,8 @@ export default function BlockManager() { ( blockType ) => blockType.category === category.slug ) } + selectedBlockTypes={ selectedBlockTypes } + onChange={ onChange } /> ) ) } ! category ) } + selectedBlockTypes={ selectedBlockTypes } + onChange={ onChange } /> diff --git a/packages/editor/src/components/preferences-modal/block-visibility.js b/packages/editor/src/components/preferences-modal/block-visibility.js new file mode 100644 index 0000000000000..49d6888c5dbfe --- /dev/null +++ b/packages/editor/src/components/preferences-modal/block-visibility.js @@ -0,0 +1,94 @@ +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { store as preferencesStore } from '@wordpress/preferences'; +import { hasBlockSupport, store as blocksStore } from '@wordpress/blocks'; +import { useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { store as editorStore } from '../../store'; +import { unlock } from '../../lock-unlock'; +import BlockManager from '../block-manager'; + +export default function BlockVisibility() { + const { showBlockTypes, hideBlockTypes } = unlock( + useDispatch( editorStore ) + ); + + const { + blockTypes, + allowedBlockTypes: _allowedBlockTypes, + hiddenBlockTypes: _hiddenBlockTypes, + } = useSelect( ( select ) => { + return { + blockTypes: select( blocksStore ).getBlockTypes(), + allowedBlockTypes: + select( editorStore ).getEditorSettings().allowedBlockTypes, + hiddenBlockTypes: + select( preferencesStore ).get( 'core', 'hiddenBlockTypes' ) ?? + [], + }; + }, [] ); + + const allowedBlockTypes = useMemo( () => { + if ( _allowedBlockTypes === true ) { + return blockTypes; + } + return blockTypes.filter( ( { name } ) => { + return _allowedBlockTypes?.includes( name ); + } ); + }, [ _allowedBlockTypes, blockTypes ] ); + + const filteredBlockTypes = allowedBlockTypes.filter( + ( blockType ) => + hasBlockSupport( blockType, 'inserter', true ) && + ( ! blockType.parent || + blockType.parent.includes( 'core/post-content' ) ) + ); + + // Some hidden blocks become unregistered + // by removing for instance the plugin that registered them, yet + // they're still remain as hidden by the user's action. + // We consider "hidden", blocks which were hidden and + // are still registered. + const hiddenBlockTypes = _hiddenBlockTypes.filter( ( hiddenBlock ) => { + return filteredBlockTypes.some( + ( registeredBlock ) => registeredBlock.name === hiddenBlock + ); + } ); + + const selectedBlockTypes = filteredBlockTypes.filter( + ( blockType ) => ! hiddenBlockTypes.includes( blockType.name ) + ); + + const onChangeSelectedBlockTypes = ( newSelectedBlockTypes ) => { + if ( selectedBlockTypes.length > newSelectedBlockTypes.length ) { + const blockTypesToHide = selectedBlockTypes.filter( + ( blockType ) => + ! newSelectedBlockTypes.find( + ( { name } ) => name === blockType.name + ) + ); + hideBlockTypes( blockTypesToHide.map( ( { name } ) => name ) ); + } else if ( selectedBlockTypes.length < newSelectedBlockTypes.length ) { + const blockTypesToShow = newSelectedBlockTypes.filter( + ( blockType ) => + ! selectedBlockTypes.find( + ( { name } ) => name === blockType.name + ) + ); + showBlockTypes( blockTypesToShow.map( ( { name } ) => name ) ); + } + }; + + return ( + + ); +} diff --git a/packages/editor/src/components/preferences-modal/index.js b/packages/editor/src/components/preferences-modal/index.js index 7ea7ea456ce28..72042bca03b70 100644 --- a/packages/editor/src/components/preferences-modal/index.js +++ b/packages/editor/src/components/preferences-modal/index.js @@ -18,7 +18,7 @@ import { store as interfaceStore } from '@wordpress/interface'; import EnablePanelOption from './enable-panel'; import EnablePluginDocumentSettingPanelOption from './enable-plugin-document-setting-panel'; import EnablePublishSidebarOption from './enable-publish-sidebar'; -import BlockManager from '../block-manager'; +import BlockVisibility from './block-visibility'; import PostTaxonomies from '../post-taxonomies'; import PostFeaturedImageCheck from '../post-featured-image/check'; import PostExcerptCheck from '../post-excerpt/check'; @@ -297,7 +297,7 @@ function PreferencesModalContents( { extraSections = {} } ) { "Disable blocks that you don't want to appear in the inserter. They can always be toggled back on later." ) } > - + ), From 62704a0167913527203e48e5c7d5a2dda575f44d Mon Sep 17 00:00:00 2001 From: Marin Atanasov <8436925+tyxla@users.noreply.github.com> Date: Tue, 19 Nov 2024 15:59:41 +0200 Subject: [PATCH 06/20] ESLint: Bump `eslint-plugin-react-compiler` to latest beta (#67106) * Bump eslint-plugin-react-compiler to 19.0.0-beta-0dec889-20241115 * Use ref for prev heading level in DocumentOutline Co-authored-by: tyxla Co-authored-by: Mamaduka --- package-lock.json | 8 ++++---- package.json | 2 +- .../editor/src/components/document-outline/index.js | 10 ++++++---- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 036acafe885fa..376cd0b9e6edf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -91,7 +91,7 @@ "eslint-plugin-jest": "27.2.3", "eslint-plugin-jest-dom": "5.0.2", "eslint-plugin-prettier": "5.0.0", - "eslint-plugin-react-compiler": "19.0.0-beta-8a03594-20241020", + "eslint-plugin-react-compiler": "19.0.0-beta-0dec889-20241115", "eslint-plugin-ssr-friendly": "1.0.6", "eslint-plugin-storybook": "0.6.13", "eslint-plugin-testing-library": "6.0.2", @@ -25365,9 +25365,9 @@ } }, "node_modules/eslint-plugin-react-compiler": { - "version": "19.0.0-beta-8a03594-20241020", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-19.0.0-beta-8a03594-20241020.tgz", - "integrity": "sha512-bYg1COih1s3r14IV/AKdQs/SN7CQmNI0ZaMtPdgZ6gp1S1Q/KGP9P43w7R6dHJ4wYpuMBvekNJHQdVu+x6UM+A==", + "version": "19.0.0-beta-0dec889-20241115", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-19.0.0-beta-0dec889-20241115.tgz", + "integrity": "sha512-jTjEHuE8/R6qD/CD2d+5YvWMy1q9/tX3kft4WDyg42/HktjHtHXrEToyZ6THEQf8t/YWMY1RGeCkykePbACtFA==", "dev": true, "dependencies": { "@babel/core": "^7.24.4", diff --git a/package.json b/package.json index 751bde4024081..a7470a1333ffa 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "eslint-plugin-jest": "27.2.3", "eslint-plugin-jest-dom": "5.0.2", "eslint-plugin-prettier": "5.0.0", - "eslint-plugin-react-compiler": "19.0.0-beta-8a03594-20241020", + "eslint-plugin-react-compiler": "19.0.0-beta-0dec889-20241115", "eslint-plugin-ssr-friendly": "1.0.6", "eslint-plugin-storybook": "0.6.13", "eslint-plugin-testing-library": "6.0.2", diff --git a/packages/editor/src/components/document-outline/index.js b/packages/editor/src/components/document-outline/index.js index ab5caa8cf0f8a..c5e5983736209 100644 --- a/packages/editor/src/components/document-outline/index.js +++ b/packages/editor/src/components/document-outline/index.js @@ -3,6 +3,7 @@ */ import { __ } from '@wordpress/i18n'; import { useDispatch, useSelect } from '@wordpress/data'; +import { useRef } from '@wordpress/element'; import { create, getTextContent } from '@wordpress/rich-text'; import { store as blockEditorStore } from '@wordpress/block-editor'; import { store as coreStore } from '@wordpress/core-data'; @@ -125,6 +126,8 @@ export default function DocumentOutline( { }; } ); + const prevHeadingLevelRef = useRef( 1 ); + const headings = computeOutlineHeadings( blocks ); if ( headings.length < 1 ) { return ( @@ -139,8 +142,6 @@ export default function DocumentOutline( { ); } - let prevHeadingLevel = 1; - // Not great but it's the simplest way to locate the title right now. const titleNode = document.querySelector( '.editor-post-title__input' ); const hasTitle = isTitleSupported && title && titleNode; @@ -170,7 +171,8 @@ export default function DocumentOutline( { { headings.map( ( item, index ) => { // Headings remain the same, go up by one, or down by any amount. // Otherwise there are missing levels. - const isIncorrectLevel = item.level > prevHeadingLevel + 1; + const isIncorrectLevel = + item.level > prevHeadingLevelRef.current + 1; const isValid = ! item.isEmpty && @@ -178,7 +180,7 @@ export default function DocumentOutline( { !! item.level && ( item.level !== 1 || ( ! hasMultipleH1 && ! hasTitle ) ); - prevHeadingLevel = item.level; + prevHeadingLevelRef.current = item.level; return ( Date: Tue, 19 Nov 2024 09:12:00 -0500 Subject: [PATCH 07/20] Bump gradle/actions from 4.2.0 to 4.2.1 in the react-native group (#67115) Bumps the react-native group with 1 update: [gradle/actions](https://github.com/gradle/actions). Updates `gradle/actions` from 4.2.0 to 4.2.1 - [Release notes](https://github.com/gradle/actions/releases) - [Commits](https://github.com/gradle/actions/compare/473878a77f1b98e2b5ac4af93489d1656a80a5ed...cc4fc85e6b35bafd578d5ffbc76a5518407e1af0) --- updated-dependencies: - dependency-name: gradle/actions dependency-type: direct:production update-type: version-update:semver-patch dependency-group: react-native ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: desrosj --- .github/workflows/rnmobile-android-runner.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rnmobile-android-runner.yml b/.github/workflows/rnmobile-android-runner.yml index 43a71809b5bbe..f8ff0441a95b7 100644 --- a/.github/workflows/rnmobile-android-runner.yml +++ b/.github/workflows/rnmobile-android-runner.yml @@ -47,7 +47,7 @@ jobs: run: npm run native test:e2e:setup - name: Gradle cache - uses: gradle/actions/setup-gradle@473878a77f1b98e2b5ac4af93489d1656a80a5ed # v4.2.0 + uses: gradle/actions/setup-gradle@cc4fc85e6b35bafd578d5ffbc76a5518407e1af0 # v4.2.1 # AVD cache disabled as it caused emulator termination to hang indefinitely. # https://github.com/ReactiveCircus/android-emulator-runner/issues/385 From cf59c28e1b0cd0870eb82c21eedf221ebf92c606 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Tue, 19 Nov 2024 18:24:22 +0400 Subject: [PATCH 08/20] Inserter: Set initial active tab ID during render (#67103) Co-authored-by: Mamaduka Co-authored-by: tyxla --- .../components/inserter/category-tabs/index.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/block-editor/src/components/inserter/category-tabs/index.js b/packages/block-editor/src/components/inserter/category-tabs/index.js index 7b6baaab398f8..ff0a130f1a827 100644 --- a/packages/block-editor/src/components/inserter/category-tabs/index.js +++ b/packages/block-editor/src/components/inserter/category-tabs/index.js @@ -6,7 +6,7 @@ import { privateApis as componentsPrivateApis, __unstableMotion as motion, } from '@wordpress/components'; -import { useState, useEffect } from '@wordpress/element'; +import { useState } from '@wordpress/element'; /** * Internal dependencies @@ -35,14 +35,13 @@ function CategoryTabs( { const selectedTabId = selectedCategory ? selectedCategory.name : null; const [ activeTabId, setActiveId ] = useState(); const firstTabId = categories?.[ 0 ]?.name; - useEffect( () => { - // If there is no active tab, make the first tab the active tab, so that - // when focus is moved to the tablist, the first tab will be focused - // despite not being selected - if ( selectedTabId === null && ! activeTabId && firstTabId ) { - setActiveId( firstTabId ); - } - }, [ selectedTabId, activeTabId, firstTabId, setActiveId ] ); + + // If there is no active tab, make the first tab the active tab, so that + // when focus is moved to the tablist, the first tab will be focused + // despite not being selected + if ( selectedTabId === null && ! activeTabId && firstTabId ) { + setActiveId( firstTabId ); + } return ( Date: Tue, 19 Nov 2024 10:33:59 -0500 Subject: [PATCH 09/20] Feature: Set editor rendering mode by post type (#62304) Co-authored-by: TylerB24890 Co-authored-by: Sidsector9 Co-authored-by: fabiankaegy Co-authored-by: youknowriad Co-authored-by: dcalhoun Co-authored-by: ramonjd Co-authored-by: mcsf Co-authored-by: jasmussen Co-authored-by: annezazu Co-authored-by: jameskoster Co-authored-by: dinhtungdu --- backport-changelog/6.8/7129.md | 3 + ...tenberg-rest-post-types-controller-6-8.php | 61 ++++++++++++++ lib/compat/wordpress-6.8/post.php | 57 +++++++++++++ lib/compat/wordpress-6.8/rest-api.php | 22 +++++ lib/load.php | 3 + .../block-editor/use-site-editor-settings.js | 11 +-- .../edit-site/src/components/editor/index.js | 4 +- .../editor/src/components/provider/index.js | 83 ++++++++++++------- packages/editor/src/store/reducer.native.js | 2 + .../initialize-editor.js | 17 ++++ test/performance/fixtures/perf-utils.ts | 20 +++++ test/performance/specs/site-editor.spec.js | 2 + 12 files changed, 243 insertions(+), 42 deletions(-) create mode 100644 backport-changelog/6.8/7129.md create mode 100644 lib/compat/wordpress-6.8/class-gutenberg-rest-post-types-controller-6-8.php create mode 100644 lib/compat/wordpress-6.8/post.php create mode 100644 lib/compat/wordpress-6.8/rest-api.php diff --git a/backport-changelog/6.8/7129.md b/backport-changelog/6.8/7129.md new file mode 100644 index 0000000000000..90c9168cdc6f8 --- /dev/null +++ b/backport-changelog/6.8/7129.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/7129 + +* https://github.com/WordPress/gutenberg/pull/62304 diff --git a/lib/compat/wordpress-6.8/class-gutenberg-rest-post-types-controller-6-8.php b/lib/compat/wordpress-6.8/class-gutenberg-rest-post-types-controller-6-8.php new file mode 100644 index 0000000000000..da0489210e21f --- /dev/null +++ b/lib/compat/wordpress-6.8/class-gutenberg-rest-post-types-controller-6-8.php @@ -0,0 +1,61 @@ +default_rendering_mode, $item ); + + /** + * Filters the block editor rendering mode for a specific post type. + * Applied after the generic `post_type_default_rendering_mode` filter. + * + * The dynamic portion of the hook name, `$item->name`, refers to the post type slug. + * + * @since 6.8.0 + * @param string $default_rendering_mode Default rendering mode for the post type. + * @param WP_Post_Type $post_type Post type object. + * @return string Default rendering mode for the post type. + */ + $rendering_mode = apply_filters( "post_type_{$item->name}_default_rendering_mode", $rendering_mode, $item ); + + // Validate the filtered rendering mode. + if ( ! in_array( $rendering_mode, gutenberg_post_type_rendering_modes(), true ) ) { + $rendering_mode = 'post-only'; + } + + $response->data['default_rendering_mode'] = $rendering_mode; + } + + return rest_ensure_response( $response ); + } +} diff --git a/lib/compat/wordpress-6.8/post.php b/lib/compat/wordpress-6.8/post.php new file mode 100644 index 0000000000000..26e6c3adc07a3 --- /dev/null +++ b/lib/compat/wordpress-6.8/post.php @@ -0,0 +1,57 @@ +register_routes(); + } +} +add_action( 'rest_api_init', 'gutenberg_add_post_type_rendering_mode' ); diff --git a/lib/load.php b/lib/load.php index d7e4a33cd02c9..100160176f391 100644 --- a/lib/load.php +++ b/lib/load.php @@ -49,6 +49,8 @@ function gutenberg_is_experiment_enabled( $name ) { // WordPress 6.8 compat. require __DIR__ . '/compat/wordpress-6.8/block-comments.php'; require __DIR__ . '/compat/wordpress-6.8/class-gutenberg-rest-comment-controller-6-8.php'; + require __DIR__ . '/compat/wordpress-6.8/class-gutenberg-rest-post-types-controller-6-8.php'; + require __DIR__ . '/compat/wordpress-6.8/rest-api.php'; // Plugin specific code. require_once __DIR__ . '/class-wp-rest-global-styles-controller-gutenberg.php'; @@ -120,6 +122,7 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/compat/wordpress-6.8/preload.php'; require __DIR__ . '/compat/wordpress-6.8/blocks.php'; require __DIR__ . '/compat/wordpress-6.8/functions.php'; +require __DIR__ . '/compat/wordpress-6.8/post.php'; // Experimental features. require __DIR__ . '/experimental/block-editor-settings-mobile.php'; diff --git a/packages/edit-site/src/components/block-editor/use-site-editor-settings.js b/packages/edit-site/src/components/block-editor/use-site-editor-settings.js index 5c75de6d81e72..186f4aacf7923 100644 --- a/packages/edit-site/src/components/block-editor/use-site-editor-settings.js +++ b/packages/edit-site/src/components/block-editor/use-site-editor-settings.js @@ -36,9 +36,7 @@ function useNavigateToPreviousEntityRecord() { return goBack; } -export function useSpecificEditorSettings( - shouldUseTemplateAsDefaultRenderingMode -) { +export function useSpecificEditorSettings() { const { params } = useLocation(); const { canvas = 'view' } = params; const onNavigateToEntityRecord = useNavigateToEntityRecord(); @@ -49,11 +47,6 @@ export function useSpecificEditorSettings( }; }, [] ); - // TODO: The `shouldUseTemplateAsDefaultRenderingMode` check should be removed when the default rendering mode per post type is merged. - // @see https://github.com/WordPress/gutenberg/pull/62304/ - const defaultRenderingMode = shouldUseTemplateAsDefaultRenderingMode - ? 'template-locked' - : 'post-only'; const onNavigateToPreviousEntityRecord = useNavigateToPreviousEntityRecord(); const defaultEditorSettings = useMemo( () => { @@ -63,7 +56,6 @@ export function useSpecificEditorSettings( richEditingEnabled: true, supportsTemplateMode: true, focusMode: canvas !== 'view', - defaultRenderingMode, onNavigateToEntityRecord, onNavigateToPreviousEntityRecord, isPreviewMode: canvas === 'view', @@ -71,7 +63,6 @@ export function useSpecificEditorSettings( }, [ settings, canvas, - defaultRenderingMode, onNavigateToEntityRecord, onNavigateToPreviousEntityRecord, ] ); diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 51d734f25c6ad..1d115dca7518d 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -131,9 +131,7 @@ export default function EditSiteEditor( { isPostsList = false } ) { 'edit-site-editor__loading-progress' ); - const settings = useSpecificEditorSettings( - !! context?.postId && context?.postType !== 'post' - ); + const settings = useSpecificEditorSettings(); const styles = useMemo( () => [ ...settings.styles, diff --git a/packages/editor/src/components/provider/index.js b/packages/editor/src/components/provider/index.js index 50d02610062c0..6c05e5b58235b 100644 --- a/packages/editor/src/components/provider/index.js +++ b/packages/editor/src/components/provider/index.js @@ -72,8 +72,7 @@ const NON_CONTEXTUAL_POST_TYPES = [ * @return {Array} Block editor props. */ function useBlockEditorProps( post, template, mode ) { - const rootLevelPost = - mode === 'post-only' || ! template ? 'post' : 'template'; + const rootLevelPost = mode === 'template-locked' ? 'template' : 'post'; const [ postBlocks, onInput, onChange ] = useEntityBlockEditor( 'postType', post.type, @@ -164,30 +163,48 @@ export const ExperimentalEditorProvider = withRegistryProvider( BlockEditorProviderComponent = ExperimentalBlockEditorProvider, __unstableTemplate: template, } ) => { - const { editorSettings, selection, isReady, mode, postTypeEntities } = - useSelect( - ( select ) => { - const { - getEditorSettings, - getEditorSelection, - getRenderingMode, - __unstableIsEditorReady, - } = select( editorStore ); - const { getEntitiesConfig } = select( coreStore ); + const { + editorSettings, + selection, + isReady, + mode, + defaultMode, + postTypeEntities, + hasLoadedPostObject, + } = useSelect( + ( select ) => { + const { + getEditorSettings, + getEditorSelection, + getRenderingMode, + __unstableIsEditorReady, + } = select( editorStore ); + const { getEntitiesConfig } = select( coreStore ); + + const postTypeObject = select( coreStore ).getPostType( + post.type + ); + + const _hasLoadedPostObject = select( + coreStore + ).hasFinishedResolution( 'getPostType', [ post.type ] ); - return { - editorSettings: getEditorSettings(), - isReady: __unstableIsEditorReady(), - mode: getRenderingMode(), - selection: getEditorSelection(), - postTypeEntities: - post.type === 'wp_template' - ? getEntitiesConfig( 'postType' ) - : null, - }; - }, - [ post.type ] - ); + return { + hasLoadedPostObject: _hasLoadedPostObject, + editorSettings: getEditorSettings(), + isReady: __unstableIsEditorReady(), + mode: getRenderingMode(), + defaultMode: + postTypeObject?.default_rendering_mode ?? 'post-only', + selection: getEditorSelection(), + postTypeEntities: + post.type === 'wp_template' + ? getEntitiesConfig( 'postType' ) + : null, + }; + }, + [ post.type ] + ); const shouldRenderTemplate = !! template && mode !== 'post-only'; const rootLevelPost = shouldRenderTemplate ? template : post; const defaultBlockContext = useMemo( () => { @@ -282,7 +299,15 @@ export const ExperimentalEditorProvider = withRegistryProvider( } ); } - }, [] ); + }, [ + createWarningNotice, + initialEdits, + settings, + post, + recovery, + setupEditor, + updatePostLock, + ] ); // Synchronizes the active post with the state useEffect( () => { @@ -301,15 +326,15 @@ export const ExperimentalEditorProvider = withRegistryProvider( // Sets the right rendering mode when loading the editor. useEffect( () => { - setRenderingMode( settings.defaultRenderingMode ?? 'post-only' ); - }, [ settings.defaultRenderingMode, setRenderingMode ] ); + setRenderingMode( defaultMode ); + }, [ defaultMode, setRenderingMode ] ); useHideBlocksFromInserter( post.type, mode ); // Register the editor commands. useCommands(); - if ( ! isReady ) { + if ( ! isReady || ! mode || ! hasLoadedPostObject ) { return null; } diff --git a/packages/editor/src/store/reducer.native.js b/packages/editor/src/store/reducer.native.js index 7566dfc5dfd03..fbf6c968f57d0 100644 --- a/packages/editor/src/store/reducer.native.js +++ b/packages/editor/src/store/reducer.native.js @@ -9,6 +9,7 @@ import { combineReducers } from '@wordpress/data'; import { postId, postType, + renderingMode, saving, postLock, postSavingLock, @@ -82,6 +83,7 @@ export default combineReducers( { postId, postType, postTitle, + renderingMode, saving, postLock, postSavingLock, diff --git a/test/native/integration-test-helpers/initialize-editor.js b/test/native/integration-test-helpers/initialize-editor.js index 511f0223e1135..3b89da979aee3 100644 --- a/test/native/integration-test-helpers/initialize-editor.js +++ b/test/native/integration-test-helpers/initialize-editor.js @@ -10,6 +10,8 @@ import { v4 as uuid } from 'uuid'; import { createElement, cloneElement } from '@wordpress/element'; // eslint-disable-next-line no-restricted-imports import { initializeEditor as internalInitializeEditor } from '@wordpress/edit-post'; +import { store as coreStore } from '@wordpress/core-data'; +import { select } from '@wordpress/data'; /** * Internal dependencies @@ -28,6 +30,21 @@ import { getGlobalStyles } from './get-global-styles'; * @return {import('@testing-library/react-native').RenderAPI} A Testing Library screen. */ export async function initializeEditor( props, { component } = {} ) { + const resolutionSpy = jest.spyOn( + select( coreStore ), + 'hasFinishedResolution' + ); + const actualResolution = resolutionSpy.getMockImplementation(); + resolutionSpy.mockImplementation( ( selectorName, args ) => { + // The mobile editor only supports the `post-only` rendering mode, so we + // presume a resolved `getPostType` selector to unblock editor rendering. + if ( 'getPostType' === selectorName ) { + return true; + } + + return actualResolution( selectorName, args ); + } ); + const uniqueId = uuid(); const postId = `post-id-${ uniqueId }`; const postType = 'post'; diff --git a/test/performance/fixtures/perf-utils.ts b/test/performance/fixtures/perf-utils.ts index 592e8194852e3..8d23d91ff91bf 100644 --- a/test/performance/fixtures/perf-utils.ts +++ b/test/performance/fixtures/perf-utils.ts @@ -97,6 +97,26 @@ export class PerfUtils { return canvas; } + /** + * Change the rendering mode of the editor. + * + * Setting the rendering mode to something other than the default is sometimes + * needed when for example we want to update the contents of the editor from a + * HTML file. Calling the resetBlocks method of the core/block-editor store will + * replace the contents of the template if the rendering mode is not post-only. + * So this should always be called before the resetBlocks method is used. + * + * @param newRenderingMode Rendering mode to set + * + * @return Promise + */ + async setRenderingMode( newRenderingMode: string ) { + await this.page.evaluate( ( _newRenderingMode ) => { + const { dispatch } = window.wp.data; + dispatch( 'core/editor' ).setRenderingMode( _newRenderingMode ); + }, newRenderingMode ); + } + /** * Loads blocks from the small post with containers fixture into the editor * canvas. diff --git a/test/performance/specs/site-editor.spec.js b/test/performance/specs/site-editor.spec.js index 9c9d8aec71da4..e72d83fa8b3aa 100644 --- a/test/performance/specs/site-editor.spec.js +++ b/test/performance/specs/site-editor.spec.js @@ -64,6 +64,7 @@ test.describe( 'Site Editor Performance', () => { test( 'Setup the test page', async ( { admin, perfUtils } ) => { await admin.createNewPost( { postType: 'page' } ); + await perfUtils.setRenderingMode( 'post-only' ); await perfUtils.loadBlocksForLargePost(); draftId = await perfUtils.saveDraft(); @@ -122,6 +123,7 @@ test.describe( 'Site Editor Performance', () => { test( 'Setup the test post', async ( { admin, editor, perfUtils } ) => { await admin.createNewPost( { postType: 'page' } ); + await perfUtils.setRenderingMode( 'post-only' ); await perfUtils.loadBlocksForLargePost(); await editor.insertBlock( { name: 'core/paragraph' } ); From d478c08d4c0827864e7be4e2df487297ad36d7b0 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 20 Nov 2024 01:52:35 +0900 Subject: [PATCH 10/20] ColorPicker: Update sizes of format select and copy button (#67093) * ColorPicker: Update sizes of format select and copy button * Add changelog Co-authored-by: mirka <0mirka00@git.wordpress.org> Co-authored-by: tyxla --- packages/components/CHANGELOG.md | 4 ++++ .../src/color-picker/color-copy-button.tsx | 6 +++--- packages/components/src/color-picker/component.tsx | 1 + packages/components/src/color-picker/styles.ts | 13 ------------- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index d93eb30ac0ec5..dfb9454d8da1f 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -12,6 +12,10 @@ - `ToggleGroupControl`: Fix active background for `0` value ([#66855](https://github.com/WordPress/gutenberg/pull/66855)). - `SlotFill`: Fix a bug where a stale value of `fillProps` could be used ([#67000](https://github.com/WordPress/gutenberg/pull/67000)). +### Enhancements + +- `ColorPicker`: Update sizes of color format select and copy button ([#67093](https://github.com/WordPress/gutenberg/pull/67093)). + ### Experimental - `SlotFill`: Remove registration API methods from return value of `__experimentalUseSlot` ([#67070](https://github.com/WordPress/gutenberg/pull/67070)). diff --git a/packages/components/src/color-picker/color-copy-button.tsx b/packages/components/src/color-picker/color-copy-button.tsx index b8a4822544322..0076a2125d00c 100644 --- a/packages/components/src/color-picker/color-copy-button.tsx +++ b/packages/components/src/color-picker/color-copy-button.tsx @@ -9,7 +9,7 @@ import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ -import { CopyButton } from './styles'; +import { Button } from '../button'; import Tooltip from '../tooltip'; import type { ColorCopyButtonProps } from './types'; @@ -63,8 +63,8 @@ export const ColorCopyButton = ( props: ColorCopyButtonProps ) => { copiedColor === color.toHex() ? __( 'Copied!' ) : __( 'Copy' ) } > - diff --git a/packages/components/src/color-picker/styles.ts b/packages/components/src/color-picker/styles.ts index a78f10de2e4a3..50ce33da9f233 100644 --- a/packages/components/src/color-picker/styles.ts +++ b/packages/components/src/color-picker/styles.ts @@ -11,7 +11,6 @@ import InnerSelectControl from '../select-control'; import InnerRangeControl from '../range-control'; import { space } from '../utils/space'; import { boxSizingReset } from '../utils'; -import Button from '../button'; import { Flex } from '../flex'; import { HStack } from '../h-stack'; import CONFIG from '../utils/config-values'; @@ -22,7 +21,6 @@ export const NumberControlWrapper = styled( NumberControl )` export const SelectControl = styled( InnerSelectControl )` margin-left: ${ space( -2 ) }; - width: 5em; `; export const RangeControl = styled( InnerRangeControl )` @@ -101,14 +99,3 @@ export const ColorfulWrapper = styled.div` ${ interactiveHueStyles } `; - -export const CopyButton = styled( Button )` - &&&&& { - min-width: ${ space( 6 ) }; - padding: 0; - - > svg { - margin-right: 0; - } - } -`; From dea308b86eb32c23d384cd2d0f756fc9a047cca1 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 20 Nov 2024 07:28:07 +0900 Subject: [PATCH 11/20] ColorPicker: Add accessible label for copy button (#67094) * ColorPicker: Add accessible label for copy button * Add changelog * Use variable Co-authored-by: mirka <0mirka00@git.wordpress.org> Co-authored-by: tyxla --- packages/components/CHANGELOG.md | 1 + .../src/color-picker/color-copy-button.tsx | 12 +++++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index dfb9454d8da1f..34a90b6ca23b3 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -11,6 +11,7 @@ - `ToggleGroupControl`: Fix active background for `0` value ([#66855](https://github.com/WordPress/gutenberg/pull/66855)). - `SlotFill`: Fix a bug where a stale value of `fillProps` could be used ([#67000](https://github.com/WordPress/gutenberg/pull/67000)). +- `ColorPicker`: Add accessible label for copy button ([#67094](https://github.com/WordPress/gutenberg/pull/67094)). ### Enhancements diff --git a/packages/components/src/color-picker/color-copy-button.tsx b/packages/components/src/color-picker/color-copy-button.tsx index 0076a2125d00c..6e49fa7ae85e7 100644 --- a/packages/components/src/color-picker/color-copy-button.tsx +++ b/packages/components/src/color-picker/color-copy-button.tsx @@ -55,16 +55,14 @@ export const ColorCopyButton = ( props: ColorCopyButtonProps ) => { }; }, [] ); + const label = + copiedColor === color.toHex() ? __( 'Copied!' ) : __( 'Copy' ); + return ( - + - - ); - } ); - } + { __( 'Edit' ) } + + + ); + } ); + return ( - - - { __( 'Edit track' ) } - - - { __( 'File' ) }: { fileName } - - - - onChange( { - ...track, - label: newLabel, - } ) - } - label={ __( 'Label' ) } - value={ label } - help={ __( 'Title of track' ) } - /> - + + { __( 'Edit track' ) } + + + { __( 'File' ) }: { fileName } + + + + onChange( { + ...track, + label: newLabel, + } ) + } + label={ __( 'Label' ) } + value={ label } + help={ __( 'Title of track' ) } + /> + + onChange( { + ...track, + srcLang: newSrcLang, + } ) + } + label={ __( 'Source language' ) } + value={ srcLang } + help={ __( 'Language tag (en, fr, etc.)' ) } + /> + + + { + onChange( { + ...track, + kind: newKind, + } ); + } } + /> + + + - - - + > + { __( 'Apply' ) } + + - + ); } @@ -194,6 +179,11 @@ export default function TracksEditor( { tracks = [], onChange } ) { return select( blockEditorStore ).getSettings().mediaUpload; }, [] ); const [ trackBeingEdited, setTrackBeingEdited ] = useState( null ); + const dropdownPopoverRef = useRef(); + + useEffect( () => { + dropdownPopoverRef.current?.focus(); + }, [ trackBeingEdited ] ); if ( ! mediaUpload ) { return null; @@ -201,17 +191,32 @@ export default function TracksEditor( { tracks = [], onChange } ) { return ( ( - - - { __( 'Text tracks' ) } - - - ) } + focusOnMount + popoverProps={ { + ref: dropdownPopoverRef, + } } + renderToggle={ ( { isOpen, onToggle } ) => { + const handleOnToggle = () => { + if ( ! isOpen ) { + // When the Popover opens make sure the initial view is + // always the track list rather than the edit track UI. + setTrackBeingEdited( null ); + } + onToggle(); + }; + + return ( + + + { __( 'Text tracks' ) } + + + ); + } } renderContent={ () => { if ( trackBeingEdited !== null ) { return ( @@ -235,8 +240,21 @@ export default function TracksEditor( { tracks = [], onChange } ) { /> ); } + return ( <> + { tracks.length === 0 && ( +
+

+ { __( 'Text tracks' ) } +

+

+ { __( + 'Tracks can be subtitles, captions, chapters, or descriptions. They help make your content more accessible to a wider range of users.' + ) } +

+
+ ) }