Skip to content

Commit

Permalink
Do not mutate output of flattenStyle (#45340)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #45340

flattenStyle may return an object which is already frozen (in development), so it is incorrect to further mutate this.

Changelog: [Internal]

Reviewed By: cortinico

Differential Revision: D59515063

fbshipit-source-id: 92df158d5841988d40bcd76b861963b06dad1573
  • Loading branch information
javache authored and facebook-github-bot committed Jul 9, 2024
1 parent 0733e36 commit ef2e941
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 15 deletions.
26 changes: 17 additions & 9 deletions packages/react-native/Libraries/Text/Text.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* @format
*/

import type {____TextStyle_Internal as TextStyleInternal} from '../StyleSheet/StyleSheetTypes';
import type {PressEvent} from '../Types/CoreEventTypes';
import type {NativeTextProps} from './TextNativeComponent';
import type {PressRetentionOffset, TextProps} from './TextProps';
Expand Down Expand Up @@ -132,25 +133,32 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =

let _selectable = selectable;

const processedStyle = flattenStyle(_style);
let processedStyle: ?TextStyleInternal = flattenStyle(_style);
if (processedStyle != null) {
let overrides: ?{...TextStyleInternal} = null;
if (typeof processedStyle.fontWeight === 'number') {
// $FlowFixMe[cannot-write]
processedStyle.fontWeight = processedStyle.fontWeight.toString();
overrides = overrides || ({}: {...TextStyleInternal});
overrides.fontWeight =
// $FlowFixMe[incompatible-cast]
(processedStyle.fontWeight.toString(): TextStyleInternal['fontWeight']);
}

if (processedStyle.userSelect != null) {
_selectable = userSelectToSelectableMap[processedStyle.userSelect];
// $FlowFixMe[cannot-write]
delete processedStyle.userSelect;
overrides = overrides || ({}: {...TextStyleInternal});
overrides.userSelect = undefined;
}

if (processedStyle.verticalAlign != null) {
// $FlowFixMe[cannot-write]
processedStyle.textAlignVertical =
overrides = overrides || ({}: {...TextStyleInternal});
overrides.textAlignVertical =
verticalAlignToTextAlignVerticalMap[processedStyle.verticalAlign];
// $FlowFixMe[cannot-write]
delete processedStyle.verticalAlign;
overrides.verticalAlign = undefined;
}

if (overrides != null) {
// $FlowFixMe[incompatible-type]
processedStyle = [processedStyle, overrides];
}
}

Expand Down
18 changes: 12 additions & 6 deletions packages/react-native/Libraries/Text/__tests__/Text-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,28 @@

'use strict';

import flattenStyle from '../../StyleSheet/flattenStyle';
import React from 'react';

const render = require('../../../jest/renderer');
const Text = require('../Text');
const React = require('react');

jest.unmock('../Text');
jest.unmock('../TextNativeComponent');

function omitRef(json) {
function omitRefAndFlattenStyle(instance) {
const json = instance.toJSON();
// Omit `ref` for forward-compatibility with `enableRefAsProp`.
delete json.props.ref;
json.props.style = flattenStyle(json.props.style);
return json;
}

describe('Text', () => {
it('default render', async () => {
const instance = await render.create(<Text />);

expect(omitRef(instance.toJSON())).toMatchInlineSnapshot(`
expect(omitRefAndFlattenStyle(instance)).toMatchInlineSnapshot(`
<RCTText
accessible={true}
allowFontScaling={true}
Expand All @@ -53,7 +57,7 @@ describe('Text compat with web', () => {

const instance = await render.create(<Text {...props} />);

expect(omitRef(instance.toJSON())).toMatchInlineSnapshot(`
expect(omitRefAndFlattenStyle(instance)).toMatchInlineSnapshot(`
<RCTText
accessible={true}
allowFontScaling={true}
Expand Down Expand Up @@ -119,7 +123,7 @@ describe('Text compat with web', () => {

const instance = await render.create(<Text {...props} />);

expect(omitRef(instance.toJSON())).toMatchInlineSnapshot(`
expect(omitRefAndFlattenStyle(instance)).toMatchInlineSnapshot(`
<RCTText
accessibilityLabel="label"
accessibilityState={
Expand Down Expand Up @@ -193,7 +197,7 @@ describe('Text compat with web', () => {

const instance = await render.create(<Text style={style} />);

expect(omitRef(instance.toJSON())).toMatchInlineSnapshot(`
expect(omitRefAndFlattenStyle(instance)).toMatchInlineSnapshot(`
<RCTText
accessible={true}
allowFontScaling={true}
Expand All @@ -208,6 +212,8 @@ describe('Text compat with web', () => {
"flex": 1,
"marginInlineStart": 10,
"textAlignVertical": "center",
"userSelect": undefined,
"verticalAlign": undefined,
}
}
/>
Expand Down

0 comments on commit ef2e941

Please sign in to comment.