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

[RNMobile] Adjust font sizes in RichText based on device settings #57055

Closed
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* External dependencies
*/
import { PixelRatio } from 'react-native';

const clamp = ( value, min, max ) => {
return Math.min( Math.max( value, min ), max );
};

/**
* Function to adjust font size for screen display based on user's device settings.
*
* This function calculates an adjusted font size by scaling the provided `currentFontSize`
* according to the user's device font scale settings. This is particularly useful for
* respecting accessibility preferences such as larger text sizes set by the user.
*
* The calculated font size is then clamped within the specified range defined by
* `minFontSize` and `maxFontSize` to ensure it remains within a reasonable and
* manageable range for the app's UI.
*
* @param {number} currentFontSize - The base font size to be adjusted.
* @param {number} minFontSize - The minimum font size limit for the adjustment.
* @param {number} maxFontSize - The maximum font size limit for the adjustment.
* @return {number} - The adjusted font size.
*/
export function getScreenAdjustedFontSize(
currentFontSize,
minFontSize = 10,
maxFontSize = 100
) {
if ( typeof currentFontSize !== 'number' || isNaN( currentFontSize ) ) {
return undefined;
}

const fontScale = PixelRatio.getFontScale() ?? 1;
const scaledFontSize = currentFontSize * fontScale;
const fontSize = clamp( scaledFontSize, minFontSize, maxFontSize );
return fontSize;
}
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,13 @@ describe( '<RichText/>', () => {
it( `should display rich text at the font size computed from the LOCAL \`style.fontSize\` CSS with HIGHEST PRIORITY
when CSS is provided ambiguously from ALL possible sources.`, () => {
// Arrange.
const expectedFontSize = 1;
const expectedFontSize = 10;
mockGlobalSettings( { fontSize: '0' } );
// Act.
const { getByLabelText } = render(
<RichText
accessibilityLabel={ 'editor' }
style={ { fontSize: '1' } }
style={ { fontSize: '10' } }
fontSize={ '2' }
tagName="p"
/>
Expand All @@ -188,13 +188,13 @@ describe( '<RichText/>', () => {
it( `should display rich text at the font size computed from the LOCAL \`style.fontSize\` CSS with
NEXT PRIORITY when CSS is provided ambiguously from MULTIPLE possible sources EXCLUDING \`fontSize\`.`, () => {
// Arrange.
const expectedFontSize = 1;
const expectedFontSize = 10;
mockGlobalSettings( { fontSize: '0' } );
// Act.
const { getByLabelText } = render(
<RichText
accessibilityLabel={ 'editor' }
style={ { fontSize: '1' } }
style={ { fontSize: '10' } }
tagName="p"
/>
);
Expand All @@ -205,8 +205,8 @@ describe( '<RichText/>', () => {

it( 'should display rich text at the font size computed from CSS relative to the VIEWPORT WIDTH.', () => {
// Arrange.
const expectedFontSize = 3;
Dimensions.set( { window: { ...window, width: 300 } } );
const expectedFontSize = 10;
Dimensions.set( { window: { ...window, width: 1000 } } );
// Act.
const { getByLabelText } = render(
<RichText accessibilityLabel={ 'editor' } fontSize={ '1vw' } />
Expand All @@ -218,8 +218,8 @@ describe( '<RichText/>', () => {

it( 'should display rich text at the font size computed from CSS relative to the VIEWPORT HEIGHT.', () => {
// Arrange.
const expectedFontSize = 3;
Dimensions.set( { window: { ...window, height: 300 } } );
const expectedFontSize = 10;
Dimensions.set( { window: { ...window, height: 1000 } } );
// Act.
const { getByLabelText } = render(
<RichText accessibilityLabel={ 'editor' } fontSize={ '1vh' } />
Expand Down
6 changes: 5 additions & 1 deletion test/native/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/
import 'react-native-gesture-handler/jestSetup';
import mockSafeAreaContext from 'react-native-safe-area-context/jest/mock';
import { Image, Linking } from 'react-native';
import { Image, Linking, PixelRatio } from 'react-native';

// React Native sets up a global navigator, but that is not executed in the
// testing environment: https://github.com/facebook/react-native/blob/6c19dc3266b84f47a076b647a1c93b3c3b69d2c5/Libraries/Core/setUpNavigator.js#L17
Expand Down Expand Up @@ -280,3 +280,7 @@ jest.mock( '@wordpress/compose', () => {
jest.spyOn( Image, 'getSize' ).mockImplementation( ( url, success ) =>
success( 0, 0 )
);

// Jest's environment returns pixel ratio, not font scale, when getFontScale() is called.
// It's necessary to mock this method to return 1, the standard default for most devices.
jest.spyOn( PixelRatio, 'getFontScale' ).mockImplementation( () => 1 );
Loading