Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make font size an implicit attribute of the block #21153

Merged
merged 13 commits into from
Apr 6, 2020
15 changes: 14 additions & 1 deletion packages/block-editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ _Parameters_

_Returns_

- `?string`: If fontSizeAttribute is set and an equal slug is found in fontSizes it returns the font size object for that slug. Otherwise, an object with just the size value based on customFontSize is returned.
- `?Object`: If fontSizeAttribute is set and an equal slug is found in fontSizes it returns the font size object for that slug. Otherwise, an object with just the size value based on customFontSize is returned.

<a name="getFontSizeClass" href="#getFontSizeClass">#</a> **getFontSizeClass**

Expand All @@ -304,6 +304,19 @@ _Returns_

- `string`: String with the class corresponding to the fontSize passed. The class is generated by appending 'has-' followed by fontSizeSlug in kebabCase and ending with '-font-size'.

<a name="getFontSizeObjectByValue" href="#getFontSizeObjectByValue">#</a> **getFontSizeObjectByValue**

Returns the corresponding font size object for a given value.

_Parameters_

- _fontSizes_ `Array`: Array of font size objects.
- _value_ `number`: Font size value.

_Returns_

- `Object`: Font size object.

<a name="InnerBlocks" href="#InnerBlocks">#</a> **InnerBlocks**

_Related_
Expand Down
6 changes: 5 additions & 1 deletion packages/block-editor/src/components/font-sizes/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
export { getFontSize, getFontSizeClass } from './utils';
export {
getFontSize,
getFontSizeClass,
getFontSizeObjectByValue,
} from './utils';
export { default as FontSizePicker } from './font-size-picker';
export { default as withFontSizes } from './with-font-sizes';
21 changes: 20 additions & 1 deletion packages/block-editor/src/components/font-sizes/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { find, kebabCase } from 'lodash';
* @param {?string} fontSizeAttribute Content of the font size attribute (slug).
* @param {?number} customFontSizeAttribute Contents of the custom font size attribute (value).
*
* @return {?string} If fontSizeAttribute is set and an equal slug is found in fontSizes it returns the font size object for that slug.
* @return {?Object} If fontSizeAttribute is set and an equal slug is found in fontSizes it returns the font size object for that slug.
* Otherwise, an object with just the size value based on customFontSize is returned.
*/
export const getFontSize = (
Expand All @@ -30,6 +30,25 @@ export const getFontSize = (
};
};

/**
* Returns the corresponding font size object for a given value.
*
* @param {Array} fontSizes Array of font size objects.
* @param {number} value Font size value.
*
* @return {Object} Font size object.
*/
export function getFontSizeObjectByValue( fontSizes, value ) {
const fontSizeObject = find( fontSizes, { size: value } );
if ( fontSizeObject ) {
return fontSizeObject;
}

return {
size: value,
};
}

