UNPKG

@gechiui/block-editor

Version:
183 lines (165 loc) 4.13 kB
/** * External dependencies */ import { find, noop } from 'lodash'; import classnames from 'classnames'; /** * GeChiUI dependencies */ import { useMemo } from '@gechiui/element'; import { useSelect, useDispatch } from '@gechiui/data'; import { ENTER, SPACE } from '@gechiui/keycodes'; import { _x } from '@gechiui/i18n'; import { getBlockType, cloneBlock, getBlockFromExample, store as blocksStore, } from '@gechiui/blocks'; /** * Internal dependencies */ import { getActiveStyle, replaceActiveStyle } from './utils'; import BlockPreview from '../block-preview'; import { store as blockEditorStore } from '../../store'; const EMPTY_OBJECT = {}; function useGenericPreviewBlock( block, type ) { return useMemo( () => { const example = type?.example; const blockName = type?.name; if ( example && blockName ) { return getBlockFromExample( blockName, { attributes: example.attributes, innerBlocks: example.innerBlocks, } ); } if ( block ) { return cloneBlock( block ); } }, [ type?.example ? block?.name : block, type ] ); } function BlockStyles( { clientId, onSwitch = noop, onHoverClassName = noop, itemRole, } ) { const selector = ( select ) => { const { getBlock } = select( blockEditorStore ); const block = getBlock( clientId ); if ( ! block ) { return EMPTY_OBJECT; } const blockType = getBlockType( block.name ); const { getBlockStyles } = select( blocksStore ); return { block, type: blockType, styles: getBlockStyles( block.name ), className: block.attributes.className || '', }; }; const { styles, block, type, className } = useSelect( selector, [ clientId, ] ); const { updateBlockAttributes } = useDispatch( blockEditorStore ); const genericPreviewBlock = useGenericPreviewBlock( block, type ); if ( ! styles || styles.length === 0 ) { return null; } const renderedStyles = find( styles, 'isDefault' ) ? styles : [ { name: 'default', label: _x( 'Default', 'block style' ), isDefault: true, }, ...styles, ]; const activeStyle = getActiveStyle( renderedStyles, className ); return ( <div className="block-editor-block-styles"> { renderedStyles.map( ( style ) => { const styleClassName = replaceActiveStyle( className, activeStyle, style ); return ( <BlockStyleItem genericPreviewBlock={ genericPreviewBlock } viewportWidth={ type.example?.viewportWidth ?? 500 } className={ className } isActive={ activeStyle === style } key={ style.name } onSelect={ () => { updateBlockAttributes( clientId, { className: styleClassName, } ); onHoverClassName( null ); onSwitch(); } } onBlur={ () => onHoverClassName( null ) } onHover={ () => onHoverClassName( styleClassName ) } style={ style } styleClassName={ styleClassName } itemRole={ itemRole } /> ); } ) } </div> ); } function BlockStyleItem( { genericPreviewBlock, viewportWidth, style, isActive, onBlur, onHover, onSelect, styleClassName, itemRole, } ) { const previewBlocks = useMemo( () => { return { ...genericPreviewBlock, attributes: { ...genericPreviewBlock.attributes, className: styleClassName, }, }; }, [ genericPreviewBlock, styleClassName ] ); return ( <div key={ style.name } className={ classnames( 'block-editor-block-styles__item', { 'is-active': isActive, } ) } onClick={ () => onSelect() } onKeyDown={ ( event ) => { if ( ENTER === event.keyCode || SPACE === event.keyCode ) { event.preventDefault(); onSelect(); } } } onMouseEnter={ onHover } onMouseLeave={ onBlur } role={ itemRole || 'button' } tabIndex="0" aria-label={ style.label || style.name } > <div className="block-editor-block-styles__item-preview"> <BlockPreview viewportWidth={ viewportWidth } blocks={ previewBlocks } /> </div> <div className="block-editor-block-styles__item-label"> { style.label || style.name } </div> </div> ); } export default BlockStyles;