react-native 0.72.0-rc.0 → 0.72.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/Core/ReactNativeVersionCheck.js +5 -1
- package/Libraries/ReactNative/UIManager.js +27 -1
- package/Libraries/Renderer/implementations/ReactFabric-dev.js +26 -3
- package/Libraries/Renderer/implementations/ReactFabric-prod.js +13 -1
- package/Libraries/Renderer/implementations/ReactFabric-profiling.js +13 -1
- package/React/Base/RCTVersion.m +1 -1
- package/React/Fabric/Mounting/ComponentViews/LegacyViewManagerInterop/RCTLegacyViewManagerInteropCoordinatorAdapter.mm +1 -1
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java +40 -1
- package/ReactAndroid/src/main/java/com/facebook/react/ReactFragment.java +22 -7
- package/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java +3 -0
- package/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactActivityDelegate.kt +4 -0
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomLetterSpacingSpan.java +4 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomStyleSpan.java +4 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java +1 -5
- package/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +190 -134
- package/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +23 -10
- package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundManager.java +5 -0
- package/ReactAndroid/src/main/jni/react/fabric/Binding.cpp +3 -0
- package/ReactCommon/React-rncore.podspec +12 -4
- package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
- package/ReactCommon/react/config/ReactNativeConfig.cpp +3 -0
- package/ReactCommon/react/renderer/components/legacyviewmanagerinterop/RCTLegacyViewManagerInteropCoordinator.h +4 -1
- package/ReactCommon/react/renderer/components/legacyviewmanagerinterop/RCTLegacyViewManagerInteropCoordinator.mm +49 -2
- package/ReactCommon/react/renderer/components/text/ParagraphLayoutManager.cpp +30 -5
- package/ReactCommon/react/renderer/components/text/ParagraphLayoutManager.h +12 -0
- package/ReactCommon/react/renderer/core/CoreFeatures.cpp +1 -0
- package/ReactCommon/react/renderer/core/CoreFeatures.h +5 -0
- package/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.cpp +5 -1
- package/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm +112 -83
- package/build.gradle.kts +17 -0
- package/gradle.properties +1 -0
- package/package.json +7 -7
- package/scripts/cocoapods/__tests__/codegen_utils-test.rb +9 -1
- package/scripts/cocoapods/codegen_utils.rb +1 -1
- package/sdks/hermesc/osx-bin/hermesc +0 -0
- package/sdks/hermesc/win64-bin/hermesc.exe +0 -0
- package/settings.gradle.kts +30 -0
- package/template/metro.config.js +7 -13
- package/template/package.json +4 -2
|
@@ -100,13 +100,23 @@ using namespace facebook::react;
|
|
|
100
100
|
return RCTDropReactPrefixes(_componentData.name);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
- (void)handleCommand:(NSString *)commandName
|
|
103
|
+
- (void)handleCommand:(NSString *)commandName
|
|
104
|
+
args:(NSArray *)args
|
|
105
|
+
reactTag:(NSInteger)tag
|
|
106
|
+
paperView:(nonnull UIView *)paperView
|
|
104
107
|
{
|
|
105
108
|
Class managerClass = _componentData.managerClass;
|
|
106
109
|
[self _lookupModuleMethodsIfNecessary];
|
|
107
110
|
RCTModuleData *moduleData = [_bridge.batchedBridge moduleDataForName:RCTBridgeModuleNameForClass(managerClass)];
|
|
108
111
|
id<RCTBridgeMethod> method;
|
|
109
|
-
|
|
112
|
+
|
|
113
|
+
// We can't use `[NSString intValue]` as "0" is a valid command,
|
|
114
|
+
// but also a falsy value. [NSNumberFormatter numberFromString] returns a
|
|
115
|
+
// `NSNumber *` which is NULL when it's to be NULL
|
|
116
|
+
// and it points to 0 when the string is @"0" (not a falsy value).
|
|
117
|
+
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
|
|
118
|
+
|
|
119
|
+
if ([commandName isKindOfClass:[NSNumber class]] || [formatter numberFromString:commandName] != NULL) {
|
|
110
120
|
method = moduleData ? moduleData.methods[[commandName intValue]] : _moduleMethods[[commandName intValue]];
|
|
111
121
|
} else if ([commandName isKindOfClass:[NSString class]]) {
|
|
112
122
|
method = moduleData ? moduleData.methodsByName[commandName] : _moduleMethodsByName[commandName];
|
|
@@ -121,12 +131,14 @@ using namespace facebook::react;
|
|
|
121
131
|
NSArray *newArgs = [@[ [NSNumber numberWithInteger:tag] ] arrayByAddingObjectsFromArray:args];
|
|
122
132
|
|
|
123
133
|
if (_bridge) {
|
|
134
|
+
[self _addViewToRegistry:paperView withTag:tag];
|
|
124
135
|
[_bridge.batchedBridge
|
|
125
136
|
dispatchBlock:^{
|
|
126
137
|
[method invokeWithBridge:self->_bridge module:self->_componentData.manager arguments:newArgs];
|
|
127
138
|
[self->_bridge.uiManager setNeedsLayout];
|
|
128
139
|
}
|
|
129
140
|
queue:RCTGetUIManagerQueue()];
|
|
141
|
+
[self _removeViewFromRegistryWithTag:tag];
|
|
130
142
|
} else {
|
|
131
143
|
// TODO T86826778 - Figure out which queue this should be dispatched to.
|
|
132
144
|
[method invokeWithBridge:nil module:self->_componentData.manager arguments:newArgs];
|
|
@@ -134,6 +146,41 @@ using namespace facebook::react;
|
|
|
134
146
|
}
|
|
135
147
|
|
|
136
148
|
#pragma mark - Private
|
|
149
|
+
- (void)_addViewToRegistry:(UIView *)view withTag:(NSInteger)tag
|
|
150
|
+
{
|
|
151
|
+
[self _addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
|
152
|
+
if ([viewRegistry objectForKey:@(tag)] != NULL) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
NSMutableDictionary<NSNumber *, UIView *> *mutableViewRegistry =
|
|
156
|
+
(NSMutableDictionary<NSNumber *, UIView *> *)viewRegistry;
|
|
157
|
+
[mutableViewRegistry setObject:view forKey:@(tag)];
|
|
158
|
+
}];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
- (void)_removeViewFromRegistryWithTag:(NSInteger)tag
|
|
162
|
+
{
|
|
163
|
+
[self _addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
|
164
|
+
if ([viewRegistry objectForKey:@(tag)] == NULL) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
NSMutableDictionary<NSNumber *, UIView *> *mutableViewRegistry =
|
|
169
|
+
(NSMutableDictionary<NSNumber *, UIView *> *)viewRegistry;
|
|
170
|
+
[mutableViewRegistry removeObjectForKey:@(tag)];
|
|
171
|
+
}];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
- (void)_addUIBlock:(RCTViewManagerUIBlock)block
|
|
175
|
+
{
|
|
176
|
+
__weak __typeof__(self) weakSelf = self;
|
|
177
|
+
[_bridge.batchedBridge
|
|
178
|
+
dispatchBlock:^{
|
|
179
|
+
__typeof__(self) strongSelf = weakSelf;
|
|
180
|
+
[strongSelf->_bridge.uiManager addUIBlock:block];
|
|
181
|
+
}
|
|
182
|
+
queue:RCTGetUIManagerQueue()];
|
|
183
|
+
}
|
|
137
184
|
|
|
138
185
|
// This is copy-pasta from RCTModuleData.
|
|
139
186
|
- (void)_lookupModuleMethodsIfNecessary
|
|
@@ -15,6 +15,19 @@ TextMeasurement ParagraphLayoutManager::measure(
|
|
|
15
15
|
AttributedString const &attributedString,
|
|
16
16
|
ParagraphAttributes const ¶graphAttributes,
|
|
17
17
|
LayoutConstraints layoutConstraints) const {
|
|
18
|
+
bool cacheLastTextMeasurement = CoreFeatures::cacheLastTextMeasurement;
|
|
19
|
+
if (cacheLastTextMeasurement &&
|
|
20
|
+
(layoutConstraints.maximumSize.width == availableWidth_ ||
|
|
21
|
+
layoutConstraints.maximumSize.width ==
|
|
22
|
+
cachedTextMeasurement_.size.width)) {
|
|
23
|
+
/* Yoga has requested measurement for this size before. Let's use cached
|
|
24
|
+
* value. `TextLayoutManager` might not have cached this because it could be
|
|
25
|
+
* using different width to generate cache key. This happens because Yoga
|
|
26
|
+
* switches between available width and exact width but since we already
|
|
27
|
+
* know exact width, it is wasteful to calculate it again.
|
|
28
|
+
*/
|
|
29
|
+
return cachedTextMeasurement_;
|
|
30
|
+
}
|
|
18
31
|
if (CoreFeatures::cacheNSTextStorage) {
|
|
19
32
|
size_t newHash = folly::hash::hash_combine(
|
|
20
33
|
0,
|
|
@@ -28,11 +41,23 @@ TextMeasurement ParagraphLayoutManager::measure(
|
|
|
28
41
|
}
|
|
29
42
|
}
|
|
30
43
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
44
|
+
if (cacheLastTextMeasurement) {
|
|
45
|
+
cachedTextMeasurement_ = textLayoutManager_->measure(
|
|
46
|
+
AttributedStringBox(attributedString),
|
|
47
|
+
paragraphAttributes,
|
|
48
|
+
layoutConstraints,
|
|
49
|
+
hostTextStorage_);
|
|
50
|
+
|
|
51
|
+
availableWidth_ = layoutConstraints.maximumSize.width;
|
|
52
|
+
|
|
53
|
+
return cachedTextMeasurement_;
|
|
54
|
+
} else {
|
|
55
|
+
return textLayoutManager_->measure(
|
|
56
|
+
AttributedStringBox(attributedString),
|
|
57
|
+
paragraphAttributes,
|
|
58
|
+
layoutConstraints,
|
|
59
|
+
hostTextStorage_);
|
|
60
|
+
}
|
|
36
61
|
}
|
|
37
62
|
|
|
38
63
|
LinesMeasurements ParagraphLayoutManager::measureLines(
|
|
@@ -54,6 +54,18 @@ class ParagraphLayoutManager {
|
|
|
54
54
|
std::shared_ptr<TextLayoutManager const> mutable textLayoutManager_{};
|
|
55
55
|
std::shared_ptr<void> mutable hostTextStorage_{};
|
|
56
56
|
|
|
57
|
+
/* The width Yoga set as maximum width.
|
|
58
|
+
* Yoga sometimes calls measure twice with two
|
|
59
|
+
* different maximum width. One if available space.
|
|
60
|
+
* The other one is exact space needed for the string.
|
|
61
|
+
* This happens when node is dirtied but its size is not affected.
|
|
62
|
+
* To deal with this inefficiency, we cache `TextMeasurement` for each
|
|
63
|
+
* `ParagraphShadowNode`. If Yoga tries to re-measure with available width
|
|
64
|
+
* or exact width, we provide it with the cached value.
|
|
65
|
+
*/
|
|
66
|
+
Float mutable availableWidth_{};
|
|
67
|
+
TextMeasurement mutable cachedTextMeasurement_{};
|
|
68
|
+
|
|
57
69
|
size_t mutable hash_{};
|
|
58
70
|
};
|
|
59
71
|
} // namespace facebook::react
|
|
@@ -15,6 +15,7 @@ bool CoreFeatures::enableMapBuffer = false;
|
|
|
15
15
|
bool CoreFeatures::blockPaintForUseLayoutEffect = false;
|
|
16
16
|
bool CoreFeatures::useNativeState = false;
|
|
17
17
|
bool CoreFeatures::cacheNSTextStorage = false;
|
|
18
|
+
bool CoreFeatures::cacheLastTextMeasurement = false;
|
|
18
19
|
|
|
19
20
|
} // namespace react
|
|
20
21
|
} // namespace facebook
|
|
@@ -39,6 +39,11 @@ class CoreFeatures {
|
|
|
39
39
|
// creating it twice. Once when measuring text and once when rendering it.
|
|
40
40
|
// This flag caches it inside ParagraphState.
|
|
41
41
|
static bool cacheNSTextStorage;
|
|
42
|
+
|
|
43
|
+
// Yoga might measure multiple times the same Text with the same constraints
|
|
44
|
+
// This flag enables a caching mechanism to avoid subsequents measurements
|
|
45
|
+
// of the same Text with the same constrainst.
|
|
46
|
+
static bool cacheLastTextMeasurement;
|
|
42
47
|
};
|
|
43
48
|
|
|
44
49
|
} // namespace react
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
#include <react/common/mapbuffer/JReadableMapBuffer.h>
|
|
13
13
|
#include <react/jni/ReadableNativeMap.h>
|
|
14
14
|
#include <react/renderer/attributedstring/conversions.h>
|
|
15
|
+
#include <react/renderer/core/CoreFeatures.h>
|
|
15
16
|
#include <react/renderer/core/conversions.h>
|
|
16
17
|
#include <react/renderer/mapbuffer/MapBuffer.h>
|
|
17
18
|
#include <react/renderer/mapbuffer/MapBufferBuilder.h>
|
|
@@ -146,7 +147,10 @@ Size measureAndroidComponentMapBuffer(
|
|
|
146
147
|
TextLayoutManager::TextLayoutManager(
|
|
147
148
|
const ContextContainer::Shared &contextContainer)
|
|
148
149
|
: contextContainer_(contextContainer),
|
|
149
|
-
measureCache_(
|
|
150
|
+
measureCache_(
|
|
151
|
+
CoreFeatures::cacheLastTextMeasurement
|
|
152
|
+
? 8096
|
|
153
|
+
: kSimpleThreadSafeCacheSizeCap) {}
|
|
150
154
|
|
|
151
155
|
void *TextLayoutManager::getNativeTextLayoutManager() const {
|
|
152
156
|
return self_;
|
|
@@ -52,47 +52,9 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
|
|
|
52
52
|
textStorage = [self _textStorageForNSAttributesString:attributedString
|
|
53
53
|
paragraphAttributes:paragraphAttributes
|
|
54
54
|
size:maximumSize];
|
|
55
|
-
} else {
|
|
56
|
-
textStorage.layoutManagers.firstObject.textContainers.firstObject.size = maximumSize;
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
|
|
61
|
-
[layoutManager ensureLayoutForTextContainer:textContainer];
|
|
62
|
-
|
|
63
|
-
CGSize size = [layoutManager usedRectForTextContainer:textContainer].size;
|
|
64
|
-
|
|
65
|
-
size = (CGSize){RCTCeilPixelValue(size.width), RCTCeilPixelValue(size.height)};
|
|
66
|
-
|
|
67
|
-
__block auto attachments = TextMeasurement::Attachments{};
|
|
68
|
-
|
|
69
|
-
[textStorage
|
|
70
|
-
enumerateAttribute:NSAttachmentAttributeName
|
|
71
|
-
inRange:NSMakeRange(0, textStorage.length)
|
|
72
|
-
options:0
|
|
73
|
-
usingBlock:^(NSTextAttachment *attachment, NSRange range, BOOL *stop) {
|
|
74
|
-
if (!attachment) {
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
CGSize attachmentSize = attachment.bounds.size;
|
|
79
|
-
CGRect glyphRect = [layoutManager boundingRectForGlyphRange:range inTextContainer:textContainer];
|
|
80
|
-
|
|
81
|
-
UIFont *font = [textStorage attribute:NSFontAttributeName atIndex:range.location effectiveRange:nil];
|
|
82
|
-
|
|
83
|
-
CGRect frame = {
|
|
84
|
-
{glyphRect.origin.x,
|
|
85
|
-
glyphRect.origin.y + glyphRect.size.height - attachmentSize.height + font.descender},
|
|
86
|
-
attachmentSize};
|
|
87
|
-
|
|
88
|
-
auto rect = facebook::react::Rect{
|
|
89
|
-
facebook::react::Point{frame.origin.x, frame.origin.y},
|
|
90
|
-
facebook::react::Size{frame.size.width, frame.size.height}};
|
|
91
|
-
|
|
92
|
-
attachments.push_back(TextMeasurement::Attachment{rect, false});
|
|
93
|
-
}];
|
|
94
|
-
|
|
95
|
-
return TextMeasurement{{size.width, size.height}, attachments};
|
|
57
|
+
return [self _measureTextStorage:textStorage];
|
|
96
58
|
}
|
|
97
59
|
|
|
98
60
|
- (TextMeasurement)measureAttributedString:(AttributedString)attributedString
|
|
@@ -100,10 +62,14 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
|
|
|
100
62
|
layoutConstraints:(LayoutConstraints)layoutConstraints
|
|
101
63
|
textStorage:(NSTextStorage *_Nullable)textStorage
|
|
102
64
|
{
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
65
|
+
if (textStorage) {
|
|
66
|
+
return [self _measureTextStorage:textStorage];
|
|
67
|
+
} else {
|
|
68
|
+
return [self measureNSAttributedString:[self _nsAttributedStringFromAttributedString:attributedString]
|
|
69
|
+
paragraphAttributes:paragraphAttributes
|
|
70
|
+
layoutConstraints:layoutConstraints
|
|
71
|
+
textStorage:nil];
|
|
72
|
+
}
|
|
107
73
|
}
|
|
108
74
|
|
|
109
75
|
- (void)drawAttributedString:(AttributedString)attributedString
|
|
@@ -111,13 +77,33 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
|
|
|
111
77
|
frame:(CGRect)frame
|
|
112
78
|
textStorage:(NSTextStorage *_Nullable)textStorage
|
|
113
79
|
{
|
|
80
|
+
BOOL createdStorageForFrame = NO;
|
|
81
|
+
|
|
114
82
|
if (!textStorage) {
|
|
115
83
|
textStorage = [self textStorageForAttributesString:attributedString
|
|
116
84
|
paragraphAttributes:paragraphAttributes
|
|
117
85
|
size:frame.size];
|
|
86
|
+
createdStorageForFrame = YES;
|
|
118
87
|
}
|
|
88
|
+
|
|
119
89
|
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
|
|
120
90
|
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
|
|
91
|
+
CGPoint origin = frame.origin;
|
|
92
|
+
|
|
93
|
+
if (!createdStorageForFrame) {
|
|
94
|
+
CGRect rect = [layoutManager usedRectForTextContainer:textContainer];
|
|
95
|
+
static auto threshold = 1.0 / RCTScreenScale() + 0.01; // Size of a pixel plus some small threshold.
|
|
96
|
+
|
|
97
|
+
// `rect`'s width is stored in double precesion.
|
|
98
|
+
// `frame`'s width is also in double precesion but was stored as float in Yoga previously, precesion was lost.
|
|
99
|
+
if (std::abs(RCTCeilPixelValue(rect.size.width) - frame.size.width) < threshold) {
|
|
100
|
+
// `textStorage` passed to this method was used to calculate size of frame. If that's the case, it's
|
|
101
|
+
// width is the same as frame's width. Origin must be adjusted, otherwise glyhps will be painted in wrong
|
|
102
|
+
// place.
|
|
103
|
+
// We could create new `NSTextStorage` for the specific frame, but that is expensive.
|
|
104
|
+
origin.x -= RCTCeilPixelValue(rect.origin.x);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
121
107
|
|
|
122
108
|
#if TARGET_OS_MACCATALYST
|
|
123
109
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
@@ -126,8 +112,8 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
|
|
|
126
112
|
#endif
|
|
127
113
|
|
|
128
114
|
NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
|
|
129
|
-
[layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:
|
|
130
|
-
[layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:
|
|
115
|
+
[layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:origin];
|
|
116
|
+
[layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:origin];
|
|
131
117
|
|
|
132
118
|
#if TARGET_OS_MACCATALYST
|
|
133
119
|
CGContextRestoreGState(context);
|
|
@@ -178,35 +164,6 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
|
|
|
178
164
|
return paragraphLines;
|
|
179
165
|
}
|
|
180
166
|
|
|
181
|
-
- (NSTextStorage *)_textStorageForNSAttributesString:(NSAttributedString *)attributedString
|
|
182
|
-
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
|
183
|
-
size:(CGSize)size
|
|
184
|
-
{
|
|
185
|
-
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:size];
|
|
186
|
-
|
|
187
|
-
textContainer.lineFragmentPadding = 0.0; // Note, the default value is 5.
|
|
188
|
-
textContainer.lineBreakMode = paragraphAttributes.maximumNumberOfLines > 0
|
|
189
|
-
? RCTNSLineBreakModeFromEllipsizeMode(paragraphAttributes.ellipsizeMode)
|
|
190
|
-
: NSLineBreakByClipping;
|
|
191
|
-
textContainer.maximumNumberOfLines = paragraphAttributes.maximumNumberOfLines;
|
|
192
|
-
|
|
193
|
-
NSLayoutManager *layoutManager = [NSLayoutManager new];
|
|
194
|
-
layoutManager.usesFontLeading = NO;
|
|
195
|
-
[layoutManager addTextContainer:textContainer];
|
|
196
|
-
|
|
197
|
-
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];
|
|
198
|
-
|
|
199
|
-
[textStorage addLayoutManager:layoutManager];
|
|
200
|
-
|
|
201
|
-
if (paragraphAttributes.adjustsFontSizeToFit) {
|
|
202
|
-
CGFloat minimumFontSize = !isnan(paragraphAttributes.minimumFontSize) ? paragraphAttributes.minimumFontSize : 4.0;
|
|
203
|
-
CGFloat maximumFontSize = !isnan(paragraphAttributes.maximumFontSize) ? paragraphAttributes.maximumFontSize : 96.0;
|
|
204
|
-
[textStorage scaleFontSizeToFitSize:size minimumFontSize:minimumFontSize maximumFontSize:maximumFontSize];
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return textStorage;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
167
|
- (NSTextStorage *)textStorageForAttributesString:(AttributedString)attributedString
|
|
211
168
|
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
|
212
169
|
size:(CGSize)size
|
|
@@ -246,15 +203,6 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
|
|
|
246
203
|
return nil;
|
|
247
204
|
}
|
|
248
205
|
|
|
249
|
-
- (NSAttributedString *)_nsAttributedStringFromAttributedString:(AttributedString)attributedString
|
|
250
|
-
{
|
|
251
|
-
auto sharedNSAttributedString = _cache.get(attributedString, [](AttributedString attributedString) {
|
|
252
|
-
return wrapManagedObject(RCTNSAttributedStringFromAttributedString(attributedString));
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
return unwrapManagedObject(sharedNSAttributedString);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
206
|
- (void)getRectWithAttributedString:(AttributedString)attributedString
|
|
259
207
|
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
|
260
208
|
enumerateAttribute:(NSString *)enumerateAttribute
|
|
@@ -294,4 +242,85 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
|
|
|
294
242
|
}];
|
|
295
243
|
}
|
|
296
244
|
|
|
245
|
+
#pragma mark - Private
|
|
246
|
+
|
|
247
|
+
- (NSTextStorage *)_textStorageForNSAttributesString:(NSAttributedString *)attributedString
|
|
248
|
+
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
|
249
|
+
size:(CGSize)size
|
|
250
|
+
{
|
|
251
|
+
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:size];
|
|
252
|
+
|
|
253
|
+
textContainer.lineFragmentPadding = 0.0; // Note, the default value is 5.
|
|
254
|
+
textContainer.lineBreakMode = paragraphAttributes.maximumNumberOfLines > 0
|
|
255
|
+
? RCTNSLineBreakModeFromEllipsizeMode(paragraphAttributes.ellipsizeMode)
|
|
256
|
+
: NSLineBreakByClipping;
|
|
257
|
+
textContainer.maximumNumberOfLines = paragraphAttributes.maximumNumberOfLines;
|
|
258
|
+
|
|
259
|
+
NSLayoutManager *layoutManager = [NSLayoutManager new];
|
|
260
|
+
layoutManager.usesFontLeading = NO;
|
|
261
|
+
[layoutManager addTextContainer:textContainer];
|
|
262
|
+
|
|
263
|
+
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];
|
|
264
|
+
|
|
265
|
+
[textStorage addLayoutManager:layoutManager];
|
|
266
|
+
|
|
267
|
+
if (paragraphAttributes.adjustsFontSizeToFit) {
|
|
268
|
+
CGFloat minimumFontSize = !isnan(paragraphAttributes.minimumFontSize) ? paragraphAttributes.minimumFontSize : 4.0;
|
|
269
|
+
CGFloat maximumFontSize = !isnan(paragraphAttributes.maximumFontSize) ? paragraphAttributes.maximumFontSize : 96.0;
|
|
270
|
+
[textStorage scaleFontSizeToFitSize:size minimumFontSize:minimumFontSize maximumFontSize:maximumFontSize];
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return textStorage;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
- (NSAttributedString *)_nsAttributedStringFromAttributedString:(AttributedString)attributedString
|
|
277
|
+
{
|
|
278
|
+
auto sharedNSAttributedString = _cache.get(attributedString, [](AttributedString attributedString) {
|
|
279
|
+
return wrapManagedObject(RCTNSAttributedStringFromAttributedString(attributedString));
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
return unwrapManagedObject(sharedNSAttributedString);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
- (TextMeasurement)_measureTextStorage:(NSTextStorage *)textStorage
|
|
286
|
+
{
|
|
287
|
+
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
|
|
288
|
+
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
|
|
289
|
+
[layoutManager ensureLayoutForTextContainer:textContainer];
|
|
290
|
+
|
|
291
|
+
CGSize size = [layoutManager usedRectForTextContainer:textContainer].size;
|
|
292
|
+
|
|
293
|
+
size = (CGSize){RCTCeilPixelValue(size.width), RCTCeilPixelValue(size.height)};
|
|
294
|
+
|
|
295
|
+
__block auto attachments = TextMeasurement::Attachments{};
|
|
296
|
+
|
|
297
|
+
[textStorage
|
|
298
|
+
enumerateAttribute:NSAttachmentAttributeName
|
|
299
|
+
inRange:NSMakeRange(0, textStorage.length)
|
|
300
|
+
options:0
|
|
301
|
+
usingBlock:^(NSTextAttachment *attachment, NSRange range, BOOL *stop) {
|
|
302
|
+
if (!attachment) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
CGSize attachmentSize = attachment.bounds.size;
|
|
307
|
+
CGRect glyphRect = [layoutManager boundingRectForGlyphRange:range inTextContainer:textContainer];
|
|
308
|
+
|
|
309
|
+
UIFont *font = [textStorage attribute:NSFontAttributeName atIndex:range.location effectiveRange:nil];
|
|
310
|
+
|
|
311
|
+
CGRect frame = {
|
|
312
|
+
{glyphRect.origin.x,
|
|
313
|
+
glyphRect.origin.y + glyphRect.size.height - attachmentSize.height + font.descender},
|
|
314
|
+
attachmentSize};
|
|
315
|
+
|
|
316
|
+
auto rect = facebook::react::Rect{
|
|
317
|
+
facebook::react::Point{frame.origin.x, frame.origin.y},
|
|
318
|
+
facebook::react::Size{frame.size.width, frame.size.height}};
|
|
319
|
+
|
|
320
|
+
attachments.push_back(TextMeasurement::Attachment{rect, false});
|
|
321
|
+
}];
|
|
322
|
+
|
|
323
|
+
return TextMeasurement{{size.width, size.height}, attachments};
|
|
324
|
+
}
|
|
325
|
+
|
|
297
326
|
@end
|
package/build.gradle.kts
CHANGED
|
@@ -1 +1,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
1
7
|
|
|
8
|
+
// This is the top level build.gradle.kts file used when the users
|
|
9
|
+
// is doing a build from source. It's triggered as the user
|
|
10
|
+
// will add an `includeBuild(../node_modules/react-native)` in
|
|
11
|
+
// their settings.gradle.kts file.
|
|
12
|
+
// More on this here: https://reactnative.dev/contributing/how-to-build-from-source
|
|
13
|
+
plugins {
|
|
14
|
+
id("com.android.library") version "7.4.2" apply false
|
|
15
|
+
id("com.android.application") version "7.4.2" apply false
|
|
16
|
+
id("de.undercouch.download") version "5.0.1" apply false
|
|
17
|
+
kotlin("android") version "1.7.22" apply false
|
|
18
|
+
}
|
package/gradle.properties
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
android.useAndroidX=true
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native",
|
|
3
|
-
"version": "0.72.0-rc.
|
|
3
|
+
"version": "0.72.0-rc.1",
|
|
4
4
|
"bin": "./cli.js",
|
|
5
5
|
"description": "A framework for building native apps using React",
|
|
6
6
|
"license": "MIT",
|
|
@@ -79,15 +79,15 @@
|
|
|
79
79
|
},
|
|
80
80
|
"dependencies": {
|
|
81
81
|
"@jest/create-cache-key-function": "^29.2.1",
|
|
82
|
-
"@react-native-community/cli": "11.
|
|
83
|
-
"@react-native-community/cli-platform-android": "11.
|
|
84
|
-
"@react-native-community/cli-platform-ios": "11.
|
|
82
|
+
"@react-native-community/cli": "11.1.1",
|
|
83
|
+
"@react-native-community/cli-platform-android": "11.1.1",
|
|
84
|
+
"@react-native-community/cli-platform-ios": "11.1.1",
|
|
85
85
|
"@react-native/assets-registry": "^0.72.0",
|
|
86
86
|
"@react-native/codegen": "^0.72.4",
|
|
87
87
|
"@react-native/gradle-plugin": "^0.72.6",
|
|
88
88
|
"@react-native/js-polyfills": "^0.72.1",
|
|
89
89
|
"@react-native/normalize-colors": "^0.72.0",
|
|
90
|
-
"@react-native/virtualized-lists": "^0.72.
|
|
90
|
+
"@react-native/virtualized-lists": "^0.72.4",
|
|
91
91
|
"abort-controller": "^3.0.0",
|
|
92
92
|
"anser": "^1.4.9",
|
|
93
93
|
"base64-js": "^1.1.2",
|
|
@@ -98,8 +98,8 @@
|
|
|
98
98
|
"jest-environment-node": "^29.2.1",
|
|
99
99
|
"jsc-android": "^250231.0.0",
|
|
100
100
|
"memoize-one": "^5.0.0",
|
|
101
|
-
"metro-runtime": "0.
|
|
102
|
-
"metro-source-map": "0.
|
|
101
|
+
"metro-runtime": "0.76.0",
|
|
102
|
+
"metro-source-map": "0.76.0",
|
|
103
103
|
"mkdirp": "^0.5.1",
|
|
104
104
|
"nullthrows": "^1.1.1",
|
|
105
105
|
"pretty-format": "^26.5.2",
|
|
@@ -15,6 +15,14 @@ require_relative "./test_utils/CodegenUtilsMock.rb"
|
|
|
15
15
|
require_relative "./test_utils/CodegenScriptPhaseExtractorMock.rb"
|
|
16
16
|
require_relative "./test_utils/FileUtilsMock.rb"
|
|
17
17
|
|
|
18
|
+
# mocking the min_ios_version_supported function
|
|
19
|
+
# as it is not possible to require the original react_native_pod
|
|
20
|
+
# without incurring in circular deps
|
|
21
|
+
# TODO: move `min_ios_version_supported` to utils.rb
|
|
22
|
+
def min_ios_version_supported
|
|
23
|
+
return '12.4'
|
|
24
|
+
end
|
|
25
|
+
|
|
18
26
|
class CodegenUtilsTests < Test::Unit::TestCase
|
|
19
27
|
:base_path
|
|
20
28
|
|
|
@@ -527,7 +535,7 @@ class CodegenUtilsTests < Test::Unit::TestCase
|
|
|
527
535
|
'source' => { :git => '' },
|
|
528
536
|
'header_mappings_dir' => './',
|
|
529
537
|
'platforms' => {
|
|
530
|
-
'ios' => '
|
|
538
|
+
'ios' => '12.4',
|
|
531
539
|
},
|
|
532
540
|
'source_files' => "**/*.{h,mm,cpp}",
|
|
533
541
|
'pod_target_xcconfig' => {
|
|
Binary file
|
|
Binary file
|
package/settings.gradle.kts
CHANGED
|
@@ -1 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
1
7
|
|
|
8
|
+
// This is the settings.gradle.kts file used when the users
|
|
9
|
+
// is doing a build from source. It's triggered as the user
|
|
10
|
+
// will add an `includeBuild(../node_modules/react-native)` in
|
|
11
|
+
// their settings.gradle.kts file.
|
|
12
|
+
// More on this here: https://reactnative.dev/contributing/how-to-build-from-source
|
|
13
|
+
|
|
14
|
+
pluginManagement {
|
|
15
|
+
repositories {
|
|
16
|
+
mavenCentral()
|
|
17
|
+
google()
|
|
18
|
+
gradlePluginPortal()
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
rootProject.name = "react-native-github"
|
|
23
|
+
|
|
24
|
+
include(":packages:react-native:ReactAndroid")
|
|
25
|
+
|
|
26
|
+
project(":packages:react-native:ReactAndroid").projectDir = file("ReactAndroid/")
|
|
27
|
+
|
|
28
|
+
include(":packages:react-native:ReactAndroid:hermes-engine")
|
|
29
|
+
|
|
30
|
+
project(":packages:react-native:ReactAndroid:hermes-engine").projectDir =
|
|
31
|
+
file("ReactAndroid/hermes-engine/")
|
package/template/metro.config.js
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
|
+
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
|
-
* Metro configuration
|
|
3
|
-
* https://github.
|
|
4
|
+
* Metro configuration
|
|
5
|
+
* https://facebook.github.io/metro/docs/configuration
|
|
4
6
|
*
|
|
5
|
-
* @
|
|
7
|
+
* @type {import('metro-config').MetroConfig}
|
|
6
8
|
*/
|
|
9
|
+
const config = {};
|
|
7
10
|
|
|
8
|
-
module.exports =
|
|
9
|
-
transformer: {
|
|
10
|
-
getTransformOptions: async () => ({
|
|
11
|
-
transform: {
|
|
12
|
-
experimentalImportSupport: false,
|
|
13
|
-
inlineRequires: true,
|
|
14
|
-
},
|
|
15
|
-
}),
|
|
16
|
-
},
|
|
17
|
-
};
|
|
11
|
+
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
|
package/template/package.json
CHANGED
|
@@ -11,20 +11,22 @@
|
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"react": "18.2.0",
|
|
14
|
-
"react-native": "0.72.0-rc.
|
|
14
|
+
"react-native": "0.72.0-rc.1"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@babel/core": "^7.20.0",
|
|
18
18
|
"@babel/preset-env": "^7.20.0",
|
|
19
19
|
"@babel/runtime": "^7.12.5",
|
|
20
20
|
"@react-native/eslint-config": "^0.72.1",
|
|
21
|
+
"@react-native/metro-config": "^0.72.1",
|
|
21
22
|
"@tsconfig/react-native": "^2.0.2",
|
|
23
|
+
"@types/metro-config": "^0.76.1",
|
|
22
24
|
"@types/react": "^18.0.24",
|
|
23
25
|
"@types/react-test-renderer": "^18.0.0",
|
|
24
26
|
"babel-jest": "^29.2.1",
|
|
25
27
|
"eslint": "^8.19.0",
|
|
26
28
|
"jest": "^29.2.1",
|
|
27
|
-
"metro-react-native-babel-preset": "0.
|
|
29
|
+
"metro-react-native-babel-preset": "0.76.0",
|
|
28
30
|
"prettier": "^2.4.1",
|
|
29
31
|
"react-test-renderer": "18.2.0",
|
|
30
32
|
"typescript": "4.8.4"
|