Skip to content

Commit

Permalink
[Mobile] Fix regressions with wrapper props and font size customizati…
Browse files Browse the repository at this point in the history
…on (#56985)

* Mobile - Hooks - Use createBlockListBlockFilter

* Mobile - Typography - Refactor the code to incorporate the latest changes from its web counterpart

* Mobile - BlockList: Apply editor.BlockListBlock filter to fix issue with missing block props, as well as refactoring the getEditWrapperProps logic to use the same approach as its web counterpart

* Mobile - Test helpers - Add more global styles data: font sizes and line height

* Mobile - Font Size Picker - Improvde the accessibility label for the Font Size selector

* Mobile - Paragraph tests - Add test for font size and line height customization

* Mobile - Safe guard from an undefined wrapperProps value

* Mobile - Fix having the default font sizes when there are theme font sizes available

* Mobile - Global styles context test - Remove default font sizes

* Mobile - Paragraph tests - Update tests to use modal helpers

* Mobile - Paragraph tests - Adds test to check if the available font sizes are the ones expected with no duplicates

* Update Changelog
  • Loading branch information
geriux authored and artemiomorales committed Jan 4, 2024
1 parent e86fc55 commit 5ca4051
Show file tree
Hide file tree
Showing 10 changed files with 363 additions and 95 deletions.
59 changes: 39 additions & 20 deletions packages/block-editor/src/components/block-list/block.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* External dependencies
*/
import { Pressable, View } from 'react-native';
import classnames from 'classnames';

/**
* WordPress dependencies
Expand All @@ -12,6 +13,7 @@ import {
getMergedGlobalStyles,
useMobileGlobalStylesColors,
useGlobalStyles,
withFilters,
} from '@wordpress/components';
import {
__experimentalGetAccessibleBlockLabel as getAccessibleBlockLabel,
Expand Down Expand Up @@ -42,20 +44,36 @@ import { useSettings } from '../use-settings';

const EMPTY_ARRAY = [];

// Helper function to memoize the wrapperProps since getEditWrapperProps always returns a new reference.
const wrapperPropsCache = new WeakMap();
const emptyObj = {};
function getWrapperProps( value, getWrapperPropsFunction ) {
if ( ! getWrapperPropsFunction ) {
return emptyObj;
/**
* Merges wrapper props with special handling for classNames and styles.
*
* @param {Object} propsA
* @param {Object} propsB
*
* @return {Object} Merged props.
*/
function mergeWrapperProps( propsA, propsB ) {
const newProps = {
...propsA,
...propsB,
};

// May be set to undefined, so check if the property is set!
if (
propsA?.hasOwnProperty( 'className' ) &&
propsB?.hasOwnProperty( 'className' )
) {
newProps.className = classnames( propsA.className, propsB.className );
}
const cachedValue = wrapperPropsCache.get( value );
if ( ! cachedValue ) {
const wrapperProps = getWrapperPropsFunction( value );
wrapperPropsCache.set( value, wrapperProps );
return wrapperProps;

if (
propsA?.hasOwnProperty( 'style' ) &&
propsB?.hasOwnProperty( 'style' )
) {
newProps.style = { ...propsA.style, ...propsB.style };
}
return cachedValue;

return newProps;
}

function BlockWrapper( {
Expand Down Expand Up @@ -136,6 +154,7 @@ function BlockListBlock( {
rootClientId,
setAttributes,
toggleSelection,
wrapperProps,
} ) {
const {
baseGlobalStyles,
Expand Down Expand Up @@ -252,12 +271,11 @@ function BlockListBlock( {
[ blockWidth, setBlockWidth ]
);

// Block level styles.
let wrapperProps = {};
// Determine whether the block has props to apply to the wrapper.
if ( blockType?.getEditWrapperProps ) {
wrapperProps = getWrapperProps(
attributes,
blockType.getEditWrapperProps
wrapperProps = mergeWrapperProps(
wrapperProps,
blockType.getEditWrapperProps( attributes )
);
}

Expand All @@ -266,7 +284,7 @@ function BlockListBlock( {
return getMergedGlobalStyles(
baseGlobalStyles,
globalStyle,
wrapperProps.style,
wrapperProps?.style,
attributes,
defaultColors,
name,
Expand All @@ -284,7 +302,7 @@ function BlockListBlock( {
// eslint-disable-next-line react-hooks/exhaustive-deps
JSON.stringify( globalStyle ),
// eslint-disable-next-line react-hooks/exhaustive-deps
JSON.stringify( wrapperProps.style ),
JSON.stringify( wrapperProps?.style ),
// eslint-disable-next-line react-hooks/exhaustive-deps
JSON.stringify(
Object.fromEntries(
Expand Down Expand Up @@ -651,5 +669,6 @@ export default compose(
// Block is sometimes not mounted at the right time, causing it be undefined
// see issue for more info
// https://github.com/WordPress/gutenberg/issues/17013
ifCondition( ( { block } ) => !! block )
ifCondition( ( { block } ) => !! block ),
withFilters( 'editor.BlockListBlock' )
)( BlockListBlock );
7 changes: 4 additions & 3 deletions packages/block-editor/src/hooks/index.native.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
/**
* Internal dependencies
*/
import { createBlockEditFilter } from './utils';
import { createBlockEditFilter, createBlockListBlockFilter } from './utils';
import './compat';
import align from './align';
import anchor from './anchor';
import './custom-class-name';
import './generated-class-name';
import style from './style';
import './color';
import './font-size';
import color from './color';
import fontSize from './font-size';
import './layout';

createBlockEditFilter( [ align, anchor, style ] );
createBlockListBlockFilter( [ align, style, color, fontSize ] );

export { getBorderClassesAndStyles, useBorderProps } from './use-border-props';
export { getColorClassesAndStyles, useColorProps } from './use-color-props';
Expand Down
64 changes: 31 additions & 33 deletions packages/block-editor/src/hooks/typography.native.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,48 @@
/**
* WordPress dependencies
*/
import { hasBlockSupport } from '@wordpress/blocks';
/**
* External dependencies
*/
import { useSelect } from '@wordpress/data';
import { pure } from '@wordpress/compose';
import { PanelBody } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import InspectorControls from '../components/inspector-controls';
import { useHasTypographyPanel } from '../components/global-styles/typography-panel';

import {
LINE_HEIGHT_SUPPORT_KEY,
LineHeightEdit,
useIsLineHeightDisabled,
} from './line-height';
import {
FONT_SIZE_SUPPORT_KEY,
FontSizeEdit,
useIsFontSizeDisabled,
} from './font-size';
import { store as blockEditorStore } from '../store';

import { LINE_HEIGHT_SUPPORT_KEY, LineHeightEdit } from './line-height';
import { FONT_SIZE_SUPPORT_KEY, FontSizeEdit } from './font-size';

export const TYPOGRAPHY_SUPPORT_KEY = 'typography';
export const TYPOGRAPHY_SUPPORT_KEYS = [
LINE_HEIGHT_SUPPORT_KEY,
FONT_SIZE_SUPPORT_KEY,
];

export function TypographyPanel( props ) {
const isDisabled = useIsTypographyDisabled( props );
const isSupported = hasTypographySupport( props.name );

if ( isDisabled || ! isSupported ) return null;
function TypographyPanelPure( { clientId, setAttributes, settings } ) {
function selector( select ) {
const { style, fontFamily, fontSize } =
select( blockEditorStore ).getBlockAttributes( clientId ) || {};
return { style, fontFamily, fontSize };
}
const { style, fontSize } = useSelect( selector, [ clientId ] );
const isEnabled = useHasTypographyPanel( settings );

if ( ! isEnabled ) {
return null;
}

const props = {
attributes: {
fontSize,
style,
},
setAttributes,
};

return (
<InspectorControls>
Expand All @@ -46,17 +54,7 @@ export function TypographyPanel( props ) {
);
}

const hasTypographySupport = ( blockName ) => {
return TYPOGRAPHY_SUPPORT_KEYS.some( ( key ) =>
hasBlockSupport( blockName, key )
);
};

function useIsTypographyDisabled( props = {} ) {
const configs = [
useIsFontSizeDisabled( props ),
useIsLineHeightDisabled( props ),
];

return configs.filter( Boolean ).length === configs.length;
}
// We don't want block controls to re-render when typing inside a block. `pure`
// will prevent re-renders unless props change, so only pass the needed props
// and not the whole attributes object.
export const TypographyPanel = pure( TypographyPanelPure );
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,15 @@ exports[`Paragraph block should render without crashing and match snapshot 1`] =
/>
</View>
`;

exports[`Paragraph block should set a font size value 1`] = `
"<!-- wp:paragraph {"style":{"typography":{"fontSize":"30px"}}} -->
<p style="font-size:30px">A quick brown fox jumps over the lazy dog.</p>
<!-- /wp:paragraph -->"
`;

exports[`Paragraph block should set a line height value 1`] = `
"<!-- wp:paragraph {"style":{"typography":{"lineHeight":1.8}}} -->
<p style="line-height:1.8">A quick brown fox jumps over the lazy dog.</p>
<!-- /wp:paragraph -->"
`;
114 changes: 114 additions & 0 deletions packages/block-library/src/paragraph/test/edit.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import {
act,
addBlock,
dismissModal,
getBlock,
typeInRichText,
fireEvent,
Expand All @@ -15,6 +16,7 @@ import {
within,
withFakeTimers,
waitForElementToBeRemoved,
waitForModalVisible,
} from 'test/helpers';
import Clipboard from '@react-native-clipboard/clipboard';
import TextInputState from 'react-native/Libraries/Components/TextInput/TextInputState';
Expand Down Expand Up @@ -687,6 +689,118 @@ describe( 'Paragraph block', () => {
` );
} );

it( 'should show the expected font sizes values', async () => {
// Arrange
const screen = await initializeEditor( { withGlobalStyles: true } );
await addBlock( screen, 'Paragraph' );

// Act
const paragraphBlock = getBlock( screen, 'Paragraph' );
fireEvent.press( paragraphBlock );
const paragraphTextInput =
within( paragraphBlock ).getByPlaceholderText( 'Start writing…' );
typeInRichText(
paragraphTextInput,
'A quick brown fox jumps over the lazy dog.'
);
// Open Block Settings.
fireEvent.press( screen.getByLabelText( 'Open Settings' ) );

// Wait for Block Settings to be visible.
const blockSettingsModal = screen.getByTestId( 'block-settings-modal' );
await waitForModalVisible( blockSettingsModal );

// Open Font size settings
fireEvent.press( screen.getByLabelText( 'Font Size, Custom' ) );
await waitFor( () => screen.getByLabelText( 'Selected: Default' ) );

// Assert
const modalContent = within( blockSettingsModal );
expect( modalContent.getByLabelText( 'Small' ) ).toBeVisible();
expect( modalContent.getByText( '14px' ) ).toBeVisible();
expect( modalContent.getByLabelText( 'Medium' ) ).toBeVisible();
expect( modalContent.getByText( '17px' ) ).toBeVisible();
expect( modalContent.getByLabelText( 'Large' ) ).toBeVisible();
expect( modalContent.getByText( '30px' ) ).toBeVisible();
expect( modalContent.getByLabelText( 'Extra Large' ) ).toBeVisible();
expect( modalContent.getByText( '40px' ) ).toBeVisible();
expect(
modalContent.getByLabelText( 'Extra Extra Large' )
).toBeVisible();
expect( modalContent.getByText( '52px' ) ).toBeVisible();
} );

it( 'should set a font size value', async () => {
// Arrange
const screen = await initializeEditor( { withGlobalStyles: true } );
await addBlock( screen, 'Paragraph' );

// Act
const paragraphBlock = getBlock( screen, 'Paragraph' );
fireEvent.press( paragraphBlock );
const paragraphTextInput =
within( paragraphBlock ).getByPlaceholderText( 'Start writing…' );
typeInRichText(
paragraphTextInput,
'A quick brown fox jumps over the lazy dog.'
);
// Open Block Settings.
fireEvent.press( screen.getByLabelText( 'Open Settings' ) );

// Wait for Block Settings to be visible.
const blockSettingsModal = screen.getByTestId( 'block-settings-modal' );
await waitForModalVisible( blockSettingsModal );

// Open Font size settings
fireEvent.press( screen.getByLabelText( 'Font Size, Custom' ) );

// Tap one font size
fireEvent.press( screen.getByLabelText( 'Large' ) );

// Dismiss the Block Settings modal.
await dismissModal( blockSettingsModal );

// Assert
expect( getEditorHtml() ).toMatchSnapshot();
} );

it( 'should set a line height value', async () => {
// Arrange
const screen = await initializeEditor( { withGlobalStyles: true } );
await addBlock( screen, 'Paragraph' );

// Act
const paragraphBlock = getBlock( screen, 'Paragraph' );
fireEvent.press( paragraphBlock );
const paragraphTextInput =
within( paragraphBlock ).getByPlaceholderText( 'Start writing…' );
typeInRichText(
paragraphTextInput,
'A quick brown fox jumps over the lazy dog.'
);
// Open Block Settings.
fireEvent.press( screen.getByLabelText( 'Open Settings' ) );

// Wait for Block Settings to be visible.
const blockSettingsModal = screen.getByTestId( 'block-settings-modal' );
await waitForModalVisible( blockSettingsModal );

const lineHeightControl = screen.getByLabelText( /Line Height/ );
fireEvent.press(
within( lineHeightControl ).getByText( '1.5', { hidden: true } )
);
const lineHeightTextInput = within(
lineHeightControl
).getByDisplayValue( '1.5', { hidden: true } );
fireEvent.changeText( lineHeightTextInput, '1.8' );

// Dismiss the Block Settings modal.
await dismissModal( blockSettingsModal );

// Assert
expect( getEditorHtml() ).toMatchSnapshot();
} );

it( 'should focus on the previous Paragraph block when backspacing in an empty Paragraph block', async () => {
// Arrange
const screen = await initializeEditor();
Expand Down
Loading

0 comments on commit 5ca4051

Please sign in to comment.