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

[Components - FontSizePicker]: Use incremental sequence of numbers as labels for the available font-sizes at the segmented control (conditionally) #37038

Merged
merged 5 commits into from
Dec 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
- Wrapped `Modal` in a `forwardRef` call ([#36831](https://github.com/WordPress/gutenberg/pull/36831)).
- Unify styles for `ColorIndicator` with how they appear in Global Styles ([#37028](https://github.com/WordPress/gutenberg/pull/37028))
- Add support for rendering the `ColorPalette` in a `Dropdown` when opened in the sidebar ([#37067](https://github.com/WordPress/gutenberg/pull/37067))
- 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)

Expand Down
40 changes: 27 additions & 13 deletions packages/components/src/font-size-picker/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
44 changes: 34 additions & 10 deletions packages/components/src/font-size-picker/stories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div style={ { maxWidth: '248px' } }>
<FontSizePickerWithState
fontSizes={ fontSizes }
initialValue={ '1rem' }
initialValue={ '1.125rem' }
/>
</div>
);
Expand Down
87 changes: 87 additions & 0 deletions packages/components/src/font-size-picker/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
<FontSizePicker
fontSizes={ fontSizes }
value={ fontSizes[ 0 ].size }
/>
);
// 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(
<FontSizePicker
fontSizes={ fontSizes }
value={ fontSizes[ 0 ].size }
/>
);
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(
<FontSizePicker
fontSizes={ fontSizes }
value={ fontSizes[ 0 ].size }
/>
);
const element = screen.getByLabelText( 'Large' );
expect( element ).toBeInTheDocument();
expect( element.children ).toHaveLength( 2 );
expect( element.children[ 0 ].textContent ).toBe( '3' );
} );
} );
} );
} );
31 changes: 22 additions & 9 deletions packages/components/src/font-size-picker/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 ) {
Expand All @@ -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;
}
Expand Down