UNPKG

@wordpress/block-editor

Version:
313 lines (286 loc) 11 kB
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