Files
react-native/ReactCommon/react/renderer/components/view/accessibilityPropsConversions.h
T
Moti Zilberman a064de151f Reduce use of assertions in parsing accessibility props
Summary:
Changelog:
[General][Fixed] - Reduce use of assertions when parsing accessibility props passed from JS

Fixes some more cases along the same lines as D43184380 (https://github.com/facebook/react-native/commit/d16c1a04d8ceaf6b6df07d734cd54d490b6c6093) and D43184994 (https://github.com/facebook/react-native/commit/ee4714e3693a3bd88215bd7a19ff805e3262b1c8).

Reviewed By: jacdebug

Differential Revision: D43324899

fbshipit-source-id: fb343203f16464009931f07592e663b06dcf20e7
2023-02-16 07:03:06 -08:00

304 lines
8.2 KiB
C++

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <folly/dynamic.h>
#include <glog/logging.h>
#include <react/debug/react_native_assert.h>
#include <react/debug/react_native_expect.h>
#include <react/renderer/components/view/AccessibilityPrimitives.h>
#include <react/renderer/core/PropsParserContext.h>
#include <react/renderer/core/propsConversions.h>
namespace facebook {
namespace react {
inline void fromString(const std::string &string, AccessibilityTraits &result) {
if (string == "none") {
result = AccessibilityTraits::None;
return;
}
if (string == "button" || string == "togglebutton") {
result = AccessibilityTraits::Button;
return;
}
if (string == "link") {
result = AccessibilityTraits::Link;
return;
}
if (string == "image") {
result = AccessibilityTraits::Image;
return;
}
if (string == "selected") {
result = AccessibilityTraits::Selected;
return;
}
if (string == "plays") {
result = AccessibilityTraits::PlaysSound;
return;
}
if (string == "keyboardkey" || string == "key") {
result = AccessibilityTraits::KeyboardKey;
return;
}
if (string == "text") {
result = AccessibilityTraits::StaticText;
return;
}
if (string == "disabled") {
result = AccessibilityTraits::NotEnabled;
return;
}
if (string == "frequentUpdates") {
result = AccessibilityTraits::UpdatesFrequently;
return;
}
if (string == "search") {
result = AccessibilityTraits::SearchField;
return;
}
if (string == "startsMedia") {
result = AccessibilityTraits::StartsMediaSession;
return;
}
if (string == "adjustable") {
result = AccessibilityTraits::Adjustable;
return;
}
if (string == "allowsDirectInteraction") {
result = AccessibilityTraits::AllowsDirectInteraction;
return;
}
if (string == "pageTurn") {
result = AccessibilityTraits::CausesPageTurn;
return;
}
if (string == "header") {
result = AccessibilityTraits::Header;
return;
}
if (string == "imagebutton") {
result = AccessibilityTraits::Image | AccessibilityTraits::Button;
return;
}
if (string == "summary") {
result = AccessibilityTraits::SummaryElement;
return;
}
if (string == "switch") {
result = AccessibilityTraits::Switch;
return;
}
if (string == "tabbar") {
result = AccessibilityTraits::TabBar;
return;
}
if (string == "progressbar") {
result = AccessibilityTraits::UpdatesFrequently;
return;
}
result = AccessibilityTraits::None;
}
inline void fromRawValue(
const PropsParserContext &context,
const RawValue &value,
AccessibilityTraits &result) {
if (value.hasType<std::string>()) {
fromString((std::string)value, result);
return;
}
result = {};
react_native_expect(value.hasType<std::vector<std::string>>());
if (value.hasType<std::vector<std::string>>()) {
auto items = (std::vector<std::string>)value;
for (auto &item : items) {
AccessibilityTraits itemAccessibilityTraits;
fromString(item, itemAccessibilityTraits);
result = result | itemAccessibilityTraits;
}
} else {
LOG(ERROR) << "AccessibilityTraits parsing: unsupported type";
}
}
inline void fromRawValue(
const PropsParserContext &context,
const RawValue &value,
AccessibilityState &result) {
auto map = (butter::map<std::string, RawValue>)value;
auto selected = map.find("selected");
if (selected != map.end()) {
fromRawValue(context, selected->second, result.selected);
}
auto disabled = map.find("disabled");
if (disabled != map.end()) {
fromRawValue(context, disabled->second, result.disabled);
}
auto checked = map.find("checked");
if (checked != map.end()) {
if (checked->second.hasType<std::string>()) {
if ((std::string)checked->second == "mixed") {
result.checked = AccessibilityState::Mixed;
} else {
result.checked = AccessibilityState::None;
}
} else if (checked->second.hasType<bool>()) {
if ((bool)checked->second == true) {
result.checked = AccessibilityState::Checked;
} else {
result.checked = AccessibilityState::Unchecked;
}
} else {
result.checked = AccessibilityState::None;
}
}
auto busy = map.find("busy");
if (busy != map.end()) {
fromRawValue(context, busy->second, result.busy);
}
auto expanded = map.find("expanded");
if (expanded != map.end()) {
fromRawValue(context, expanded->second, result.expanded);
}
}
inline std::string toString(
const ImportantForAccessibility &importantForAccessibility) {
switch (importantForAccessibility) {
case ImportantForAccessibility::Auto:
return "auto";
case ImportantForAccessibility::Yes:
return "yes";
case ImportantForAccessibility::No:
return "no";
case ImportantForAccessibility::NoHideDescendants:
return "no-hide-descendants";
}
}
inline void fromRawValue(
const PropsParserContext &context,
const RawValue &value,
ImportantForAccessibility &result) {
result = ImportantForAccessibility::Auto;
react_native_expect(value.hasType<std::string>());
if (value.hasType<std::string>()) {
auto string = (std::string)value;
if (string == "auto") {
result = ImportantForAccessibility::Auto;
} else if (string == "yes") {
result = ImportantForAccessibility::Yes;
} else if (string == "no") {
result = ImportantForAccessibility::No;
} else if (string == "no-hide-descendants") {
result = ImportantForAccessibility::NoHideDescendants;
} else {
LOG(ERROR) << "Unsupported ImportantForAccessiblity value: " << string;
react_native_expect(false);
}
} else {
LOG(ERROR) << "Unsupported ImportantForAccessiblity type";
}
}
inline void fromRawValue(
const PropsParserContext &context,
const RawValue &value,
AccessibilityAction &result) {
auto map = (butter::map<std::string, RawValue>)value;
auto name = map.find("name");
react_native_assert(name != map.end() && name->second.hasType<std::string>());
if (name != map.end()) {
fromRawValue(context, name->second, result.name);
}
auto label = map.find("label");
if (label != map.end()) {
if (label->second.hasType<std::string>()) {
result.label = (std::string)label->second;
}
}
}
inline void fromRawValue(
const PropsParserContext &,
const RawValue &value,
AccessibilityValue &result) {
auto map = (butter::map<std::string, RawValue>)value;
auto min = map.find("min");
if (min != map.end()) {
if (min->second.hasType<int>()) {
result.min = (int)min->second;
}
}
auto max = map.find("max");
if (max != map.end()) {
if (max->second.hasType<int>()) {
result.max = (int)max->second;
}
}
auto now = map.find("now");
if (now != map.end()) {
if (now->second.hasType<int>()) {
result.now = (int)now->second;
}
}
auto text = map.find("text");
if (text != map.end()) {
if (text->second.hasType<std::string>()) {
result.text = (std::string)text->second;
}
}
}
inline void fromRawValue(
const PropsParserContext &context,
const RawValue &value,
AccessibilityLabelledBy &result) {
if (value.hasType<std::string>()) {
result.value.push_back((std::string)value);
} else if (value.hasType<std::vector<std::string>>()) {
result.value = (std::vector<std::string>)value;
}
}
inline void fromRawValue(
const PropsParserContext &context,
const RawValue &value,
AccessibilityLiveRegion &result) {
result = AccessibilityLiveRegion::None;
react_native_expect(value.hasType<std::string>());
if (value.hasType<std::string>()) {
auto string = (std::string)value;
if (string == "none") {
result = AccessibilityLiveRegion::None;
} else if (string == "polite") {
result = AccessibilityLiveRegion::Polite;
} else if (string == "assertive") {
result = AccessibilityLiveRegion::Assertive;
} else {
LOG(ERROR) << "Unsupported AccessibilityLiveRegion value: " << string;
react_native_expect(false);
}
} else {
LOG(ERROR) << "Unsupported AccessibilityLiveRegion type";
}
}
} // namespace react
} // namespace facebook