Skip to content

Commit d4d996d

Browse files
jorge-cabfacebook-github-bot
authored andcommitted
Add KeyboardFocusableNode ShadowNodeTrait
Summary: Introduce a trait to be able to tell if a ShadowNode is focusable by keyboard. This will be used for focus ordering that delegates the work to the shadow tree when Native platforms don't have enough information to define the next focusable node Changelog: [Internal] Differential Revision: D72258544
1 parent 47157aa commit d4d996d

File tree

6 files changed

+47
-0
lines changed

6 files changed

+47
-0
lines changed

Diff for: packages/react-native/ReactCommon/react/renderer/components/text/ParagraphShadowNode.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,22 @@ using Content = ParagraphShadowNode::Content;
2626

2727
const char ParagraphComponentName[] = "Paragraph";
2828

29+
void ParagraphShadowNode::initialize() noexcept {
30+
#ifdef ANDROID
31+
if (getConcreteProps().isSelectable) {
32+
traits_.set(ShadowNodeTraits::Trait::KeyboardFocusable);
33+
}
34+
#endif
35+
}
36+
37+
ParagraphShadowNode::ParagraphShadowNode(
38+
const ShadowNodeFragment& fragment,
39+
const ShadowNodeFamily::Shared& family,
40+
ShadowNodeTraits traits)
41+
: ConcreteViewShadowNode(fragment, family, traits) {
42+
initialize();
43+
}
44+
2945
ParagraphShadowNode::ParagraphShadowNode(
3046
const ShadowNode& sourceShadowNode,
3147
const ShadowNodeFragment& fragment)
@@ -49,6 +65,7 @@ ParagraphShadowNode::ParagraphShadowNode(
4965
// to stop Yoga from traversing it.
5066
cleanLayout();
5167
}
68+
initialize();
5269
}
5370

5471
const Content& ParagraphShadowNode::getContent(

Diff for: packages/react-native/ReactCommon/react/renderer/components/text/ParagraphShadowNode.h

+6
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ class ParagraphShadowNode final : public ConcreteViewShadowNode<
3535
public:
3636
using ConcreteViewShadowNode::ConcreteViewShadowNode;
3737

38+
ParagraphShadowNode(
39+
const ShadowNodeFragment& fragment,
40+
const ShadowNodeFamily::Shared& family,
41+
ShadowNodeTraits traits);
42+
3843
ParagraphShadowNode(
3944
const ShadowNode& sourceShadowNode,
4045
const ShadowNodeFragment& fragment);
@@ -84,6 +89,7 @@ class ParagraphShadowNode final : public ConcreteViewShadowNode<
8489
};
8590

8691
private:
92+
void initialize() noexcept;
8793
/*
8894
* Builds (if needed) and returns a reference to a `Content` object.
8995
*/

Diff for: packages/react-native/ReactCommon/react/renderer/components/view/ConcreteViewShadowNode.h

+13
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#pragma once
99

10+
#include <react/renderer/components/view/HostPlatformViewTraitsInitializer.h>
1011
#include <react/renderer/components/view/ViewEventEmitter.h>
1112
#include <react/renderer/components/view/ViewProps.h>
1213
#include <react/renderer/components/view/YogaLayoutableShadowNode.h>
@@ -15,6 +16,7 @@
1516
#include <react/renderer/core/ShadowNode.h>
1617
#include <react/renderer/core/ShadowNodeFragment.h>
1718
#include <react/renderer/debug/DebugStringConvertibleItem.h>
19+
#include <type_traits>
1820

1921
namespace facebook::react {
2022

@@ -29,6 +31,7 @@ template <
2931
typename ViewEventEmitterT = ViewEventEmitter,
3032
typename StateDataT = StateData,
3133
bool usesMapBufferForStateData = false>
34+
requires(std::is_base_of_v<ViewProps, ViewPropsT>)
3235
class ConcreteViewShadowNode : public ConcreteShadowNode<
3336
concreteComponentName,
3437
YogaLayoutableShadowNode,
@@ -117,6 +120,16 @@ class ConcreteViewShadowNode : public ConcreteShadowNode<
117120
} else {
118121
BaseShadowNode::orderIndex_ = 0;
119122
}
123+
124+
bool isKeyboardFocusable =
125+
HostPlatformViewTraitsInitializer::isKeyboardFocusable(props) ||
126+
props.accessible;
127+
128+
if (isKeyboardFocusable) {
129+
BaseShadowNode::traits_.set(ShadowNodeTraits::Trait::KeyboardFocusable);
130+
} else {
131+
BaseShadowNode::traits_.unset(ShadowNodeTraits::Trait::KeyboardFocusable);
132+
}
120133
}
121134
};
122135

Diff for: packages/react-native/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/HostPlatformViewTraitsInitializer.h

+4
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,8 @@ inline bool formsView(const ViewProps& viewProps) {
2424
viewProps.renderToHardwareTextureAndroid;
2525
}
2626

27+
inline bool isKeyboardFocusable(const ViewProps& viewProps) {
28+
return (viewProps.focusable || viewProps.hasTVPreferredFocus);
29+
}
30+
2731
} // namespace facebook::react::HostPlatformViewTraitsInitializer

Diff for: packages/react-native/ReactCommon/react/renderer/components/view/platform/cxx/react/renderer/components/view/HostPlatformViewTraitsInitializer.h

+4
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,8 @@ inline bool formsView(const ViewProps& props) {
2020
return false;
2121
}
2222

23+
inline bool isKeyboardFocusable(const ViewProps& /*props*/) {
24+
return false;
25+
}
26+
2327
} // namespace facebook::react::HostPlatformViewTraitsInitializer

Diff for: packages/react-native/ReactCommon/react/renderer/core/ShadowNodeTraits.h

+3
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ class ShadowNodeTraits {
7878

7979
// Forces the node not to form a host view.
8080
ForceFlattenView = 1 << 11,
81+
82+
// Indicates if the node is keyboard focusable.
83+
KeyboardFocusable = 1 << 12,
8184
};
8285

8386
/*

0 commit comments

Comments
 (0)