/**
* Returns a class based on fontSizeName.
*
Expand Down
127 changes: 57 additions & 70 deletions packages/block-editor/src/hooks/color.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import classnames from 'classnames';
*/
import { addFilter } from '@wordpress/hooks';
import { hasBlockSupport } from '@wordpress/blocks';
import { createHigherOrderComponent } from '@wordpress/compose';
import { __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';

Expand Down Expand Up @@ -115,75 +114,69 @@ export function addEditProps( settings ) {
}

/**
* Override the default edit UI to include new inspector controls for block
* color, if block defines support.
* Inspector control panel containing the color related configuration
*
* @param {Function} BlockEdit Original component
* @return {Function} Wrapped component
* @param {Object} props
*
* @return {WPElement} Color edit element.
*/
export const withBlockControls = createHigherOrderComponent(
( BlockEdit ) => ( props ) => {
const { name: blockName } = props;
const colors = useSelect( ( select ) => {
return select( 'core/block-editor' ).getSettings().colors;
}, [] );

if ( ! hasBlockSupport( blockName, COLOR_SUPPORT_KEY ) ) {
return <BlockEdit key="edit" { ...props } />;
}
const { style, textColor, backgroundColor } = props.attributes;

const onChangeColor = ( name ) => ( value ) => {
const colorObject = getColorObjectByColorValue( colors, value );
const attributeName = name + 'Color';
const newStyle = {
...style,
color: {
...style?.color,
[ name ]: colorObject?.slug ? undefined : value,
},
};
const newNamedColor = colorObject?.slug
? colorObject.slug
: undefined;
props.setAttributes( {
style: cleanEmptyObject( newStyle ),
[ attributeName ]: newNamedColor,
} );
export function ColorEdit( props ) {
const { name: blockName } = props;
const colors = useSelect( ( select ) => {
return select( 'core/block-editor' ).getSettings().colors;
}, [] );

if ( ! hasBlockSupport( blockName, COLOR_SUPPORT_KEY ) ) {
return null;
}
const { style, textColor, backgroundColor } = props.attributes;

const onChangeColor = ( name ) => ( value ) => {
const colorObject = getColorObjectByColorValue( colors, value );
const attributeName = name + 'Color';
const newStyle = {
...style,
color: {
...style?.color,
[ name ]: colorObject?.slug ? undefined : value,
},
};
const newNamedColor = colorObject?.slug ? colorObject.slug : undefined;
props.setAttributes( {
style: cleanEmptyObject( newStyle ),
[ attributeName ]: newNamedColor,
} );
};

return [
<ColorPanel
key="colors"
clientId={ props.clientId }
colorSettings={ [
{
label: __( 'Text Color' ),
onChange: onChangeColor( 'text' ),
return (
<ColorPanel
key="colors"
clientId={ props.clientId }
colorSettings={ [
{
label: __( 'Text Color' ),
onChange: onChangeColor( 'text' ),
colors,
value: getColorObjectByAttributeValues(
colors,
value: getColorObjectByAttributeValues(
colors,
textColor,
style?.color?.text
).color,
},
{
label: __( 'Background Color' ),
onChange: onChangeColor( 'background' ),
textColor,
style?.color?.text
).color,
},
{
label: __( 'Background Color' ),
onChange: onChangeColor( 'background' ),
colors,
value: getColorObjectByAttributeValues(
colors,
value: getColorObjectByAttributeValues(
colors,
backgroundColor,
style?.color?.background
).color,
},
] }
/>,
<BlockEdit key="edit" { ...props } />,
];
},
'withToolbarControls'
);
backgroundColor,
style?.color?.background
).color,
},
] }
/>
);
}

addFilter(
'blocks.registerBlockType',
Expand All @@ -202,9 +195,3 @@ addFilter(
'core/color/addEditProps',
addEditProps
);

addFilter(
'editor.BlockEdit',
'core/color/with-block-controls',
withBlockControls
);
151 changes: 151 additions & 0 deletions packages/block-editor/src/hooks/font-size.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/**
* WordPress dependencies
*/
import { addFilter } from '@wordpress/hooks';
import { hasBlockSupport } from '@wordpress/blocks';
import { useSelect } from '@wordpress/data';
import TokenList from '@wordpress/token-list';

/**
* Internal dependencies
*/
import {
getFontSize,
getFontSizeClass,
getFontSizeObjectByValue,
FontSizePicker,
} from '../components/font-sizes';
import { cleanEmptyObject } from './utils';

export const FONT_SIZE_SUPPORT_KEY = '__experimentalFontSize';

/**
* Filters registered block settings, extending attributes to include
* `fontSize` and `fontWeight` attributes.
*
* @param {Object} settings Original block settings
* @return {Object} Filtered block settings
*/
function addAttributes( settings ) {
if ( ! hasBlockSupport( settings, FONT_SIZE_SUPPORT_KEY ) ) {
return settings;
}

// Allow blocks to specify a default value if needed.
if ( ! settings.attributes.fontSize ) {
Object.assign( settings.attributes, {
fontSize: {
type: 'string',
},
} );
}

return settings;
}

/**
* Override props assigned to save component to inject font size.
*
* @param {Object} props Additional props applied to save element
* @param {Object} blockType Block type
* @param {Object} attributes Block attributes
* @return {Object} Filtered props applied to save element
*/
function addSaveProps( props, blockType, attributes ) {
if ( ! hasBlockSupport( blockType, FONT_SIZE_SUPPORT_KEY ) ) {
return props;
}

// Use TokenList to dedupe classes.
const classes = new TokenList( props.className );
classes.add( getFontSizeClass( attributes.fontSize ) );
const newClassName = classes.value;
props.className = newClassName ? newClassName : undefined;
Copy link
Member Author

@oandregal oandregal Apr 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noting here that this has the side-effect of removing duplicated classes for old blocks that are updated. I can't think of any reason why this would be a problem but thought to highlight anyway before merging. cc @youknowriad

I've tested this with old content (preset values, custom values, duplicated classes) and works nicely, so I'm going to land in a few hours.


return props;
}

/**
* Filters registered block settings to expand the block edit wrapper
* by applying the desired styles and classnames.
*
* @param {Object} settings Original block settings
* @return {Object} Filtered block settings
*/
function addEditProps( settings ) {
if ( ! hasBlockSupport( settings, FONT_SIZE_SUPPORT_KEY ) ) {
return settings;
}

const existingGetEditWrapperProps = settings.getEditWrapperProps;
settings.getEditWrapperProps = ( attributes ) => {
let props = {};
if ( existingGetEditWrapperProps ) {
props = existingGetEditWrapperProps( attributes );
}
return addSaveProps( props, settings, attributes );
};

return settings;
}

/**
* Inspector control panel containing the font size related configuration
*
* @param {Object} props
*
* @return {WPElement} Font size edit element.
*/
export function FontSizeEdit( props ) {
const {
name: blockName,
attributes: { fontSize, style },
setAttributes,
} = props;

const { fontSizes } = useSelect( ( select ) =>
select( 'core/block-editor' ).getSettings()
);

if ( ! hasBlockSupport( blockName, FONT_SIZE_SUPPORT_KEY ) ) {
return null;
}

const fontSizeObject = getFontSize(
fontSizes,
fontSize,
style?.typography?.fontSize
);
const onChange = ( value ) => {
const fontSizeSlug = getFontSizeObjectByValue( fontSizes, value ).slug;

setAttributes( {
style: cleanEmptyObject( {
...style,
typography: {
...style?.typography,
fontSize: fontSizeSlug ? undefined : value,
},
} ),
fontSize: fontSizeSlug,
} );
};

return (
<FontSizePicker value={ fontSizeObject.size } onChange={ onChange } />
);
}

addFilter(
'blocks.registerBlockType',
'core/font/addAttribute',
addAttributes
);

addFilter(
'blocks.getSaveContent.extraProps',
'core/font/addSaveProps',
addSaveProps
);

addFilter( 'blocks.registerBlockType', 'core/font/addEditProps', addEditProps );
1 change: 1 addition & 0 deletions packages/block-editor/src/hooks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ import './custom-class-name';
import './generated-class-name';
import './style';
import './color';
import './font-size';

export { AlignmentHookSettingsProvider };
Loading