UNPKG

@wordpress/block-library

Version:
271 lines (251 loc) 7.38 kB
/** * External dependencies */ import classnames from 'classnames'; /** * WordPress dependencies */ import { __, _x } from '@wordpress/i18n'; import { Component, Fragment, } from '@wordpress/element'; import { PanelBody, ToggleControl, Toolbar, withFallbackStyles, } from '@wordpress/components'; import { withColors, AlignmentToolbar, BlockControls, ContrastChecker, FontSizePicker, InspectorControls, PanelColorSettings, RichText, withFontSizes, } from '@wordpress/block-editor'; import { createBlock } from '@wordpress/blocks'; import { compose } from '@wordpress/compose'; import { withSelect } from '@wordpress/data'; const { getComputedStyle } = window; const name = 'core/paragraph'; const applyFallbackStyles = withFallbackStyles( ( node, ownProps ) => { const { textColor, backgroundColor, fontSize, customFontSize } = ownProps.attributes; const editableNode = node.querySelector( '[contenteditable="true"]' ); //verify if editableNode is available, before using getComputedStyle. const computedStyles = editableNode ? getComputedStyle( editableNode ) : null; return { fallbackBackgroundColor: backgroundColor || ! computedStyles ? undefined : computedStyles.backgroundColor, fallbackTextColor: textColor || ! computedStyles ? undefined : computedStyles.color, fallbackFontSize: fontSize || customFontSize || ! computedStyles ? undefined : parseInt( computedStyles.fontSize ) || undefined, }; } ); class ParagraphBlock extends Component { constructor() { super( ...arguments ); this.onReplace = this.onReplace.bind( this ); this.toggleDropCap = this.toggleDropCap.bind( this ); this.splitBlock = this.splitBlock.bind( this ); } onReplace( blocks ) { const { attributes, onReplace } = this.props; onReplace( blocks.map( ( block, index ) => ( index === 0 && block.name === name ? { ...block, attributes: { ...attributes, ...block.attributes, }, } : block ) ) ); } toggleDropCap() { const { attributes, setAttributes } = this.props; setAttributes( { dropCap: ! attributes.dropCap } ); } getDropCapHelp( checked ) { return checked ? __( 'Showing large initial letter.' ) : __( 'Toggle to show a large initial letter.' ); } /** * Split handler for RichText value, namely when content is pasted or the * user presses the Enter key. * * @param {?Array} before Optional before value, to be used as content * in place of what exists currently for the * block. If undefined, the block is deleted. * @param {?Array} after Optional after value, to be appended in a new * paragraph block to the set of blocks passed * as spread. * @param {...WPBlock} blocks Optional blocks inserted between the before * and after value blocks. */ splitBlock( before, after, ...blocks ) { const { attributes, insertBlocksAfter, setAttributes, onReplace, } = this.props; if ( after !== null ) { // Append "After" content as a new paragraph block to the end of // any other blocks being inserted after the current paragraph. blocks.push( createBlock( name, { content: after } ) ); } if ( blocks.length && insertBlocksAfter ) { insertBlocksAfter( blocks ); } const { content } = attributes; if ( before === null ) { // If before content is omitted, treat as intent to delete block. onReplace( [] ); } else if ( content !== before ) { // Only update content if it has in-fact changed. In case that user // has created a new paragraph at end of an existing one, the value // of before will be strictly equal to the current content. setAttributes( { content: before } ); } } render() { const { attributes, setAttributes, mergeBlocks, onReplace, className, backgroundColor, textColor, setBackgroundColor, setTextColor, fallbackBackgroundColor, fallbackTextColor, fallbackFontSize, fontSize, setFontSize, isRTL, } = this.props; const { align, content, dropCap, placeholder, direction, } = attributes; return ( <Fragment> <BlockControls> <AlignmentToolbar value={ align } onChange={ ( nextAlign ) => { setAttributes( { align: nextAlign } ); } } /> { isRTL && ( <Toolbar controls={ [ { icon: 'editor-ltr', title: _x( 'Left to right', 'editor button' ), isActive: direction === 'ltr', onClick() { const nextDirection = direction === 'ltr' ? undefined : 'ltr'; setAttributes( { direction: nextDirection, } ); }, }, ] } /> ) } </BlockControls> <InspectorControls> <PanelBody title={ __( 'Text Settings' ) } className="blocks-font-size"> <FontSizePicker fallbackFontSize={ fallbackFontSize } value={ fontSize.size } onChange={ setFontSize } /> <ToggleControl label={ __( 'Drop Cap' ) } checked={ !! dropCap } onChange={ this.toggleDropCap } help={ this.getDropCapHelp } /> </PanelBody> <PanelColorSettings title={ __( 'Color Settings' ) } initialOpen={ false } colorSettings={ [ { value: backgroundColor.color, onChange: setBackgroundColor, label: __( 'Background Color' ), }, { value: textColor.color, onChange: setTextColor, label: __( 'Text Color' ), }, ] } > <ContrastChecker { ...{ textColor: textColor.color, backgroundColor: backgroundColor.color, fallbackTextColor, fallbackBackgroundColor, } } fontSize={ fontSize.size } /> </PanelColorSettings> </InspectorControls> <RichText identifier="content" tagName="p" className={ classnames( 'wp-block-paragraph', className, { 'has-text-color': textColor.color, 'has-background': backgroundColor.color, 'has-drop-cap': dropCap, [ backgroundColor.class ]: backgroundColor.class, [ textColor.class ]: textColor.class, [ fontSize.class ]: fontSize.class, } ) } style={ { backgroundColor: backgroundColor.color, color: textColor.color, fontSize: fontSize.size ? fontSize.size + 'px' : undefined, textAlign: align, direction, } } value={ content } onChange={ ( nextContent ) => { setAttributes( { content: nextContent, } ); } } unstableOnSplit={ this.splitBlock } onMerge={ mergeBlocks } onReplace={ this.onReplace } onRemove={ () => onReplace( [] ) } aria-label={ content ? __( 'Paragraph block' ) : __( 'Empty block; start writing or type forward slash to choose a block' ) } placeholder={ placeholder || __( 'Start writing or type / to choose a block' ) } /> </Fragment> ); } } const ParagraphEdit = compose( [ withColors( 'backgroundColor', { textColor: 'color' } ), withFontSizes( 'fontSize' ), applyFallbackStyles, withSelect( ( select ) => { const { getSettings } = select( 'core/block-editor' ); return { isRTL: getSettings().isRTL, }; } ), ] )( ParagraphBlock ); export default ParagraphEdit;