diff --git a/packages/editor/src/components/block-manager/category.js b/packages/editor/src/components/block-manager/category.js
index e7125fa151f72..341584fee03b9 100644
--- a/packages/editor/src/components/block-manager/category.js
+++ b/packages/editor/src/components/block-manager/category.js
@@ -1,73 +1,79 @@
/**
* WordPress dependencies
*/
-import { useMemo, useCallback } from '@wordpress/element';
-import { useDispatch, useSelect } from '@wordpress/data';
+import { useCallback } from '@wordpress/element';
import { useInstanceId } from '@wordpress/compose';
import { CheckboxControl } from '@wordpress/components';
-import { store as preferencesStore } from '@wordpress/preferences';
/**
* Internal dependencies
*/
import BlockTypesChecklist from './checklist';
-import { store as editorStore } from '../../store';
-import { unlock } from '../../lock-unlock';
-function BlockManagerCategory( { title, blockTypes } ) {
+function BlockManagerCategory( {
+ title,
+ blockTypes,
+ selectedBlockTypes,
+ onChange,
+} ) {
const instanceId = useInstanceId( BlockManagerCategory );
- const { allowedBlockTypes, hiddenBlockTypes } = useSelect( ( select ) => {
- const { getEditorSettings } = select( editorStore );
- const { get } = select( preferencesStore );
- return {
- allowedBlockTypes: getEditorSettings().allowedBlockTypes,
- hiddenBlockTypes: get( 'core', 'hiddenBlockTypes' ),
- };
- }, [] );
- const filteredBlockTypes = useMemo( () => {
- if ( allowedBlockTypes === true ) {
- return blockTypes;
- }
- return blockTypes.filter( ( { name } ) => {
- return allowedBlockTypes?.includes( name );
- } );
- }, [ allowedBlockTypes, blockTypes ] );
- const { showBlockTypes, hideBlockTypes } = unlock(
- useDispatch( editorStore )
- );
+
const toggleVisible = useCallback(
- ( blockName, nextIsChecked ) => {
+ ( blockType, nextIsChecked ) => {
if ( nextIsChecked ) {
- showBlockTypes( blockName );
+ onChange( [ ...selectedBlockTypes, blockType ] );
} else {
- hideBlockTypes( blockName );
+ onChange(
+ selectedBlockTypes.filter(
+ ( { name } ) => name !== blockType.name
+ )
+ );
}
},
- [ showBlockTypes, hideBlockTypes ]
+ [ selectedBlockTypes, onChange ]
);
+
const toggleAllVisible = useCallback(
( nextIsChecked ) => {
- const blockNames = blockTypes.map( ( { name } ) => name );
if ( nextIsChecked ) {
- showBlockTypes( blockNames );
+ onChange( [
+ ...selectedBlockTypes,
+ ...blockTypes.filter(
+ ( blockType ) =>
+ ! selectedBlockTypes.find(
+ ( { name } ) => name === blockType.name
+ )
+ ),
+ ] );
} else {
- hideBlockTypes( blockNames );
+ onChange(
+ selectedBlockTypes.filter(
+ ( selectedBlockType ) =>
+ ! blockTypes.find(
+ ( { name } ) => name === selectedBlockType.name
+ )
+ )
+ );
}
},
- [ blockTypes, showBlockTypes, hideBlockTypes ]
+ [ blockTypes, selectedBlockTypes, onChange ]
);
- if ( ! filteredBlockTypes.length ) {
+ if ( ! blockTypes.length ) {
return null;
}
- const checkedBlockNames = filteredBlockTypes
+ const checkedBlockNames = blockTypes
.map( ( { name } ) => name )
- .filter( ( type ) => ! ( hiddenBlockTypes ?? [] ).includes( type ) );
+ .filter( ( type ) =>
+ ( selectedBlockTypes ?? [] ).some(
+ ( selectedBlockType ) => selectedBlockType.name === type
+ )
+ );
const titleId = 'editor-block-manager__category-title-' + instanceId;
- const isAllChecked = checkedBlockNames.length === filteredBlockTypes.length;
+ const isAllChecked = checkedBlockNames.length === blockTypes.length;
const isIndeterminate = ! isAllChecked && checkedBlockNames.length > 0;
return (
@@ -85,7 +91,7 @@ function BlockManagerCategory( { title, blockTypes } ) {
label={ { title } }
/>
diff --git a/packages/editor/src/components/block-manager/checklist.js b/packages/editor/src/components/block-manager/checklist.js
index 01bd06abdeba8..2839e2c9e14c1 100644
--- a/packages/editor/src/components/block-manager/checklist.js
+++ b/packages/editor/src/components/block-manager/checklist.js
@@ -17,7 +17,7 @@ function BlockTypesChecklist( { blockTypes, value, onItemChange } ) {
label={ blockType.title }
checked={ value.includes( blockType.name ) }
onChange={ ( ...args ) =>
- onItemChange( blockType.name, ...args )
+ onItemChange( blockType, ...args )
}
/>
diff --git a/packages/editor/src/components/block-manager/index.js b/packages/editor/src/components/block-manager/index.js
index 4a1145839976f..5c719c62a5a0b 100644
--- a/packages/editor/src/components/block-manager/index.js
+++ b/packages/editor/src/components/block-manager/index.js
@@ -2,69 +2,49 @@
* WordPress dependencies
*/
import { store as blocksStore } from '@wordpress/blocks';
-import { useDispatch, useSelect } from '@wordpress/data';
+import { useSelect } from '@wordpress/data';
import { SearchControl, Button } from '@wordpress/components';
import { __, _n, sprintf } from '@wordpress/i18n';
import { useEffect, useState } from '@wordpress/element';
import { useDebounce } from '@wordpress/compose';
import { speak } from '@wordpress/a11y';
-import { store as preferencesStore } from '@wordpress/preferences';
/**
* Internal dependencies
*/
-import { unlock } from '../../lock-unlock';
-import { store as editorStore } from '../../store';
import BlockManagerCategory from './category';
-export default function BlockManager() {
+/**
+ * Provides a list of blocks with checkboxes.
+ *
+ * @param {Object} props Props.
+ * @param {Array} props.blockTypes An array of blocks.
+ * @param {Array} props.selectedBlockTypes An array of selected blocks.
+ * @param {Function} props.onChange Function to be called when the selected blocks change.
+ */
+export default function BlockManager( {
+ blockTypes,
+ selectedBlockTypes,
+ onChange,
+} ) {
const debouncedSpeak = useDebounce( speak, 500 );
const [ search, setSearch ] = useState( '' );
- const { showBlockTypes } = unlock( useDispatch( editorStore ) );
-
- const {
- blockTypes,
- categories,
- hasBlockSupport,
- isMatchingSearchTerm,
- numberOfHiddenBlocks,
- } = useSelect( ( select ) => {
- // Some hidden blocks become unregistered
- // by removing for instance the plugin that registered them, yet
- // they're still remain as hidden by the user's action.
- // We consider "hidden", blocks which were hidden and
- // are still registered.
- const _blockTypes = select( blocksStore ).getBlockTypes();
- const hiddenBlockTypes = (
- select( preferencesStore ).get( 'core', 'hiddenBlockTypes' ) ?? []
- ).filter( ( hiddenBlock ) => {
- return _blockTypes.some(
- ( registeredBlock ) => registeredBlock.name === hiddenBlock
- );
- } );
-
+ const { categories, isMatchingSearchTerm } = useSelect( ( select ) => {
return {
- blockTypes: _blockTypes,
categories: select( blocksStore ).getCategories(),
- hasBlockSupport: select( blocksStore ).hasBlockSupport,
isMatchingSearchTerm: select( blocksStore ).isMatchingSearchTerm,
- numberOfHiddenBlocks:
- Array.isArray( hiddenBlockTypes ) && hiddenBlockTypes.length,
};
}, [] );
- function enableAllBlockTypes( newBlockTypes ) {
- const blockNames = newBlockTypes.map( ( { name } ) => name );
- showBlockTypes( blockNames );
+ function enableAllBlockTypes() {
+ onChange( blockTypes );
}
- const filteredBlockTypes = blockTypes.filter(
- ( blockType ) =>
- hasBlockSupport( blockType, 'inserter', true ) &&
- ( ! search || isMatchingSearchTerm( blockType, search ) ) &&
- ( ! blockType.parent ||
- blockType.parent.includes( 'core/post-content' ) )
- );
+ const filteredBlockTypes = blockTypes.filter( ( blockType ) => {
+ return ! search || isMatchingSearchTerm( blockType, search );
+ } );
+
+ const numberOfHiddenBlocks = blockTypes.length - selectedBlockTypes.length;
// Announce search results on change
useEffect( () => {
@@ -96,9 +76,7 @@ export default function BlockManager() {
@@ -131,6 +109,8 @@ export default function BlockManager() {
( blockType ) =>
blockType.category === category.slug
) }
+ selectedBlockTypes={ selectedBlockTypes }
+ onChange={ onChange }
/>
) ) }
! category
) }
+ selectedBlockTypes={ selectedBlockTypes }
+ onChange={ onChange }
/>
diff --git a/packages/editor/src/components/preferences-modal/block-visibility.js b/packages/editor/src/components/preferences-modal/block-visibility.js
new file mode 100644
index 0000000000000..49d6888c5dbfe
--- /dev/null
+++ b/packages/editor/src/components/preferences-modal/block-visibility.js
@@ -0,0 +1,94 @@
+/**
+ * WordPress dependencies
+ */
+import { useSelect, useDispatch } from '@wordpress/data';
+import { store as preferencesStore } from '@wordpress/preferences';
+import { hasBlockSupport, store as blocksStore } from '@wordpress/blocks';
+import { useMemo } from '@wordpress/element';
+
+/**
+ * Internal dependencies
+ */
+import { store as editorStore } from '../../store';
+import { unlock } from '../../lock-unlock';
+import BlockManager from '../block-manager';
+
+export default function BlockVisibility() {
+ const { showBlockTypes, hideBlockTypes } = unlock(
+ useDispatch( editorStore )
+ );
+
+ const {
+ blockTypes,
+ allowedBlockTypes: _allowedBlockTypes,
+ hiddenBlockTypes: _hiddenBlockTypes,
+ } = useSelect( ( select ) => {
+ return {
+ blockTypes: select( blocksStore ).getBlockTypes(),
+ allowedBlockTypes:
+ select( editorStore ).getEditorSettings().allowedBlockTypes,
+ hiddenBlockTypes:
+ select( preferencesStore ).get( 'core', 'hiddenBlockTypes' ) ??
+ [],
+ };
+ }, [] );
+
+ const allowedBlockTypes = useMemo( () => {
+ if ( _allowedBlockTypes === true ) {
+ return blockTypes;
+ }
+ return blockTypes.filter( ( { name } ) => {
+ return _allowedBlockTypes?.includes( name );
+ } );
+ }, [ _allowedBlockTypes, blockTypes ] );
+
+ const filteredBlockTypes = allowedBlockTypes.filter(
+ ( blockType ) =>
+ hasBlockSupport( blockType, 'inserter', true ) &&
+ ( ! blockType.parent ||
+ blockType.parent.includes( 'core/post-content' ) )
+ );
+
+ // Some hidden blocks become unregistered
+ // by removing for instance the plugin that registered them, yet
+ // they're still remain as hidden by the user's action.
+ // We consider "hidden", blocks which were hidden and
+ // are still registered.
+ const hiddenBlockTypes = _hiddenBlockTypes.filter( ( hiddenBlock ) => {
+ return filteredBlockTypes.some(
+ ( registeredBlock ) => registeredBlock.name === hiddenBlock
+ );
+ } );
+
+ const selectedBlockTypes = filteredBlockTypes.filter(
+ ( blockType ) => ! hiddenBlockTypes.includes( blockType.name )
+ );
+
+ const onChangeSelectedBlockTypes = ( newSelectedBlockTypes ) => {
+ if ( selectedBlockTypes.length > newSelectedBlockTypes.length ) {
+ const blockTypesToHide = selectedBlockTypes.filter(
+ ( blockType ) =>
+ ! newSelectedBlockTypes.find(
+ ( { name } ) => name === blockType.name
+ )
+ );
+ hideBlockTypes( blockTypesToHide.map( ( { name } ) => name ) );
+ } else if ( selectedBlockTypes.length < newSelectedBlockTypes.length ) {
+ const blockTypesToShow = newSelectedBlockTypes.filter(
+ ( blockType ) =>
+ ! selectedBlockTypes.find(
+ ( { name } ) => name === blockType.name
+ )
+ );
+ showBlockTypes( blockTypesToShow.map( ( { name } ) => name ) );
+ }
+ };
+
+ return (
+
+ );
+}
diff --git a/packages/editor/src/components/preferences-modal/index.js b/packages/editor/src/components/preferences-modal/index.js
index 7ea7ea456ce28..72042bca03b70 100644
--- a/packages/editor/src/components/preferences-modal/index.js
+++ b/packages/editor/src/components/preferences-modal/index.js
@@ -18,7 +18,7 @@ import { store as interfaceStore } from '@wordpress/interface';
import EnablePanelOption from './enable-panel';
import EnablePluginDocumentSettingPanelOption from './enable-plugin-document-setting-panel';
import EnablePublishSidebarOption from './enable-publish-sidebar';
-import BlockManager from '../block-manager';
+import BlockVisibility from './block-visibility';
import PostTaxonomies from '../post-taxonomies';
import PostFeaturedImageCheck from '../post-featured-image/check';
import PostExcerptCheck from '../post-excerpt/check';
@@ -297,7 +297,7 @@ function PreferencesModalContents( { extraSections = {} } ) {
"Disable blocks that you don't want to appear in the inserter. They can always be toggled back on later."
) }
>
-
+
>
),