From aa282ef561f6610246fadbfa8b7f83542edb888c Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Fri, 2 Dec 2022 16:27:44 +0800 Subject: [PATCH] Block Editor Store: Allow management of block inspector tabs --- packages/block-editor/src/store/actions.js | 43 +++++++++++ packages/block-editor/src/store/reducer.js | 50 +++++++++++++ packages/block-editor/src/store/selectors.js | 27 +++++++ .../block-editor/src/store/test/actions.js | 45 ++++++++++++ .../block-editor/src/store/test/reducer.js | 73 +++++++++++++++++++ .../block-editor/src/store/test/selectors.js | 63 ++++++++++++++++ 6 files changed, 301 insertions(+) diff --git a/packages/block-editor/src/store/actions.js b/packages/block-editor/src/store/actions.js index e1c88c2bd99b49..071316f590ffe8 100644 --- a/packages/block-editor/src/store/actions.js +++ b/packages/block-editor/src/store/actions.js @@ -1748,3 +1748,46 @@ export function __unstableSetTemporarilyEditingAsBlocks( temporarilyEditingAsBlocks, }; } + +/** + * Action used to enable display of block inspector tabs overriding the + * Gutenberg block inspector tabs experiment setting. + * + * @param {?string} blockName The block's name. + */ +export function __experimentalEnableBlockInspectorTabs( blockName ) { + return { + type: 'ENABLE_BLOCK_INSPECTOR_TABS', + blockName, + }; +} + +/** + * Action used to disable display of block inspector tabs overriding the + * Gutenberg block inspector tabs experiment setting. + * + * @param {?string} blockName The block's name. + */ +export function __experimentalDisableBlockInspectorTabs( blockName ) { + return { + type: 'DISABLE_BLOCK_INSPECTOR_TABS', + blockName, + }; +} + +/** + * Action to set default tab for a specific block type. + * + * @param {string} blockName The block's name. + * @param {string} defaultTab Name of tab to display by default. + */ +export function __experimentalSetDefaultBlockInspectorTab( + blockName, + defaultTab +) { + return { + type: 'SET_DEFAULT_BLOCK_INSPECTOR_TAB', + blockName, + defaultTab, + }; +} diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index 4df5a948e8681a..f36830fe5ec875 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -1842,6 +1842,55 @@ export function temporarilyEditingAsBlocks( state = '', action ) { return state; } +/** + * Reducer returning the current configuration for block inspector tabs. + * + * @param {Object} state Current configuration state for block inspector tabs. + * @param {Object} action Dispatched action. + * + * @return {Object} Updated state. + */ +export function blockInspectorTabs( state = {}, action ) { + switch ( action.type ) { + case 'ENABLE_BLOCK_INSPECTOR_TABS': + if ( ! action.blockName ) { + return { ...state, enabled: true }; + } + + return { + ...state, + [ action.blockName ]: { + ...state?.[ action.blockName ], + enabled: true, + }, + }; + + case 'DISABLE_BLOCK_INSPECTOR_TABS': + if ( ! action.blockName ) { + return { ...state, enabled: false }; + } + + return { + ...state, + [ action.blockName ]: { + ...state?.[ action.blockName ], + enabled: false, + }, + }; + + case 'SET_DEFAULT_BLOCK_INSPECTOR_TAB': + return { + ...state, + [ action.blockName ]: { + ...state?.[ action.blockName ], + defaultTab: action.defaultTab, + }, + }; + } + + return state; +} + export default combineReducers( { blocks, isTyping, @@ -1865,4 +1914,5 @@ export default combineReducers( { lastBlockInserted, temporarilyEditingAsBlocks, blockVisibility, + blockInspectorTabs, } ); diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index dab952c3d1c223..7cdc95a18e0036 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -2766,3 +2766,30 @@ export function __unstableIsWithinBlockOverlay( state, clientId ) { } return false; } + +/** + * Returns true if the block inspector should display tabs, false otherwise. + * + * @param {Object} state Global application state. + * @param {?string} blockName The block type name. + * + * @return {boolean} Whether block inspector tabs should be shown or not. + */ +export function __experimentalAreBlockInspectorTabsEnabled( state, blockName ) { + const enabled = state.blockInspectorTabs?.[ blockName ]?.enabled; + + return enabled === undefined ? state.blockInspectorTabs?.enabled : enabled; +} + +/** + * Retrieves the default block inspector tab's name for the block type, if + * available. + * + * @param {Object} state Global application state. + * @param {string} blockName The block type name. + * + * @return {string|undefined} The name of the default block inspector tab if set. + */ +export function __experimentalGetDefaultBlockInspectorTab( state, blockName ) { + return state.blockInspectorTabs?.[ blockName ]?.defaultTab; +} diff --git a/packages/block-editor/src/store/test/actions.js b/packages/block-editor/src/store/test/actions.js index 82cf9831f104a2..6d7beaf951b880 100644 --- a/packages/block-editor/src/store/test/actions.js +++ b/packages/block-editor/src/store/test/actions.js @@ -27,6 +27,8 @@ const noop = () => {}; const { clearSelectedBlock, + __experimentalDisableBlockInspectorTabs: disableBlockInspectorTabs, + __experimentalEnableBlockInspectorTabs: enableBlockInspectorTabs, __experimentalHideBlockInterface: hideBlockInterface, insertBlock, insertBlocks, @@ -40,6 +42,7 @@ const { replaceInnerBlocks, resetBlocks, selectBlock, + __experimentalSetDefaultBlockInspectorTab: setDefaultBlockInspectorTab, __experimentalShowBlockInterface: showBlockInterface, showInsertionPoint, startMultiSelect, @@ -793,6 +796,48 @@ describe( 'actions', () => { } ); } ); + describe( 'enableBlockInspectorTabs', () => { + it( 'should return the ENABLE_BLOCK_INSPECTOR_TABS action', () => { + expect( enableBlockInspectorTabs() ).toEqual( { + type: 'ENABLE_BLOCK_INSPECTOR_TABS', + } ); + } ); + + it( 'should return the ENABLE_BLOCK_INSPECTOR_TABS action for specific block', () => { + expect( enableBlockInspectorTabs( 'core/foo' ) ).toEqual( { + type: 'ENABLE_BLOCK_INSPECTOR_TABS', + blockName: 'core/foo', + } ); + } ); + } ); + + describe( 'disableBlockInspectorTabs', () => { + it( 'should return the DISABLE_BLOCK_INSPECTOR_TABS action', () => { + expect( disableBlockInspectorTabs() ).toEqual( { + type: 'DISABLE_BLOCK_INSPECTOR_TABS', + } ); + } ); + + it( 'should return the DISABLE_BLOCK_INSPECTOR_TABSDISABLE_BLOCK_INSPECTOR_TABS action for specific block', () => { + expect( disableBlockInspectorTabs( 'core/foo' ) ).toEqual( { + type: 'DISABLE_BLOCK_INSPECTOR_TABS', + blockName: 'core/foo', + } ); + } ); + } ); + + describe( 'setDefaultBlockInspectorTab', () => { + it( 'should return SET_DEFAULT_BLOCK_INSPECTOR_TAB action', () => { + expect( + setDefaultBlockInspectorTab( 'core/foo', 'settings' ) + ).toEqual( { + type: 'SET_DEFAULT_BLOCK_INSPECTOR_TAB', + blockName: 'core/foo', + defaultTab: 'settings', + } ); + } ); + } ); + describe( 'startTyping', () => { it( 'should return the START_TYPING action', () => { expect( startTyping() ).toEqual( { diff --git a/packages/block-editor/src/store/test/reducer.js b/packages/block-editor/src/store/test/reducer.js index 4cf18bc613b425..451282462e502f 100644 --- a/packages/block-editor/src/store/test/reducer.js +++ b/packages/block-editor/src/store/test/reducer.js @@ -32,6 +32,7 @@ import { blockListSettings, lastBlockAttributesChange, lastBlockInserted, + blockInspectorTabs, } from '../reducer'; const noop = () => {}; @@ -2360,6 +2361,78 @@ describe( 'state', () => { } ); } ); + describe( 'blockInspectorTabs()', () => { + it( 'should enable inspector tabs for all blocks', () => { + const state = blockInspectorTabs( + { enabled: false }, + { type: 'ENABLE_BLOCK_INSPECTOR_TABS' } + ); + + expect( state ).toEqual( { enabled: true } ); + } ); + + it( 'should enable inspector tabs for a single block', () => { + const state = blockInspectorTabs( + { enabled: false }, + { + type: 'ENABLE_BLOCK_INSPECTOR_TABS', + blockName: 'core/block', + } + ); + + expect( state ).toEqual( { + enabled: false, + 'core/block': { enabled: true }, + } ); + } ); + + it( 'should disable inspector tabs for all blocks', () => { + const state = blockInspectorTabs( + { enabled: true }, + { type: 'DISABLE_BLOCK_INSPECTOR_TABS' } + ); + + expect( state ).toEqual( { enabled: false } ); + } ); + + it( 'should disable inspector tabs for a single block', () => { + const state = blockInspectorTabs( + { enabled: true }, + { + type: 'DISABLE_BLOCK_INSPECTOR_TABS', + blockName: 'core/block', + } + ); + + expect( state ).toEqual( { + enabled: true, + 'core/block': { enabled: false }, + } ); + } ); + + it( 'should set the default inspector tab for a single block', () => { + const state = blockInspectorTabs( + { + enabled: false, + 'core/block': { enabled: true }, + }, + { + type: 'SET_DEFAULT_BLOCK_INSPECTOR_TAB', + blockName: 'core/block', + defaultTab: 'settings', + } + ); + + expect( state ).toEqual( { + enabled: false, + 'core/block': { + enabled: true, + defaultTab: 'settings', + }, + } ); + } ); + } ); + describe( 'isTyping()', () => { it( 'should set the typing flag to true', () => { const state = isTyping( false, { diff --git a/packages/block-editor/src/store/test/selectors.js b/packages/block-editor/src/store/test/selectors.js index 1511a66b43c9c2..17c3c38e841534 100644 --- a/packages/block-editor/src/store/test/selectors.js +++ b/packages/block-editor/src/store/test/selectors.js @@ -73,6 +73,8 @@ const { __experimentalGetPatternTransformItems, wasBlockJustInserted, __experimentalGetGlobalBlocksByName, + __experimentalAreBlockInspectorTabsEnabled: areBlockInspectorTabsEnabled, + __experimentalGetDefaultBlockInspectorTab: getDefaultBlockInspectorTab, } = selectors; describe( 'selectors', () => { @@ -2084,6 +2086,67 @@ describe( 'selectors', () => { } ); } ); + describe( 'areBlockInspectorTabsEnabled', () => { + it( 'should not provide default if not set in state', () => { + const state = {}; + + expect( areBlockInspectorTabsEnabled( state ) ).toBe( undefined ); + } ); + + it( 'should return true when toggled true in state', () => { + const state = { + blockInspectorTabs: { enabled: true }, + }; + + expect( areBlockInspectorTabsEnabled( state ) ).toBe( true ); + } ); + + it( 'should return false when toggled false in state', () => { + const state = { + blockInspectorTabs: { enabled: false }, + }; + + expect( areBlockInspectorTabsEnabled( state ) ).toBe( false ); + } ); + + it( 'should return block specific override for tabs display', () => { + const state = { + blockInspectorTabs: { + enable: false, + 'core/block': { enabled: true }, + }, + }; + + expect( areBlockInspectorTabsEnabled( state, 'core/block' ) ).toBe( + true + ); + } ); + + it( 'should fallback to default value when block not specifically set', () => { + const state = { + blockInspectorTabs: { enabled: true }, + }; + + expect( areBlockInspectorTabsEnabled( state, 'core/block' ) ).toBe( + true + ); + } ); + } ); + + describe( 'getDefaultBlockInspectorTab', () => { + it( 'should return default tab for block when set', () => { + const state = { + blockInspectorTabs: { + 'core/block': { defaultTab: 'settings' }, + }, + }; + + expect( getDefaultBlockInspectorTab( state, 'core/block' ) ).toBe( + 'settings' + ); + } ); + } ); + describe( 'isTyping', () => { it( 'should return the isTyping flag if the block is selected', () => { const state = {