From 69adf95498bab1e68de12a05da309b1cb4a447ea Mon Sep 17 00:00:00 2001 From: Marin Atanasov <8436925+tyxla@users.noreply.github.com> Date: Tue, 23 Apr 2024 14:29:47 +0300 Subject: [PATCH 01/10] ComboboxControl: Simplify string normalization (#60893) * ComboboxControl: Simplify string normalization * CHANGELOG * Update CHANGELOG * Try literal notation * Add inline comment to clarify regex * Fix test comments Co-authored-by: tyxla Co-authored-by: Mamaduka --- packages/components/CHANGELOG.md | 4 ++ packages/components/src/utils/strings.ts | 70 +++---------------- packages/components/src/utils/test/strings.js | 62 ++++++++++++++++ 3 files changed, 77 insertions(+), 59 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 0df9c6c9df8425..fe370102abfff7 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -10,6 +10,10 @@ - `SlotFill`: fixed missing `getServerSnapshot` parameter in slot map ([#60943](https://github.com/WordPress/gutenberg/pull/60943)). +### Enhancements + +- `ComboboxControl`: Simplify string normalization ([#60893](https://github.com/WordPress/gutenberg/pull/60893)). + ## 27.4.0 (2024-04-19) ### Deprecation diff --git a/packages/components/src/utils/strings.ts b/packages/components/src/utils/strings.ts index bb43a5e53a4050..e15886da61f5a6 100644 --- a/packages/components/src/utils/strings.ts +++ b/packages/components/src/utils/strings.ts @@ -4,66 +4,18 @@ import removeAccents from 'remove-accents'; import { paramCase } from 'change-case'; +/** + * All unicode characters that we consider "dash-like": + * - `\u007e`: ~ (tilde) + * - `\u00ad`: ­ (soft hyphen) + * - `\u2053`: ⁓ (swung dash) + * - `\u207b`: ⁻ (superscript minus) + * - `\u208b`: ₋ (subscript minus) + * - `\u2212`: − (minus sign) + * - `\\p{Pd}`: any other Unicode dash character + */ const ALL_UNICODE_DASH_CHARACTERS = new RegExp( - `[${ [ - // - (hyphen-minus) - '\u002d', - // ~ (tilde) - '\u007e', - // ­ (soft hyphen) - '\u00ad', - // ֊ (armenian hyphen) - '\u058a', - // ־ (hebrew punctuation maqaf) - '\u05be', - // ᐀ (canadian syllabics hyphen) - '\u1400', - // ᠆ (mongolian todo soft hyphen) - '\u1806', - // ‐ (hyphen) - '\u2010', - // non-breaking hyphen) - '\u2011', - // ‒ (figure dash) - '\u2012', - // – (en dash) - '\u2013', - // — (em dash) - '\u2014', - // ― (horizontal bar) - '\u2015', - // ⁓ (swung dash) - '\u2053', - // superscript minus) - '\u207b', - // subscript minus) - '\u208b', - // − (minus sign) - '\u2212', - // ⸗ (double oblique hyphen) - '\u2e17', - // ⸺ (two-em dash) - '\u2e3a', - // ⸻ (three-em dash) - '\u2e3b', - // 〜 (wave dash) - '\u301c', - // 〰 (wavy dash) - '\u3030', - // ゠ (katakana-hiragana double hyphen) - '\u30a0', - // ︱ (presentation form for vertical em dash) - '\ufe31', - // ︲ (presentation form for vertical en dash) - '\ufe32', - // ﹘ (small em dash) - '\ufe58', - // ﹣ (small hyphen-minus) - '\ufe63', - // - (fullwidth hyphen-minus) - '\uff0d', - ].join( '' ) }]`, - 'g' + /[\u007e\u00ad\u2053\u207b\u208b\u2212\p{Pd}]/gu ); export const normalizeTextString = ( value: string ): string => { diff --git a/packages/components/src/utils/test/strings.js b/packages/components/src/utils/test/strings.js index 2c7d9641260f5f..7d03075897318f 100644 --- a/packages/components/src/utils/test/strings.js +++ b/packages/components/src/utils/test/strings.js @@ -106,5 +106,67 @@ describe( 'normalizeTextString', () => { expect( normalizeTextString( 'foo⸻bar' ) ).toBe( 'foo-bar' ); expect( normalizeTextString( 'foo゠bar' ) ).toBe( 'foo-bar' ); expect( normalizeTextString( 'foo-bar' ) ).toBe( 'foo-bar' ); + + const dashCharacters = [ + // - (hyphen-minus) + '\u002d', + // ~ (tilde) + '\u007e', + // ­ (soft hyphen) + '\u00ad', + // ֊ (armenian hyphen) + '\u058a', + // ־ (hebrew punctuation maqaf) + '\u05be', + // ᐀ (canadian syllabics hyphen) + '\u1400', + // ᠆ (mongolian todo soft hyphen) + '\u1806', + // ‐ (hyphen) + '\u2010', + // non-breaking hyphen) + '\u2011', + // ‒ (figure dash) + '\u2012', + // – (en dash) + '\u2013', + // — (em dash) + '\u2014', + // ― (horizontal bar) + '\u2015', + // ⁓ (swung dash) + '\u2053', + // ⁻ (superscript minus) + '\u207b', + // ₋ (subscript minus) + '\u208b', + // − (minus sign) + '\u2212', + // ⸗ (double oblique hyphen) + '\u2e17', + // ⸺ (two-em dash) + '\u2e3a', + // ⸻ (three-em dash) + '\u2e3b', + // 〜 (wave dash) + '\u301c', + // 〰 (wavy dash) + '\u3030', + // ゠ (katakana-hiragana double hyphen) + '\u30a0', + // ︱ (presentation form for vertical em dash) + '\ufe31', + // ︲ (presentation form for vertical en dash) + '\ufe32', + // ﹘ (small em dash) + '\ufe58', + // ﹣ (small hyphen-minus) + '\ufe63', + // - (fullwidth hyphen-minus) + '\uff0d', + ]; + expect( normalizeTextString( dashCharacters.join( '' ) ) ).toBe( + '-'.repeat( dashCharacters.length ) + ); } ); } ); From 6527034b9e00c4a1297f5fcf5d11e5a10dfbaa02 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Tue, 23 Apr 2024 12:40:27 +0100 Subject: [PATCH 02/10] Editor: Unify the more menu (#60910) Co-authored-by: youknowriad Co-authored-by: ntsekouras Co-authored-by: jasmussen Co-authored-by: jameskoster --- .../edit-post/src/components/header/index.js | 7 +- .../src/components/header/more-menu/index.js | 69 +++----- .../more-menu/manage-patterns-menu-item.js | 39 +++++ .../more-menu/welcome-guide-menu-item.js} | 0 .../header/preferences-menu-item/index.js | 31 ---- .../components/header/writing-menu/index.js | 73 -------- .../edit-post/src/components/layout/index.js | 2 - .../preferences-modal/test/index.js | 28 ---- packages/edit-post/src/index.js | 1 - .../plugins/copy-content-menu-item/index.js | 29 ---- packages/edit-post/src/plugins/index.js | 85 ---------- .../index.js | 36 ---- .../src/components/header-edit-mode/index.js | 7 +- .../header-edit-mode/more-menu/index.js | 153 +---------------- .../tools-more-menu-group/index.js | 16 -- .../more-menu/copy-content-menu-item.js | 8 +- .../editor/src/components/more-menu/index.js | 158 ++++++++++++++++++ .../more-menu/tools-more-menu-group.js | 11 ++ .../more-menu/view-more-menu-group.js | 13 ++ packages/editor/src/private-apis.js | 8 +- 20 files changed, 274 insertions(+), 500 deletions(-) create mode 100644 packages/edit-post/src/components/header/more-menu/manage-patterns-menu-item.js rename packages/edit-post/src/{plugins/welcome-guide-menu-item/index.js => components/header/more-menu/welcome-guide-menu-item.js} (100%) delete mode 100644 packages/edit-post/src/components/header/preferences-menu-item/index.js delete mode 100644 packages/edit-post/src/components/header/writing-menu/index.js delete mode 100644 packages/edit-post/src/components/preferences-modal/test/index.js delete mode 100644 packages/edit-post/src/plugins/copy-content-menu-item/index.js delete mode 100644 packages/edit-post/src/plugins/index.js delete mode 100644 packages/edit-post/src/plugins/keyboard-shortcuts-help-menu-item/index.js delete mode 100644 packages/edit-site/src/components/header-edit-mode/tools-more-menu-group/index.js rename packages/{edit-site/src/components/header-edit-mode => editor/src/components}/more-menu/copy-content-menu-item.js (87%) create mode 100644 packages/editor/src/components/more-menu/index.js create mode 100644 packages/editor/src/components/more-menu/tools-more-menu-group.js create mode 100644 packages/editor/src/components/more-menu/view-more-menu-group.js diff --git a/packages/edit-post/src/components/header/index.js b/packages/edit-post/src/components/header/index.js index 3aabcf87fae1e2..6aed47542ebcfe 100644 --- a/packages/edit-post/src/components/header/index.js +++ b/packages/edit-post/src/components/header/index.js @@ -23,14 +23,14 @@ import { useState, useCallback } from '@wordpress/element'; * Internal dependencies */ import FullscreenModeClose from './fullscreen-mode-close'; -import MoreMenu from './more-menu'; +import PostEditorMoreMenu from './more-menu'; import PostPublishButtonOrToggle from './post-publish-button-or-toggle'; import MainDashboardButton from './main-dashboard-button'; import ContextualToolbar from './contextual-toolbar'; import { store as editPostStore } from '../../store'; import { unlock } from '../../lock-unlock'; -const { DocumentTools, PostViewLink, PreviewDropdown, PinnedItems } = +const { DocumentTools, PostViewLink, PreviewDropdown, PinnedItems, MoreMenu } = unlock( editorPrivateApis ); const slideY = { @@ -152,7 +152,8 @@ function Header( { setEntitiesSavedStatesCallback, initialPost } ) { { ( isWideViewport || ! showIconLabels ) && ( ) } - + + ); diff --git a/packages/edit-post/src/components/header/more-menu/index.js b/packages/edit-post/src/components/header/more-menu/index.js index df67ddae775a5e..c9f1c50251ca21 100644 --- a/packages/edit-post/src/components/header/more-menu/index.js +++ b/packages/edit-post/src/components/header/more-menu/index.js @@ -2,62 +2,47 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { MenuGroup, DropdownMenu } from '@wordpress/components'; import { useViewportMatch } from '@wordpress/compose'; import { privateApis as editorPrivateApis } from '@wordpress/editor'; -import { moreVertical } from '@wordpress/icons'; +import { PreferenceToggleMenuItem } from '@wordpress/preferences'; +import { displayShortcut } from '@wordpress/keycodes'; /** * Internal dependencies */ -import PreferencesMenuItem from '../preferences-menu-item'; -import ToolsMoreMenuGroup from '../tools-more-menu-group'; -import WritingMenu from '../writing-menu'; import { unlock } from '../../../lock-unlock'; +import ManagePatternsMenuItem from './manage-patterns-menu-item'; +import WelcomeGuideMenuItem from './welcome-guide-menu-item'; +import EditPostPreferencesModal from '../../preferences-modal'; -const { ModeSwitcher, ActionItem, PinnedItems } = unlock( editorPrivateApis ); +const { ToolsMoreMenuGroup, ViewMoreMenuGroup } = unlock( editorPrivateApis ); -const MoreMenu = ( { showIconLabels } ) => { +const MoreMenu = () => { const isLargeViewport = useViewportMatch( 'large' ); return ( - - { ( { onClose } ) => ( - <> - { showIconLabels && ! isLargeViewport && ( - - ) } - - - + { isLargeViewport && ( + + - - - - - + ) } - + + + + + + ); }; diff --git a/packages/edit-post/src/components/header/more-menu/manage-patterns-menu-item.js b/packages/edit-post/src/components/header/more-menu/manage-patterns-menu-item.js new file mode 100644 index 00000000000000..9c528214699d6f --- /dev/null +++ b/packages/edit-post/src/components/header/more-menu/manage-patterns-menu-item.js @@ -0,0 +1,39 @@ +/** + * WordPress dependencies + */ +import { MenuItem } from '@wordpress/components'; +import { store as coreStore } from '@wordpress/core-data'; +import { store as editorStore } from '@wordpress/editor'; +import { useSelect } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; +import { addQueryArgs } from '@wordpress/url'; + +function ManagePatternsMenuItem() { + const url = useSelect( ( select ) => { + const { canUser } = select( coreStore ); + const { getEditorSettings } = select( editorStore ); + + const isBlockTheme = getEditorSettings().__unstableIsBlockBasedTheme; + const defaultUrl = addQueryArgs( 'edit.php', { + post_type: 'wp_block', + } ); + const patternsUrl = addQueryArgs( 'site-editor.php', { + path: '/patterns', + } ); + + // The site editor and templates both check whether the user has + // edit_theme_options capabilities. We can leverage that here and not + // display the manage patterns link if the user can't access it. + return canUser( 'read', 'templates' ) && isBlockTheme + ? patternsUrl + : defaultUrl; + }, [] ); + + return ( + + { __( 'Manage patterns' ) } + + ); +} + +export default ManagePatternsMenuItem; diff --git a/packages/edit-post/src/plugins/welcome-guide-menu-item/index.js b/packages/edit-post/src/components/header/more-menu/welcome-guide-menu-item.js similarity index 100% rename from packages/edit-post/src/plugins/welcome-guide-menu-item/index.js rename to packages/edit-post/src/components/header/more-menu/welcome-guide-menu-item.js diff --git a/packages/edit-post/src/components/header/preferences-menu-item/index.js b/packages/edit-post/src/components/header/preferences-menu-item/index.js deleted file mode 100644 index cf8db6123da117..00000000000000 --- a/packages/edit-post/src/components/header/preferences-menu-item/index.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * WordPress dependencies - */ -import { useDispatch } from '@wordpress/data'; -import { __ } from '@wordpress/i18n'; -import { MenuItem } from '@wordpress/components'; -import { privateApis as editorPrivateApis } from '@wordpress/editor'; - -/** - * Internal dependencies - */ -import { unlock } from '../../../lock-unlock'; - -const { interfaceStore } = unlock( editorPrivateApis ); - -/** - * Internal dependencies - */ - -export default function PreferencesMenuItem() { - const { openModal } = useDispatch( interfaceStore ); - return ( - { - openModal( 'editor/preferences' ); - } } - > - { __( 'Preferences' ) } - - ); -} diff --git a/packages/edit-post/src/components/header/writing-menu/index.js b/packages/edit-post/src/components/header/writing-menu/index.js deleted file mode 100644 index 9c369c4717e9f6..00000000000000 --- a/packages/edit-post/src/components/header/writing-menu/index.js +++ /dev/null @@ -1,73 +0,0 @@ -/** - * WordPress dependencies - */ -import { useDispatch } from '@wordpress/data'; -import { MenuGroup } from '@wordpress/components'; -import { __, _x } from '@wordpress/i18n'; -import { useViewportMatch } from '@wordpress/compose'; -import { displayShortcut } from '@wordpress/keycodes'; -import { - PreferenceToggleMenuItem, - store as preferencesStore, -} from '@wordpress/preferences'; -import { store as editorStore } from '@wordpress/editor'; - -function WritingMenu() { - const { set: setPreference } = useDispatch( preferencesStore ); - const { toggleDistractionFree } = useDispatch( editorStore ); - - const turnOffDistractionFree = () => { - setPreference( 'core', 'distractionFree', false ); - }; - - const isLargeViewport = useViewportMatch( 'medium' ); - if ( ! isLargeViewport ) { - return null; - } - - return ( - - - - - - - ); -} - -export default WritingMenu; diff --git a/packages/edit-post/src/components/layout/index.js b/packages/edit-post/src/components/layout/index.js index 6169e38122a0b2..176b3512eb8a4d 100644 --- a/packages/edit-post/src/components/layout/index.js +++ b/packages/edit-post/src/components/layout/index.js @@ -42,7 +42,6 @@ import { privateApis as blockLibraryPrivateApis } from '@wordpress/block-library import TextEditor from '../text-editor'; import VisualEditor from '../visual-editor'; import EditPostKeyboardShortcuts from '../keyboard-shortcuts'; -import EditPostPreferencesModal from '../preferences-modal'; import InitPatternModal from '../init-pattern-modal'; import BrowserURL from '../browser-url'; import Header from '../header'; @@ -361,7 +360,6 @@ function Layout( { initialPost } ) { next: nextShortcut, } } /> - diff --git a/packages/edit-post/src/components/preferences-modal/test/index.js b/packages/edit-post/src/components/preferences-modal/test/index.js deleted file mode 100644 index 01ac1a88fbe7d8..00000000000000 --- a/packages/edit-post/src/components/preferences-modal/test/index.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * External dependencies - */ -import { render, screen } from '@testing-library/react'; - -/** - * WordPress dependencies - */ -import { useSelect } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import EditPostPreferencesModal from '../'; - -// This allows us to tweak the returned value on each test. -jest.mock( '@wordpress/data/src/components/use-select', () => jest.fn() ); -jest.mock( '@wordpress/compose/src/hooks/use-viewport-match', () => jest.fn() ); - -describe( 'EditPostPreferencesModal', () => { - it( 'should not render when the modal is not active', () => { - useSelect.mockImplementation( () => [ false, false, false ] ); - render( ); - expect( - screen.queryByRole( 'dialog', { name: 'Preferences' } ) - ).not.toBeInTheDocument(); - } ); -} ); diff --git a/packages/edit-post/src/index.js b/packages/edit-post/src/index.js index b9555f6590d711..656fa54d87bfeb 100644 --- a/packages/edit-post/src/index.js +++ b/packages/edit-post/src/index.js @@ -29,7 +29,6 @@ import { * Internal dependencies */ import './hooks'; -import './plugins'; import Editor from './editor'; import { unlock } from './lock-unlock'; diff --git a/packages/edit-post/src/plugins/copy-content-menu-item/index.js b/packages/edit-post/src/plugins/copy-content-menu-item/index.js deleted file mode 100644 index 60bbbf9c83d6eb..00000000000000 --- a/packages/edit-post/src/plugins/copy-content-menu-item/index.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * WordPress dependencies - */ -import { MenuItem } from '@wordpress/components'; -import { useSelect, useDispatch } from '@wordpress/data'; -import { __ } from '@wordpress/i18n'; -import { useCopyToClipboard } from '@wordpress/compose'; -import { store as noticesStore } from '@wordpress/notices'; -import { store as editorStore } from '@wordpress/editor'; - -export default function CopyContentMenuItem() { - const { createNotice } = useDispatch( noticesStore ); - const { getEditedPostAttribute } = useSelect( editorStore ); - - function getText() { - return getEditedPostAttribute( 'content' ); - } - - function onSuccess() { - createNotice( 'info', __( 'All content copied.' ), { - isDismissible: true, - type: 'snackbar', - } ); - } - - const ref = useCopyToClipboard( getText, onSuccess ); - - return { __( 'Copy all blocks' ) }; -} diff --git a/packages/edit-post/src/plugins/index.js b/packages/edit-post/src/plugins/index.js deleted file mode 100644 index aa663659acbdc1..00000000000000 --- a/packages/edit-post/src/plugins/index.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * WordPress dependencies - */ -import { MenuItem, VisuallyHidden } from '@wordpress/components'; -import { store as coreStore } from '@wordpress/core-data'; -import { store as editorStore } from '@wordpress/editor'; -import { useSelect } from '@wordpress/data'; -import { external } from '@wordpress/icons'; -import { __ } from '@wordpress/i18n'; -import { registerPlugin } from '@wordpress/plugins'; -import { addQueryArgs } from '@wordpress/url'; - -/** - * Internal dependencies - */ -import CopyContentMenuItem from './copy-content-menu-item'; -import KeyboardShortcutsHelpMenuItem from './keyboard-shortcuts-help-menu-item'; -import ToolsMoreMenuGroup from '../components/header/tools-more-menu-group'; -import WelcomeGuideMenuItem from './welcome-guide-menu-item'; - -function ManagePatternsMenuItem() { - const url = useSelect( ( select ) => { - const { canUser } = select( coreStore ); - const { getEditorSettings } = select( editorStore ); - - const isBlockTheme = getEditorSettings().__unstableIsBlockBasedTheme; - const defaultUrl = addQueryArgs( 'edit.php', { - post_type: 'wp_block', - } ); - const patternsUrl = addQueryArgs( 'site-editor.php', { - path: '/patterns', - } ); - - // The site editor and templates both check whether the user has - // edit_theme_options capabilities. We can leverage that here and not - // display the manage patterns link if the user can't access it. - return canUser( 'read', 'templates' ) && isBlockTheme - ? patternsUrl - : defaultUrl; - }, [] ); - - return ( - - { __( 'Manage patterns' ) } - - ); -} - -registerPlugin( 'edit-post', { - render() { - return ( - <> - - { ( { onClose } ) => ( - <> - - - - - - { __( 'Help' ) } - - { - /* translators: accessibility text */ - __( '(opens in a new tab)' ) - } - - - - ) } - - - ); - }, -} ); diff --git a/packages/edit-post/src/plugins/keyboard-shortcuts-help-menu-item/index.js b/packages/edit-post/src/plugins/keyboard-shortcuts-help-menu-item/index.js deleted file mode 100644 index e86807ac4644f4..00000000000000 --- a/packages/edit-post/src/plugins/keyboard-shortcuts-help-menu-item/index.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * WordPress dependencies - */ -import { MenuItem } from '@wordpress/components'; -import { withDispatch } from '@wordpress/data'; -import { __ } from '@wordpress/i18n'; -import { displayShortcut } from '@wordpress/keycodes'; -import { privateApis as editorPrivateApis } from '@wordpress/editor'; - -/** - * Internal dependencies - */ -import { unlock } from '../../lock-unlock'; - -const { interfaceStore } = unlock( editorPrivateApis ); - -export function KeyboardShortcutsHelpMenuItem( { openModal } ) { - return ( - { - openModal( 'editor/keyboard-shortcut-help' ); - } } - shortcut={ displayShortcut.access( 'h' ) } - > - { __( 'Keyboard shortcuts' ) } - - ); -} - -export default withDispatch( ( dispatch ) => { - const { openModal } = dispatch( interfaceStore ); - - return { - openModal, - }; -} )( KeyboardShortcutsHelpMenuItem ); diff --git a/packages/edit-site/src/components/header-edit-mode/index.js b/packages/edit-site/src/components/header-edit-mode/index.js index 902ccb19093d89..f56e370de6438f 100644 --- a/packages/edit-site/src/components/header-edit-mode/index.js +++ b/packages/edit-site/src/components/header-edit-mode/index.js @@ -31,7 +31,7 @@ import { /** * Internal dependencies */ -import MoreMenu from './more-menu'; +import SiteEditorMoreMenuItems from './more-menu'; import SaveButton from '../save-button'; import DocumentTools from './document-tools'; import { store as editSiteStore } from '../../store'; @@ -43,7 +43,7 @@ import { unlock } from '../../lock-unlock'; import { FOCUSABLE_ENTITIES } from '../../utils/constants'; const { useHasBlockToolbar } = unlock( blockEditorPrivateApis ); -const { PostViewLink, PreviewDropdown, PinnedItems } = +const { MoreMenu, PostViewLink, PreviewDropdown, PinnedItems } = unlock( editorPrivateApis ); export default function HeaderEditMode() { @@ -206,7 +206,8 @@ export default function HeaderEditMode() { { ! isDistractionFree && } - + + diff --git a/packages/edit-site/src/components/header-edit-mode/more-menu/index.js b/packages/edit-site/src/components/header-edit-mode/more-menu/index.js index 5e9577a6286321..f0df5cf57fe6f0 100644 --- a/packages/edit-site/src/components/header-edit-mode/more-menu/index.js +++ b/packages/edit-site/src/components/header-edit-mode/more-menu/index.js @@ -1,167 +1,30 @@ /** * WordPress dependencies */ -import { __, _x } from '@wordpress/i18n'; -import { useSelect, useDispatch } from '@wordpress/data'; -import { displayShortcut } from '@wordpress/keycodes'; -import { external, moreVertical } from '@wordpress/icons'; -import { - MenuGroup, - MenuItem, - VisuallyHidden, - DropdownMenu, -} from '@wordpress/components'; -import { - PreferenceToggleMenuItem, - store as preferencesStore, -} from '@wordpress/preferences'; +import { useSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; -import { - store as editorStore, - privateApis as editorPrivateApis, -} from '@wordpress/editor'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; /** * Internal dependencies */ -import ToolsMoreMenuGroup from '../tools-more-menu-group'; import SiteExport from './site-export'; import WelcomeGuideMenuItem from './welcome-guide-menu-item'; -import CopyContentMenuItem from './copy-content-menu-item'; import { unlock } from '../../../lock-unlock'; -const { ModeSwitcher, ActionItem, interfaceStore, PreferencesModal } = - unlock( editorPrivateApis ); +const { ToolsMoreMenuGroup, PreferencesModal } = unlock( editorPrivateApis ); -export default function MoreMenu( { showIconLabels } ) { - const { openModal } = useDispatch( interfaceStore ); - const { set: setPreference } = useDispatch( preferencesStore ); +export default function MoreMenu() { const isBlockBasedTheme = useSelect( ( select ) => { return select( coreStore ).getCurrentTheme().is_block_theme; }, [] ); - const { toggleDistractionFree } = useDispatch( editorStore ); - - const turnOffDistractionFree = () => { - setPreference( 'core', 'distractionFree', false ); - }; - return ( <> - - { ( { onClose } ) => ( - <> - - - - - - - - - { isBlockBasedTheme && } - - openModal( 'editor/keyboard-shortcut-help' ) - } - shortcut={ displayShortcut.access( 'h' ) } - > - { __( 'Keyboard shortcuts' ) } - - - - - { __( 'Help' ) } - - { - /* translators: accessibility text */ - __( '(opens in a new tab)' ) - } - - - - - - - openModal( 'editor/preferences' ) - } - > - { __( 'Preferences' ) } - - - - ) } - + + { isBlockBasedTheme && } + + ); diff --git a/packages/edit-site/src/components/header-edit-mode/tools-more-menu-group/index.js b/packages/edit-site/src/components/header-edit-mode/tools-more-menu-group/index.js deleted file mode 100644 index 8babbdd0c3dc71..00000000000000 --- a/packages/edit-site/src/components/header-edit-mode/tools-more-menu-group/index.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * WordPress dependencies - */ -import { createSlotFill } from '@wordpress/components'; - -const { Fill: ToolsMoreMenuGroup, Slot } = createSlotFill( - 'EditSiteToolsMoreMenuGroup' -); - -ToolsMoreMenuGroup.Slot = ( { fillProps } ) => ( - - { ( fills ) => fills && fills.length > 0 } - -); - -export default ToolsMoreMenuGroup; diff --git a/packages/edit-site/src/components/header-edit-mode/more-menu/copy-content-menu-item.js b/packages/editor/src/components/more-menu/copy-content-menu-item.js similarity index 87% rename from packages/edit-site/src/components/header-edit-mode/more-menu/copy-content-menu-item.js rename to packages/editor/src/components/more-menu/copy-content-menu-item.js index 887817692239c9..8b9de82f7ac96a 100644 --- a/packages/edit-site/src/components/header-edit-mode/more-menu/copy-content-menu-item.js +++ b/packages/editor/src/components/more-menu/copy-content-menu-item.js @@ -12,18 +12,18 @@ import { __unstableSerializeAndClean } from '@wordpress/blocks'; /** * Internal dependencies */ -import { store as editSiteStore } from '../../../store'; +import { store as editorStore } from '../../store'; export default function CopyContentMenuItem() { const { createNotice } = useDispatch( noticesStore ); - const { getEditedPostId, getEditedPostType } = useSelect( editSiteStore ); + const { getCurrentPostId, getCurrentPostType } = useSelect( editorStore ); const { getEditedEntityRecord } = useSelect( coreStore ); function getText() { const record = getEditedEntityRecord( 'postType', - getEditedPostType(), - getEditedPostId() + getCurrentPostType(), + getCurrentPostId() ); if ( ! record ) { return ''; diff --git a/packages/editor/src/components/more-menu/index.js b/packages/editor/src/components/more-menu/index.js new file mode 100644 index 00000000000000..6ccc01c6ac049c --- /dev/null +++ b/packages/editor/src/components/more-menu/index.js @@ -0,0 +1,158 @@ +/** + * WordPress dependencies + */ +import { __, _x } from '@wordpress/i18n'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { displayShortcut } from '@wordpress/keycodes'; +import { external, moreVertical } from '@wordpress/icons'; +import { + MenuGroup, + MenuItem, + VisuallyHidden, + DropdownMenu, +} from '@wordpress/components'; +import { + PreferenceToggleMenuItem, + store as preferencesStore, +} from '@wordpress/preferences'; +import { store as interfaceStore, ActionItem } from '@wordpress/interface'; + +/** + * Internal dependencies + */ +import CopyContentMenuItem from './copy-content-menu-item'; +import ModeSwitcher from '../mode-switcher'; +import ToolsMoreMenuGroup from './tools-more-menu-group'; +import ViewMoreMenuGroup from './view-more-menu-group'; +import { store as editorStore } from '../../store'; + +export default function MoreMenu() { + const { openModal } = useDispatch( interfaceStore ); + const { set: setPreference } = useDispatch( preferencesStore ); + const { toggleDistractionFree } = useDispatch( editorStore ); + const showIconLabels = useSelect( + ( select ) => + select( preferencesStore ).get( 'core', 'showIconLabels' ), + [] + ); + const turnOffDistractionFree = () => { + setPreference( 'core', 'distractionFree', false ); + }; + + return ( + <> + + { ( { onClose } ) => ( + <> + + + + + + + + + + + openModal( 'editor/keyboard-shortcut-help' ) + } + shortcut={ displayShortcut.access( 'h' ) } + > + { __( 'Keyboard shortcuts' ) } + + + + { __( 'Help' ) } + + { + /* translators: accessibility text */ + __( '(opens in a new tab)' ) + } + + + + + + + openModal( 'editor/preferences' ) + } + > + { __( 'Preferences' ) } + + + + ) } + + + ); +} diff --git a/packages/editor/src/components/more-menu/tools-more-menu-group.js b/packages/editor/src/components/more-menu/tools-more-menu-group.js new file mode 100644 index 00000000000000..7dec9d9d490d86 --- /dev/null +++ b/packages/editor/src/components/more-menu/tools-more-menu-group.js @@ -0,0 +1,11 @@ +/** + * WordPress dependencies + */ +import { createSlotFill } from '@wordpress/components'; + +const { Fill: ToolsMoreMenuGroup, Slot } = + createSlotFill( 'ToolsMoreMenuGroup' ); + +ToolsMoreMenuGroup.Slot = ( { fillProps } ) => ; + +export default ToolsMoreMenuGroup; diff --git a/packages/editor/src/components/more-menu/view-more-menu-group.js b/packages/editor/src/components/more-menu/view-more-menu-group.js new file mode 100644 index 00000000000000..23e2cf82d82c6d --- /dev/null +++ b/packages/editor/src/components/more-menu/view-more-menu-group.js @@ -0,0 +1,13 @@ +/** + * WordPress dependencies + */ +import { createSlotFill } from '@wordpress/components'; +import { Platform } from '@wordpress/element'; + +const { Fill: ViewMoreMenuGroup, Slot } = createSlotFill( + Platform.OS === 'web' ? Symbol( 'ViewMoreMenuGroup' ) : 'ViewMoreMenuGroup' +); + +ViewMoreMenuGroup.Slot = ( { fillProps } ) => ; + +export default ViewMoreMenuGroup; diff --git a/packages/editor/src/private-apis.js b/packages/editor/src/private-apis.js index bff79cc034f1a7..aae3762794b4d6 100644 --- a/packages/editor/src/private-apis.js +++ b/packages/editor/src/private-apis.js @@ -15,7 +15,7 @@ import useBlockEditorSettings from './components/provider/use-block-editor-setti import DocumentTools from './components/document-tools'; import InserterSidebar from './components/inserter-sidebar'; import ListViewSidebar from './components/list-view-sidebar'; -import ModeSwitcher from './components/mode-switcher'; +import MoreMenu from './components/more-menu'; import PatternOverridesPanel from './components/pattern-overrides-panel'; import PluginPostExcerpt from './components/post-excerpt/plugin'; import PostPanelRow from './components/post-panel-row'; @@ -26,6 +26,8 @@ import PostActions from './components/post-actions'; import { usePostActions } from './components/post-actions/actions'; import PostCardPanel from './components/post-card-panel'; import PostStatus from './components/post-status'; +import ToolsMoreMenuGroup from './components/more-menu/tools-more-menu-group'; +import ViewMoreMenuGroup from './components/more-menu/view-more-menu-group'; const { store: interfaceStore, ...remainingInterfaceApis } = interfaceApis; @@ -37,7 +39,7 @@ lock( privateApis, { EntitiesSavedStatesExtensible, InserterSidebar, ListViewSidebar, - ModeSwitcher, + MoreMenu, PatternOverridesPanel, PluginPostExcerpt, PostActions, @@ -48,6 +50,8 @@ lock( privateApis, { usePostActions, PostCardPanel, PostStatus, + ToolsMoreMenuGroup, + ViewMoreMenuGroup, // This is a temporary private API while we're updating the site editor to use EditorProvider. useAutoSwitchEditorSidebars, From 2bbae36c2ed0c2151f88bf1856e6a60f0066fc44 Mon Sep 17 00:00:00 2001 From: Carolina Nymark Date: Tue, 23 Apr 2024 14:21:23 +0200 Subject: [PATCH 03/10] [Data Views] User patterns: Use excerpt as description (#60549) * [Data Views] User patterns: Use excerpt as description Enable excerpts on the w_block post type. On the Site Editor Pattern pages, use the excerpt as the description for user created patterns. * CS fix: Remove duplicate empty line * Place the description before the instructions. * Remove the incorrect instructions from ariaDescribedBy - Removes the instructions from `ariaDescribedBy`, since they were not working and are not needed anymore. - Because only one piece of content is added to `ariaDescribedBy`, the `ariaDescriptions` array and the `.map()` are not needed anymore, and are removed. * Try using the button and the description for all pattern types. - Remove the condition that hides the item description on non user patterns. - Use the button for all pattern types and for parts. Disable the button for patterns that are not editable. - Add a title attribute on the non user patterns, to try to avoid confusion for sighted users that clicks the disabled button. * Remove title attribute and replace cursor style Rename blocks.php to post.php. Remove the title attribute from the button. Reset the cursor style to the default when the button is disabled. * CS fix: Add empty line at end of file * Fix pattern preview dimensions * Update dimensions to match templates --------- Co-authored-by: carolinan Co-authored-by: jameskoster Co-authored-by: ntsekouras Co-authored-by: talldan Co-authored-by: unscripted --- lib/compat/wordpress-6.6/post.php | 15 ++++++ lib/load.php | 1 + .../src/components/page-patterns/index.js | 46 ++++--------------- .../src/components/page-patterns/style.scss | 14 ++++++ .../components/page-patterns/use-patterns.js | 1 + 5 files changed, 40 insertions(+), 37 deletions(-) create mode 100644 lib/compat/wordpress-6.6/post.php diff --git a/lib/compat/wordpress-6.6/post.php b/lib/compat/wordpress-6.6/post.php new file mode 100644 index 00000000000000..42707989fc0828 --- /dev/null +++ b/lib/compat/wordpress-6.6/post.php @@ -0,0 +1,15 @@ + { children } @@ -131,21 +129,8 @@ function PreviewWrapper( { item, onClick, ariaDescribedBy, children } ) { function Preview( { item, categoryId, viewType } ) { const descriptionId = useId(); const isUserPattern = item.type === PATTERN_TYPES.user; - const isNonUserPattern = item.type === PATTERN_TYPES.theme; const isTemplatePart = item.type === TEMPLATE_PART_POST_TYPE; const isEmpty = ! item.blocks?.length; - // Only custom patterns or custom template parts can be renamed or deleted. - const isCustomPattern = - isUserPattern || ( isTemplatePart && item.isCustom ); - const ariaDescriptions = []; - if ( isCustomPattern ) { - // User patterns don't have descriptions, but can be edited and deleted, so include some help text. - ariaDescriptions.push( - __( 'Press Enter to edit, or Delete to delete the pattern.' ) - ); - } else if ( item.description ) { - ariaDescriptions.push( item.description ); - } const [ backgroundColor ] = useGlobalStyle( 'color.background' ); const { onClick } = useLink( { @@ -164,16 +149,7 @@ function Preview( { item, categoryId, viewType } ) { - `${ descriptionId }-${ index }` - ) - .join( ' ' ) - : undefined - } + ariaDescribedBy={ item.description ? descriptionId : undefined } > { isEmpty && isTemplatePart && __( 'Empty template part' ) } { isEmpty && ! isTemplatePart && __( 'Empty pattern' ) } @@ -186,16 +162,11 @@ function Preview( { item, categoryId, viewType } ) { ) } - { ! isNonUserPattern && - ariaDescriptions.map( ( ariaDescription, index ) => ( - - ) ) } + { item.description && ( + + ) } ); } @@ -344,6 +315,7 @@ export default function DataviewsPatterns() { ), enableSorting: false, enableHiding: false, + width: '1%', }, { header: __( 'Title' ), diff --git a/packages/edit-site/src/components/page-patterns/style.scss b/packages/edit-site/src/components/page-patterns/style.scss index 6c616426aa3894..c8d23fc1843b17 100644 --- a/packages/edit-site/src/components/page-patterns/style.scss +++ b/packages/edit-site/src/components/page-patterns/style.scss @@ -56,6 +56,16 @@ } } + &.is-viewtype-table { + width: 96px; + flex-grow: 0; + border-radius: 2px; + + .page-patterns-preview-field__button { + border-radius: 2px; + } + } + .page-patterns-preview-field__button { box-shadow: none; border: none; @@ -72,6 +82,10 @@ // Windows High Contrast mode will show this outline, but not the box-shadow. outline: 2px solid transparent; } + + &[aria-disabled="true"] { + cursor: default; + } } } diff --git a/packages/edit-site/src/components/page-patterns/use-patterns.js b/packages/edit-site/src/components/page-patterns/use-patterns.js index 8b6c6f26ddd44b..68c70d9447be89 100644 --- a/packages/edit-site/src/components/page-patterns/use-patterns.js +++ b/packages/edit-site/src/components/page-patterns/use-patterns.js @@ -223,6 +223,7 @@ const convertPatternPostToItem = ( patternPost, categories ) => ( { syncStatus: patternPost.wp_pattern_sync_status || PATTERN_SYNC_TYPES.full, title: patternPost.title.raw, type: patternPost.type, + description: patternPost.excerpt.raw, patternPost, } ); From a1a3391006d4250d14edd06ce2f18b9e3aa40bab Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Tue, 23 Apr 2024 14:44:45 +0200 Subject: [PATCH 04/10] Fix: Post actions in post card panel is not checking for eligibility. (#60994) Co-authored-by: jorgefilipecosta --- packages/editor/src/components/post-actions/index.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/editor/src/components/post-actions/index.js b/packages/editor/src/components/post-actions/index.js index 269748685758c1..48d83f992e7056 100644 --- a/packages/editor/src/components/post-actions/index.js +++ b/packages/editor/src/components/post-actions/index.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { useSelect } from '@wordpress/data'; -import { useState } from '@wordpress/element'; +import { useState, useMemo } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { privateApis as componentsPrivateApis, @@ -46,11 +46,17 @@ export default function PostActions( { onActionPerformed, buttonProps } ) { item: getCurrentPost(), }; } ); - const actions = usePostActions( + const allActions = usePostActions( onActionPerformed, POST_ACTIONS_WHILE_EDITING ); + const actions = useMemo( () => { + return allActions.filter( ( action ) => { + return ! action.isEligible || action.isEligible( item ); + } ); + }, [ allActions, item ] ); + if ( [ TEMPLATE_POST_TYPE, From c2c5bef9c28d2612ddb2ecaaa6b1fccaccf98e58 Mon Sep 17 00:00:00 2001 From: Jarda Snajdr Date: Tue, 23 Apr 2024 14:58:45 +0200 Subject: [PATCH 05/10] lint-staged-typecheck: don't run TSC when no TS project is affected (#60998) Co-authored-by: jsnajdr Co-authored-by: sirreal --- bin/packages/lint-staged-typecheck.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/bin/packages/lint-staged-typecheck.js b/bin/packages/lint-staged-typecheck.js index 7b7eb7b846bfb0..8e656755134f18 100644 --- a/bin/packages/lint-staged-typecheck.js +++ b/bin/packages/lint-staged-typecheck.js @@ -28,9 +28,11 @@ const changedPackages = [ fs.existsSync( path.join( packageRoot, 'tsconfig.json' ) ) ); -try { - execa.sync( tscPath, [ '--build', ...changedPackages ] ); -} catch ( err ) { - console.error( err.stdout ); - process.exitCode = 1; +if ( changedPackages.length > 0 ) { + try { + execa.sync( tscPath, [ '--build', ...changedPackages ] ); + } catch ( err ) { + console.error( err.stdout ); + process.exitCode = 1; + } } From 73f91a28ad8b05b69c93b80fb03e2e466c5fe74b Mon Sep 17 00:00:00 2001 From: Ella <4710635+ellatrix@users.noreply.github.com> Date: Tue, 23 Apr 2024 15:05:51 +0200 Subject: [PATCH 06/10] Drop zone: avoid media query on mount (#60546) Co-authored-by: ellatrix Co-authored-by: mirka <0mirka00@git.wordpress.org> Co-authored-by: jsnajdr Co-authored-by: tyxla --- packages/components/CHANGELOG.md | 2 + packages/components/src/drop-zone/index.tsx | 132 ++++++++++---------- 2 files changed, 68 insertions(+), 66 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index fe370102abfff7..0ba235f6f564d1 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -12,7 +12,9 @@ ### Enhancements +- `DropZone`: Avoid a media query on mount [#60546](https://github.com/WordPress/gutenberg/pull/60546)). - `ComboboxControl`: Simplify string normalization ([#60893](https://github.com/WordPress/gutenberg/pull/60893)). +### Internal ## 27.4.0 (2024-04-19) diff --git a/packages/components/src/drop-zone/index.tsx b/packages/components/src/drop-zone/index.tsx index f620e6a03c6b85..9d5255a1d771e3 100644 --- a/packages/components/src/drop-zone/index.tsx +++ b/packages/components/src/drop-zone/index.tsx @@ -25,6 +25,71 @@ import { import type { DropType, DropZoneProps } from './types'; import type { WordPressComponentProps } from '../context'; +const backdrop = { + hidden: { opacity: 0 }, + show: { + opacity: 1, + transition: { + type: 'tween', + duration: 0.2, + delay: 0, + delayChildren: 0.1, + }, + }, + exit: { + opacity: 0, + transition: { + duration: 0.2, + delayChildren: 0, + }, + }, +}; + +const foreground = { + hidden: { opacity: 0, scale: 0.9 }, + show: { + opacity: 1, + scale: 1, + transition: { + duration: 0.1, + }, + }, + exit: { opacity: 0, scale: 0.9 }, +}; + +function DropIndicator( { label }: { label?: string } ) { + const disableMotion = useReducedMotion(); + const children = ( + + + + + { label ? label : __( 'Drop files to upload' ) } + + + + ); + + if ( disableMotion ) { + return children; + } + + return { children }; +} + /** * `DropZone` is a component creating a drop zone area taking the full size of its parent element. It supports dropping files, HTML content or any other HTML drop event. * @@ -116,67 +181,6 @@ export function DropZoneComponent( { setIsDraggingOverElement( false ); }, } ); - const disableMotion = useReducedMotion(); - - let children; - const backdrop = { - hidden: { opacity: 0 }, - show: { - opacity: 1, - transition: { - type: 'tween', - duration: 0.2, - delay: 0, - delayChildren: 0.1, - }, - }, - exit: { - opacity: 0, - transition: { - duration: 0.2, - delayChildren: 0, - }, - }, - }; - - const foreground = { - hidden: { opacity: 0, scale: 0.9 }, - show: { - opacity: 1, - scale: 1, - transition: { - duration: 0.1, - }, - }, - exit: { opacity: 0, scale: 0.9 }, - }; - - if ( isDraggingOverElement ) { - children = ( - - - - - { label ? label : __( 'Drop files to upload' ) } - - - - ); - } - const classes = classnames( 'components-drop-zone', className, { 'is-active': ( isDraggingOverDocument || isDraggingOverElement ) && @@ -190,11 +194,7 @@ export function DropZoneComponent( { return (
- { disableMotion ? ( - children - ) : ( - { children } - ) } + { isDraggingOverElement && }
); } From 4ec0363304cf7ef6d5b254dfb966e5c738fd1b98 Mon Sep 17 00:00:00 2001 From: Ella <4710635+ellatrix@users.noreply.github.com> Date: Tue, 23 Apr 2024 15:39:42 +0200 Subject: [PATCH 07/10] Core data: getEditedEntityRecord: do not return empty object (#60988) Co-authored-by: ellatrix Co-authored-by: Mamaduka --- docs/reference-guides/data/data-core.md | 2 +- packages/core-data/README.md | 2 +- .../src/hooks/test/use-entity-record.js | 2 +- packages/core-data/src/selectors.ts | 21 ++++++++++++++----- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md index b80703dcc67b18..e740998a236233 100644 --- a/docs/reference-guides/data/data-core.md +++ b/docs/reference-guides/data/data-core.md @@ -178,7 +178,7 @@ _Parameters_ _Returns_ -- `undefined< EntityRecord > | undefined`: The entity record, merged with its edits. +- `undefined< EntityRecord > | false`: The entity record, merged with its edits. ### getEmbedPreview diff --git a/packages/core-data/README.md b/packages/core-data/README.md index 6677a32df08dc9..444bce35ee5218 100644 --- a/packages/core-data/README.md +++ b/packages/core-data/README.md @@ -499,7 +499,7 @@ _Parameters_ _Returns_ -- `undefined< EntityRecord > | undefined`: The entity record, merged with its edits. +- `undefined< EntityRecord > | false`: The entity record, merged with its edits. ### getEmbedPreview diff --git a/packages/core-data/src/hooks/test/use-entity-record.js b/packages/core-data/src/hooks/test/use-entity-record.js index 49964339a4f2b8..1bfb13f38ac156 100644 --- a/packages/core-data/src/hooks/test/use-entity-record.js +++ b/packages/core-data/src/hooks/test/use-entity-record.js @@ -45,7 +45,7 @@ describe( 'useEntityRecord', () => { expect( data ).toEqual( { edit: expect.any( Function ), - editedRecord: {}, + editedRecord: false, hasEdits: false, edits: {}, record: undefined, diff --git a/packages/core-data/src/selectors.ts b/packages/core-data/src/selectors.ts index 4a135f343a0979..d238438e10eb13 100644 --- a/packages/core-data/src/selectors.ts +++ b/packages/core-data/src/selectors.ts @@ -846,10 +846,21 @@ export const getEditedEntityRecord = createSelector( kind: string, name: string, recordId: EntityRecordKey - ): ET.Updatable< EntityRecord > | undefined => ( { - ...getRawEntityRecord( state, kind, name, recordId ), - ...getEntityRecordEdits( state, kind, name, recordId ), - } ), + ): ET.Updatable< EntityRecord > | false => { + const raw = getRawEntityRecord( state, kind, name, recordId ); + const edited = getEntityRecordEdits( state, kind, name, recordId ); + // Never return a non-falsy empty object. Unfortunately we can't return + // undefined or null because we were previously returning an empty + // object, so trying to read properties from the result would throw. + // Using false here is a workaround to avoid breaking changes. + if ( ! raw && ! edited ) { + return false; + } + return { + ...raw, + ...edited, + }; + }, ( state: State, kind: string, @@ -1264,7 +1275,7 @@ export function getReferenceByDistinctEdits( state ) { export function __experimentalGetTemplateForLink( state: State, link: string -): Optional< ET.Updatable< ET.WpTemplate > > | null { +): Optional< ET.Updatable< ET.WpTemplate > > | null | false { const records = getEntityRecords< ET.WpTemplate >( state, 'postType', From e6c62c8f3d92f492ba7505fb6dbde73a0db540e6 Mon Sep 17 00:00:00 2001 From: Ella <4710635+ellatrix@users.noreply.github.com> Date: Tue, 23 Apr 2024 16:38:12 +0200 Subject: [PATCH 08/10] useMatchMedia: cache queries (#61000) Co-authored-by: ellatrix Co-authored-by: jsnajdr Co-authored-by: tyxla --- .../compose/src/hooks/use-media-query/index.js | 17 +++++++++++++++-- .../src/hooks/use-media-query/test/index.js | 9 +++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/packages/compose/src/hooks/use-media-query/index.js b/packages/compose/src/hooks/use-media-query/index.js index 59e6e5d99a4af3..598ab006ecb747 100644 --- a/packages/compose/src/hooks/use-media-query/index.js +++ b/packages/compose/src/hooks/use-media-query/index.js @@ -3,6 +3,8 @@ */ import { useMemo, useSyncExternalStore } from '@wordpress/element'; +const matchMediaCache = new Map(); + /** * A new MediaQueryList object for the media query * @@ -10,12 +12,23 @@ import { useMemo, useSyncExternalStore } from '@wordpress/element'; * @return {MediaQueryList|null} A new object for the media query */ function getMediaQueryList( query ) { + if ( ! query ) { + return null; + } + + let match = matchMediaCache.get( query ); + + if ( match ) { + return match; + } + if ( - query && typeof window !== 'undefined' && typeof window.matchMedia === 'function' ) { - return window.matchMedia( query ); + match = window.matchMedia( query ); + matchMediaCache.set( query, match ); + return match; } return null; diff --git a/packages/compose/src/hooks/use-media-query/test/index.js b/packages/compose/src/hooks/use-media-query/test/index.js index 88b2c1b0a3bd24..f8a61a8469c070 100644 --- a/packages/compose/src/hooks/use-media-query/test/index.js +++ b/packages/compose/src/hooks/use-media-query/test/index.js @@ -2,7 +2,7 @@ * External dependencies */ import { act, render } from '@testing-library/react'; -import { matchMedia, setMedia, cleanup } from 'mock-match-media'; +import { matchMedia, setMedia } from 'mock-match-media'; /** * Internal dependencies @@ -26,10 +26,11 @@ describe( 'useMediaQuery', () => { } ); afterEach( () => { - cleanup(); + // Do not clean up, this will break our cache. Browsers also do not + // reset media queries. } ); - it( 'should return true when query matches', async () => { + it( 'should return true when the query matches', async () => { const { container } = render( ); @@ -53,7 +54,7 @@ describe( 'useMediaQuery', () => { expect( container ).toHaveTextContent( 'useMediaQuery: false' ); } ); - it( 'should return false when the query does not matches', async () => { + it( 'should return false when the query does not match', async () => { const { container } = render( ); From 006107338d284b9d88f3ecf901dad4e41eca86dc Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Tue, 23 Apr 2024 18:59:25 +0400 Subject: [PATCH 09/10] Editor: Optimize some of the post-support panels (#61003) Co-authored-by: Mamaduka Co-authored-by: ntsekouras --- .../src/components/page-attributes/panel.js | 33 +++++++------- .../src/components/post-discussion/panel.js | 44 ++++++++++--------- .../src/components/post-excerpt/panel.js | 36 ++++++++------- 3 files changed, 61 insertions(+), 52 deletions(-) diff --git a/packages/editor/src/components/page-attributes/panel.js b/packages/editor/src/components/page-attributes/panel.js index 63d5bbb5a87048..d6fb9294748ab0 100644 --- a/packages/editor/src/components/page-attributes/panel.js +++ b/packages/editor/src/components/page-attributes/panel.js @@ -17,7 +17,7 @@ import PageAttributesParent from './parent'; const PANEL_NAME = 'page-attributes'; -export function PageAttributesPanel() { +function AttributesPanel() { const { isEnabled, isOpened, postType } = useSelect( ( select ) => { const { getEditedPostAttribute, @@ -38,25 +38,24 @@ export function PageAttributesPanel() { return null; } - const onTogglePanel = ( ...args ) => - toggleEditorPanelOpened( PANEL_NAME, ...args ); + return ( + toggleEditorPanelOpened( PANEL_NAME ) } + > + + + + + + ); +} +export default function PageAttributesPanel() { return ( - - - - - - + ); } - -export default PageAttributesPanel; diff --git a/packages/editor/src/components/post-discussion/panel.js b/packages/editor/src/components/post-discussion/panel.js index 8d9a6a691ac901..6ff022a2b8b52e 100644 --- a/packages/editor/src/components/post-discussion/panel.js +++ b/packages/editor/src/components/post-discussion/panel.js @@ -15,7 +15,7 @@ import PostPingbacks from '../post-pingbacks'; const PANEL_NAME = 'discussion-panel'; -function PostDiscussionPanel() { +function DiscussionPanel() { const { isEnabled, isOpened } = useSelect( ( select ) => { const { isEditorPanelEnabled, isEditorPanelOpened } = select( editorStore ); @@ -31,27 +31,31 @@ function PostDiscussionPanel() { return null; } + return ( + toggleEditorPanelOpened( PANEL_NAME ) } + > + + + + + + + + + + + + + ); +} + +export default function PostDiscussionPanel() { return ( - toggleEditorPanelOpened( PANEL_NAME ) } - > - - - - - - - - - - - - + ); } - -export default PostDiscussionPanel; diff --git a/packages/editor/src/components/post-excerpt/panel.js b/packages/editor/src/components/post-excerpt/panel.js index ab4b60611493cc..63149a05222385 100644 --- a/packages/editor/src/components/post-excerpt/panel.js +++ b/packages/editor/src/components/post-excerpt/panel.js @@ -18,7 +18,7 @@ import { store as editorStore } from '../../store'; */ const PANEL_NAME = 'post-excerpt'; -export default function PostExcerptPanel() { +function ExcerptPanel() { const { isOpened, isEnabled } = useSelect( ( select ) => { const { isEditorPanelOpened, isEditorPanelEnabled } = select( editorStore ); @@ -36,22 +36,28 @@ export default function PostExcerptPanel() { return null; } + return ( + + + { ( fills ) => ( + <> + + { fills } + + ) } + + + ); +} + +export default function PostExcerptPanel() { return ( - - - { ( fills ) => ( - <> - - { fills } - - ) } - - + ); } From 14db362f9603d876b273e85dce42f739d0bebf02 Mon Sep 17 00:00:00 2001 From: James Koster Date: Tue, 23 Apr 2024 16:30:43 +0100 Subject: [PATCH 10/10] Reduce list view spacing to decrease likelihood of scrolling (#60713) Co-authored-by: jameskoster Co-authored-by: richtabor Co-authored-by: andrewserong Co-authored-by: jasmussen Co-authored-by: mikemcalister --- .../src/components/list-view/index.js | 2 +- .../src/components/list-view/style.scss | 48 ++++++++----------- .../list-view/use-list-view-drop-zone.js | 2 +- .../components/list-view-sidebar/style.scss | 2 +- 4 files changed, 23 insertions(+), 31 deletions(-) diff --git a/packages/block-editor/src/components/list-view/index.js b/packages/block-editor/src/components/list-view/index.js index 8a696c6f56c241..7ef5d270f50a27 100644 --- a/packages/block-editor/src/components/list-view/index.js +++ b/packages/block-editor/src/components/list-view/index.js @@ -64,7 +64,7 @@ const expanded = ( state, action ) => { return state; }; -export const BLOCK_LIST_ITEM_HEIGHT = 36; +export const BLOCK_LIST_ITEM_HEIGHT = 32; /** @typedef {import('react').ComponentType} ComponentType */ /** @typedef {import('react').Ref} Ref */ diff --git a/packages/block-editor/src/components/list-view/style.scss b/packages/block-editor/src/components/list-view/style.scss index 7a9abb7a6b4814..ea3cc5bb78cdf3 100644 --- a/packages/block-editor/src/components/list-view/style.scss +++ b/packages/block-editor/src/components/list-view/style.scss @@ -156,13 +156,13 @@ &.is-displacement-up { transition: transform 0.2s; - transform: translateY(-36px); + transform: translateY(-32px); @include reduce-motion("transition"); } &.is-displacement-down { transition: transform 0.2s; - transform: translateY(36px); + transform: translateY(32px); @include reduce-motion("transition"); } @@ -172,20 +172,20 @@ // worth of space for the visual indicator of where a block will be placed when dropped. &.is-after-dragged-blocks { transition: transform 0.2s; - transform: translateY(calc(var(--wp-admin--list-view-dragged-items-height, 36px) * -1)); + transform: translateY(calc(var(--wp-admin--list-view-dragged-items-height, 32px) * -1)); @include reduce-motion("transition"); } &.is-after-dragged-blocks.is-displacement-up { transition: transform 0.2s; - transform: translateY(calc(-36px + var(--wp-admin--list-view-dragged-items-height, 36px) * -1)); + transform: translateY(calc(-32px + var(--wp-admin--list-view-dragged-items-height, 32px) * -1)); @include reduce-motion("transition"); } &.is-after-dragged-blocks.is-displacement-down { transition: transform 0.2s; transform: - translateY(calc(36px + var(--wp-admin--list-view-dragged-items-height, 36px) * + translateY(calc(32px + var(--wp-admin--list-view-dragged-items-height, 32px) * -1)); @include reduce-motion("transition"); } @@ -204,15 +204,15 @@ z-index: -9999; } - // List View renders a fixed number of items and relies on each item having a fixed height of 36px. + // List View renders a fixed number of items and relies on each item having a fixed height of 32px. // If this value changes, we should also change the itemHeight value set in useFixedWindowList. // See: https://github.com/WordPress/gutenberg/pull/35230 for additional context. .block-editor-list-view-block-contents { display: flex; align-items: center; width: 100%; - height: auto; - padding: ($grid-unit-15 * 0.5) ($grid-unit-15 * 0.5) ($grid-unit-15 * 0.5) 0; + height: $grid-unit-40; + padding: ($grid-unit-15 * 0.5) $grid-unit-05 ($grid-unit-15 * 0.5) 0; text-align: left; border-radius: $radius-block-ui; position: relative; @@ -277,15 +277,14 @@ } .block-editor-block-icon { - margin-right: $grid-unit-10; + margin-right: $grid-unit-10 * 0.5; // 6px. flex: 0 0 $icon-size; } .block-editor-list-view-block__menu-cell, .block-editor-list-view-block__mover-cell, .block-editor-list-view-block__contents-cell { - padding-top: 0; - padding-bottom: 0; + padding: 0; } .block-editor-list-view-block__menu-cell, @@ -316,7 +315,7 @@ } .block-editor-list-view-block__menu-cell { - padding-right: $grid-unit-15 * 0.5; // 6px. + padding-right: $grid-unit-05; .components-button.has-icon { height: 24px; @@ -379,8 +378,10 @@ } } - .block-editor-list-view-block-select-button__label-wrapper { - min-width: 120px; + // Style lock and position icons in line with image previews. + .block-editor-list-view-block-select-button__label-wrapper svg { + left: $grid-unit-05 * 0.5; // 2px. + position: relative; } .block-editor-list-view-block-select-button__title { @@ -464,21 +465,12 @@ $block-navigation-max-indent: 8; // Chevron container metrics. .block-editor-list-view__expander { height: $icon-size; - margin-left: $grid-unit-05; width: $icon-size; cursor: pointer; } .block-editor-list-view-leaf[aria-level] .block-editor-list-view__expander { - margin-left: - ($icon-size) * $block-navigation-max-indent + 4 * - ($block-navigation-max-indent - 1); -} - -.block-editor-list-view-leaf:not([aria-level="1"]) { - .block-editor-list-view__expander { - margin-right: 4px; - } + margin-left: ($grid-unit-30 * $block-navigation-max-indent); } // When updating the margin for each indentation level, the corresponding @@ -488,9 +480,9 @@ $block-navigation-max-indent: 8; .block-editor-list-view-leaf[aria-level="#{ $i + 1 }"] .block-editor-list-view__expander { @if $i - 1 >= 0 { - margin-left: ($icon-size * $i) + 4 * ($i - 1); + margin-left: ($grid-unit-30 * $i); // Effectivly centers the expander below the parent's icon. } @else { - margin-left: ($icon-size * $i); + margin-left: 0; } } } @@ -540,7 +532,7 @@ svg { .block-editor-list-view-drop-indicator__line { background: rgba(var(--wp-admin-theme-color--rgb), 0.04); - height: 36px; + height: 32px; border-radius: 4px; overflow: hidden; } @@ -553,7 +545,7 @@ svg { .block-editor-list-view-placeholder { padding: 0; margin: 0; - height: 36px; + height: 32px; } .list-view-appender .block-editor-inserter__toggle { diff --git a/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js b/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js index 67908a43fc3c00..64730be6156df9 100644 --- a/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js +++ b/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js @@ -62,7 +62,7 @@ import { store as blockEditorStore } from '../../store'; // When the indentation level, the corresponding left margin in `style.scss` // must be updated as well to ensure the drop zone is aligned with the indentation. -export const NESTING_LEVEL_INDENTATION = 28; +export const NESTING_LEVEL_INDENTATION = 24; /** * Determines whether the user is positioning the dragged block to be diff --git a/packages/editor/src/components/list-view-sidebar/style.scss b/packages/editor/src/components/list-view-sidebar/style.scss index 5e547c1bfc079b..b3138605641dee 100644 --- a/packages/editor/src/components/list-view-sidebar/style.scss +++ b/packages/editor/src/components/list-view-sidebar/style.scss @@ -49,7 +49,7 @@ scrollbar-gutter: auto; // The table cells use an extra pixels of space left and right. We compensate for that here. - padding: $grid-unit-10 ($grid-unit-10 - $border-width - $border-width); + padding: $grid-unit-05; } .editor-list-view-sidebar__list-view-container {