Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 44 additions & 11 deletions packages/block-editor/src/components/block-tools/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import BlockToolbarPopover from './block-toolbar-popover';
import { store as blockEditorStore } from '../../store';
import usePopoverScroll from '../block-popover/use-popover-scroll';
import ZoomOutModeInserters from './zoom-out-mode-inserters';
import { useShowBlockTools } from './use-show-block-tools';
import { shouldShowBlockTools } from './should-show-block-tools';
import { unlock } from '../../lock-unlock';
import { cleanEmptyObject } from '../../hooks/utils';
import usePasteStyles from '../use-paste-styles';
Expand All @@ -39,17 +39,47 @@ function selector( select ) {
isTyping,
isDragging,
isZoomOut,
getBlocksByClientId,
getSelectedBlockClientIds,
getBlockRootClientId,
isGroupable,
getBlockName,
getBlock,
getBlockMode,
isBlockInterfaceHidden,
} = unlock( select( blockEditorStore ) );

const { getGroupingBlockName } = select( blocksStore );

const clientId =
getSelectedBlockClientId() || getFirstMultiSelectedBlockClientId();
const _isTyping = isTyping();
const _hasFixedToolbar = getSettings().hasFixedToolbar;

const { showEmptyBlockSideInserter, showBlockToolbarPopover } =
shouldShowBlockTools( {
block: getBlock( clientId ),
blockMode: clientId ? getBlockMode( clientId ) : null,
isBlockInterfaceHidden: isBlockInterfaceHidden(),
clientId,
isTyping: _isTyping,
hasFixedToolbar: _hasFixedToolbar,
} );

return {
clientId,
hasFixedToolbar: getSettings().hasFixedToolbar,
isTyping: isTyping(),
hasFixedToolbar: _hasFixedToolbar,
isTyping: _isTyping,
isZoomOutMode: isZoomOut(),
isDragging: isDragging(),
showEmptyBlockSideInserter,
showBlockToolbarPopover,
getBlocksByClientId,
getSelectedBlockClientIds,
getBlockRootClientId,
isGroupable,
getBlockName,
getGroupingBlockName,
};
}

Expand All @@ -67,20 +97,23 @@ export default function BlockTools( {
__unstableContentRef,
...props
} ) {
const { clientId, hasFixedToolbar, isTyping, isZoomOutMode, isDragging } =
useSelect( selector, [] );

const isMatch = useShortcutEventMatch();
const {
clientId,
hasFixedToolbar,
isTyping,
isZoomOutMode,
isDragging,
getBlocksByClientId,
getSelectedBlockClientIds,
getBlockRootClientId,
isGroupable,
getBlockName,
} = useSelect( blockEditorStore );
const { getGroupingBlockName } = useSelect( blocksStore );
const { showEmptyBlockSideInserter, showBlockToolbarPopover } =
useShowBlockTools();
getGroupingBlockName,
showEmptyBlockSideInserter,
showBlockToolbarPopover,
} = useSelect( selector, [] );

const isMatch = useShortcutEventMatch();
const pasteStyles = usePasteStyles();

