diff --git a/docs/reference-guides/data/data-core-edit-post.md b/docs/reference-guides/data/data-core-edit-post.md index aee88ce40bc731..b579e7e658007a 100644 --- a/docs/reference-guides/data/data-core-edit-post.md +++ b/docs/reference-guides/data/data-core-edit-post.md @@ -264,6 +264,8 @@ _Returns_ ### isModalActive +> **Deprecated** since WP 6.3 use `core/interface` store's selector with the same name instead. + Returns true if a modal is active, or false otherwise. _Parameters_ @@ -336,6 +338,8 @@ Returns an action object signalling that the user closed the sidebar. ### closeModal +> **Deprecated** since WP 6.3 use `core/interface` store's action with the same name instead. + Returns an action object signalling that the user closed a modal. _Returns_ @@ -388,6 +392,8 @@ _Parameters_ ### openModal +> **Deprecated** since WP 6.3 use `core/interface` store's action with the same name instead. + Returns an action object used in signalling that the user opened a modal. _Parameters_ diff --git a/lib/compat/wordpress-6.2/block-template-utils.php b/lib/compat/wordpress-6.2/block-template-utils.php index 7611b9be5cf1bb..db9bf427e6b471 100644 --- a/lib/compat/wordpress-6.2/block-template-utils.php +++ b/lib/compat/wordpress-6.2/block-template-utils.php @@ -1,7 +1,7 @@ _x( 'Index', 'Template name', 'gutenberg' ), - 'description' => __( - 'Used as a fallback template for all pages when a more specific template is not defined.', - 'gutenberg' - ), - ); - } - if ( isset( $default_template_types['home'] ) ) { - $default_template_types['home'] = array( - 'title' => _x( 'Home', 'Template name', 'gutenberg' ), - 'description' => __( - 'Displays the latest posts as either the site homepage or a custom page defined under reading settings. If it exists, the Front Page template overrides this template when posts are shown on the front page.', - 'gutenberg' - ), - ); - } - if ( isset( $default_template_types['front-page'] ) ) { - $default_template_types['front-page'] = array( - 'title' => _x( 'Front Page', 'Template name', 'gutenberg' ), - 'description' => __( - "Displays your site's front page, whether it is set to display latest posts or a static page. The Front Page template takes precedence over all templates.", - 'gutenberg' - ), - ); - } - if ( isset( $default_template_types['singular'] ) ) { - $default_template_types['singular'] = array( - 'title' => _x( 'Singular', 'Template name', 'gutenberg' ), - 'description' => __( - 'Displays any single entry, such as a post or a page. This template will serve as a fallback when a more specific template (e.g., Single Post, Page, or Attachment) cannot be found.', - 'gutenberg' - ), - ); - } - if ( isset( $default_template_types['single'] ) ) { - $default_template_types['single'] = array( - 'title' => _x( 'Single', 'Template name', 'gutenberg' ), - 'description' => __( 'Displays single posts on your website unless a custom template has been applied to that post or a dedicated template exists.', 'gutenberg' ), - ); - } - if ( isset( $default_template_types['page'] ) ) { - $default_template_types['page'] = array( - 'title' => _x( 'Page', 'Template name', 'gutenberg' ), - 'description' => __( 'Display all static pages unless a custom template has been applied or a dedicated template exists.', 'gutenberg' ), - ); - } - if ( isset( $default_template_types['archive'] ) ) { - $default_template_types['archive'] = array( - 'title' => _x( 'Archive', 'Template name', 'gutenberg' ), - 'description' => __( - 'Displays any archive, including posts by a single author, category, tag, taxonomy, custom post type, and date. This template will serve as a fallback when more specific templates (e.g., Category or Tag) cannot be found.', - 'gutenberg' - ), - ); - } - if ( isset( $default_template_types['author'] ) ) { - $default_template_types['author'] = array( - 'title' => _x( 'Author', 'Template name', 'gutenberg' ), - 'description' => __( - "Displays a single author's post archive. This template will serve as a fallback when a more a specific template (e.g., Author: Admin) cannot be found.", - 'gutenberg' - ), - ); - } - if ( isset( $default_template_types['category'] ) ) { - $default_template_types['category'] = array( - 'title' => _x( 'Category', 'Template name', 'gutenberg' ), - 'description' => __( - 'Displays a post category archive. This template will serve as a fallback when more specific template (e.g., Category: Recipes) cannot be found.', - 'gutenberg' - ), - ); - } - if ( isset( $default_template_types['taxonomy'] ) ) { - $default_template_types['taxonomy'] = array( - 'title' => _x( 'Taxonomy', 'Template name', 'gutenberg' ), - 'description' => __( - 'Displays a custom taxonomy archive. Like categories and tags, taxonomies have terms which you use to classify things. For example: a taxonomy named "Art" can have multiple terms, such as "Modern" and "18th Century." This template will serve as a fallback when a more specific template (e.g, Taxonomy: Art) cannot be found.', - 'gutenberg' - ), - ); - } - if ( isset( $default_template_types['date'] ) ) { - $default_template_types['date'] = array( - 'title' => _x( 'Date', 'Template name', 'gutenberg' ), - 'description' => __( 'Displays a post archive when a specific date is visited (e.g., example.com/2023/).', 'gutenberg' ), - ); - } - if ( isset( $default_template_types['tag'] ) ) { - $default_template_types['tag'] = array( - 'title' => _x( 'Tag', 'Template name', 'gutenberg' ), - 'description' => __( - 'Displays a post tag archive. This template will serve as a fallback when more specific template (e.g., Tag: Pizza) cannot be found.', - 'gutenberg' - ), - ); - } - if ( isset( $default_template_types['attachment'] ) ) { - $default_template_types['attachment'] = array( - 'title' => _x( 'Media', 'Template name', 'gutenberg' ), - 'description' => __( 'Displays when a visitor views the dedicated page that exists for any media attachment.', 'gutenberg' ), - ); - } - if ( isset( $default_template_types['search'] ) ) { - $default_template_types['search'] = array( - 'title' => _x( 'Search', 'Template name', 'gutenberg' ), - 'description' => __( 'Displays when a visitor performs a search on your website.', 'gutenberg' ), - ); - } - if ( isset( $default_template_types['privacy-policy'] ) ) { - $default_template_types['privacy-policy'] = array( - 'title' => _x( 'Privacy Policy', 'Template name', 'gutenberg' ), - 'description' => __( - "Displays your site's Privacy Policy page.", - 'gutenberg' - ), - ); - } - if ( isset( $default_template_types['404'] ) ) { - $default_template_types['404'] = array( - 'title' => _x( '404', 'Template name', 'gutenberg' ), - 'description' => __( 'Displays when a visitor views a non-existent page, such as a dead link or a mistyped URL.', 'gutenberg' ), - ); - } - - return $default_template_types; -} -add_filter( 'default_template_types', 'gutenberg_get_default_block_template_types', 10 ); diff --git a/lib/compat/wordpress-6.3/block-template-utils.php b/lib/compat/wordpress-6.3/block-template-utils.php new file mode 100644 index 00000000000000..cdd870db2d0813 --- /dev/null +++ b/lib/compat/wordpress-6.3/block-template-utils.php @@ -0,0 +1,150 @@ + _x( 'Index', 'Template name', 'gutenberg' ), + 'description' => __( + 'Used as a fallback template for all pages when a more specific template is not defined.', + 'gutenberg' + ), + ); + } + if ( isset( $default_template_types['home'] ) ) { + $default_template_types['home'] = array( + 'title' => _x( 'Home', 'Template name', 'gutenberg' ), + 'description' => __( + 'Displays the latest posts as either the site homepage or as the "Posts page" as defined under reading settings. If it exists, the Front Page template overrides this template when posts are shown on the homepage.', + 'gutenberg' + ), + ); + } + if ( isset( $default_template_types['front-page'] ) ) { + $default_template_types['front-page'] = array( + 'title' => _x( 'Front Page', 'Template name', 'gutenberg' ), + 'description' => __( + "Displays your site's homepage, whether it is set to display latest posts or a static page. The Front Page template takes precedence over all templates.", + 'gutenberg' + ), + ); + } + if ( isset( $default_template_types['singular'] ) ) { + $default_template_types['singular'] = array( + 'title' => _x( 'Single Entries', 'Template name', 'gutenberg' ), + 'description' => __( + 'Displays any single entry, such as a post or a page. This template will serve as a fallback when a more specific template (e.g., Single Post, Page, or Attachment) cannot be found.', + 'gutenberg' + ), + ); + } + if ( isset( $default_template_types['single'] ) ) { + $default_template_types['single'] = array( + 'title' => _x( 'Single Posts', 'Template name', 'gutenberg' ), + 'description' => __( 'Displays single posts on your website unless a custom template has been applied to that post or a dedicated template exists.', 'gutenberg' ), + ); + } + if ( isset( $default_template_types['page'] ) ) { + $default_template_types['page'] = array( + 'title' => _x( 'Pages', 'Template name', 'gutenberg' ), + 'description' => __( 'Display all static pages unless a custom template has been applied or a dedicated template exists.', 'gutenberg' ), + ); + } + if ( isset( $default_template_types['archive'] ) ) { + $default_template_types['archive'] = array( + 'title' => _x( 'All Archives', 'Template name', 'gutenberg' ), + 'description' => __( + 'Displays any archive, including posts by a single author, category, tag, taxonomy, custom post type, and date. This template will serve as a fallback when more specific templates (e.g., Category or Tag) cannot be found.', + 'gutenberg' + ), + ); + } + if ( isset( $default_template_types['author'] ) ) { + $default_template_types['author'] = array( + 'title' => _x( 'Author Archives', 'Template name', 'gutenberg' ), + 'description' => __( + "Displays a single author's post archive. This template will serve as a fallback when a more a specific template (e.g., Author: Admin) cannot be found.", + 'gutenberg' + ), + ); + } + if ( isset( $default_template_types['category'] ) ) { + $default_template_types['category'] = array( + 'title' => _x( 'Category Archives', 'Template name', 'gutenberg' ), + 'description' => __( + 'Displays a post category archive. This template will serve as a fallback when more specific template (e.g., Category: Recipes) cannot be found.', + 'gutenberg' + ), + ); + } + if ( isset( $default_template_types['taxonomy'] ) ) { + $default_template_types['taxonomy'] = array( + 'title' => _x( 'Taxonomy', 'Template name', 'gutenberg' ), + 'description' => __( + 'Displays a custom taxonomy archive. Like categories and tags, taxonomies have terms which you use to classify things. For example: a taxonomy named "Art" can have multiple terms, such as "Modern" and "18th Century." This template will serve as a fallback when a more specific template (e.g, Taxonomy: Art) cannot be found.', + 'gutenberg' + ), + ); + } + if ( isset( $default_template_types['date'] ) ) { + $default_template_types['date'] = array( + 'title' => _x( 'Date Archives', 'Template name', 'gutenberg' ), + 'description' => __( 'Displays a post archive when a specific date is visited (e.g., example.com/2023/).', 'gutenberg' ), + ); + } + if ( isset( $default_template_types['tag'] ) ) { + $default_template_types['tag'] = array( + 'title' => _x( 'Tag Archives', 'Template name', 'gutenberg' ), + 'description' => __( + 'Displays a post tag archive. This template will serve as a fallback when more specific template (e.g., Tag: Pizza) cannot be found.', + 'gutenberg' + ), + ); + } + if ( isset( $default_template_types['attachment'] ) ) { + $default_template_types['attachment'] = array( + 'title' => _x( 'Attachment Pages', 'Template name', 'gutenberg' ), + 'description' => __( 'Displays when a visitor views the dedicated page that exists for any media attachment.', 'gutenberg' ), + ); + } + if ( isset( $default_template_types['search'] ) ) { + $default_template_types['search'] = array( + 'title' => _x( 'Search Results', 'Template name', 'gutenberg' ), + 'description' => __( 'Displays when a visitor performs a search on your website.', 'gutenberg' ), + ); + } + if ( isset( $default_template_types['privacy-policy'] ) ) { + $default_template_types['privacy-policy'] = array( + 'title' => _x( 'Privacy Policy', 'Template name', 'gutenberg' ), + 'description' => __( + "Displays your site's Privacy Policy page.", + 'gutenberg' + ), + ); + } + if ( isset( $default_template_types['404'] ) ) { + $default_template_types['404'] = array( + 'title' => _x( 'Page: 404', 'Template name', 'gutenberg' ), + 'description' => __( 'Displays when a visitor views a non-existent page, such as a dead link or a mistyped URL.', 'gutenberg' ), + ); + } + + return $default_template_types; +} +add_filter( 'default_template_types', 'gutenberg_get_default_block_template_types', 10 ); diff --git a/lib/compat/wordpress-6.3/class-wp-classic-to-block-menu-converter.php b/lib/compat/wordpress-6.3/class-gutenberg-classic-to-block-menu-converter.php similarity index 97% rename from lib/compat/wordpress-6.3/class-wp-classic-to-block-menu-converter.php rename to lib/compat/wordpress-6.3/class-gutenberg-classic-to-block-menu-converter.php index 65c8a6d5bcba74..8677f9abaee170 100644 --- a/lib/compat/wordpress-6.3/class-wp-classic-to-block-menu-converter.php +++ b/lib/compat/wordpress-6.3/class-gutenberg-classic-to-block-menu-converter.php @@ -1,6 +1,6 @@ 404 ) ) ); diff --git a/lib/compat/wordpress-6.3/rest-api.php b/lib/compat/wordpress-6.3/rest-api.php index ed6832c3b84119..5a6860ee799c8c 100644 --- a/lib/compat/wordpress-6.3/rest-api.php +++ b/lib/compat/wordpress-6.3/rest-api.php @@ -110,3 +110,13 @@ function gutenberg_register_rest_block_patterns() { $block_patterns->register_routes(); } add_action( 'rest_api_init', 'gutenberg_register_rest_block_patterns' ); + + +/** + * Registers the Navigation Fallbacks REST API routes. + */ +function gutenberg_register_rest_navigation_fallbacks() { + $editor_settings = new Gutenberg_REST_Navigation_Fallback_Controller(); + $editor_settings->register_routes(); +} +add_action( 'rest_api_init', 'gutenberg_register_rest_navigation_fallbacks' ); diff --git a/lib/experimental/rest-api.php b/lib/experimental/rest-api.php index 4eca4232d3eb57..77f7d091d2655d 100644 --- a/lib/experimental/rest-api.php +++ b/lib/experimental/rest-api.php @@ -29,16 +29,6 @@ function gutenberg_register_block_editor_settings() { add_action( 'rest_api_init', 'gutenberg_register_block_editor_settings' ); -/** - * Registers the Navigation Fallbacks REST API routes. - */ -function gutenberg_register_rest_navigation_fallbacks() { - $editor_settings = new WP_REST_Navigation_Fallback_Controller(); - $editor_settings->register_routes(); -} -add_action( 'rest_api_init', 'gutenberg_register_rest_navigation_fallbacks' ); - - /** * Shim for get_sample_permalink() to add support for auto-draft status. * diff --git a/lib/load.php b/lib/load.php index 0fd23fc28f5133..1af8177e044841 100644 --- a/lib/load.php +++ b/lib/load.php @@ -48,7 +48,9 @@ function gutenberg_is_experiment_enabled( $name ) { require_once __DIR__ . '/compat/wordpress-6.3/class-gutenberg-rest-templates-controller-6-3.php'; require_once __DIR__ . '/compat/wordpress-6.3/class-gutenberg-rest-global-styles-controller-6-3.php'; require_once __DIR__ . '/compat/wordpress-6.3/class-gutenberg-rest-global-styles-revisions-controller-6-3.php'; - require_once __DIR__ . '/compat/wordpress-6.3/class-wp-rest-navigation-fallback-controller.php'; + require_once __DIR__ . '/compat/wordpress-6.3/class-gutenberg-classic-to-block-menu-converter.php'; + require_once __DIR__ . '/compat/wordpress-6.3/class-gutenberg-navigation-fallback.php'; + require_once __DIR__ . '/compat/wordpress-6.3/class-gutenberg-rest-navigation-fallback-controller.php'; require_once __DIR__ . '/compat/wordpress-6.3/rest-api.php'; require_once __DIR__ . '/compat/wordpress-6.3/theme-previews.php'; require_once __DIR__ . '/compat/wordpress-6.3/navigation-block-preloading.php'; @@ -80,9 +82,6 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/compat/wordpress-6.2/widgets.php'; require __DIR__ . '/compat/wordpress-6.2/menu.php'; -// WordPress 6.3 compat. -require __DIR__ . '/compat/wordpress-6.3/get-global-styles-and-settings.php'; - if ( ! class_exists( 'WP_HTML_Tag_Processor' ) ) { require __DIR__ . '/compat/wordpress-6.2/html-api/class-wp-html-attribute-token.php'; require __DIR__ . '/compat/wordpress-6.2/html-api/class-wp-html-span.php'; @@ -91,6 +90,8 @@ function gutenberg_is_experiment_enabled( $name ) { } // WordPress 6.3 compat. +require __DIR__ . '/compat/wordpress-6.3/get-global-styles-and-settings.php'; +require __DIR__ . '/compat/wordpress-6.3/block-template-utils.php'; require __DIR__ . '/compat/wordpress-6.3/html-api/class-gutenberg-html-tag-processor-6-3.php'; require __DIR__ . '/compat/wordpress-6.3/script-loader.php'; require __DIR__ . '/compat/wordpress-6.3/blocks.php'; diff --git a/packages/block-library/src/social-link/index.php b/packages/block-library/src/social-link/index.php index 51ed9374c9bcdf..1e5c4cf5de6fbd 100644 --- a/packages/block-library/src/social-link/index.php +++ b/packages/block-library/src/social-link/index.php @@ -47,8 +47,8 @@ function render_block_core_social_link( $attributes, $content, $block ) { $icon = block_core_social_link_get_icon( $service ); $wrapper_attributes = get_block_wrapper_attributes( array( - 'class' => 'wp-social-link wp-social-link-' . $service . block_core_social_link_get_color_classes( $block->context ), - 'style' => block_core_social_link_get_color_styles( $block->context ), + 'class' => esc_attr( 'wp-social-link wp-social-link-' . $service . block_core_social_link_get_color_classes( $block->context ) ), + 'style' => esc_attr( block_core_social_link_get_color_styles( $block->context ) ), ) ); diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 01db98978c1088..6409ce7515646f 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -18,6 +18,7 @@ - `Autocomplete`: Announce how many results are available to screen readers when suggestions list first renders ([#51018](https://github.com/WordPress/gutenberg/pull/51018)). - `ConfirmDialog`: Ensure onConfirm isn't called an extra time when submitting one of the buttons using the keyboard ([#51730](https://github.com/WordPress/gutenberg/pull/51730)). - `ZStack`: ZStack: fix component bounding box to match children ([#51836](https://github.com/WordPress/gutenberg/pull/51836)). +- `Modal`: Add small top padding to the content so that avoid cutting off the visible outline when hovering items ([#51829](https://github.com/WordPress/gutenberg/pull/51829)). ### Internal diff --git a/packages/components/src/modal/style.scss b/packages/components/src/modal/style.scss index 4c210022b8bb6c..d4ca7c311fcf19 100644 --- a/packages/components/src/modal/style.scss +++ b/packages/components/src/modal/style.scss @@ -72,7 +72,7 @@ .components-modal__header { box-sizing: border-box; border-bottom: $border-width solid transparent; - padding: $grid-unit-30 $grid-unit-40 $grid-unit-15; + padding: $grid-unit-30 $grid-unit-40 $grid-unit-10; display: flex; flex-direction: row; justify-content: space-between; @@ -130,7 +130,8 @@ .components-modal__content { flex: 1; margin-top: $header-height + $grid-unit-15; - padding: 0 $grid-unit-40 $grid-unit-40; + // Small top padding required to avoid cutting off the visible outline when the first child element is focusable. + padding: $grid-unit-05 $grid-unit-40 $grid-unit-40; overflow: auto; &.hide-header { diff --git a/packages/core-commands/src/site-editor-navigation-commands.js b/packages/core-commands/src/site-editor-navigation-commands.js index a46c8c02d2220f..6331afd058de34 100644 --- a/packages/core-commands/src/site-editor-navigation-commands.js +++ b/packages/core-commands/src/site-editor-navigation-commands.js @@ -203,7 +203,7 @@ function useSiteEditorBasicNavigationCommands() { icon: symbolFilled, callback: ( { close } ) => { const args = { - path: '/wp_template_part', + path: '/library', }; const targetUrl = addQueryArgs( 'site-editor.php', args ); if ( isSiteEditor ) { diff --git a/packages/e2e-tests/specs/experiments/blocks/post-comments-form.test.js b/packages/e2e-tests/specs/experiments/blocks/post-comments-form.test.js index 9d395707e382f3..3a561ad1e2cb6c 100644 --- a/packages/e2e-tests/specs/experiments/blocks/post-comments-form.test.js +++ b/packages/e2e-tests/specs/experiments/blocks/post-comments-form.test.js @@ -37,7 +37,7 @@ describe( 'Post Comments Form', () => { ); await expect( page ).toClick( '.edit-site-sidebar-navigation-item', - { text: /singular/i } + { text: /single entries/i } ); await enterEditMode(); diff --git a/packages/e2e-tests/specs/site-editor/settings-sidebar.test.js b/packages/e2e-tests/specs/site-editor/settings-sidebar.test.js index ae28019cf0d992..8bd33d7138fc95 100644 --- a/packages/e2e-tests/specs/site-editor/settings-sidebar.test.js +++ b/packages/e2e-tests/specs/site-editor/settings-sidebar.test.js @@ -79,7 +79,7 @@ describe( 'Settings sidebar', () => { 'Used as a fallback template for all pages when a more specific template is not defined.', } ); expect( templateCardAfterNavigation ).toMatchObject( { - title: 'Singular', + title: 'Single Entries', description: 'Displays any single entry, such as a post or a page. This template will serve as a fallback when a more specific template (e.g., Single Post, Page, or Attachment) cannot be found.', } ); 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 index bc747ca0afde88..037a896fc7f070 100644 --- a/packages/edit-post/src/components/header/preferences-menu-item/index.js +++ b/packages/edit-post/src/components/header/preferences-menu-item/index.js @@ -4,18 +4,19 @@ import { useDispatch } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { MenuItem } from '@wordpress/components'; +import { store as interfaceStore } from '@wordpress/interface'; /** * Internal dependencies */ -import { store as editPostStore } from '../../../store'; +import { PREFERENCES_MODAL_NAME } from '../../../components/preferences-modal'; export default function PreferencesMenuItem() { - const { openModal } = useDispatch( editPostStore ); + const { openModal } = useDispatch( interfaceStore ); return ( { - openModal( 'edit-post/preferences' ); + openModal( PREFERENCES_MODAL_NAME ); } } > { __( 'Preferences' ) } diff --git a/packages/edit-post/src/components/keyboard-shortcut-help-modal/index.js b/packages/edit-post/src/components/keyboard-shortcut-help-modal/index.js index 54565bb5dcd5b5..9a7ce46704d479 100644 --- a/packages/edit-post/src/components/keyboard-shortcut-help-modal/index.js +++ b/packages/edit-post/src/components/keyboard-shortcut-help-modal/index.js @@ -14,6 +14,7 @@ import { } from '@wordpress/keyboard-shortcuts'; import { withSelect, withDispatch, useSelect } from '@wordpress/data'; import { compose } from '@wordpress/compose'; +import { store as interfaceStore } from '@wordpress/interface'; /** * Internal dependencies @@ -21,9 +22,9 @@ import { compose } from '@wordpress/compose'; import { textFormattingShortcuts } from './config'; import Shortcut from './shortcut'; import DynamicShortcut from './dynamic-shortcut'; -import { store as editPostStore } from '../../store'; -const MODAL_NAME = 'edit-post/keyboard-shortcut-help'; +export const KEYBOARD_SHORTCUT_HELP_MODAL_NAME = + 'edit-post/keyboard-shortcut-help'; const ShortcutList = ( { shortcuts } ) => ( /* @@ -141,14 +142,18 @@ export function KeyboardShortcutHelpModal( { isModalActive, toggleModal } ) { export default compose( [ withSelect( ( select ) => ( { - isModalActive: select( editPostStore ).isModalActive( MODAL_NAME ), + isModalActive: select( interfaceStore ).isModalActive( + KEYBOARD_SHORTCUT_HELP_MODAL_NAME + ), } ) ), withDispatch( ( dispatch, { isModalActive } ) => { - const { openModal, closeModal } = dispatch( editPostStore ); + const { openModal, closeModal } = dispatch( interfaceStore ); return { toggleModal: () => - isModalActive ? closeModal() : openModal( MODAL_NAME ), + isModalActive + ? closeModal() + : openModal( KEYBOARD_SHORTCUT_HELP_MODAL_NAME ), }; } ), ] )( KeyboardShortcutHelpModal ); diff --git a/packages/edit-post/src/components/preferences-modal/index.js b/packages/edit-post/src/components/preferences-modal/index.js index 77c6383b13f32c..bb0c8b5cd12715 100644 --- a/packages/edit-post/src/components/preferences-modal/index.js +++ b/packages/edit-post/src/components/preferences-modal/index.js @@ -18,6 +18,7 @@ import { PreferencesModal, PreferencesModalTabs, PreferencesModalSection, + store as interfaceStore, } from '@wordpress/interface'; import { store as preferencesStore } from '@wordpress/preferences'; @@ -35,17 +36,18 @@ import MetaBoxesSection from './meta-boxes-section'; import { store as editPostStore } from '../../store'; import BlockManager from '../block-manager'; -const MODAL_NAME = 'edit-post/preferences'; +export const PREFERENCES_MODAL_NAME = 'edit-post/preferences'; export default function EditPostPreferencesModal() { const isLargeViewport = useViewportMatch( 'medium' ); - const { closeModal } = useDispatch( editPostStore ); + const { closeModal } = useDispatch( interfaceStore ); const [ isModalActive, showBlockBreadcrumbsOption ] = useSelect( ( select ) => { const { getEditorSettings } = select( editorStore ); const { getEditorMode, isFeatureActive } = select( editPostStore ); - const modalActive = - select( editPostStore ).isModalActive( MODAL_NAME ); + const modalActive = select( interfaceStore ).isModalActive( + PREFERENCES_MODAL_NAME + ); const mode = getEditorMode(); const isRichEditingEnabled = getEditorSettings().richEditingEnabled; const isDistractionFreeEnabled = diff --git a/packages/edit-post/src/components/start-page-options/style.scss b/packages/edit-post/src/components/start-page-options/style.scss index 0e26c93e386374..52f3f5ff9a8889 100644 --- a/packages/edit-post/src/components/start-page-options/style.scss +++ b/packages/edit-post/src/components/start-page-options/style.scss @@ -3,9 +3,6 @@ column-count: 2; column-gap: $grid-unit-30; - // Small top padding required to avoid cutting off the visible outline when hovering items - padding-top: $border-width-focus-fallback; - @include break-medium() { column-count: 3; } diff --git a/packages/edit-post/src/hooks/commands/use-common-commands.js b/packages/edit-post/src/hooks/commands/use-common-commands.js index 796e0665fc2fa3..0366e781799856 100644 --- a/packages/edit-post/src/hooks/commands/use-common-commands.js +++ b/packages/edit-post/src/hooks/commands/use-common-commands.js @@ -9,6 +9,7 @@ import { drawerLeft, drawerRight, blockDefault, + keyboardClose, } from '@wordpress/icons'; import { useCommand } from '@wordpress/commands'; import { store as preferencesStore } from '@wordpress/preferences'; @@ -17,11 +18,14 @@ import { store as interfaceStore } from '@wordpress/interface'; /** * Internal dependencies */ +import { KEYBOARD_SHORTCUT_HELP_MODAL_NAME } from '../../components/keyboard-shortcut-help-modal'; +import { PREFERENCES_MODAL_NAME } from '../../components/preferences-modal'; import { store as editPostStore } from '../../store'; export default function useCommonCommands() { const { openGeneralSidebar, closeGeneralSidebar, switchEditorMode } = useDispatch( editPostStore ); + const { openModal } = useDispatch( interfaceStore ); const { editorMode, activeSidebar } = useSelect( ( select ) => ( { activeSidebar: select( interfaceStore ).getActiveComplementaryArea( @@ -100,4 +104,22 @@ export default function useCommonCommands() { close(); }, } ); + + useCommand( { + name: 'core/open-preferences', + label: __( 'Open editor preferences' ), + icon: cog, + callback: () => { + openModal( PREFERENCES_MODAL_NAME ); + }, + } ); + + useCommand( { + name: 'core/open-shortcut-help', + label: __( 'Open keyboard shortcuts' ), + icon: keyboardClose, + callback: () => { + openModal( KEYBOARD_SHORTCUT_HELP_MODAL_NAME ); + }, + } ); } 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 index 69f7b35c3f1167..930f420a241299 100644 --- 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 @@ -5,17 +5,18 @@ import { MenuItem } from '@wordpress/components'; import { withDispatch } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { displayShortcut } from '@wordpress/keycodes'; +import { store as interfaceStore } from '@wordpress/interface'; /** * Internal dependencies */ -import { store as editPostStore } from '../../store'; +import { KEYBOARD_SHORTCUT_HELP_MODAL_NAME } from '../../components/keyboard-shortcut-help-modal'; export function KeyboardShortcutsHelpMenuItem( { openModal } ) { return ( { - openModal( 'edit-post/keyboard-shortcut-help' ); + openModal( KEYBOARD_SHORTCUT_HELP_MODAL_NAME ); } } shortcut={ displayShortcut.access( 'h' ) } > @@ -25,7 +26,7 @@ export function KeyboardShortcutsHelpMenuItem( { openModal } ) { } export default withDispatch( ( dispatch ) => { - const { openModal } = dispatch( editPostStore ); + const { openModal } = dispatch( interfaceStore ); return { openModal, diff --git a/packages/edit-post/src/store/actions.js b/packages/edit-post/src/store/actions.js index 90f29f37b145cf..f938a9837516e0 100644 --- a/packages/edit-post/src/store/actions.js +++ b/packages/edit-post/src/store/actions.js @@ -10,6 +10,7 @@ import { store as noticesStore } from '@wordpress/notices'; import { store as coreStore } from '@wordpress/core-data'; import { store as blockEditorStore } from '@wordpress/block-editor'; import { store as editorStore } from '@wordpress/editor'; +import deprecated from '@wordpress/deprecated'; /** * Internal dependencies @@ -42,27 +43,39 @@ export const closeGeneralSidebar = /** * Returns an action object used in signalling that the user opened a modal. * + * @deprecated since WP 6.3 use `core/interface` store's action with the same name instead. + * + * * @param {string} name A string that uniquely identifies the modal. * * @return {Object} Action object. */ -export function openModal( name ) { - return { - type: 'OPEN_MODAL', - name, +export const openModal = + ( name ) => + ( { registry } ) => { + deprecated( "select( 'core/edit-post' ).openModal( name )", { + since: '6.3', + alternative: "select( 'core/interface').openModal( name )", + } ); + return registry.dispatch( interfaceStore ).openModal( name ); }; -} /** * Returns an action object signalling that the user closed a modal. * + * @deprecated since WP 6.3 use `core/interface` store's action with the same name instead. + * * @return {Object} Action object. */ -export function closeModal() { - return { - type: 'CLOSE_MODAL', +export const closeModal = + () => + ( { registry } ) => { + deprecated( "select( 'core/edit-post' ).closeModal()", { + since: '6.3', + alternative: "select( 'core/interface').closeModal()", + } ); + return registry.dispatch( interfaceStore ).closeModal(); }; -} /** * Returns an action object used in signalling that the user opened the publish diff --git a/packages/edit-post/src/store/reducer.js b/packages/edit-post/src/store/reducer.js index 8a4031ecf9b098..622b2e2667f7fc 100644 --- a/packages/edit-post/src/store/reducer.js +++ b/packages/edit-post/src/store/reducer.js @@ -22,25 +22,6 @@ export function removedPanels( state = [], action ) { return state; } -/** - * Reducer for storing the name of the open modal, or null if no modal is open. - * - * @param {Object} state Previous state. - * @param {Object} action Action object containing the `name` of the modal - * - * @return {Object} Updated state - */ -export function activeModal( state = null, action ) { - switch ( action.type ) { - case 'OPEN_MODAL': - return action.name; - case 'CLOSE_MODAL': - return null; - } - - return state; -} - export function publishSidebarActive( state = false, action ) { switch ( action.type ) { case 'OPEN_PUBLISH_SIDEBAR': @@ -209,7 +190,6 @@ const metaBoxes = combineReducers( { } ); export default combineReducers( { - activeModal, metaBoxes, publishSidebarActive, removedPanels, diff --git a/packages/edit-post/src/store/selectors.js b/packages/edit-post/src/store/selectors.js index b84e2b6887431a..5ae7d6b4437b71 100644 --- a/packages/edit-post/src/store/selectors.js +++ b/packages/edit-post/src/store/selectors.js @@ -298,14 +298,22 @@ export const isEditorPanelOpened = createRegistrySelector( /** * Returns true if a modal is active, or false otherwise. * + * @deprecated since WP 6.3 use `core/interface` store's selector with the same name instead. + * * @param {Object} state Global application state. * @param {string} modalName A string that uniquely identifies the modal. * * @return {boolean} Whether the modal is active. */ -export function isModalActive( state, modalName ) { - return state.activeModal === modalName; -} +export const isModalActive = createRegistrySelector( + ( select ) => ( state, modalName ) => { + deprecated( `select( 'core/edit-post' ).isModalActive`, { + since: '6.3', + alternative: `select( 'core/interface' ).isModalActive`, + } ); + return !! select( interfaceStore ).isModalActive( modalName ); + } +); /** * Returns whether the given feature is enabled or not. diff --git a/packages/edit-post/src/store/test/reducer.js b/packages/edit-post/src/store/test/reducer.js index 4be7c7cb3ffd80..a083de9c672868 100644 --- a/packages/edit-post/src/store/test/reducer.js +++ b/packages/edit-post/src/store/test/reducer.js @@ -7,7 +7,6 @@ import deepFreeze from 'deep-freeze'; * Internal dependencies */ import { - activeModal, isSavingMetaBoxes, metaBoxLocations, removedPanels, @@ -18,30 +17,6 @@ import { import { setIsInserterOpened, setIsListViewOpened } from '../actions'; describe( 'state', () => { - describe( 'activeModal', () => { - it( 'should default to null', () => { - const state = activeModal( undefined, {} ); - expect( state ).toBeNull(); - } ); - - it( 'should set the activeModal to the provided name', () => { - const state = activeModal( null, { - type: 'OPEN_MODAL', - name: 'test-modal', - } ); - - expect( state ).toEqual( 'test-modal' ); - } ); - - it( 'should set the activeModal to null', () => { - const state = activeModal( 'test-modal', { - type: 'CLOSE_MODAL', - } ); - - expect( state ).toBeNull(); - } ); - } ); - describe( 'isSavingMetaBoxes', () => { it( 'should return default state', () => { const actual = isSavingMetaBoxes( undefined, {} ); diff --git a/packages/edit-post/src/store/test/selectors.js b/packages/edit-post/src/store/test/selectors.js index 5df8456dd8534d..34c66ed7cf8e67 100644 --- a/packages/edit-post/src/store/test/selectors.js +++ b/packages/edit-post/src/store/test/selectors.js @@ -7,7 +7,6 @@ import deepFreeze from 'deep-freeze'; * Internal dependencies */ import { - isModalActive, hasMetaBoxes, isSavingMetaBoxes, getActiveMetaBoxLocations, @@ -18,32 +17,6 @@ import { } from '../selectors'; describe( 'selectors', () => { - describe( 'isModalActive', () => { - it( 'returns true if the provided name matches the value in the preferences activeModal property', () => { - const state = { - activeModal: 'test-modal', - }; - - expect( isModalActive( state, 'test-modal' ) ).toBe( true ); - } ); - - it( 'returns false if the provided name does not match the preferences activeModal property', () => { - const state = { - activeModal: 'something-else', - }; - - expect( isModalActive( state, 'test-modal' ) ).toBe( false ); - } ); - - it( 'returns false if the preferences activeModal property is null', () => { - const state = { - activeModal: null, - }; - - expect( isModalActive( state, 'test-modal' ) ).toBe( false ); - } ); - } ); - describe( 'isEditorPanelRemoved', () => { it( 'should return false by default', () => { const state = deepFreeze( { 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 7fe63a343960ae..4b9d6c40fc6eec 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 @@ -2,13 +2,15 @@ * WordPress dependencies */ import { __, _x } from '@wordpress/i18n'; -import { useReducer } from '@wordpress/element'; import { useSelect, useDispatch, useRegistry } from '@wordpress/data'; -import { useShortcut } from '@wordpress/keyboard-shortcuts'; import { displayShortcut } from '@wordpress/keycodes'; import { external } from '@wordpress/icons'; import { MenuGroup, MenuItem, VisuallyHidden } from '@wordpress/components'; -import { ActionItem, MoreMenuDropdown } from '@wordpress/interface'; +import { + ActionItem, + MoreMenuDropdown, + store as interfaceStore, +} from '@wordpress/interface'; import { PreferenceToggleMenuItem, store as preferencesStore, @@ -17,8 +19,14 @@ import { /** * Internal dependencies */ -import KeyboardShortcutHelpModal from '../../keyboard-shortcut-help-modal'; -import EditSitePreferencesModal from '../../preferences-modal'; +import { + KEYBOARD_SHORTCUT_HELP_MODAL_NAME, + default as KeyboardShortcutHelpModal, +} from '../../keyboard-shortcut-help-modal'; +import { + PREFERENCES_MODAL_NAME, + default as EditSitePreferencesModal, +} from '../../preferences-modal'; import ToolsMoreMenuGroup from '../tools-more-menu-group'; import SiteExport from './site-export'; import WelcomeGuideMenuItem from './welcome-guide-menu-item'; @@ -27,16 +35,6 @@ import ModeSwitcher from '../mode-switcher'; import { store as siteEditorStore } from '../../../store'; export default function MoreMenu( { showIconLabels } ) { - const [ isModalActive, toggleModal ] = useReducer( - ( isActive ) => ! isActive, - false - ); - - const [ isPreferencesModalActive, togglePreferencesModal ] = useReducer( - ( isActive ) => ! isActive, - false - ); - const registry = useRegistry(); const isDistractionFree = useSelect( ( select ) => @@ -49,6 +47,7 @@ export default function MoreMenu( { showIconLabels } ) { const { setIsInserterOpened, setIsListViewOpened, closeGeneralSidebar } = useDispatch( siteEditorStore ); + const { openModal } = useDispatch( interfaceStore ); const { set: setPreference } = useDispatch( preferencesStore ); const toggleDistractionFree = () => { @@ -60,8 +59,6 @@ export default function MoreMenu( { showIconLabels } ) { } ); }; - useShortcut( 'core/edit-site/keyboard-shortcuts', toggleModal ); - return ( <> + openModal( + KEYBOARD_SHORTCUT_HELP_MODAL_NAME + ) + } shortcut={ displayShortcut.access( 'h' ) } > { __( 'Keyboard shortcuts' ) } @@ -156,21 +157,19 @@ export default function MoreMenu( { showIconLabels } ) { /> - + + openModal( PREFERENCES_MODAL_NAME ) + } + > { __( 'Preferences' ) } ) } - - + + ); } diff --git a/packages/edit-site/src/components/keyboard-shortcut-help-modal/index.js b/packages/edit-site/src/components/keyboard-shortcut-help-modal/index.js index aac95775cf1d0d..1da14a7cccbe77 100644 --- a/packages/edit-site/src/components/keyboard-shortcut-help-modal/index.js +++ b/packages/edit-site/src/components/keyboard-shortcut-help-modal/index.js @@ -8,8 +8,12 @@ import classnames from 'classnames'; */ import { Modal } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; -import { useSelect } from '@wordpress/data'; +import { + useShortcut, + store as keyboardShortcutsStore, +} from '@wordpress/keyboard-shortcuts'; +import { store as interfaceStore } from '@wordpress/interface'; +import { useSelect, useDispatch } from '@wordpress/data'; /** * Internal dependencies @@ -18,6 +22,9 @@ import { textFormattingShortcuts } from './config'; import Shortcut from './shortcut'; import DynamicShortcut from './dynamic-shortcut'; +export const KEYBOARD_SHORTCUT_HELP_MODAL_NAME = + 'edit-site/keyboard-shortcut-help'; + const ShortcutList = ( { shortcuts } ) => ( /* * Disable reason: The `list` ARIA role is redundant but @@ -82,14 +89,21 @@ const ShortcutCategorySection = ( { ); }; -export default function KeyboardShortcutHelpModal( { - isModalActive, - toggleModal, -} ) { +export default function KeyboardShortcutHelpModal() { + const isModalActive = useSelect( ( select ) => + select( interfaceStore ).isModalActive( + KEYBOARD_SHORTCUT_HELP_MODAL_NAME + ) + ); + const { closeModal, openModal } = useDispatch( interfaceStore ); + const toggleModal = () => + isModalActive + ? closeModal() + : openModal( KEYBOARD_SHORTCUT_HELP_MODAL_NAME ); + useShortcut( 'core/edit-site/keyboard-shortcuts', toggleModal ); if ( ! isModalActive ) { return null; } - return ( { diff --git a/packages/edit-site/src/components/preferences-modal/index.js b/packages/edit-site/src/components/preferences-modal/index.js index 87aa58270e1c9d..c8a8d103250f5b 100644 --- a/packages/edit-site/src/components/preferences-modal/index.js +++ b/packages/edit-site/src/components/preferences-modal/index.js @@ -5,25 +5,31 @@ import { PreferencesModal, PreferencesModalTabs, PreferencesModalSection, + store as interfaceStore, } from '@wordpress/interface'; import { useMemo } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; -import { useDispatch, useRegistry } from '@wordpress/data'; +import { useSelect, useDispatch, useRegistry } from '@wordpress/data'; import { store as preferencesStore } from '@wordpress/preferences'; /** * Internal dependencies */ import EnableFeature from './enable-feature'; -import { store as siteEditorStore } from '../../store'; +import { store as editSiteStore } from '../../store'; -export default function EditSitePreferencesModal( { - isModalActive, - toggleModal, -} ) { +export const PREFERENCES_MODAL_NAME = 'edit-site/preferences'; + +export default function EditSitePreferencesModal() { + const isModalActive = useSelect( ( select ) => + select( interfaceStore ).isModalActive( PREFERENCES_MODAL_NAME ) + ); + const { closeModal, openModal } = useDispatch( interfaceStore ); + const toggleModal = () => + isModalActive ? closeModal() : openModal( PREFERENCES_MODAL_NAME ); const registry = useRegistry(); const { closeGeneralSidebar, setIsListViewOpened, setIsInserterOpened } = - useDispatch( siteEditorStore ); + useDispatch( editSiteStore ); const { set: setPreference } = useDispatch( preferencesStore ); const toggleDistractionFree = () => { diff --git a/packages/edit-site/src/components/sidebar-navigation-item/style.scss b/packages/edit-site/src/components/sidebar-navigation-item/style.scss index d032bece171075..d81b6764f7b721 100644 --- a/packages/edit-site/src/components/sidebar-navigation-item/style.scss +++ b/packages/edit-site/src/components/sidebar-navigation-item/style.scss @@ -15,6 +15,7 @@ &[aria-current] { background: var(--wp-admin-theme-color); + color: $white; } .edit-site-sidebar-navigation-item__drilldown-indicator { diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menu/style.scss b/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menu/style.scss index ae35cb4525b88b..012622f9b1040b 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menu/style.scss +++ b/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menu/style.scss @@ -8,8 +8,3 @@ } } } - -.sidebar-navigation__rename-modal-form { - // Fix for input focus style being cut off by the modal. - padding-top: 1px; -} diff --git a/packages/edit-site/src/components/start-template-options/style.scss b/packages/edit-site/src/components/start-template-options/style.scss index 7515861099b380..53cd38a8c9bfad 100644 --- a/packages/edit-site/src/components/start-template-options/style.scss +++ b/packages/edit-site/src/components/start-template-options/style.scss @@ -29,9 +29,6 @@ $actions-height: 92px; column-count: 2; column-gap: $grid-unit-30; - // Small top padding required to avoid cutting off the visible outline when hovering items - padding-top: $border-width-focus-fallback; - @include break-medium() { column-count: 3; } diff --git a/packages/edit-site/src/hooks/commands/use-edit-mode-commands.js b/packages/edit-site/src/hooks/commands/use-edit-mode-commands.js index 2466bb2a706c4e..92ccee08592cde 100644 --- a/packages/edit-site/src/hooks/commands/use-edit-mode-commands.js +++ b/packages/edit-site/src/hooks/commands/use-edit-mode-commands.js @@ -4,8 +4,6 @@ import { useSelect, useDispatch } from '@wordpress/data'; import { __, isRTL } from '@wordpress/i18n'; import { - code, - cog, trash, backup, layout, @@ -13,6 +11,9 @@ import { drawerLeft, drawerRight, blockDefault, + cog, + code, + keyboardClose, } from '@wordpress/icons'; import { useCommandLoader } from '@wordpress/commands'; import { privateApis as routerPrivateApis } from '@wordpress/router'; @@ -26,6 +27,8 @@ import { store as editSiteStore } from '../../store'; import useEditedEntityRecord from '../../components/use-edited-entity-record'; import isTemplateRemovable from '../../utils/is-template-removable'; import isTemplateRevertable from '../../utils/is-template-revertable'; +import { KEYBOARD_SHORTCUT_HELP_MODAL_NAME } from '../../components/keyboard-shortcut-help-modal'; +import { PREFERENCES_MODAL_NAME } from '../../components/preferences-modal'; import { unlock } from '../../lock-unlock'; const { useHistory } = unlock( routerPrivateApis ); @@ -142,6 +145,7 @@ function useEditUICommands() { } ), [] ); + const { openModal } = useDispatch( interfaceStore ); const { toggle } = useDispatch( preferencesStore ); if ( canvasMode !== 'edit' ) { @@ -208,6 +212,24 @@ function useEditUICommands() { }, } ); + commands.push( { + name: 'core/open-preferences', + label: __( 'Open editor preferences' ), + icon: cog, + callback: () => { + openModal( PREFERENCES_MODAL_NAME ); + }, + } ); + + commands.push( { + name: 'core/open-shortcut-help', + label: __( 'Open keyboard shortcuts' ), + icon: keyboardClose, + callback: () => { + openModal( KEYBOARD_SHORTCUT_HELP_MODAL_NAME ); + }, + } ); + return { isLoading: false, commands, diff --git a/packages/interface/src/store/actions.js b/packages/interface/src/store/actions.js index bc51d4fca72202..b7a9935e888b51 100644 --- a/packages/interface/src/store/actions.js +++ b/packages/interface/src/store/actions.js @@ -181,3 +181,28 @@ export function setFeatureDefaults( scope, defaults ) { registry.dispatch( preferencesStore ).setDefaults( scope, defaults ); }; } + +/** + * Returns an action object used in signalling that the user opened a modal. + * + * @param {string} name A string that uniquely identifies the modal. + * + * @return {Object} Action object. + */ +export function openModal( name ) { + return { + type: 'OPEN_MODAL', + name, + }; +} + +/** + * Returns an action object signalling that the user closed a modal. + * + * @return {Object} Action object. + */ +export function closeModal() { + return { + type: 'CLOSE_MODAL', + }; +} diff --git a/packages/interface/src/store/reducer.js b/packages/interface/src/store/reducer.js index 433f71d15bcc57..8317e53cec95bf 100644 --- a/packages/interface/src/store/reducer.js +++ b/packages/interface/src/store/reducer.js @@ -30,6 +30,26 @@ export function complementaryAreas( state = {}, action ) { return state; } +/** + * Reducer for storing the name of the open modal, or null if no modal is open. + * + * @param {Object} state Previous state. + * @param {Object} action Action object containing the `name` of the modal + * + * @return {Object} Updated state + */ +export function activeModal( state = null, action ) { + switch ( action.type ) { + case 'OPEN_MODAL': + return action.name; + case 'CLOSE_MODAL': + return null; + } + + return state; +} + export default combineReducers( { complementaryAreas, + activeModal, } ); diff --git a/packages/interface/src/store/selectors.js b/packages/interface/src/store/selectors.js index c92e45bbd3c590..548cb2f70346ac 100644 --- a/packages/interface/src/store/selectors.js +++ b/packages/interface/src/store/selectors.js @@ -90,3 +90,15 @@ export const isFeatureActive = createRegistrySelector( return !! select( preferencesStore ).get( scope, featureName ); } ); + +/** + * Returns true if a modal is active, or false otherwise. + * + * @param {Object} state Global application state. + * @param {string} modalName A string that uniquely identifies the modal. + * + * @return {boolean} Whether the modal is active. + */ +export function isModalActive( state, modalName ) { + return state.activeModal === modalName; +} diff --git a/packages/interface/src/store/test/reducer.js b/packages/interface/src/store/test/reducer.js new file mode 100644 index 00000000000000..eb9424637bca0f --- /dev/null +++ b/packages/interface/src/store/test/reducer.js @@ -0,0 +1,30 @@ +/** + * Internal dependencies + */ +import { activeModal } from '../reducer'; + +describe( 'state', () => { + describe( 'activeModal', () => { + it( 'should default to null', () => { + const state = activeModal( undefined, {} ); + expect( state ).toBeNull(); + } ); + + it( 'should set the activeModal to the provided name', () => { + const state = activeModal( null, { + type: 'OPEN_MODAL', + name: 'test-modal', + } ); + + expect( state ).toEqual( 'test-modal' ); + } ); + + it( 'should set the activeModal to null', () => { + const state = activeModal( 'test-modal', { + type: 'CLOSE_MODAL', + } ); + + expect( state ).toBeNull(); + } ); + } ); +} ); diff --git a/packages/interface/src/store/test/selectors.js b/packages/interface/src/store/test/selectors.js new file mode 100644 index 00000000000000..a3bea882043d29 --- /dev/null +++ b/packages/interface/src/store/test/selectors.js @@ -0,0 +1,32 @@ +/** + * Internal dependencies + */ +import { isModalActive } from '../selectors'; + +describe( 'selectors', () => { + describe( 'isModalActive', () => { + it( 'returns true if the provided name matches the value in the preferences activeModal property', () => { + const state = { + activeModal: 'test-modal', + }; + + expect( isModalActive( state, 'test-modal' ) ).toBe( true ); + } ); + + it( 'returns false if the provided name does not match the preferences activeModal property', () => { + const state = { + activeModal: 'something-else', + }; + + expect( isModalActive( state, 'test-modal' ) ).toBe( false ); + } ); + + it( 'returns false if the preferences activeModal property is null', () => { + const state = { + activeModal: null, + }; + + expect( isModalActive( state, 'test-modal' ) ).toBe( false ); + } ); + } ); +} ); diff --git a/phpunit/block-template-utils-test.php b/phpunit/block-template-utils-test.php index ac2e4145cd0ed2..08fb0c2c2c1e3b 100644 --- a/phpunit/block-template-utils-test.php +++ b/phpunit/block-template-utils-test.php @@ -9,9 +9,6 @@ class Tests_Block_Template_Utils extends WP_UnitTestCase { public function set_up() { parent::set_up(); switch_theme( 'emptytheme' ); - } - - public static function wpSetUpBeforeClass() { register_post_type( 'custom_book', array( @@ -22,9 +19,10 @@ public static function wpSetUpBeforeClass() { register_taxonomy( 'book_type', 'custom_book' ); } - public static function wpTearDownAfterClass() { + public function tear_down() { unregister_post_type( 'custom_book' ); unregister_taxonomy( 'book_type' ); + parent::tear_down(); } public function test_get_template_hierarchy() { diff --git a/phpunit/bootstrap.php b/phpunit/bootstrap.php index c11233b1e89525..f64e6fa5c7ef14 100644 --- a/phpunit/bootstrap.php +++ b/phpunit/bootstrap.php @@ -22,6 +22,12 @@ define( 'LOCAL_WP_ENVIRONMENT_TYPE', 'local' ); } +// Pretend that these are Core unit tests. This is needed so that +// wp_theme_has_theme_json() does not cache its return value between each test. +if ( ! defined( 'WP_RUN_CORE_TESTS' ) ) { + define( 'WP_RUN_CORE_TESTS', true ); +} + // Require composer dependencies. require_once dirname( __DIR__ ) . '/vendor/autoload.php'; diff --git a/phpunit/class-wp-classic-to-block-menu-converter-test.php b/phpunit/class-gutenberg-classic-to-block-menu-converter-test.php similarity index 90% rename from phpunit/class-wp-classic-to-block-menu-converter-test.php rename to phpunit/class-gutenberg-classic-to-block-menu-converter-test.php index 0d7670d8ec867e..5f0a8ceee52a10 100644 --- a/phpunit/class-wp-classic-to-block-menu-converter-test.php +++ b/phpunit/class-gutenberg-classic-to-block-menu-converter-test.php @@ -1,20 +1,20 @@ assertTrue( class_exists( 'WP_Classic_To_Block_Menu_Converter' ) ); + $this->assertTrue( class_exists( 'Gutenberg_Classic_To_Block_Menu_Converter' ) ); } /** @@ -23,7 +23,7 @@ public function test_class_exists() { */ public function test_passing_non_menu_object_to_converter_returns_wp_error( $data ) { - $result = WP_Classic_To_Block_Menu_Converter::convert( $data ); + $result = Gutenberg_Classic_To_Block_Menu_Converter::convert( $data ); $this->assertTrue( is_wp_error( $result ), 'Should be a WP_Error instance' ); @@ -88,7 +88,7 @@ public function test_can_convert_classic_menu_to_blocks() { $classic_nav_menu = wp_get_nav_menu_object( $menu_id ); - $blocks = WP_Classic_To_Block_Menu_Converter::convert( $classic_nav_menu ); + $blocks = Gutenberg_Classic_To_Block_Menu_Converter::convert( $classic_nav_menu ); $this->assertNotEmpty( $blocks ); @@ -179,7 +179,7 @@ public function test_does_not_convert_menu_items_with_non_publish_status() { $classic_nav_menu = wp_get_nav_menu_object( $menu_id ); - $blocks = WP_Classic_To_Block_Menu_Converter::convert( $classic_nav_menu ); + $blocks = Gutenberg_Classic_To_Block_Menu_Converter::convert( $classic_nav_menu ); $this->assertNotEmpty( $blocks ); @@ -204,7 +204,7 @@ public function test_returns_empty_array_for_menus_with_no_items() { $classic_nav_menu = wp_get_nav_menu_object( $menu_id ); - $blocks = WP_Classic_To_Block_Menu_Converter::convert( $classic_nav_menu ); + $blocks = Gutenberg_Classic_To_Block_Menu_Converter::convert( $classic_nav_menu ); $this->assertEmpty( $blocks, 'Result should be empty.' ); diff --git a/phpunit/class-wp-navigation-fallback-gutenberg-test.php b/phpunit/class-gutenberg-navigation-fallback-gutenberg-test.php similarity index 91% rename from phpunit/class-wp-navigation-fallback-gutenberg-test.php rename to phpunit/class-gutenberg-navigation-fallback-gutenberg-test.php index fe32e8a640c078..7b0719950df8b5 100644 --- a/phpunit/class-wp-navigation-fallback-gutenberg-test.php +++ b/phpunit/class-gutenberg-navigation-fallback-gutenberg-test.php @@ -1,14 +1,14 @@ assertTrue( class_exists( 'WP_Navigation_Fallback_Gutenberg' ), 'WP_Navigation_Fallback_Gutenberg class should exist.' ); + $this->assertTrue( class_exists( 'Gutenberg_Navigation_Fallback' ), 'Gutenberg_Navigation_Fallback class should exist.' ); } @@ -37,7 +37,7 @@ public function test_it_exists() { * @covers WP_REST_Navigation_Fallback_Controller::get_fallback */ public function test_should_return_a_default_fallback_navigation_menu_in_absence_of_other_fallbacks() { - $data = WP_Navigation_Fallback_Gutenberg::get_fallback(); + $data = Gutenberg_Navigation_Fallback::get_fallback(); $this->assertInstanceOf( 'WP_Post', $data, 'Response should be of the correct type.' ); @@ -63,7 +63,7 @@ public function test_should_return_a_default_fallback_navigation_menu_with_no_bl unregister_block_type( 'core/page-list' ); - $data = WP_Navigation_Fallback_Gutenberg::get_fallback(); + $data = Gutenberg_Navigation_Fallback::get_fallback(); $this->assertInstanceOf( 'WP_Post', $data, 'Response should be of the correct type.' ); @@ -79,11 +79,11 @@ public function test_should_return_a_default_fallback_navigation_menu_with_no_bl */ public function test_should_handle_consecutive_invocations() { // Invoke the method multiple times to ensure that it doesn't create a new fallback menu on each invocation. - WP_Navigation_Fallback_Gutenberg::get_fallback(); - WP_Navigation_Fallback_Gutenberg::get_fallback(); + Gutenberg_Navigation_Fallback::get_fallback(); + Gutenberg_Navigation_Fallback::get_fallback(); // Assert on the final invocation. - $data = WP_Navigation_Fallback_Gutenberg::get_fallback(); + $data = Gutenberg_Navigation_Fallback::get_fallback(); $this->assertInstanceOf( 'WP_Post', $data, 'Response should be of the correct type.' ); @@ -115,7 +115,7 @@ public function test_should_return_the_most_recently_created_navigation_menu() { ) ); - $data = WP_Navigation_Fallback_Gutenberg::get_fallback(); + $data = Gutenberg_Navigation_Fallback::get_fallback(); $this->assertInstanceOf( 'WP_Post', $data, 'Response should be of the correct type.' ); @@ -147,7 +147,7 @@ public function test_should_return_fallback_navigation_from_existing_classic_men ) ); - $data = WP_Navigation_Fallback_Gutenberg::get_fallback(); + $data = Gutenberg_Navigation_Fallback::get_fallback(); $this->assertInstanceOf( 'WP_Post', $data, 'Response should be of the correct type.' ); @@ -201,7 +201,7 @@ public function test_should_prioritise_fallback_to_classic_menu_in_primary_locat $locations['header'] = $another_menu_id; set_theme_mod( 'nav_menu_locations', $locations ); - $data = WP_Navigation_Fallback_Gutenberg::get_fallback(); + $data = Gutenberg_Navigation_Fallback::get_fallback(); $this->assertInstanceOf( 'WP_Post', $data, 'Response should be of the correct type.' ); @@ -238,7 +238,7 @@ public function test_should_fallback_to_classic_menu_with_primary_slug() { ) ); - $data = WP_Navigation_Fallback_Gutenberg::get_fallback(); + $data = Gutenberg_Navigation_Fallback::get_fallback(); $this->assertInstanceOf( 'WP_Post', $data, 'Response should be of the correct type.' ); @@ -275,7 +275,7 @@ public function test_should_fallback_to_most_recently_created_classic_menu() { ) ); - $data = WP_Navigation_Fallback_Gutenberg::get_fallback(); + $data = Gutenberg_Navigation_Fallback::get_fallback(); $this->assertInstanceOf( 'WP_Post', $data, 'Response should be of the correct type.' ); @@ -306,7 +306,7 @@ public function test_should_not_create_fallback_from_classic_menu_if_a_navigatio ) ); - $data = WP_Navigation_Fallback_Gutenberg::get_fallback(); + $data = Gutenberg_Navigation_Fallback::get_fallback(); $this->assertInstanceOf( 'WP_Post', $data, 'Response should be of the correct type.' ); diff --git a/phpunit/class-wp-rest-navigation-fallback-controller-test.php b/phpunit/class-gutenberg-rest-navigation-fallback-controller-test.php similarity index 96% rename from phpunit/class-wp-rest-navigation-fallback-controller-test.php rename to phpunit/class-gutenberg-rest-navigation-fallback-controller-test.php index 1cdedb568a5cd7..14ab8ee0971dd9 100644 --- a/phpunit/class-wp-rest-navigation-fallback-controller-test.php +++ b/phpunit/class-gutenberg-rest-navigation-fallback-controller-test.php @@ -1,6 +1,6 @@