From 0404277783a179aa541cd38c0b39142545b82459 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Wed, 15 Dec 2021 10:48:42 +0200 Subject: [PATCH] [Components - FontSizePicker]: Use incremental sequence of numbers as labels for the available font-sizes at the segmented control (conditionally) (#37038) * [Components - FontSizePicker]: Add alias option in font sizes * use `T-shirt` sizes * add changelog entry * add unit tests * use incremental sequence of numbers as labels --- packages/components/CHANGELOG.md | 4 + .../components/src/font-size-picker/index.js | 40 ++++++--- .../src/font-size-picker/stories/index.js | 44 +++++++--- .../src/font-size-picker/test/index.js | 87 +++++++++++++++++++ .../components/src/font-size-picker/utils.js | 31 +++++-- 5 files changed, 174 insertions(+), 32 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 27463abf290786..49f819de165777 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -10,6 +10,10 @@ - Allowed `ToolsPanel` to register items when `panelId` is `null` due to multiple block selection ([37216](https://github.com/WordPress/gutenberg/pull/37216)). +### Enhancements + +- Show an incremental sequence of numbers (1/2/3/4/5) as a label of the font size, when we have at most five font sizes, where at least one the them contains a complex css value(clamp, var, etc..). We do this because complex css values cannot be calculated properly and the incremental sequence of numbers as labels can help the user better mentally map the different available font sizes. ([#37038](https://github.com/WordPress/gutenberg/pull/37038)) + ## 19.1.4 (2021-12-13) ### Bug Fix diff --git a/packages/components/src/font-size-picker/index.js b/packages/components/src/font-size-picker/index.js index ccb3e62fcab4b2..97c4fa39e4bd8b 100644 --- a/packages/components/src/font-size-picker/index.js +++ b/packages/components/src/font-size-picker/index.js @@ -47,23 +47,28 @@ function FontSizePicker( availableUnits: [ 'px', 'em', 'rem' ], } ); - // The main font size UI displays a toggle group when the presets are less - // than six and a select control when they are more. - // - // A select control is also used when the value of a preset cannot be - // immediately computed (eg. 'calc', 'var'). - const shouldUseSelectControl = - fontSizes.length > 5 || - fontSizes.some( ( { size } ) => ! isSimpleCssValue( size ) ); - + /** + * The main font size UI displays a toggle group when the presets are less + * than six and a select control when they are more. + */ + const fontSizesContainComplexValues = fontSizes.some( + ( { size } ) => ! isSimpleCssValue( size ) + ); + const shouldUseSelectControl = fontSizes.length > 5; const options = useMemo( () => getFontSizeOptions( shouldUseSelectControl, fontSizes, - disableCustomFontSizes + disableCustomFontSizes, + fontSizesContainComplexValues ), - [ shouldUseSelectControl, fontSizes, disableCustomFontSizes ] + [ + shouldUseSelectControl, + fontSizes, + disableCustomFontSizes, + fontSizesContainComplexValues, + ] ); const selectedOption = getSelectedOption( fontSizes, value ); const isCustomValue = selectedOption.slug === CUSTOM_FONT_SIZE; @@ -88,12 +93,21 @@ function FontSizePicker( } // Calculate the `hint` for toggle group control. let hint = selectedOption.name; - if ( typeof selectedOption.size === 'string' ) { + if ( + ! fontSizesContainComplexValues && + typeof selectedOption.size === 'string' + ) { const [ , unit ] = splitValueAndUnitFromSize( selectedOption.size ); hint += `(${ unit })`; } return hint; - }, [ showCustomValueControl, selectedOption?.slug, value, isCustomValue ] ); + }, [ + showCustomValueControl, + selectedOption?.slug, + value, + isCustomValue, + fontSizesContainComplexValues, + ] ); if ( ! options ) { return null; diff --git a/packages/components/src/font-size-picker/stories/index.js b/packages/components/src/font-size-picker/stories/index.js index 48236de9aa5a29..4f97dc9dd7d288 100644 --- a/packages/components/src/font-size-picker/stories/index.js +++ b/packages/components/src/font-size-picker/stories/index.js @@ -158,38 +158,62 @@ export const differentControlBySize = () => { }; export const withComplexCSSValues = () => { - const fontSizes = object( 'Font Sizes', [ + const options = [ { name: 'Small', slug: 'small', - size: '0.75rem', + size: '0.65rem', }, { - name: 'Normal', - slug: 'normal', - size: '1rem', + name: 'Medium', + slug: 'medium', + size: '1.125rem', }, { name: 'Large', slug: 'large', - size: '2.5rem', + size: '1.7rem', }, { name: 'Extra Large', slug: 'extra-large', - size: '3.5rem', + size: '1.95rem', + }, + { + name: 'Extra Extra Large', + slug: 'extra-extra-large', + size: '2.5rem', }, { name: 'Huge', slug: 'huge', - size: 'clamp(2.5rem, 4vw, 3rem)', + size: '2.8rem', }, - ] ); + ]; + const showMoreFontSizes = boolean( 'Add more font sizes', false ); + const addComplexCssValues = boolean( + 'Add some complex css values(calc, var, etc..)', + true + ); + + const _options = options.map( ( option, index ) => { + const _option = { ...option }; + // Adding just one complex css value is enough (first element); + if ( addComplexCssValues && ! index ) { + _option.size = 'clamp(1.75rem, 3vw, 2.25rem)'; + } + return _option; + } ); + + const fontSizes = _options.slice( + 0, + showMoreFontSizes ? _options.length : 5 + ); return (
); diff --git a/packages/components/src/font-size-picker/test/index.js b/packages/components/src/font-size-picker/test/index.js index 2742da0d774395..a1158f50e26f25 100644 --- a/packages/components/src/font-size-picker/test/index.js +++ b/packages/components/src/font-size-picker/test/index.js @@ -141,4 +141,91 @@ describe( 'FontSizePicker', () => { expect( fontSize ).toBe( '16px' ); } ); } ); + describe( 'renders different control', () => { + const options = [ + { + name: 'Small', + slug: 'small', + size: '0.65rem', + }, + { + name: 'Medium', + slug: 'medium', + size: '1.125rem', + }, + { + name: 'Large', + slug: 'large', + size: '1.7rem', + }, + ]; + it( 'should render select control when we have more than five font sizes', () => { + const extraOptions = [ + { + name: 'Extra Large', + slug: 'extra-large', + size: '1.95rem', + }, + { + name: 'Extra Extra Large', + slug: 'extra-extra-large', + size: '2.5rem', + }, + { + name: 'Huge', + slug: 'huge', + size: '2.8rem', + }, + ]; + const fontSizes = [ ...options, ...extraOptions ]; + render( + + ); + // Trigger click to open the select menu and take into account + // the two extra options (default, custom); + fireEvent.click( + screen.getByLabelText( 'Font size', { selector: 'button' } ) + ); + const element = screen.getAllByRole( 'option' ); + expect( element ).toHaveLength( fontSizes.length + 2 ); + } ); + describe( 'segmented control', () => { + it( 'should use numeric labels for simple css values', () => { + const fontSizes = [ ...options ]; + render( + + ); + const element = screen.getByLabelText( 'Large' ); + expect( element ).toBeInTheDocument(); + expect( element.children ).toHaveLength( 2 ); + expect( element.children[ 0 ].textContent ).toBe( '1.7' ); + } ); + it( 'should use incremental sequence of numbers as labels if we have complex css', () => { + const fontSizes = [ + ...options, + { + name: 'Extra Large', + slug: 'extra-large', + size: 'clamp(1.75rem, 3vw, 2.25rem)', + }, + ]; + render( + + ); + const element = screen.getByLabelText( 'Large' ); + expect( element ).toBeInTheDocument(); + expect( element.children ).toHaveLength( 2 ); + expect( element.children[ 0 ].textContent ).toBe( '3' ); + } ); + } ); + } ); } ); diff --git a/packages/components/src/font-size-picker/utils.js b/packages/components/src/font-size-picker/utils.js index 507706b4440987..cc5be4f91821e9 100644 --- a/packages/components/src/font-size-picker/utils.js +++ b/packages/components/src/font-size-picker/utils.js @@ -14,6 +14,15 @@ const CUSTOM_FONT_SIZE_OPTION = { name: __( 'Custom' ), }; +/** + * In case we have at most five font sizes, where at least one the them + * contain a complex css value(clamp, var, etc..) show a incremental sequence + * of numbers as a label of the font size. We do this because complex css values + * cannot be caluclated properly and the incremental sequence of numbers as labels + * can help the user better mentally map the different available font sizes. + */ +const FONT_SIZES_ALIASES = [ '1', '2', '3', '4', '5' ]; + /** * Helper util to split a font size to its numeric value * and its `unit`, if exists. @@ -47,22 +56,24 @@ export function isSimpleCssValue( value ) { * Return font size options in the proper format depending * on the currently used control (select, toggle group). * - * @param {boolean} useSelectControl Whether to use a select control. - * @param {Object[]} optionsArray Array of available font sizes objects. - * @param {*} disableCustomFontSizes Flag that indicates if custom font sizes are disabled. + * @param {boolean} useSelectControl Whether to use a select control. + * @param {Object[]} optionsArray Array of available font sizes objects. + * @param {*} disableCustomFontSizes Flag that indicates if custom font sizes are disabled. + * @param {boolean} optionsContainComplexCssValues Whether font sizes contain at least one complex css value(clamp, var, etc..). * @return {Object[]|null} Array of font sizes in proper format for the used control. */ export function getFontSizeOptions( useSelectControl, optionsArray, - disableCustomFontSizes + disableCustomFontSizes, + optionsContainComplexCssValues ) { if ( disableCustomFontSizes && ! optionsArray.length ) { return null; } return useSelectControl ? getSelectOptions( optionsArray, disableCustomFontSizes ) - : getToggleGroupOptions( optionsArray ); + : getToggleGroupOptions( optionsArray, optionsContainComplexCssValues ); } function getSelectOptions( optionsArray, disableCustomFontSizes ) { @@ -80,10 +91,12 @@ function getSelectOptions( optionsArray, disableCustomFontSizes ) { } ) ); } -function getToggleGroupOptions( optionsArray ) { - return optionsArray.map( ( { slug, size, name } ) => { - let label = size; - if ( typeof size === 'string' ) { +function getToggleGroupOptions( optionsArray, optionsContainComplexCssValues ) { + return optionsArray.map( ( { slug, size, name }, index ) => { + let label = optionsContainComplexCssValues + ? FONT_SIZES_ALIASES[ index ] + : size; + if ( ! optionsContainComplexCssValues && typeof size === 'string' ) { const [ numericValue ] = splitValueAndUnitFromSize( size ); label = numericValue; }