@wordpress/block-editor
Version:
313 lines (286 loc) • 11 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import { createElement, Fragment } from "@wordpress/element";
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { getBlockType, getUnregisteredTypeHandlerName, hasBlockSupport, store as blocksStore } from '@wordpress/blocks';
import { FlexItem, PanelBody, __experimentalHStack as HStack, __experimentalVStack as VStack, Button, __unstableMotion as motion } from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
import { useMemo, useCallback } from '@wordpress/element';
/**
* Internal dependencies
*/
import SkipToSelectedBlock from '../skip-to-selected-block';
import BlockCard from '../block-card';
import MultiSelectionInspector from '../multi-selection-inspector';
import BlockVariationTransforms from '../block-variation-transforms';
import useBlockDisplayInformation from '../use-block-display-information';
import { store as blockEditorStore } from '../../store';
import BlockIcon from '../block-icon';
import BlockStyles from '../block-styles';
import DefaultStylePicker from '../default-style-picker';
import { default as InspectorControls } from '../inspector-controls';
import { default as InspectorControlsTabs } from '../inspector-controls-tabs';
import useInspectorControlsTabs from '../inspector-controls-tabs/use-inspector-controls-tabs';
import AdvancedControls from '../inspector-controls-tabs/advanced-controls-panel';
import PositionControls from '../inspector-controls-tabs/position-controls-panel';
import useBlockInspectorAnimationSettings from './useBlockInspectorAnimationSettings';
import BlockInfo from '../block-info-slot-fill';
function useContentBlocks(blockTypes, block) {
const contentBlocksObjectAux = useMemo(() => {
return blockTypes.reduce((result, blockType) => {
if (blockType.name !== 'core/list-item' && Object.entries(blockType.attributes).some(([, {
__experimentalRole
}]) => __experimentalRole === 'content')) {
result[blockType.name] = true;
}
return result;
}, {});
}, [blockTypes]);
const isContentBlock = useCallback(blockName => {
return !!contentBlocksObjectAux[blockName];
}, [contentBlocksObjectAux]);
return useMemo(() => {
return getContentBlocks([block], isContentBlock);
}, [block, isContentBlock]);
}
function getContentBlocks(blocks, isContentBlock) {
const result = [];
for (const block of blocks) {
if (isContentBlock(block.name)) {
result.push(block);
}
result.push(...getContentBlocks(block.innerBlocks, isContentBlock));
}
return result;
}
function BlockNavigationButton({
blockTypes,
block,
selectedBlock
}) {
const {
selectBlock
} = useDispatch(blockEditorStore);
const blockType = blockTypes.find(({
name
}) => name === block.name);
const isSelected = selectedBlock && selectedBlock.clientId === block.clientId;
return createElement(Button, {
isPressed: isSelected,
onClick: () => selectBlock(block.clientId)
}, createElement(HStack, {
justify: "flex-start"
}, createElement(BlockIcon, {
icon: blockType.icon
}), createElement(FlexItem, null, blockType.title)));
}
function BlockInspectorLockedBlocks({
topLevelLockedBlock
}) {
const {
blockTypes,
block,
selectedBlock
} = useSelect(select => {
return {
blockTypes: select(blocksStore).getBlockTypes(),
block: select(blockEditorStore).getBlock(topLevelLockedBlock),
selectedBlock: select(blockEditorStore).getSelectedBlock()
};
}, [topLevelLockedBlock]);
const blockInformation = useBlockDisplayInformation(topLevelLockedBlock);
const contentBlocks = useContentBlocks(blockTypes, block);
return createElement("div", {
className: "block-editor-block-inspector"
}, createElement(BlockCard, _extends({}, blockInformation, {
className: blockInformation.isSynced && 'is-synced'
})), createElement(BlockVariationTransforms, {
blockClientId: topLevelLockedBlock
}), createElement(BlockInfo.Slot, null), createElement(VStack, {
spacing: 1,
padding: 4,
className: "block-editor-block-inspector__block-buttons-container"
}, createElement("h2", {
className: "block-editor-block-card__title"
}, __('Content')), contentBlocks.map(contentBlock => createElement(BlockNavigationButton, {
selectedBlock: selectedBlock,
key: contentBlock.clientId,
block: contentBlock,
blockTypes: blockTypes
}))));
}
const BlockInspector = ({
showNoBlockSelectedMessage = true
}) => {
const {
count,
selectedBlockName,
selectedBlockClientId,
blockType,
topLevelLockedBlock
} = useSelect(select => {
const {
getSelectedBlockClientId,
getSelectedBlockCount,
getBlockName,
__unstableGetContentLockingParent,
getTemplateLock
} = select(blockEditorStore);
const _selectedBlockClientId = getSelectedBlockClientId();
const _selectedBlockName = _selectedBlockClientId && getBlockName(_selectedBlockClientId);
const _blockType = _selectedBlockName && getBlockType(_selectedBlockName);
return {
count: getSelectedBlockCount(),
selectedBlockClientId: _selectedBlockClientId,
selectedBlockName: _selectedBlockName,
blockType: _blockType,
topLevelLockedBlock: __unstableGetContentLockingParent(_selectedBlockClientId) || (getTemplateLock(_selectedBlockClientId) === 'contentOnly' ? _selectedBlockClientId : undefined)
};
}, []);
const availableTabs = useInspectorControlsTabs(blockType?.name);
const showTabs = availableTabs?.length > 1; // The block inspector animation settings will be completely
// removed in the future to create an API which allows the block
// inspector to transition between what it
// displays based on the relationship between the selected block
// and its parent, and only enable it if the parent is controlling
// its children blocks.
const blockInspectorAnimationSettings = useBlockInspectorAnimationSettings(blockType, selectedBlockClientId);
if (count > 1) {
return createElement("div", {
className: "block-editor-block-inspector"
}, createElement(MultiSelectionInspector, null), showTabs ? createElement(InspectorControlsTabs, {
tabs: availableTabs
}) : createElement(Fragment, null, createElement(InspectorControls.Slot, null), createElement(InspectorControls.Slot, {
group: "color",
label: __('Color'),
className: "color-block-support-panel__inner-wrapper"
}), createElement(InspectorControls.Slot, {
group: "typography",
label: __('Typography')
}), createElement(InspectorControls.Slot, {
group: "dimensions",
label: __('Dimensions')
}), createElement(InspectorControls.Slot, {
group: "border",
label: __('Border')
}), createElement(InspectorControls.Slot, {
group: "styles"
})));
}
const isSelectedBlockUnregistered = selectedBlockName === getUnregisteredTypeHandlerName();
/*
* If the selected block is of an unregistered type, avoid showing it as an actual selection
* because we want the user to focus on the unregistered block warning, not block settings.
*/
if (!blockType || !selectedBlockClientId || isSelectedBlockUnregistered) {
if (showNoBlockSelectedMessage) {
return createElement("span", {
className: "block-editor-block-inspector__no-blocks"
}, __('No block selected.'));
}
return null;
}
if (topLevelLockedBlock) {
return createElement(BlockInspectorLockedBlocks, {
topLevelLockedBlock: topLevelLockedBlock
});
}
return createElement(BlockInspectorSingleBlockWrapper, {
animate: blockInspectorAnimationSettings,
wrapper: children => createElement(AnimatedContainer, {
blockInspectorAnimationSettings: blockInspectorAnimationSettings,
selectedBlockClientId: selectedBlockClientId
}, children)
}, createElement(BlockInspectorSingleBlock, {
clientId: selectedBlockClientId,
blockName: blockType.name
}));
};
const BlockInspectorSingleBlockWrapper = ({
animate,
wrapper,
children
}) => {
return animate ? wrapper(children) : children;
};
const AnimatedContainer = ({
blockInspectorAnimationSettings,
selectedBlockClientId,
children
}) => {
const animationOrigin = blockInspectorAnimationSettings && blockInspectorAnimationSettings.enterDirection === 'leftToRight' ? -50 : 50;
return createElement(motion.div, {
animate: {
x: 0,
opacity: 1,
transition: {
ease: 'easeInOut',
duration: 0.14
}
},
initial: {
x: animationOrigin,
opacity: 0
},
key: selectedBlockClientId
}, children);
};
const BlockInspectorSingleBlock = ({
clientId,
blockName
}) => {
const availableTabs = useInspectorControlsTabs(blockName);
const showTabs = availableTabs?.length > 1;
const hasBlockStyles = useSelect(select => {
const {
getBlockStyles
} = select(blocksStore);
const blockStyles = getBlockStyles(blockName);
return blockStyles && blockStyles.length > 0;
}, [blockName]);
const blockInformation = useBlockDisplayInformation(clientId);
return createElement("div", {
className: "block-editor-block-inspector"
}, createElement(BlockCard, _extends({}, blockInformation, {
className: blockInformation.isSynced && 'is-synced'
})), createElement(BlockVariationTransforms, {
blockClientId: clientId
}), createElement(BlockInfo.Slot, null), showTabs && createElement(InspectorControlsTabs, {
hasBlockStyles: hasBlockStyles,
clientId: clientId,
blockName: blockName,
tabs: availableTabs
}), !showTabs && createElement(Fragment, null, hasBlockStyles && createElement("div", null, createElement(PanelBody, {
title: __('Styles')
}, createElement(BlockStyles, {
clientId: clientId
}), hasBlockSupport(blockName, 'defaultStylePicker', true) && createElement(DefaultStylePicker, {
blockName: blockName
}))), createElement(InspectorControls.Slot, null), createElement(InspectorControls.Slot, {
group: "list"
}), createElement(InspectorControls.Slot, {
group: "color",
label: __('Color'),
className: "color-block-support-panel__inner-wrapper"
}), createElement(InspectorControls.Slot, {
group: "typography",
label: __('Typography')
}), createElement(InspectorControls.Slot, {
group: "dimensions",
label: __('Dimensions')
}), createElement(InspectorControls.Slot, {
group: "border",
label: __('Border')
}), createElement(InspectorControls.Slot, {
group: "styles"
}), createElement(PositionControls, null), createElement("div", null, createElement(AdvancedControls, null))), createElement(SkipToSelectedBlock, {
key: "back"
}));
};
/**
* @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/block-inspector/README.md
*/
export default BlockInspector;
//# sourceMappingURL=index.js.map