UNPKG

@wordpress/block-editor

Version:
215 lines (200 loc) 5.64 kB
/** * WordPress dependencies */ import { createHigherOrderComponent, compose } from '@wordpress/compose'; import { Component } from '@wordpress/element'; /** * Internal dependencies */ import { getFontSize, getFontSizeClass } from './utils'; import { useSettings } from '../use-settings'; const DEFAULT_FONT_SIZES = []; /** * Capitalizes the first letter in a string. * * @param {string} str The string whose first letter the function will capitalize. * * @return {string} Capitalized string. */ const upperFirst = ( [ firstLetter, ...rest ] ) => firstLetter.toUpperCase() + rest.join( '' ); /** * Higher-order component, which handles font size logic for class generation, * font size value retrieval, and font size change handling. * * @param {...(Object|string)} fontSizeNames The arguments should all be strings. * Each string contains the font size * attribute name e.g: 'fontSize'. * * @return {Function} Higher-order component. */ export default ( ...fontSizeNames ) => { /* * Computes an object whose key is the font size attribute name as passed in the array, * and the value is the custom font size attribute name. * Custom font size is automatically compted by appending custom followed by the font size attribute name in with the first letter capitalized. */ const fontSizeAttributeNames = fontSizeNames.reduce( ( fontSizeAttributeNamesAccumulator, fontSizeAttributeName ) => { fontSizeAttributeNamesAccumulator[ fontSizeAttributeName ] = `custom${ upperFirst( fontSizeAttributeName ) }`; return fontSizeAttributeNamesAccumulator; }, {} ); return createHigherOrderComponent( compose( [ createHigherOrderComponent( ( WrappedComponent ) => ( props ) => { const [ fontSizes ] = useSettings( 'typography.fontSizes' ); return ( <WrappedComponent { ...props } fontSizes={ fontSizes || DEFAULT_FONT_SIZES } /> ); }, 'withFontSizes' ), ( WrappedComponent ) => { return class extends Component { constructor( props ) { super( props ); this.setters = this.createSetters(); this.state = {}; } createSetters() { return Object.entries( fontSizeAttributeNames ).reduce( ( settersAccumulator, [ fontSizeAttributeName, customFontSizeAttributeName, ] ) => { const upperFirstFontSizeAttributeName = upperFirst( fontSizeAttributeName ); settersAccumulator[ `set${ upperFirstFontSizeAttributeName }` ] = this.createSetFontSize( fontSizeAttributeName, customFontSizeAttributeName ); return settersAccumulator; }, {} ); } createSetFontSize( fontSizeAttributeName, customFontSizeAttributeName ) { return ( fontSizeValue ) => { const fontSizeObject = this.props.fontSizes?.find( ( { size } ) => size === Number( fontSizeValue ) ); this.props.setAttributes( { [ fontSizeAttributeName ]: fontSizeObject && fontSizeObject.slug ? fontSizeObject.slug : undefined, [ customFontSizeAttributeName ]: fontSizeObject && fontSizeObject.slug ? undefined : fontSizeValue, } ); }; } static getDerivedStateFromProps( { attributes, fontSizes }, previousState ) { const didAttributesChange = ( customFontSizeAttributeName, fontSizeAttributeName ) => { if ( previousState[ fontSizeAttributeName ] ) { // If new font size is name compare with the previous slug. if ( attributes[ fontSizeAttributeName ] ) { return ( attributes[ fontSizeAttributeName ] !== previousState[ fontSizeAttributeName ] .slug ); } // If font size is not named, update when the font size value changes. return ( previousState[ fontSizeAttributeName ] .size !== attributes[ customFontSizeAttributeName ] ); } // In this case we need to build the font size object. return true; }; if ( ! Object.values( fontSizeAttributeNames ).some( didAttributesChange ) ) { return null; } const newState = Object.entries( fontSizeAttributeNames ) .filter( ( [ key, value ] ) => didAttributesChange( value, key ) ) .reduce( ( newStateAccumulator, [ fontSizeAttributeName, customFontSizeAttributeName, ] ) => { const fontSizeAttributeValue = attributes[ fontSizeAttributeName ]; const fontSizeObject = getFontSize( fontSizes, fontSizeAttributeValue, attributes[ customFontSizeAttributeName ] ); newStateAccumulator[ fontSizeAttributeName ] = { ...fontSizeObject, class: getFontSizeClass( fontSizeAttributeValue ), }; return newStateAccumulator; }, {} ); return { ...previousState, ...newState, }; } render() { return ( <WrappedComponent { ...{ ...this.props, fontSizes: undefined, ...this.state, ...this.setters, } } /> ); } }; }, ] ), 'withFontSizes' ); };