Skip to content

Commit

Permalink
Paragraph: Add LineHeightControl + Attribute (#20775)
Browse files Browse the repository at this point in the history
* Update emotion library to latest. Adds to block-library package.

* Add LineHeightControl component to block-editor

* Export LineHeightControl as experimental from block-editor

* Hook up LineHeightControl with core Paragraph block

* Improve undefined/reset interactions for line-height attribute

* Refactor store hook usage with LineHeightControl

* Refactor with withLineHeight HOC for Edit and Save components

* Improve reset logic. Simplifies stlye value output.

* Refactor function names and comments

* Fix import/export of new experimental attribute hooks

* Export LineHeightControls and withLineHeight for native

* Adjust mechanism to get block attributes in useBlockAttributes hook

* Add theme support for disable-custom-line-height

* Clarify logic + add comments for lineHeight attribute -> value evaluation

* Simplify CSS output for lineHeight in paragraph block

* Add experimental prefix for disableCustomLineHeight setting

* Add comment for :root based CSS rule

* Removes @emotion from block-library. Refactor to use scss

* Remove withLineHeight HOC abstraction.

Reverted to use inline styles instead of CSS variable for line-height style rendering

* Revert className implementation

Also revert @emotion library versions to master

* Revert @emotion/native from 10.0.23 -> 10.0.22 (to match master)

* Updates package-lock.json

* Fix e2e test to target correct text input

* Reverting package-lock.json

* Provide clientId in dependency array in useSetAttributes hook

* Use CSS variables and a support flag for the line height customization

* Improves handling of "zero" key press

* Update packages/block-editor/src/components/line-height-control/utils.js

Co-Authored-By: Zebulan Stanphill <zebulanstanphill@protonmail.com>

* Remove unused import

* Remove useless hooks file

Co-authored-by: Riad Benguella <benguella@gmail.com>
Co-authored-by: Zebulan Stanphill <zebulanstanphill@protonmail.com>
  • Loading branch information
3 people authored Mar 27, 2020
1 parent 65520ef commit a9f23ba
Show file tree
Hide file tree
Showing 22 changed files with 271 additions and 25 deletions.
13 changes: 13 additions & 0 deletions lib/client-assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,19 @@ function gutenberg_extend_settings_block_patterns( $settings ) {
}
add_filter( 'block_editor_settings', 'gutenberg_extend_settings_block_patterns', 0 );

/**
* Extends block editor settings to determine whether to use custom line height controls.
* Currently experimental.
*
* @param array $settings Default editor settings.
*
* @return array Filtered editor settings.
*/
function gutenberg_extend_settings_custom_line_height( $settings ) {
$settings['__experimentalDisableCustomLineHeight'] = get_theme_support( 'disable-custom-line-height' );
return $settings;
}
add_filter( 'block_editor_settings', 'gutenberg_extend_settings_custom_line_height' );

/*
* Register default patterns if not registered in Core already.
Expand Down
1 change: 1 addition & 0 deletions packages/block-editor/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export { default as InnerBlocks } from './inner-blocks';
export { default as InspectorAdvancedControls } from './inspector-advanced-controls';
export { default as InspectorControls } from './inspector-controls';
export { default as __experimentalLinkControl } from './link-control';
export { default as __experimentalLineHeightControl } from './line-height-control';
export { default as MediaReplaceFlow } from './media-replace-flow';
export { default as MediaPlaceholder } from './media-placeholder';
export { default as MediaUpload } from './media-upload';
Expand Down
1 change: 1 addition & 0 deletions packages/block-editor/src/components/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export * from './font-sizes';
export { default as AlignmentToolbar } from './alignment-toolbar';
export { default as InnerBlocks } from './inner-blocks';
export { default as InspectorControls } from './inspector-controls';
export { default as __experimentalLineHeightControl } from './line-height-control';
export { default as PlainText } from './plain-text';
export {
default as RichText,
Expand Down
88 changes: 88 additions & 0 deletions packages/block-editor/src/components/line-height-control/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { TextControl } from '@wordpress/components';
import { ZERO } from '@wordpress/keycodes';

/**
* Internal dependencies
*/
import {
BASE_DEFAULT_VALUE,
RESET_VALUE,
STEP,
useIsLineHeightControlsDisabled,
isLineHeightDefined,
} from './utils';

export default function LineHeightControl( { value: lineHeight, onChange } ) {
const isDisabled = useIsLineHeightControlsDisabled();
const isDefined = isLineHeightDefined( lineHeight );

// Don't render the controls if disabled by editor settings
if ( isDisabled ) {
return null;
}

const handleOnKeyDown = ( event ) => {
const { keyCode } = event;

if ( keyCode === ZERO && ! isDefined ) {
/**
* Prevents the onChange callback from firing, which prevents
* the logic from assuming the change was triggered from
* an input arrow CLICK.
*/
event.preventDefault();
onChange( '0' );
}
};

const handleOnChange = ( nextValue ) => {
// Set the next value without modification if lineHeight has been defined
if ( isDefined ) {
onChange( nextValue );
return;
}

// Otherwise...
/**
* The following logic handles the initial up/down arrow CLICK of the
* input element. This is so that the next values (from an undefined value state)
* are more better suited for line-height rendering.
*/
let adjustedNextValue = nextValue;

switch ( nextValue ) {
case `${ STEP }`:
// Increment by step value
adjustedNextValue = BASE_DEFAULT_VALUE + STEP;
break;
case '0':
// Decrement by step value
adjustedNextValue = BASE_DEFAULT_VALUE - STEP;
break;
}

onChange( adjustedNextValue );
};

const value = isDefined ? lineHeight : RESET_VALUE;

return (
<div className="block-editor-line-height-control">
<TextControl
autoComplete="off"
onKeyDown={ handleOnKeyDown }
onChange={ handleOnChange }
label={ __( 'Line height' ) }
placeholder={ BASE_DEFAULT_VALUE }
step={ STEP }
type="number"
value={ value }
min={ 0 }
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.block-editor-line-height-control {
margin-bottom: 24px;

input {
display: block;
max-width: 60px;
}
}
44 changes: 44 additions & 0 deletions packages/block-editor/src/components/line-height-control/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';

export const BASE_DEFAULT_VALUE = 1.5;
export const STEP = 0.1;
/**
* There are varying value types within LineHeightControl:
*
* {undefined} Initial value. No changes from the user.
* {string} Input value. Value consumed/outputted by the input. Empty would be ''.
* {number} Block attribute type. Input value needs to be converted for attribute setting.
*
* Note: If the value is undefined, the input requires it to be an empty string ('')
* in order to be considered "controlled" by props (rather than internal state).
*/
export const RESET_VALUE = '';

/**
* Retrieves whether custom lineHeight controls should be disabled from editor settings.
*
* @return {boolean} Whether lineHeight controls should be disabled.
*/
export function useIsLineHeightControlsDisabled() {
const isDisabled = useSelect( ( select ) => {
const { getSettings } = select( 'core/block-editor' );

return !! getSettings().__experimentalDisableCustomLineHeight;
}, [] );

return isDisabled;
}

/**
* Determines if the lineHeight attribute has been properly defined.
*
* @param {any} lineHeight The value to check.
*
* @return {boolean} Whether the lineHeight attribute is valid.
*/
export function isLineHeightDefined( lineHeight ) {
return lineHeight !== undefined && lineHeight !== RESET_VALUE;
}
15 changes: 1 addition & 14 deletions packages/block-editor/src/hooks/color.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* External dependencies
*/
import classnames from 'classnames';
import { pickBy, isEqual, isObject, identity, mapValues } from 'lodash';

/**
* WordPress dependencies
Expand All @@ -26,22 +25,10 @@ import PanelColorSettings from '../components/panel-color-settings';
import ContrastChecker from '../components/contrast-checker';
import InspectorControls from '../components/inspector-controls';
import { getBlockDOMNode } from '../utils/dom';
import { cleanEmptyObject } from './utils';

export const COLOR_SUPPORT_KEY = '__experimentalColor';

export const cleanEmptyObject = ( object ) => {
if ( ! isObject( object ) ) {
return object;
}
const cleanedNestedObjects = pickBy(
mapValues( object, cleanEmptyObject ),
identity
);
return isEqual( cleanedNestedObjects, {} )
? undefined
: cleanedNestedObjects;
};

/**
* Filters registered block settings, extending attributes to include
* `backgroundColor` and `textColor` attribute.
Expand Down
64 changes: 64 additions & 0 deletions packages/block-editor/src/hooks/line-height.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* WordPress dependencies
*/
import { addFilter } from '@wordpress/hooks';
import { hasBlockSupport } from '@wordpress/blocks';
import { createHigherOrderComponent } from '@wordpress/compose';
import { PanelBody } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import LineHeightControl from '../components/line-height-control';
import InspectorControls from '../components/inspector-controls';
import { cleanEmptyObject } from './utils';

export const LINE_HEIGHT_SUPPRT_KEY = '__experimentalLineHeight';

/**
* Override the default edit UI to include new inspector controls for block
* color, if block defines support.
*
* @param {Function} BlockEdit Original component
* @return {Function} Wrapped component
*/
export const withBlockControls = createHigherOrderComponent(
( BlockEdit ) => ( props ) => {
const { name: blockName } = props;
if ( ! hasBlockSupport( blockName, LINE_HEIGHT_SUPPRT_KEY ) ) {
return <BlockEdit key="edit" { ...props } />;
}
const { style } = props.attributes;
const onChange = ( newLineHeightValue ) => {
const newStyle = {
...style,
typography: {
lineHeight: newLineHeightValue,
},
};
props.setAttributes( {
style: cleanEmptyObject( newStyle ),
} );
};

return [
<InspectorControls key="control">
<PanelBody title={ __( 'Typography' ) }>
<LineHeightControl
value={ style?.typography?.lineHeight }
onChange={ onChange }
/>
</PanelBody>
</InspectorControls>,
<BlockEdit key="edit" { ...props } />,
];
},
'withToolbarControls'
);

addFilter(
'editor.BlockEdit',
'core/color/with-block-controls',
withBlockControls
);
3 changes: 2 additions & 1 deletion packages/block-editor/src/hooks/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import { hasBlockSupport } from '@wordpress/blocks';
* Internal dependencies
*/
import { COLOR_SUPPORT_KEY } from './color';
import { LINE_HEIGHT_SUPPRT_KEY } from './line-height';

const styleSupportKeys = [ COLOR_SUPPORT_KEY ];
const styleSupportKeys = [ COLOR_SUPPORT_KEY, LINE_HEIGHT_SUPPRT_KEY ];

const hasStyleSupport = ( blockType ) =>
styleSupportKeys.some( ( key ) => hasBlockSupport( blockType, key ) );
Expand Down
2 changes: 1 addition & 1 deletion packages/block-editor/src/hooks/test/color.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Internal dependencies
*/
import { cleanEmptyObject } from '../color';
import { cleanEmptyObject } from '../utils';

describe( 'cleanEmptyObject', () => {
it( 'should remove nested keys', () => {
Expand Down
23 changes: 23 additions & 0 deletions packages/block-editor/src/hooks/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* External dependencies
*/
import { pickBy, isEqual, isObject, identity, mapValues } from 'lodash';

/**
* Removed undefined values from nested object.
*
* @param {*} object
* @return {*} Object cleaned from undefined values
*/
export const cleanEmptyObject = ( object ) => {
if ( ! isObject( object ) ) {
return object;
}
const cleanedNestedObjects = pickBy(
mapValues( object, cleanEmptyObject ),
identity
);
return isEqual( cleanedNestedObjects, {} )
? undefined
: cleanedNestedObjects;
};
1 change: 1 addition & 0 deletions packages/block-editor/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
@import "./components/contrast-checker/style.scss";
@import "./components/default-block-appender/style.scss";
@import "./components/link-control/style.scss";
@import "./components/line-height-control/style.scss";
@import "./components/image-size-control/style.scss";
@import "./components/inner-blocks/style.scss";
@import "./components/inserter-list-item/style.scss";
Expand Down
5 changes: 4 additions & 1 deletion packages/block-library/src/paragraph/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@
},
"direction": {
"type": "string",
"enum": [ "ltr", "rtl" ]
"enum": [
"ltr",
"rtl"
]
}
}
}
14 changes: 8 additions & 6 deletions packages/block-library/src/paragraph/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,19 @@ function ParagraphBlock( {
setAttributes,
setFontSize,
} ) {
const { align, content, dropCap, placeholder, direction } = attributes;
const { align, content, direction, dropCap, placeholder } = attributes;

const ref = useRef();
const dropCapMinimumHeight = useDropCapMinimumHeight( dropCap, [
fontSize.size,
] );

const styles = {
fontSize: fontSize.size ? `${ fontSize.size }px` : undefined,
direction,
minHeight: dropCapMinimumHeight,
};

return (
<>
<BlockControls>
Expand Down Expand Up @@ -132,11 +138,7 @@ function ParagraphBlock( {
[ `has-text-align-${ align }` ]: align,
[ fontSize.class ]: fontSize.class,
} ) }
style={ {
fontSize: fontSize.size ? fontSize.size + 'px' : undefined,
direction,
minHeight: dropCapMinimumHeight,
} }
style={ styles }
value={ content }
onChange={ ( newContent ) =>
setAttributes( { content: newContent } )
Expand Down
1 change: 1 addition & 0 deletions packages/block-library/src/paragraph/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const settings = {
__unstablePasteTextInline: true,
lightBlockWrapper: true,
__experimentalColor: true,
__experimentalLineHeight: true,
},
__experimentalLabel( attributes, { context } ) {
if ( context === 'accessibility' ) {
Expand Down
1 change: 1 addition & 0 deletions packages/block-library/src/paragraph/style.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
:root p {
background-color: var(--wp--color--background);
color: var(--wp--color--text);
line-height: var(--wp--typography--line-height);
}

.is-small-text {
Expand Down
2 changes: 1 addition & 1 deletion packages/e2e-tests/specs/editor/various/embedding.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ describe( 'Embedding content', () => {
await page.keyboard.type( 'Hello there!' );
await publishPost();
const postUrl = await page.$eval(
'[id^=inspector-text-control-]',
'.editor-post-publish-panel [id^=inspector-text-control-]',
( el ) => el.value
);

Expand Down
Loading

0 comments on commit a9f23ba

Please sign in to comment.