const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ function InbetweenInsertionPointPopover( {
isInserterShown,
isDistractionFree,
isZoomOutMode,
getBlockEditingMode,
} = useSelect( ( select ) => {
const {
getBlockOrder,
Expand All @@ -55,6 +56,7 @@ function InbetweenInsertionPointPopover( {
getNextBlockClientId,
getSettings,
isZoomOut,
getBlockEditingMode: _getBlockEditingMode,
} = unlock( select( blockEditorStore ) );
const insertionPoint = getBlockInsertionPoint();
const order = getBlockOrder( insertionPoint.rootClientId );
Expand Down Expand Up @@ -86,9 +88,9 @@ function InbetweenInsertionPointPopover( {
isDistractionFree: settings.isDistractionFree,
isInserterShown: insertionPoint?.__unstableWithInserter,
isZoomOutMode: isZoomOut(),
getBlockEditingMode: _getBlockEditingMode,
};
}, [] );
const { getBlockEditingMode } = useSelect( blockEditorStore );

const disableMotion = useReducedMotion();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* WordPress dependencies
*/
import { isUnmodifiedDefaultBlock } from '@wordpress/blocks';

/**
* Determines which block tools should be showing based on the current editor state.
* This is a pure function that can be called from within a selector.
*
* @param {Object} options Calculation options.
* @param {Object} options.block The selected block object.
* @param {string} options.blockMode The block mode ('visual' or 'html').
* @param {boolean} options.isBlockInterfaceHidden Whether the block interface is hidden.
* @param {string} options.clientId The selected block client ID.
* @param {boolean} options.isTyping Whether the user is currently typing.
* @param {boolean} options.hasFixedToolbar Whether the toolbar is fixed.
*
* @return {Object} Object of which block tools will be shown.
*/
export function shouldShowBlockTools( {
block,
blockMode,
isBlockInterfaceHidden,
clientId,
isTyping,
hasFixedToolbar,
} ) {
const hasSelectedBlock = !! clientId && !! block;
const isEmptyDefaultBlock =
hasSelectedBlock &&
isUnmodifiedDefaultBlock( block, 'content' ) &&
blockMode !== 'html';
const showEmptyBlockSideInserter =
clientId && ! isTyping && isEmptyDefaultBlock;
const showBlockToolbarPopover =
! isBlockInterfaceHidden &&
! hasFixedToolbar &&
! showEmptyBlockSideInserter &&
hasSelectedBlock &&
! isEmptyDefaultBlock;

return {
showEmptyBlockSideInserter,
showBlockToolbarPopover,
};
}
Original file line number Diff line number Diff line change
@@ -1,53 +1,46 @@
/**
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';
import { isUnmodifiedDefaultBlock } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import { store as blockEditorStore } from '../../store';
import { unlock } from '../../lock-unlock';

/**
* Source of truth for which block tools are showing in the block editor.
* Calculates which block tools should be showing based on the current editor state.
* This is a pure function that can be called from within a selector.
*
* @param {Object} options Calculation options.
* @param {Object} options.block The selected block object.
* @param {string} options.blockMode The block mode ('visual' or 'html').
* @param {boolean} options.isBlockInterfaceHidden Whether the block interface is hidden.
* @param {string} options.clientId The selected block client ID.
* @param {boolean} options.isTyping Whether the user is currently typing.
* @param {boolean} options.hasFixedToolbar Whether the toolbar is fixed.
*
* @return {Object} Object of which block tools will be shown.
*/
export function useShowBlockTools() {
return useSelect( ( select ) => {
const {
getSelectedBlockClientId,
getFirstMultiSelectedBlockClientId,
getBlock,
getBlockMode,
getSettings,
isTyping,
isBlockInterfaceHidden,
} = unlock( select( blockEditorStore ) );

const clientId =
getSelectedBlockClientId() || getFirstMultiSelectedBlockClientId();

const block = getBlock( clientId );
const hasSelectedBlock = !! clientId && !! block;
const isEmptyDefaultBlock =
hasSelectedBlock &&
isUnmodifiedDefaultBlock( block, 'content' ) &&
getBlockMode( clientId ) !== 'html';
const _showEmptyBlockSideInserter =
clientId && ! isTyping() && isEmptyDefaultBlock;
const _showBlockToolbarPopover =
! isBlockInterfaceHidden() &&
! getSettings().hasFixedToolbar &&
! _showEmptyBlockSideInserter &&
hasSelectedBlock &&
! isEmptyDefaultBlock;
export function calculateShowBlockTools( {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the goal of this one? An early implementation of shouldShowBlockTools?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick refactors as I go to see if they had an impact. I've heard from multiple folks that one of the performance hits of the codebase is how many selectors we have. So, if I come across a place while I'm debugging that I can quickly and easily refactor selectors into one, I'm doing it and moving on.

In this instance, use-show-block-tools was used in one place that was already using the same selectors, so I refactored so it could use the same subscription.

This PR is a dumping ground for all the quick little things I come across to see if the drops in the bucket add up over time and improve code quality. If they do, then they can be spun out to separate PRs if needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah - I didn't realize both versions were still around! I've made this sandbox PR a draft and moved this work over to #73012 to get officially reviewed.

block,
blockMode,
isBlockInterfaceHidden,
clientId,
isTyping,
hasFixedToolbar,
} ) {
const hasSelectedBlock = !! clientId && !! block;
const isEmptyDefaultBlock =
hasSelectedBlock &&
isUnmodifiedDefaultBlock( block, 'content' ) &&
blockMode !== 'html';
const showEmptyBlockSideInserter =
clientId && ! isTyping && isEmptyDefaultBlock;
const showBlockToolbarPopover =
! isBlockInterfaceHidden &&
! hasFixedToolbar &&
! showEmptyBlockSideInserter &&
hasSelectedBlock &&
! isEmptyDefaultBlock;

return {
showEmptyBlockSideInserter: _showEmptyBlockSideInserter,
showBlockToolbarPopover: _showBlockToolbarPopover,
};
}, [] );
return {
showEmptyBlockSideInserter,
showBlockToolbarPopover,
};
}
18 changes: 12 additions & 6 deletions packages/block-editor/src/hooks/border.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,18 @@ function BordersInspectorControl( { label, children, resetAllFilter } ) {

export function BorderPanel( { clientId, name, setAttributes, settings } ) {
const isEnabled = useHasBorderPanel( settings );
function selector( select ) {
const { style, borderColor } =
select( blockEditorStore ).getBlockAttributes( clientId ) || {};
return { style, borderColor };
}
const { style, borderColor } = useSelect( selector, [ clientId ] );
const { style, borderColor } = useSelect(
( select ) => {
// Early return to avoid subscription when disabled
if ( ! isEnabled ) {
return {};
}
const { style: _style, borderColor: _borderColor } =
select( blockEditorStore ).getBlockAttributes( clientId ) || {};
return { style: _style, borderColor: _borderColor };
},
[ clientId, isEnabled ]
);
const value = useMemo( () => {
return attributesToStyle( { style, borderColor } );
}, [ style, borderColor ] );
Expand Down
27 changes: 20 additions & 7 deletions packages/block-editor/src/hooks/color.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,14 +262,27 @@ function ColorInspectorControl( { children, resetAllFilter } ) {

export function ColorEdit( { clientId, name, setAttributes, settings } ) {
const isEnabled = useHasColorPanel( settings );
function selector( select ) {
const { style, textColor, backgroundColor, gradient } =
select( blockEditorStore ).getBlockAttributes( clientId ) || {};
return { style, textColor, backgroundColor, gradient };
}

const { style, textColor, backgroundColor, gradient } = useSelect(
selector,
[ clientId ]
( select ) => {
// Early return to avoid subscription when disabled
if ( ! isEnabled ) {
return {};
}
const {
style: _style,
textColor: _textColor,
backgroundColor: _backgroundColor,
gradient: _gradient,
} = select( blockEditorStore ).getBlockAttributes( clientId ) || {};
return {
style: _style,
textColor: _textColor,
backgroundColor: _backgroundColor,
gradient: _gradient,
};
},
[ clientId, isEnabled ]
);
const value = useMemo( () => {
return attributesToStyle( {
Expand Down
12 changes: 9 additions & 3 deletions packages/block-editor/src/hooks/dimensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,15 @@ function DimensionsInspectorControl( { children, resetAllFilter } ) {
export function DimensionsPanel( { clientId, name, setAttributes, settings } ) {
const isEnabled = useHasDimensionsPanel( settings );
const value = useSelect(
( select ) =>
select( blockEditorStore ).getBlockAttributes( clientId )?.style,
[ clientId ]
( select ) => {
// Early return to avoid subscription when disabled
if ( ! isEnabled ) {
return undefined;
}
return select( blockEditorStore ).getBlockAttributes( clientId )
?.style;
},
[ clientId, isEnabled ]
);
const [ visualizedProperty, setVisualizedProperty ] = useVisualizer();
const onChange = ( newStyle ) => {
Expand Down
18 changes: 11 additions & 7 deletions packages/block-editor/src/hooks/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,17 @@ export function useLayoutClasses( blockAttributes = {}, blockName = '' ) {

const hasGlobalPadding = useSelect(
( select ) => {
return (
( usedLayout?.inherit ||
usedLayout?.contentSize ||
usedLayout?.type === 'constrained' ) &&
select( blockEditorStore ).getSettings().__experimentalFeatures
?.useRootPaddingAwareAlignments
);
// Early return to avoid subscription when layout doesn't use global padding
if (
! usedLayout?.inherit &&
! usedLayout?.contentSize &&
usedLayout?.type !== 'constrained'
) {
return false;
}

return select( blockEditorStore ).getSettings()
.__experimentalFeatures?.useRootPaddingAwareAlignments;
},
[ usedLayout?.contentSize, usedLayout?.inherit, usedLayout?.type ]
);
Expand Down
30 changes: 22 additions & 8 deletions packages/block-editor/src/hooks/typography.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,29 @@ function TypographyInspectorControl( { children, resetAllFilter } ) {
}

export function TypographyPanel( { clientId, name, setAttributes, settings } ) {
function selector( select ) {
const { style, fontFamily, fontSize, fitText } =
select( blockEditorStore ).getBlockAttributes( clientId ) || {};
return { style, fontFamily, fontSize, fitText };
}
const { style, fontFamily, fontSize, fitText } = useSelect( selector, [
clientId,
] );
const isEnabled = useHasTypographyPanel( settings );

const { style, fontFamily, fontSize, fitText } = useSelect(
( select ) => {
// Early return INSIDE selector to avoid subscription when disabled
if ( ! isEnabled ) {
return {};
}
const {
style: _style,
fontFamily: _fontFamily,
fontSize: _fontSize,
fitText: _fitText,
} = select( blockEditorStore ).getBlockAttributes( clientId ) || {};
return {
style: _style,
fontFamily: _fontFamily,
fontSize: _fontSize,
fitText: _fitText,
};
},
[ clientId, isEnabled ]
);
const value = useMemo(
() => attributesToStyle( { style, fontFamily, fontSize } ),
[ style, fontSize, fontFamily ]
Expand Down
Loading
Loading