UNPKG

@wordpress/block-library

Version:
191 lines (175 loc) 5.17 kB
/** * WordPress dependencies */ import { BlockControls, useBlockProps, useInnerBlocksProps, store as blockEditorStore, } from '@wordpress/block-editor'; import { ToolbarButton } from '@wordpress/components'; import { useDispatch, useSelect, useRegistry } from '@wordpress/data'; import { isRTL, __ } from '@wordpress/i18n'; import { formatListBullets, formatListBulletsRTL, formatListNumbered, formatListNumberedRTL, formatOutdent, formatOutdentRTL, } from '@wordpress/icons'; import { createBlock } from '@wordpress/blocks'; import { useCallback, useEffect, Platform } from '@wordpress/element'; import deprecated from '@wordpress/deprecated'; /** * Internal dependencies */ import OrderedListSettings from './ordered-list-settings'; import { migrateToListV2 } from './utils'; import TagName from './tag-name'; const DEFAULT_BLOCK = { name: 'core/list-item', }; const TEMPLATE = [ [ 'core/list-item' ] ]; const NATIVE_MARGIN_SPACING = 8; /** * At the moment, deprecations don't handle create blocks from attributes * (like when using CPT templates). For this reason, this hook is necessary * to avoid breaking templates using the old list block format. * * @param {Object} attributes Block attributes. * @param {string} clientId Block client ID. */ function useMigrateOnLoad( attributes, clientId ) { const registry = useRegistry(); const { updateBlockAttributes, replaceInnerBlocks } = useDispatch( blockEditorStore ); useEffect( () => { // As soon as the block is loaded, migrate it to the new version. if ( ! attributes.values ) { return; } const [ newAttributes, newInnerBlocks ] = migrateToListV2( attributes ); deprecated( 'Value attribute on the list block', { since: '6.0', version: '6.5', alternative: 'inner blocks', } ); registry.batch( () => { updateBlockAttributes( clientId, newAttributes ); replaceInnerBlocks( clientId, newInnerBlocks ); } ); }, [ attributes.values ] ); } function useOutdentList( clientId ) { const { replaceBlocks, selectionChange } = useDispatch( blockEditorStore ); const { getBlockRootClientId, getBlockAttributes, getBlock } = useSelect( blockEditorStore ); return useCallback( () => { const parentBlockId = getBlockRootClientId( clientId ); const parentBlockAttributes = getBlockAttributes( parentBlockId ); // Create a new parent block without the inner blocks. const newParentBlock = createBlock( 'core/list-item', parentBlockAttributes ); const { innerBlocks } = getBlock( clientId ); // Replace the parent block with a new parent block without inner blocks, // and make the inner blocks siblings of the parent. replaceBlocks( [ parentBlockId ], [ newParentBlock, ...innerBlocks ] ); // Select the last child of the list being outdent. selectionChange( innerBlocks[ innerBlocks.length - 1 ].clientId ); }, [ clientId ] ); } function IndentUI( { clientId } ) { const outdentList = useOutdentList( clientId ); const canOutdent = useSelect( ( select ) => { const { getBlockRootClientId, getBlockName } = select( blockEditorStore ); return ( getBlockName( getBlockRootClientId( clientId ) ) === 'core/list-item' ); }, [ clientId ] ); return ( <> <ToolbarButton icon={ isRTL() ? formatOutdentRTL : formatOutdent } title={ __( 'Outdent' ) } description={ __( 'Outdent list item' ) } disabled={ ! canOutdent } onClick={ outdentList } /> </> ); } export default function Edit( { attributes, setAttributes, clientId, style } ) { const { ordered, type, reversed, start } = attributes; const blockProps = useBlockProps( { style: { ...( Platform.isNative && style ), listStyleType: ordered && type !== 'decimal' ? type : undefined, }, } ); const innerBlocksProps = useInnerBlocksProps( blockProps, { defaultBlock: DEFAULT_BLOCK, directInsert: true, template: TEMPLATE, templateLock: false, templateInsertUpdatesSelection: true, ...( Platform.isNative && { marginVertical: NATIVE_MARGIN_SPACING, marginHorizontal: NATIVE_MARGIN_SPACING, renderAppender: false, } ), __experimentalCaptureToolbars: true, } ); useMigrateOnLoad( attributes, clientId ); const controls = ( <BlockControls group="block"> <ToolbarButton icon={ isRTL() ? formatListBulletsRTL : formatListBullets } title={ __( 'Unordered' ) } description={ __( 'Convert to unordered list' ) } isActive={ ordered === false } onClick={ () => { setAttributes( { ordered: false } ); } } /> <ToolbarButton icon={ isRTL() ? formatListNumberedRTL : formatListNumbered } title={ __( 'Ordered' ) } description={ __( 'Convert to ordered list' ) } isActive={ ordered === true } onClick={ () => { setAttributes( { ordered: true } ); } } /> <IndentUI clientId={ clientId } /> </BlockControls> ); return ( <> <TagName ordered={ ordered } reversed={ reversed } start={ start } { ...innerBlocksProps } /> { controls } { ordered && ( <OrderedListSettings { ...{ setAttributes, reversed, start, type, } } /> ) } </> ); }