mirror of
https://github.com/react/react-native.git
synced 2026-09-28 13:23:09 +08:00
fix(text): avoid mutating accessibilityState (#58318)
Summary: When `accessibilityState.disabled` conflicts with an explicit `disabled` prop, the `Text` component currently updates `accessibilityState` in place. This mutates an object owned by the caller, which can cause issues when other code uses that same object. This fix creates a new object instead, while retaining existing behavior (giving priority to the explicit prop). ## Changelog: [GENERAL] [FIXED] - Prevent Text from mutating the accessibilityState prop Pull Request resolved: https://github.com/react/react-native/pull/58318 Test Plan: Unchanged tests pass + added a regression test Reviewed By: Abbondanzo Differential Revision: D118788803 Pulled By: javache fbshipit-source-id: 77f69e851d06250aa27e20912a2c2fc91394b81d
This commit is contained in:
committed by
meta-codesync[bot]
parent
d44efb09c1
commit
c300f84f2c
+15
-20
@@ -92,9 +92,22 @@ const TextImpl: component(
|
||||
...NativeTextProps,
|
||||
};
|
||||
const _accessibilityLabel = ariaLabel ?? accessibilityLabel;
|
||||
const _accessibilityStateDisabled =
|
||||
ariaDisabled ?? accessibilityState?.disabled;
|
||||
const _disabled = disabled ?? _accessibilityStateDisabled;
|
||||
|
||||
// If the disabled prop and accessibilityState.disabled are out of sync but not both in
|
||||
// falsy states we need to update the accessibilityState object to use the disabled prop.
|
||||
const needsAccessibilityStateDisabledUpdate =
|
||||
_disabled !== _accessibilityStateDisabled &&
|
||||
((_disabled != null && _disabled !== false) ||
|
||||
(_accessibilityStateDisabled != null &&
|
||||
_accessibilityStateDisabled !== false));
|
||||
|
||||
let _accessibilityState: ?TextProps['accessibilityState'] =
|
||||
accessibilityState;
|
||||
if (
|
||||
needsAccessibilityStateDisabledUpdate ||
|
||||
ariaBusy != null ||
|
||||
ariaChecked != null ||
|
||||
ariaDisabled != null ||
|
||||
@@ -105,7 +118,7 @@ const TextImpl: component(
|
||||
_accessibilityState = {
|
||||
busy: ariaBusy ?? _accessibilityState.busy,
|
||||
checked: ariaChecked ?? _accessibilityState.checked,
|
||||
disabled: ariaDisabled ?? _accessibilityState.disabled,
|
||||
disabled: _disabled,
|
||||
expanded: ariaExpanded ?? _accessibilityState.expanded,
|
||||
selected: ariaSelected ?? _accessibilityState.selected,
|
||||
};
|
||||
@@ -113,31 +126,13 @@ const TextImpl: component(
|
||||
_accessibilityState = {
|
||||
busy: ariaBusy,
|
||||
checked: ariaChecked,
|
||||
disabled: ariaDisabled,
|
||||
disabled: _disabled,
|
||||
expanded: ariaExpanded,
|
||||
selected: ariaSelected,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const _accessibilityStateDisabled = _accessibilityState?.disabled;
|
||||
const _disabled = disabled ?? _accessibilityStateDisabled;
|
||||
|
||||
// If the disabled prop and accessibilityState.disabled are out of sync but not both in
|
||||
// falsy states we need to update the accessibilityState object to use the disabled prop.
|
||||
if (
|
||||
_disabled !== _accessibilityStateDisabled &&
|
||||
((_disabled != null && _disabled !== false) ||
|
||||
(_accessibilityStateDisabled != null &&
|
||||
_accessibilityStateDisabled !== false))
|
||||
) {
|
||||
if (_accessibilityState == null) {
|
||||
_accessibilityState = {disabled};
|
||||
} else {
|
||||
_accessibilityState.disabled = _disabled;
|
||||
}
|
||||
}
|
||||
|
||||
if (ariaHidden !== undefined) {
|
||||
processedProps.accessibilityElementsHidden = ariaHidden;
|
||||
if (ariaHidden === true) {
|
||||
|
||||
@@ -592,6 +592,32 @@ describe('<Text>', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('accessibilityState', () => {
|
||||
it('does not mutate the prop when disabled overrides it', () => {
|
||||
const accessibilityState: AccessibilityProps['accessibilityState'] = {
|
||||
disabled: false,
|
||||
};
|
||||
const root = Fantom.createRoot();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<Text disabled accessibilityState={accessibilityState}>
|
||||
{TEST_TEXT}
|
||||
</Text>,
|
||||
);
|
||||
});
|
||||
|
||||
expect(accessibilityState).toEqual({disabled: false});
|
||||
expect(
|
||||
root.getRenderedOutput({props: ['accessibilityState']}).toJSX(),
|
||||
).toEqual(
|
||||
<rn-paragraph accessibilityState="{disabled:true,selected:false,checked:None,busy:false,expanded:null}">
|
||||
{TEST_TEXT}
|
||||
</rn-paragraph>,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('aria-hidden', () => {
|
||||
it('is is passed as importantForAccessibility', () => {
|
||||
const root = Fantom.createRoot();
|
||||
|
||||
Reference in New Issue
Block a user