From a9f23ba2562162f0f3a8f14ea6a96ebe069ac95a Mon Sep 17 00:00:00 2001 From: Jon Quach Date: Fri, 27 Mar 2020 12:54:29 -0400 Subject: [PATCH] Paragraph: Add LineHeightControl + Attribute (#20775) * 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 * Remove unused import * Remove useless hooks file Co-authored-by: Riad Benguella Co-authored-by: Zebulan Stanphill --- lib/client-assets.php | 13 +++ packages/block-editor/src/components/index.js | 1 + .../src/components/index.native.js | 1 + .../components/line-height-control/index.js | 88 +++++++++++++++++++ .../components/line-height-control/style.scss | 8 ++ .../components/line-height-control/utils.js | 44 ++++++++++ packages/block-editor/src/hooks/color.js | 15 +--- .../block-editor/src/hooks/line-height.js | 64 ++++++++++++++ packages/block-editor/src/hooks/style.js | 3 +- packages/block-editor/src/hooks/test/color.js | 2 +- .../src/hooks/test/{anchor.js => utils.js} | 0 packages/block-editor/src/hooks/utils.js | 23 +++++ packages/block-editor/src/style.scss | 1 + .../block-library/src/paragraph/block.json | 5 +- packages/block-library/src/paragraph/edit.js | 14 +-- packages/block-library/src/paragraph/index.js | 1 + .../block-library/src/paragraph/style.scss | 1 + .../specs/editor/various/embedding.test.js | 2 +- .../editor/src/components/provider/index.js | 1 + packages/editor/src/editor-styles.scss | 1 - packages/keycodes/README.md | 4 + packages/keycodes/src/index.js | 4 + 22 files changed, 271 insertions(+), 25 deletions(-) create mode 100644 packages/block-editor/src/components/line-height-control/index.js create mode 100644 packages/block-editor/src/components/line-height-control/style.scss create mode 100644 packages/block-editor/src/components/line-height-control/utils.js create mode 100644 packages/block-editor/src/hooks/line-height.js rename packages/block-editor/src/hooks/test/{anchor.js => utils.js} (100%) create mode 100644 packages/block-editor/src/hooks/utils.js diff --git a/lib/client-assets.php b/lib/client-assets.php index 1f3016019b6dc7..9c05c51667eb7a 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -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. diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index 0fd7fb2d4fb09b..0463948da0ce36 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -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'; diff --git a/packages/block-editor/src/components/index.native.js b/packages/block-editor/src/components/index.native.js index 130cde1c2303bb..a970323a0350d9 100644 --- a/packages/block-editor/src/components/index.native.js +++ b/packages/block-editor/src/components/index.native.js @@ -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, diff --git a/packages/block-editor/src/components/line-height-control/index.js b/packages/block-editor/src/components/line-height-control/index.js new file mode 100644 index 00000000000000..4aa913901a80b7 --- /dev/null +++ b/packages/block-editor/src/components/line-height-control/index.js @@ -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 ( +
+ +
+ ); +} diff --git a/packages/block-editor/src/components/line-height-control/style.scss b/packages/block-editor/src/components/line-height-control/style.scss new file mode 100644 index 00000000000000..ad98d76e4a2ed1 --- /dev/null +++ b/packages/block-editor/src/components/line-height-control/style.scss @@ -0,0 +1,8 @@ +.block-editor-line-height-control { + margin-bottom: 24px; + + input { + display: block; + max-width: 60px; + } +} diff --git a/packages/block-editor/src/components/line-height-control/utils.js b/packages/block-editor/src/components/line-height-control/utils.js new file mode 100644 index 00000000000000..351a35a66a6a0a --- /dev/null +++ b/packages/block-editor/src/components/line-height-control/utils.js @@ -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; +} diff --git a/packages/block-editor/src/hooks/color.js b/packages/block-editor/src/hooks/color.js index f02476e82caeca..61d85140cf249b 100644 --- a/packages/block-editor/src/hooks/color.js +++ b/packages/block-editor/src/hooks/color.js @@ -2,7 +2,6 @@ * External dependencies */ import classnames from 'classnames'; -import { pickBy, isEqual, isObject, identity, mapValues } from 'lodash'; /** * WordPress dependencies @@ -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. diff --git a/packages/block-editor/src/hooks/line-height.js b/packages/block-editor/src/hooks/line-height.js new file mode 100644 index 00000000000000..6f813032218118 --- /dev/null +++ b/packages/block-editor/src/hooks/line-height.js @@ -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 ; + } + const { style } = props.attributes; + const onChange = ( newLineHeightValue ) => { + const newStyle = { + ...style, + typography: { + lineHeight: newLineHeightValue, + }, + }; + props.setAttributes( { + style: cleanEmptyObject( newStyle ), + } ); + }; + + return [ + + + + + , + , + ]; + }, + 'withToolbarControls' +); + +addFilter( + 'editor.BlockEdit', + 'core/color/with-block-controls', + withBlockControls +); diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js index 5eea58cea5b9f4..9ffd3fd34d0ca7 100644 --- a/packages/block-editor/src/hooks/style.js +++ b/packages/block-editor/src/hooks/style.js @@ -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 ) ); diff --git a/packages/block-editor/src/hooks/test/color.js b/packages/block-editor/src/hooks/test/color.js index d8644c931a3e58..9c3361ce80c950 100644 --- a/packages/block-editor/src/hooks/test/color.js +++ b/packages/block-editor/src/hooks/test/color.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { cleanEmptyObject } from '../color'; +import { cleanEmptyObject } from '../utils'; describe( 'cleanEmptyObject', () => { it( 'should remove nested keys', () => { diff --git a/packages/block-editor/src/hooks/test/anchor.js b/packages/block-editor/src/hooks/test/utils.js similarity index 100% rename from packages/block-editor/src/hooks/test/anchor.js rename to packages/block-editor/src/hooks/test/utils.js diff --git a/packages/block-editor/src/hooks/utils.js b/packages/block-editor/src/hooks/utils.js new file mode 100644 index 00000000000000..dba018f2cfc8aa --- /dev/null +++ b/packages/block-editor/src/hooks/utils.js @@ -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; +}; diff --git a/packages/block-editor/src/style.scss b/packages/block-editor/src/style.scss index cdf78fbc8f4981..3f4ae8b3b31369 100644 --- a/packages/block-editor/src/style.scss +++ b/packages/block-editor/src/style.scss @@ -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"; diff --git a/packages/block-library/src/paragraph/block.json b/packages/block-library/src/paragraph/block.json index ff252ec7760a3a..dc3d4ef895c8e7 100644 --- a/packages/block-library/src/paragraph/block.json +++ b/packages/block-library/src/paragraph/block.json @@ -26,7 +26,10 @@ }, "direction": { "type": "string", - "enum": [ "ltr", "rtl" ] + "enum": [ + "ltr", + "rtl" + ] } } } diff --git a/packages/block-library/src/paragraph/edit.js b/packages/block-library/src/paragraph/edit.js index cda1879390d2cf..e09aecea77c810 100644 --- a/packages/block-library/src/paragraph/edit.js +++ b/packages/block-library/src/paragraph/edit.js @@ -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 ( <> @@ -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 } ) diff --git a/packages/block-library/src/paragraph/index.js b/packages/block-library/src/paragraph/index.js index c04c011c1b0c67..9ce400ec4077d1 100644 --- a/packages/block-library/src/paragraph/index.js +++ b/packages/block-library/src/paragraph/index.js @@ -41,6 +41,7 @@ export const settings = { __unstablePasteTextInline: true, lightBlockWrapper: true, __experimentalColor: true, + __experimentalLineHeight: true, }, __experimentalLabel( attributes, { context } ) { if ( context === 'accessibility' ) { diff --git a/packages/block-library/src/paragraph/style.scss b/packages/block-library/src/paragraph/style.scss index f43612c851d1fe..9c0f3d7edc7612 100644 --- a/packages/block-library/src/paragraph/style.scss +++ b/packages/block-library/src/paragraph/style.scss @@ -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 { diff --git a/packages/e2e-tests/specs/editor/various/embedding.test.js b/packages/e2e-tests/specs/editor/various/embedding.test.js index b33a24fd787208..9e30ec116f3c37 100644 --- a/packages/e2e-tests/specs/editor/various/embedding.test.js +++ b/packages/e2e-tests/specs/editor/various/embedding.test.js @@ -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 ); diff --git a/packages/editor/src/components/provider/index.js b/packages/editor/src/components/provider/index.js index 555b7b88f02509..5cbd7751736b93 100644 --- a/packages/editor/src/components/provider/index.js +++ b/packages/editor/src/components/provider/index.js @@ -123,6 +123,7 @@ class EditorProvider extends Component { '__experimentalEnableFullSiteEditingDemo', '__experimentalGlobalStylesUserEntityId', '__experimentalGlobalStylesBase', + '__experimentalDisableCustomLineHeight', 'gradients', ] ), mediaUpload: hasUploadPermissions ? mediaUpload : undefined, diff --git a/packages/editor/src/editor-styles.scss b/packages/editor/src/editor-styles.scss index f8eee44a116938..a7608813a5fcc2 100644 --- a/packages/editor/src/editor-styles.scss +++ b/packages/editor/src/editor-styles.scss @@ -95,7 +95,6 @@ h6 { p { font-size: inherit; - line-height: inherit; margin-top: $default-block-margin; margin-bottom: $default-block-margin; } diff --git a/packages/keycodes/README.md b/packages/keycodes/README.md index 7d54480a89b4bd..bb7036ba95de74 100644 --- a/packages/keycodes/README.md +++ b/packages/keycodes/README.md @@ -162,6 +162,10 @@ Keycode for TAB key. Keycode for UP key. +# **ZERO** + +Keycode for ZERO key. + diff --git a/packages/keycodes/src/index.js b/packages/keycodes/src/index.js index 16a002973ec070..fc975909aa4e4d 100644 --- a/packages/keycodes/src/index.js +++ b/packages/keycodes/src/index.js @@ -95,6 +95,10 @@ export const COMMAND = 'meta'; * Keycode for SHIFT key. */ export const SHIFT = 'shift'; +/** + * Keycode for ZERO key. + */ +export const ZERO = 48; /** * Object that contains functions that return the available modifier