UNPKG

@wordpress/block-library

Version:
594 lines (551 loc) 14.1 kB
/** * External dependencies */ import classnames from 'classnames'; import { get, includes } from 'lodash'; /** * WordPress dependencies */ import { getColorClassName, getColorObjectByAttributeValues, RichText, store as blockEditorStore, useBlockProps, } from '@wordpress/block-editor'; import { select } from '@wordpress/data'; import { create, replace, toHTMLString, __UNSTABLE_LINE_SEPARATOR, } from '@wordpress/rich-text'; /** * Internal dependencies */ import { SOLID_COLOR_CLASS } from './shared'; const blockAttributes = { value: { type: 'string', source: 'html', selector: 'blockquote', multiline: 'p', }, citation: { type: 'string', source: 'html', selector: 'cite', default: '', }, mainColor: { type: 'string', }, customMainColor: { type: 'string', }, textColor: { type: 'string', }, customTextColor: { type: 'string', }, }; function parseBorderColor( styleString ) { if ( ! styleString ) { return; } const matches = styleString.match( /border-color:([^;]+)[;]?/ ); if ( matches && matches[ 1 ] ) { return matches[ 1 ]; } } function multilineToInline( value ) { return toHTMLString( { value: replace( create( { html: value, multilineTag: 'p' } ), new RegExp( __UNSTABLE_LINE_SEPARATOR, 'g' ), '\n' ), } ); } const v5 = { attributes: { value: { type: 'string', source: 'html', selector: 'blockquote', multiline: 'p', __experimentalRole: 'content', }, citation: { type: 'string', source: 'html', selector: 'cite', default: '', __experimentalRole: 'content', }, textAlign: { type: 'string', }, }, save( { attributes } ) { const { textAlign, citation, value } = attributes; const shouldShowCitation = ! RichText.isEmpty( citation ); return ( <figure { ...useBlockProps.save( { className: classnames( { [ `has-text-align-${ textAlign }` ]: textAlign, } ), } ) } > <blockquote> <RichText.Content value={ value } multiline /> { shouldShowCitation && ( <RichText.Content tagName="cite" value={ citation } /> ) } </blockquote> </figure> ); }, migrate( { value, ...attributes } ) { return { value: multilineToInline( value ), ...attributes, }; }, }; // TODO: this is ripe for a bit of a clean up according to the example in https://developer.wordpress.org/block-editor/reference-guides/block-api/block-deprecation/#example const v4 = { attributes: { ...blockAttributes, }, save( { attributes } ) { const { mainColor, customMainColor, customTextColor, textColor, value, citation, className, } = attributes; const isSolidColorStyle = includes( className, SOLID_COLOR_CLASS ); let figureClasses, figureStyles; // Is solid color style if ( isSolidColorStyle ) { const backgroundClass = getColorClassName( 'background-color', mainColor ); figureClasses = classnames( { 'has-background': backgroundClass || customMainColor, [ backgroundClass ]: backgroundClass, } ); figureStyles = { backgroundColor: backgroundClass ? undefined : customMainColor, }; // Is normal style and a custom color is being used ( we can set a style directly with its value) } else if ( customMainColor ) { figureStyles = { borderColor: customMainColor, }; } const blockquoteTextColorClass = getColorClassName( 'color', textColor ); const blockquoteClasses = classnames( { 'has-text-color': textColor || customTextColor, [ blockquoteTextColorClass ]: blockquoteTextColorClass, } ); const blockquoteStyles = blockquoteTextColorClass ? undefined : { color: customTextColor }; return ( <figure { ...useBlockProps.save( { className: figureClasses, style: figureStyles, } ) } > <blockquote className={ blockquoteClasses } style={ blockquoteStyles } > <RichText.Content value={ value } multiline /> { ! RichText.isEmpty( citation ) && ( <RichText.Content tagName="cite" value={ citation } /> ) } </blockquote> </figure> ); }, migrate( { value, className, mainColor, customMainColor, customTextColor, ...attributes } ) { const isSolidColorStyle = includes( className, SOLID_COLOR_CLASS ); let style; if ( customMainColor ) { if ( ! isSolidColorStyle ) { // Block supports: Set style.border.color if a deprecated block has a default style and a `customMainColor` attribute. style = { border: { color: customMainColor, }, }; } else { // Block supports: Set style.color.background if a deprecated block has a solid style and a `customMainColor` attribute. style = { color: { background: customMainColor, }, }; } } // Block supports: Set style.color.text if a deprecated block has a `customTextColor` attribute. if ( customTextColor && style ) { style.color = { ...style.color, text: customTextColor, }; } return { value: multilineToInline( value ), className, backgroundColor: isSolidColorStyle ? mainColor : undefined, borderColor: isSolidColorStyle ? undefined : mainColor, textAlign: isSolidColorStyle ? 'left' : undefined, style, ...attributes, }; }, }; const v3 = { attributes: { ...blockAttributes, // figureStyle is an attribute that never existed. // We are using it as a way to access the styles previously applied to the figure. figureStyle: { source: 'attribute', selector: 'figure', attribute: 'style', }, }, save( { attributes } ) { const { mainColor, customMainColor, textColor, customTextColor, value, citation, className, figureStyle, } = attributes; const isSolidColorStyle = includes( className, SOLID_COLOR_CLASS ); let figureClasses, figureStyles; // Is solid color style if ( isSolidColorStyle ) { const backgroundClass = getColorClassName( 'background-color', mainColor ); figureClasses = classnames( { 'has-background': backgroundClass || customMainColor, [ backgroundClass ]: backgroundClass, } ); figureStyles = { backgroundColor: backgroundClass ? undefined : customMainColor, }; // Is normal style and a custom color is being used ( we can set a style directly with its value) } else if ( customMainColor ) { figureStyles = { borderColor: customMainColor, }; // If normal style and a named color are being used, we need to retrieve the color value to set the style, // as there is no expectation that themes create classes that set border colors. } else if ( mainColor ) { // Previously here we queried the color settings to know the color value // of a named color. This made the save function impure and the block was refactored, // because meanwhile a change in the editor made it impossible to query color settings in the save function. // Here instead of querying the color settings to know the color value, we retrieve the value // directly from the style previously serialized. const borderColor = parseBorderColor( figureStyle ); figureStyles = { borderColor, }; } const blockquoteTextColorClass = getColorClassName( 'color', textColor ); const blockquoteClasses = ( textColor || customTextColor ) && classnames( 'has-text-color', { [ blockquoteTextColorClass ]: blockquoteTextColorClass, } ); const blockquoteStyles = blockquoteTextColorClass ? undefined : { color: customTextColor }; return ( <figure className={ figureClasses } style={ figureStyles }> <blockquote className={ blockquoteClasses } style={ blockquoteStyles } > <RichText.Content value={ value } multiline /> { ! RichText.isEmpty( citation ) && ( <RichText.Content tagName="cite" value={ citation } /> ) } </blockquote> </figure> ); }, migrate( { value, className, figureStyle, mainColor, customMainColor, customTextColor, ...attributes } ) { const isSolidColorStyle = includes( className, SOLID_COLOR_CLASS ); let style; if ( customMainColor ) { if ( ! isSolidColorStyle ) { // Block supports: Set style.border.color if a deprecated block has a default style and a `customMainColor` attribute. style = { border: { color: customMainColor, }, }; } else { // Block supports: Set style.color.background if a deprecated block has a solid style and a `customMainColor` attribute. style = { color: { background: customMainColor, }, }; } } // Block supports: Set style.color.text if a deprecated block has a `customTextColor` attribute. if ( customTextColor && style ) { style.color = { ...style.color, text: customTextColor, }; } // If is the default style, and a main color is set, // migrate the main color value into a custom border color. // The custom border color value is retrieved by parsing the figure styles. if ( ! isSolidColorStyle && mainColor && figureStyle ) { const borderColor = parseBorderColor( figureStyle ); if ( borderColor ) { return { value: multilineToInline( value ), ...attributes, className, // Block supports: Set style.border.color if a deprecated block has `mainColor`, inline border CSS and is not a solid color style. style: { border: { color: borderColor, }, }, }; } } return { value: multilineToInline( value ), className, backgroundColor: isSolidColorStyle ? mainColor : undefined, borderColor: isSolidColorStyle ? undefined : mainColor, textAlign: isSolidColorStyle ? 'left' : undefined, style, ...attributes, }; }, }; const v2 = { attributes: blockAttributes, save( { attributes } ) { const { mainColor, customMainColor, textColor, customTextColor, value, citation, className, } = attributes; const isSolidColorStyle = includes( className, SOLID_COLOR_CLASS ); let figureClass, figureStyles; // Is solid color style if ( isSolidColorStyle ) { figureClass = getColorClassName( 'background-color', mainColor ); if ( ! figureClass ) { figureStyles = { backgroundColor: customMainColor, }; } // Is normal style and a custom color is being used ( we can set a style directly with its value) } else if ( customMainColor ) { figureStyles = { borderColor: customMainColor, }; // Is normal style and a named color is being used, we need to retrieve the color value to set the style, // as there is no expectation that themes create classes that set border colors. } else if ( mainColor ) { const colors = get( select( blockEditorStore ).getSettings(), [ 'colors' ], [] ); const colorObject = getColorObjectByAttributeValues( colors, mainColor ); figureStyles = { borderColor: colorObject.color, }; } const blockquoteTextColorClass = getColorClassName( 'color', textColor ); const blockquoteClasses = textColor || customTextColor ? classnames( 'has-text-color', { [ blockquoteTextColorClass ]: blockquoteTextColorClass, } ) : undefined; const blockquoteStyle = blockquoteTextColorClass ? undefined : { color: customTextColor }; return ( <figure className={ figureClass } style={ figureStyles }> <blockquote className={ blockquoteClasses } style={ blockquoteStyle } > <RichText.Content value={ value } multiline /> { ! RichText.isEmpty( citation ) && ( <RichText.Content tagName="cite" value={ citation } /> ) } </blockquote> </figure> ); }, migrate( { value, className, mainColor, customMainColor, customTextColor, ...attributes } ) { const isSolidColorStyle = includes( className, SOLID_COLOR_CLASS ); let style = {}; if ( customMainColor ) { if ( ! isSolidColorStyle ) { // Block supports: Set style.border.color if a deprecated block has a default style and a `customMainColor` attribute. style = { border: { color: customMainColor, }, }; } else { // Block supports: Set style.color.background if a deprecated block has a solid style and a `customMainColor` attribute. style = { color: { background: customMainColor, }, }; } } // Block supports: Set style.color.text if a deprecated block has a `customTextColor` attribute. if ( customTextColor && style ) { style.color = { ...style.color, text: customTextColor, }; } return { value: multilineToInline( value ), className, backgroundColor: isSolidColorStyle ? mainColor : undefined, borderColor: isSolidColorStyle ? undefined : mainColor, textAlign: isSolidColorStyle ? 'left' : undefined, style, ...attributes, }; }, }; const v1 = { attributes: { ...blockAttributes, }, save( { attributes } ) { const { value, citation } = attributes; return ( <blockquote> <RichText.Content value={ value } multiline /> { ! RichText.isEmpty( citation ) && ( <RichText.Content tagName="cite" value={ citation } /> ) } </blockquote> ); }, migrate( { value, ...attributes } ) { return { value: multilineToInline( value ), ...attributes, }; }, }; const v0 = { attributes: { ...blockAttributes, citation: { type: 'string', source: 'html', selector: 'footer', }, align: { type: 'string', default: 'none', }, }, save( { attributes } ) { const { value, citation, align } = attributes; return ( <blockquote className={ `align${ align }` }> <RichText.Content value={ value } multiline /> { ! RichText.isEmpty( citation ) && ( <RichText.Content tagName="footer" value={ citation } /> ) } </blockquote> ); }, migrate( { value, ...attributes } ) { return { value: multilineToInline( value ), ...attributes, }; }, }; /** * New deprecations need to be placed first * for them to have higher priority. * * Old deprecations may need to be updated as well. * * See block-deprecation.md */ export default [ v5, v4, v3, v2, v1, v0 ];