react-native 0.77.0 → 0.77.2

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.
Files changed (39) hide show
  1. package/Libraries/Core/ReactNativeVersion.js +1 -1
  2. package/Libraries/Core/setUpDeveloperTools.js +2 -3
  3. package/Libraries/Image/Image.android.js +2 -0
  4. package/Libraries/Image/ImageViewNativeComponent.js +3 -4
  5. package/Libraries/Image/RCTImageLoader.mm +9 -1
  6. package/Libraries/Utilities/HMRClient.js +0 -28
  7. package/Libraries/Utilities/HMRClientProdShim.js +0 -1
  8. package/React/Base/RCTVersion.m +1 -1
  9. package/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +1 -7
  10. package/ReactAndroid/api/ReactAndroid.api +2 -0
  11. package/ReactAndroid/gradle.properties +1 -1
  12. package/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +8 -2
  13. package/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java +15 -8
  14. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java +1 -1
  15. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CompositeBackgroundDrawable.kt +9 -8
  16. package/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.kt +1 -1
  17. package/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java +16 -2
  18. package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
  19. package/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTInteropTurboModule.mm +22 -4
  20. package/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.h +5 -0
  21. package/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm +51 -22
  22. package/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp +6 -0
  23. package/ReactCommon/react/renderer/attributedstring/TextAttributes.h +2 -0
  24. package/ReactCommon/react/renderer/attributedstring/conversions.h +5 -0
  25. package/ReactCommon/react/renderer/components/text/BaseTextProps.cpp +12 -0
  26. package/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.h +24 -3
  27. package/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm +6 -46
  28. package/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm +4 -5
  29. package/package.json +10 -10
  30. package/react-native.config.js +11 -21
  31. package/scripts/codegen/generate-artifacts-executor.js +8 -4
  32. package/scripts/generate-codegen-artifacts.js +6 -1
  33. package/sdks/hermesc/linux64-bin/hermesc +0 -0
  34. package/sdks/hermesc/osx-bin/hermes +0 -0
  35. package/sdks/hermesc/osx-bin/hermesc +0 -0
  36. package/sdks/hermesc/win64-bin/hermesc.exe +0 -0
  37. package/sdks/hermesc/win64-bin/msvcp140.dll +0 -0
  38. package/sdks/hermesc/win64-bin/vcruntime140.dll +0 -0
  39. package/sdks/hermesc/win64-bin/vcruntime140_1.dll +0 -0
@@ -16,7 +16,7 @@ const version: $ReadOnly<{
16
16
  }> = {
17
17
  major: 0,
18
18
  minor: 77,
19
- patch: 0,
19
+ patch: 2,
20
20
  prerelease: null,
21
21
  };
22
22
 
@@ -42,9 +42,8 @@ if (__DEV__) {
42
42
  if (!Platform.isTesting) {
43
43
  const HMRClient = require('../Utilities/HMRClient');
44
44
 
45
- if (global.__FUSEBOX_HAS_FULL_CONSOLE_SUPPORT__) {
46
- HMRClient.unstable_notifyFuseboxConsoleEnabled();
47
- } else if (console._isPolyfilled) {
45
+ // TODO(T214991636): Remove legacy Metro log forwarding
46
+ if (console._isPolyfilled) {
48
47
  // We assume full control over the console and send JavaScript logs to Metro.
49
48
  [
50
49
  'trace',
@@ -133,6 +133,7 @@ let BaseImage: AbstractImageAndroid = React.forwardRef(
133
133
  width: undefined,
134
134
  height: undefined,
135
135
  };
136
+ const defaultSource = resolveAssetSource(props.defaultSource);
136
137
  const loadingIndicatorSource = resolveAssetSource(
137
138
  props.loadingIndicatorSource,
138
139
  );
@@ -178,6 +179,7 @@ let BaseImage: AbstractImageAndroid = React.forwardRef(
178
179
  /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
179
180
  * when making Flow check .android.js files. */
180
181
  headers: (source?.[0]?.headers || source?.headers: ?{[string]: string}),
182
+ defaultSource: defaultSource ? defaultSource.uri : null,
181
183
  loadingIndicatorSrc: loadingIndicatorSource
182
184
  ? loadingIndicatorSource.uri
183
185
  : null,
@@ -21,6 +21,7 @@ import type {
21
21
  } from '../StyleSheet/StyleSheet';
22
22
  import type {ResolvedAssetSource} from './AssetSourceResolver';
23
23
  import type {ImageProps} from './ImageProps';
24
+ import type {ImageSource} from './ImageSource';
24
25
 
25
26
  import * as NativeComponentRegistry from '../NativeComponent/NativeComponentRegistry';
26
27
  import {ConditionallyIgnoredEventHandlers} from '../NativeComponent/ViewConfigIgnore';
@@ -42,7 +43,7 @@ type Props = $ReadOnly<{
42
43
  | ?ResolvedAssetSource
43
44
  | ?$ReadOnlyArray<?$ReadOnly<{uri?: ?string, ...}>>,
44
45
  headers?: ?{[string]: string},
45
- defaultSrc?: ?string,
46
+ defaultSource?: ?ImageSource | ?string,
46
47
  loadingIndicatorSrc?: ?string,
47
48
  }>;
48
49
 
@@ -82,9 +83,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig =
82
83
  },
83
84
  validAttributes: {
84
85
  blurRadius: true,
85
- defaultSource: {
86
- process: require('./resolveAssetSource'),
87
- },
86
+ defaultSource: true,
88
87
  internal_analyticTag: true,
89
88
  resizeMethod: true,
90
89
  resizeMode: true,
@@ -477,7 +477,15 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image, CGSize size, CGFloat scal
477
477
 
478
478
  // Add missing png extension
479
479
  if (request.URL.fileURL && request.URL.pathExtension.length == 0) {
480
- mutableRequest.URL = [request.URL URLByAppendingPathExtension:@"png"];
480
+ // Check if there exists a file with that url on disk already
481
+ // This should fix issue https://github.com/facebook/react-native/issues/46870
482
+ if ([[NSFileManager defaultManager] fileExistsAtPath:request.URL.path]) {
483
+ mutableRequest.URL = request.URL;
484
+ } else {
485
+ // This is the default behavior in case there is no file on disk with no extension.
486
+ // We assume that the extension is `png`.
487
+ mutableRequest.URL = [request.URL URLByAppendingPathExtension:@"png"];
488
+ }
481
489
  }
482
490
  if (_redirectDelegate != nil) {
483
491
  mutableRequest.URL = [_redirectDelegate redirectAssetsURL:mutableRequest.URL];
@@ -26,7 +26,6 @@ let hmrUnavailableReason: string | null = null;
26
26
  let currentCompileErrorMessage: string | null = null;
27
27
  let didConnect: boolean = false;
28
28
  let pendingLogs: Array<[LogLevel, $ReadOnlyArray<mixed>]> = [];
29
- let pendingFuseboxConsoleNotification = false;
30
29
 
31
30
  type LogLevel =
32
31
  | 'trace'
@@ -52,7 +51,6 @@ export type HMRClientNativeInterface = {|
52
51
  isEnabled: boolean,
53
52
  scheme?: string,
54
53
  ): void,
55
- unstable_notifyFuseboxConsoleEnabled(): void,
56
54
  |};
57
55
 
58
56
  /**
@@ -142,29 +140,6 @@ const HMRClient: HMRClientNativeInterface = {
142
140
  }
143
141
  },
144
142
 
145
- unstable_notifyFuseboxConsoleEnabled() {
146
- if (!hmrClient) {
147
- pendingFuseboxConsoleNotification = true;
148
- return;
149
- }
150
- hmrClient.send(
151
- JSON.stringify({
152
- type: 'log',
153
- level: 'info',
154
- data: [
155
- '\n' +
156
- '\u001B[7m' +
157
- ' \u001B[1m💡 JavaScript logs have moved!\u001B[22m They can now be ' +
158
- 'viewed in React Native DevTools. Tip: Type \u001B[1mj\u001B[22m in ' +
159
- 'the terminal to open (requires Google Chrome or Microsoft Edge).' +
160
- '\u001B[27m' +
161
- '\n',
162
- ],
163
- }),
164
- );
165
- pendingFuseboxConsoleNotification = false;
166
- },
167
-
168
143
  // Called once by the bridge on startup, even if Fast Refresh is off.
169
144
  // It creates the HMR client but doesn't actually set up the socket yet.
170
145
  setup(
@@ -341,9 +316,6 @@ function flushEarlyLogs(client: MetroHMRClient) {
341
316
  pendingLogs.forEach(([level, data]) => {
342
317
  HMRClient.log(level, data);
343
318
  });
344
- if (pendingFuseboxConsoleNotification) {
345
- HMRClient.unstable_notifyFuseboxConsoleEnabled();
346
- }
347
319
  } finally {
348
320
  pendingLogs.length = 0;
349
321
  }
@@ -25,7 +25,6 @@ const HMRClientProdShim: HMRClientNativeInterface = {
25
25
  disable() {},
26
26
  registerBundle() {},
27
27
  log() {},
28
- unstable_notifyFuseboxConsoleEnabled() {},
29
28
  };
30
29
 
31
30
  module.exports = HMRClientProdShim;
@@ -23,7 +23,7 @@ NSDictionary* RCTGetReactNativeVersion(void)
23
23
  __rnVersion = @{
24
24
  RCTVersionMajor: @(0),
25
25
  RCTVersionMinor: @(77),
26
- RCTVersionPatch: @(0),
26
+ RCTVersionPatch: @(2),
27
27
  RCTVersionPrerelease: [NSNull null],
28
28
  };
29
29
  });
@@ -101,11 +101,7 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
101
101
  NSMutableDictionary<NSAttributedStringKey, id> *defaultAttributes =
102
102
  [_backedTextInputView.defaultTextAttributes mutableCopy];
103
103
 
104
- #if !TARGET_OS_MACCATALYST
105
- RCTWeakEventEmitterWrapper *eventEmitterWrapper = [RCTWeakEventEmitterWrapper new];
106
- eventEmitterWrapper.eventEmitter = _eventEmitter;
107
- defaultAttributes[RCTAttributedStringEventEmitterKey] = eventEmitterWrapper;
108
- #endif
104
+ defaultAttributes[RCTAttributedStringEventEmitterKey] = RCTWrapEventEmitter(_eventEmitter);
109
105
 
110
106
  _backedTextInputView.defaultTextAttributes = defaultAttributes;
111
107
  }
@@ -266,10 +262,8 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
266
262
  if (newTextInputProps.textAttributes != oldTextInputProps.textAttributes) {
267
263
  NSMutableDictionary<NSAttributedStringKey, id> *defaultAttributes =
268
264
  RCTNSTextAttributesFromTextAttributes(newTextInputProps.getEffectiveTextAttributes(RCTFontSizeMultiplier()));
269
- #if !TARGET_OS_MACCATALYST
270
265
  defaultAttributes[RCTAttributedStringEventEmitterKey] =
271
266
  _backedTextInputView.defaultTextAttributes[RCTAttributedStringEventEmitterKey];
272
- #endif
273
267
  _backedTextInputView.defaultTextAttributes = defaultAttributes;
274
268
  }
275
269
 
@@ -7443,6 +7443,7 @@ public class com/facebook/react/views/text/TextAttributeProps {
7443
7443
  public static final field TA_KEY_LETTER_SPACING S
7444
7444
  public static final field TA_KEY_LINE_BREAK_STRATEGY S
7445
7445
  public static final field TA_KEY_LINE_HEIGHT S
7446
+ public static final field TA_KEY_MAX_FONT_SIZE_MULTIPLIER S
7446
7447
  public static final field TA_KEY_OPACITY S
7447
7448
  public static final field TA_KEY_ROLE S
7448
7449
  public static final field TA_KEY_TEXT_DECORATION_COLOR S
@@ -7475,6 +7476,7 @@ public class com/facebook/react/views/text/TextAttributeProps {
7475
7476
  protected field mLetterSpacingInput F
7476
7477
  protected field mLineHeight F
7477
7478
  protected field mLineHeightInput F
7479
+ protected field mMaxFontSizeMultiplier F
7478
7480
  protected field mNumberOfLines I
7479
7481
  protected field mOpacity F
7480
7482
  protected field mRole Lcom/facebook/react/uimanager/ReactAccessibilityDelegate$Role;
@@ -1,4 +1,4 @@
1
- VERSION_NAME=0.77.0
1
+ VERSION_NAME=0.77.2
2
2
  react.internal.publishingGroup=com.facebook.react
3
3
 
4
4
  android.useAndroidX=true
@@ -445,12 +445,18 @@ public class FabricUIManager
445
445
 
446
446
  @Override
447
447
  public void markActiveTouchForTag(int surfaceId, int reactTag) {
448
- mMountingManager.getSurfaceManager(surfaceId).markActiveTouchForTag(reactTag);
448
+ SurfaceMountingManager surfaceMountingManager = mMountingManager.getSurfaceManager(surfaceId);
449
+ if (surfaceMountingManager != null) {
450
+ surfaceMountingManager.markActiveTouchForTag(reactTag);
451
+ }
449
452
  }
450
453
 
451
454
  @Override
452
455
  public void sweepActiveTouchForTag(int surfaceId, int reactTag) {
453
- mMountingManager.getSurfaceManager(surfaceId).sweepActiveTouchForTag(reactTag);
456
+ SurfaceMountingManager surfaceMountingManager = mMountingManager.getSurfaceManager(surfaceId);
457
+ if (surfaceMountingManager != null) {
458
+ surfaceMountingManager.sweepActiveTouchForTag(reactTag);
459
+ }
454
460
  }
455
461
 
456
462
  /**
@@ -330,14 +330,11 @@ public class MountingManager {
330
330
  @AnyThread
331
331
  @ThreadConfined(ANY)
332
332
  public @Nullable EventEmitterWrapper getEventEmitter(int surfaceId, int reactTag) {
333
- SurfaceMountingManager surfaceMountingManager =
334
- (surfaceId == ViewUtil.NO_SURFACE_ID
335
- ? getSurfaceManagerForView(reactTag)
336
- : getSurfaceManager(surfaceId));
337
- if (surfaceMountingManager == null) {
333
+ SurfaceMountingManager smm = getSurfaceMountingManager(surfaceId, reactTag);
334
+ if (smm == null) {
338
335
  return null;
339
336
  }
340
- return surfaceMountingManager.getEventEmitter(reactTag);
337
+ return smm.getEventEmitter(reactTag);
341
338
  }
342
339
 
343
340
  /**
@@ -434,11 +431,21 @@ public class MountingManager {
434
431
  boolean canCoalesceEvent,
435
432
  @Nullable WritableMap params,
436
433
  @EventCategoryDef int eventCategory) {
437
- @Nullable SurfaceMountingManager smm = getSurfaceManager(surfaceId);
434
+ SurfaceMountingManager smm = getSurfaceMountingManager(surfaceId, reactTag);
438
435
  if (smm == null) {
439
- // Cannot queue event without valid surface mountng manager. Do nothing here.
436
+ FLog.d(
437
+ TAG,
438
+ "Cannot queue event without valid surface mounting manager for tag: %d, surfaceId: %d",
439
+ reactTag,
440
+ surfaceId);
440
441
  return;
441
442
  }
442
443
  smm.enqueuePendingEvent(reactTag, eventName, canCoalesceEvent, params, eventCategory);
443
444
  }
445
+
446
+ private @Nullable SurfaceMountingManager getSurfaceMountingManager(int surfaceId, int reactTag) {
447
+ return (surfaceId == ViewUtil.NO_SURFACE_ID
448
+ ? getSurfaceManagerForView(reactTag)
449
+ : getSurfaceManager(surfaceId));
450
+ }
444
451
  }
@@ -17,6 +17,6 @@ public class ReactNativeVersion {
17
17
  public static final Map<String, Object> VERSION = MapBuilder.<String, Object>of(
18
18
  "major", 0,
19
19
  "minor", 77,
20
- "patch", 0,
20
+ "patch", 2,
21
21
  "prerelease", null);
22
22
  }
@@ -16,6 +16,7 @@ import android.graphics.drawable.LayerDrawable
16
16
  import android.os.Build
17
17
  import com.facebook.react.common.annotations.UnstableReactNativeAPI
18
18
  import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
19
+ import com.facebook.react.uimanager.PixelUtil.dpToPx
19
20
  import com.facebook.react.uimanager.style.BorderInsets
20
21
  import com.facebook.react.uimanager.style.BorderRadiusStyle
21
22
 
@@ -200,14 +201,14 @@ internal class CompositeBackgroundDrawable(
200
201
  pathForOutline.addRoundRect(
201
202
  RectF(bounds),
202
203
  floatArrayOf(
203
- it.topLeft.horizontal + (computedBorderInsets?.left ?: 0f),
204
- it.topLeft.vertical + (computedBorderInsets?.top ?: 0f),
205
- it.topRight.horizontal + (computedBorderInsets?.right ?: 0f),
206
- it.topRight.vertical + (computedBorderInsets?.top ?: 0f),
207
- it.bottomRight.horizontal + (computedBorderInsets?.right ?: 0f),
208
- it.bottomRight.vertical + (computedBorderInsets?.bottom ?: 0f),
209
- it.bottomLeft.horizontal + (computedBorderInsets?.left ?: 0f),
210
- it.bottomLeft.vertical) + (computedBorderInsets?.bottom ?: 0f),
204
+ (it.topLeft.horizontal + (computedBorderInsets?.left ?: 0f)).dpToPx(),
205
+ (it.topLeft.vertical + (computedBorderInsets?.top ?: 0f)).dpToPx(),
206
+ (it.topRight.horizontal + (computedBorderInsets?.right ?: 0f)).dpToPx(),
207
+ (it.topRight.vertical + (computedBorderInsets?.top ?: 0f)).dpToPx(),
208
+ (it.bottomRight.horizontal + (computedBorderInsets?.right ?: 0f)).dpToPx(),
209
+ (it.bottomRight.vertical + (computedBorderInsets?.bottom ?: 0f)).dpToPx(),
210
+ (it.bottomLeft.horizontal + (computedBorderInsets?.left ?: 0f)).dpToPx(),
211
+ (it.bottomLeft.vertical + (computedBorderInsets?.bottom ?: 0f)).dpToPx()),
211
212
  Path.Direction.CW)
212
213
  }
213
214
 
@@ -124,7 +124,7 @@ public constructor(
124
124
  }
125
125
  }
126
126
 
127
- @ReactProp(name = "defaultSource", customType = "ImageSource")
127
+ @ReactProp(name = "defaultSource")
128
128
  public fun setDefaultSource(view: ReactImageView, source: String?) {
129
129
  view.setDefaultSource(source)
130
130
  }
@@ -61,6 +61,7 @@ public class TextAttributeProps {
61
61
  public static final short TA_KEY_LINE_BREAK_STRATEGY = 25;
62
62
  public static final short TA_KEY_ROLE = 26;
63
63
  public static final short TA_KEY_TEXT_TRANSFORM = 27;
64
+ public static final short TA_KEY_MAX_FONT_SIZE_MULTIPLIER = 29;
64
65
 
65
66
  public static final int UNSET = -1;
66
67
 
@@ -81,6 +82,7 @@ public class TextAttributeProps {
81
82
  protected float mLineHeight = Float.NaN;
82
83
  protected boolean mIsColorSet = false;
83
84
  protected boolean mAllowFontScaling = true;
85
+ protected float mMaxFontSizeMultiplier = Float.NaN;
84
86
  protected int mColor;
85
87
  protected boolean mIsBackgroundColorSet = false;
86
88
  protected int mBackgroundColor;
@@ -227,6 +229,9 @@ public class TextAttributeProps {
227
229
  case TA_KEY_TEXT_TRANSFORM:
228
230
  result.setTextTransform(entry.getStringValue());
229
231
  break;
232
+ case TA_KEY_MAX_FONT_SIZE_MULTIPLIER:
233
+ result.setMaxFontSizeMultiplier((float) entry.getDoubleValue());
234
+ break;
230
235
  }
231
236
  }
232
237
 
@@ -243,6 +248,8 @@ public class TextAttributeProps {
243
248
  result.setLineHeight(getFloatProp(props, ViewProps.LINE_HEIGHT, ReactConstants.UNSET));
244
249
  result.setLetterSpacing(getFloatProp(props, ViewProps.LETTER_SPACING, Float.NaN));
245
250
  result.setAllowFontScaling(getBooleanProp(props, ViewProps.ALLOW_FONT_SCALING, true));
251
+ result.setMaxFontSizeMultiplier(
252
+ getFloatProp(props, ViewProps.MAX_FONT_SIZE_MULTIPLIER, Float.NaN));
246
253
  result.setFontSize(getFloatProp(props, ViewProps.FONT_SIZE, ReactConstants.UNSET));
247
254
  result.setColor(props.hasKey(ViewProps.COLOR) ? props.getInt(ViewProps.COLOR, 0) : null);
248
255
  result.setColor(
@@ -411,7 +418,14 @@ public class TextAttributeProps {
411
418
  mAllowFontScaling = allowFontScaling;
412
419
  setFontSize(mFontSizeInput);
413
420
  setLineHeight(mLineHeightInput);
414
- setLetterSpacing(mLetterSpacingInput);
421
+ }
422
+ }
423
+
424
+ private void setMaxFontSizeMultiplier(float maxFontSizeMultiplier) {
425
+ if (maxFontSizeMultiplier != mMaxFontSizeMultiplier) {
426
+ mMaxFontSizeMultiplier = maxFontSizeMultiplier;
427
+ setFontSize(mFontSizeInput);
428
+ setLineHeight(mLineHeightInput);
415
429
  }
416
430
  }
417
431
 
@@ -420,7 +434,7 @@ public class TextAttributeProps {
420
434
  if (fontSize != ReactConstants.UNSET) {
421
435
  fontSize =
422
436
  mAllowFontScaling
423
- ? (float) Math.ceil(PixelUtil.toPixelFromSP(fontSize))
437
+ ? (float) Math.ceil(PixelUtil.toPixelFromSP(fontSize, mMaxFontSizeMultiplier))
424
438
  : (float) Math.ceil(PixelUtil.toPixelFromDIP(fontSize));
425
439
  }
426
440
  mFontSize = (int) fontSize;
@@ -17,7 +17,7 @@ namespace facebook::react {
17
17
  constexpr struct {
18
18
  int32_t Major = 0;
19
19
  int32_t Minor = 77;
20
- int32_t Patch = 0;
20
+ int32_t Patch = 2;
21
21
  std::string_view Prerelease = "";
22
22
  } ReactNativeVersion;
23
23
 
@@ -123,6 +123,15 @@ std::vector<ExportedMethod> parseExportedMethods(std::string moduleName, Class m
123
123
  NSArray<RCTMethodArgument *> *arguments;
124
124
  SEL objCMethodSelector = NSSelectorFromString(RCTParseMethodSignature(methodInfo->objcName, &arguments));
125
125
  NSMethodSignature *objCMethodSignature = [moduleClass instanceMethodSignatureForSelector:objCMethodSelector];
126
+ if (objCMethodSignature == nullptr) {
127
+ RCTLogWarn(
128
+ @"The objective-c `%s` method signature for the JS method `%@` can not be found in the ObjecitveC definition of the %s module.\nThe `%@` JS method will not be available.",
129
+ methodInfo->objcName,
130
+ jsMethodName,
131
+ moduleName.c_str(),
132
+ jsMethodName);
133
+ continue;
134
+ }
126
135
  std::string objCMethodReturnType = [objCMethodSignature methodReturnType];
127
136
 
128
137
  if (objCMethodSignature.numberOfArguments - 2 != [arguments count]) {
@@ -337,7 +346,7 @@ void ObjCInteropTurboModule::setInvocationArg(
337
346
  SEL selector = selectorForType(argumentType);
338
347
 
339
348
  if ([RCTConvert respondsToSelector:selector]) {
340
- id objCArg = TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_);
349
+ id objCArg = TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_, YES);
341
350
 
342
351
  if (objCArgType == @encode(char)) {
343
352
  char arg = RCTConvertTo<char>(selector, objCArg);
@@ -437,6 +446,15 @@ void ObjCInteropTurboModule::setInvocationArg(
437
446
 
438
447
  if (objCArgType == @encode(id)) {
439
448
  id arg = RCTConvertTo<id>(selector, objCArg);
449
+
450
+ // Handle the special case where there is an argument and it must be nil
451
+ // Without this check, the JS side will receive an object.
452
+ // See: discussion at
453
+ // https://github.com/facebook/react-native/pull/49250#issuecomment-2668465893
454
+ if (arg == [NSNull null]) {
455
+ return;
456
+ }
457
+
440
458
  if (arg) {
441
459
  [retainedObjectsForInvocation addObject:arg];
442
460
  }
@@ -491,7 +509,7 @@ void ObjCInteropTurboModule::setInvocationArg(
491
509
  }
492
510
 
493
511
  RCTResponseSenderBlock arg =
494
- (RCTResponseSenderBlock)TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_);
512
+ (RCTResponseSenderBlock)TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_, YES);
495
513
  if (arg) {
496
514
  [retainedObjectsForInvocation addObject:arg];
497
515
  }
@@ -506,7 +524,7 @@ void ObjCInteropTurboModule::setInvocationArg(
506
524
  }
507
525
 
508
526
  RCTResponseSenderBlock senderBlock =
509
- (RCTResponseSenderBlock)TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_);
527
+ (RCTResponseSenderBlock)TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_, YES);
510
528
  RCTResponseErrorBlock arg = ^(NSError *error) {
511
529
  senderBlock(@[ RCTJSErrorFromNSError(error) ]);
512
530
  };
@@ -536,7 +554,7 @@ void ObjCInteropTurboModule::setInvocationArg(
536
554
  runtime, errorPrefix + "JavaScript argument must be a plain object. Got " + getType(runtime, jsiArg));
537
555
  }
538
556
 
539
- id arg = TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_);
557
+ id arg = TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_, YES);
540
558
 
541
559
  RCTManagedPointer *(*convert)(id, SEL, id) = (__typeof__(convert))objc_msgSend;
542
560
  RCTManagedPointer *box = convert([RCTCxxConvert class], selector, arg);
@@ -32,6 +32,11 @@ using EventEmitterCallback = std::function<void(const std::string &, id)>;
32
32
  namespace TurboModuleConvertUtils {
33
33
  jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value);
34
34
  id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value, std::shared_ptr<CallInvoker> jsInvoker);
35
+ id convertJSIValueToObjCObject(
36
+ jsi::Runtime &runtime,
37
+ const jsi::Value &value,
38
+ std::shared_ptr<CallInvoker> jsInvoker,
39
+ BOOL useNSNull);
35
40
  } // namespace TurboModuleConvertUtils
36
41
 
37
42
  template <>
@@ -57,7 +57,7 @@ static jsi::Value convertNSNumberToJSINumber(jsi::Runtime &runtime, NSNumber *va
57
57
 
58
58
  static jsi::String convertNSStringToJSIString(jsi::Runtime &runtime, NSString *value)
59
59
  {
60
- return jsi::String::createFromUtf8(runtime, [value UTF8String] ?: "");
60
+ return jsi::String::createFromUtf8(runtime, [value UTF8String] ? [value UTF8String] : "");
61
61
  }
62
62
 
63
63
  static jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDictionary *value)
@@ -111,21 +111,27 @@ static NSString *convertJSIStringToNSString(jsi::Runtime &runtime, const jsi::St
111
111
  return [NSString stringWithUTF8String:value.utf8(runtime).c_str()];
112
112
  }
113
113
 
114
- static NSArray *
115
- convertJSIArrayToNSArray(jsi::Runtime &runtime, const jsi::Array &value, std::shared_ptr<CallInvoker> jsInvoker)
114
+ static NSArray *convertJSIArrayToNSArray(
115
+ jsi::Runtime &runtime,
116
+ const jsi::Array &value,
117
+ std::shared_ptr<CallInvoker> jsInvoker,
118
+ BOOL useNSNull)
116
119
  {
117
120
  size_t size = value.size(runtime);
118
121
  NSMutableArray *result = [NSMutableArray new];
119
122
  for (size_t i = 0; i < size; i++) {
120
123
  // Insert kCFNull when it's `undefined` value to preserve the indices.
121
- id convertedObject = convertJSIValueToObjCObject(runtime, value.getValueAtIndex(runtime, i), jsInvoker);
124
+ id convertedObject = convertJSIValueToObjCObject(runtime, value.getValueAtIndex(runtime, i), jsInvoker, useNSNull);
122
125
  [result addObject:convertedObject ? convertedObject : (id)kCFNull];
123
126
  }
124
127
  return [result copy];
125
128
  }
126
129
 
127
- static NSDictionary *
128
- convertJSIObjectToNSDictionary(jsi::Runtime &runtime, const jsi::Object &value, std::shared_ptr<CallInvoker> jsInvoker)
130
+ static NSDictionary *convertJSIObjectToNSDictionary(
131
+ jsi::Runtime &runtime,
132
+ const jsi::Object &value,
133
+ std::shared_ptr<CallInvoker> jsInvoker,
134
+ BOOL useNSNull)
129
135
  {
130
136
  jsi::Array propertyNames = value.getPropertyNames(runtime);
131
137
  size_t size = propertyNames.size(runtime);
@@ -133,7 +139,7 @@ convertJSIObjectToNSDictionary(jsi::Runtime &runtime, const jsi::Object &value,
133
139
  for (size_t i = 0; i < size; i++) {
134
140
  jsi::String name = propertyNames.getValueAtIndex(runtime, i).getString(runtime);
135
141
  NSString *k = convertJSIStringToNSString(runtime, name);
136
- id v = convertJSIValueToObjCObject(runtime, value.getProperty(runtime, name), jsInvoker);
142
+ id v = convertJSIValueToObjCObject(runtime, value.getProperty(runtime, name), jsInvoker, useNSNull);
137
143
  if (v) {
138
144
  result[k] = v;
139
145
  }
@@ -161,9 +167,21 @@ convertJSIFunctionToCallback(jsi::Runtime &rt, jsi::Function &&function, std::sh
161
167
 
162
168
  id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value, std::shared_ptr<CallInvoker> jsInvoker)
163
169
  {
164
- if (value.isUndefined() || value.isNull()) {
170
+ return convertJSIValueToObjCObject(runtime, value, jsInvoker, NO);
171
+ }
172
+
173
+ id convertJSIValueToObjCObject(
174
+ jsi::Runtime &runtime,
175
+ const jsi::Value &value,
176
+ std::shared_ptr<CallInvoker> jsInvoker,
177
+ BOOL useNSNull)
178
+ {
179
+ if (value.isUndefined() || (value.isNull() && !useNSNull)) {
165
180
  return nil;
166
181
  }
182
+ if (value.isNull() && useNSNull) {
183
+ return [NSNull null];
184
+ }
167
185
  if (value.isBool()) {
168
186
  return @(value.getBool());
169
187
  }
@@ -176,12 +194,12 @@ id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value, s
176
194
  if (value.isObject()) {
177
195
  jsi::Object o = value.getObject(runtime);
178
196
  if (o.isArray(runtime)) {
179
- return convertJSIArrayToNSArray(runtime, o.getArray(runtime), jsInvoker);
197
+ return convertJSIArrayToNSArray(runtime, o.getArray(runtime), jsInvoker, useNSNull);
180
198
  }
181
199
  if (o.isFunction(runtime)) {
182
200
  return convertJSIFunctionToCallback(runtime, o.getFunction(runtime), jsInvoker);
183
201
  }
184
- return convertJSIObjectToNSDictionary(runtime, o, jsInvoker);
202
+ return convertJSIObjectToNSDictionary(runtime, o, jsInvoker, useNSNull);
185
203
  }
186
204
 
187
205
  throw std::runtime_error("Unsupported jsi::Value kind");
@@ -195,7 +213,11 @@ static jsi::Value createJSRuntimeError(jsi::Runtime &runtime, const std::string
195
213
  /**
196
214
  * Creates JSError with current JS runtime and NSException stack trace.
197
215
  */
198
- static jsi::JSError convertNSExceptionToJSError(jsi::Runtime &runtime, NSException *exception)
216
+ static jsi::JSError convertNSExceptionToJSError(
217
+ jsi::Runtime &runtime,
218
+ NSException *exception,
219
+ const std::string &moduleName,
220
+ const std::string &methodName)
199
221
  {
200
222
  std::string reason = [exception.reason UTF8String];
201
223
 
@@ -206,7 +228,8 @@ static jsi::JSError convertNSExceptionToJSError(jsi::Runtime &runtime, NSExcepti
206
228
  cause.setProperty(
207
229
  runtime, "stackReturnAddresses", convertNSArrayToJSIArray(runtime, exception.callStackReturnAddresses));
208
230
 
209
- jsi::Value error = createJSRuntimeError(runtime, "Exception in HostFunction: " + reason);
231
+ std::string message = moduleName + "." + methodName + " raised an exception: " + reason;
232
+ jsi::Value error = createJSRuntimeError(runtime, message);
210
233
  error.asObject(runtime).setProperty(runtime, "cause", std::move(cause));
211
234
  return {runtime, std::move(error)};
212
235
  }
@@ -338,28 +361,34 @@ id ObjCTurboModule::performMethodInvocation(
338
361
  }
339
362
 
340
363
  if (isSync) {
341
- TurboModulePerfLogger::syncMethodCallExecutionStart(moduleName, methodNameStr.c_str());
364
+ TurboModulePerfLogger::syncMethodCallExecutionStart(moduleName, methodName);
342
365
  } else {
343
- TurboModulePerfLogger::asyncMethodCallExecutionStart(moduleName, methodNameStr.c_str(), asyncCallCounter);
366
+ TurboModulePerfLogger::asyncMethodCallExecutionStart(moduleName, methodName, asyncCallCounter);
344
367
  }
345
368
 
346
369
  @try {
347
370
  [inv invokeWithTarget:strongModule];
348
371
  } @catch (NSException *exception) {
349
- throw convertNSExceptionToJSError(runtime, exception);
372
+ if (isSync) {
373
+ // We can only convert NSException to JSError in sync method calls.
374
+ // See https://github.com/reactwg/react-native-new-architecture/discussions/276#discussioncomment-12567155
375
+ throw convertNSExceptionToJSError(runtime, exception, std::string{moduleName}, methodNameStr);
376
+ } else {
377
+ @throw exception;
378
+ }
350
379
  } @finally {
351
380
  [retainedObjectsForInvocation removeAllObjects];
352
381
  }
353
382
 
354
383
  if (!isSync) {
355
- TurboModulePerfLogger::asyncMethodCallExecutionEnd(moduleName, methodNameStr.c_str(), asyncCallCounter);
384
+ TurboModulePerfLogger::asyncMethodCallExecutionEnd(moduleName, methodName, asyncCallCounter);
356
385
  return;
357
386
  }
358
387
 
359
388
  void *rawResult;
360
389
  [inv getReturnValue:&rawResult];
361
390
  result = (__bridge id)rawResult;
362
- TurboModulePerfLogger::syncMethodCallExecutionEnd(moduleName, methodNameStr.c_str());
391
+ TurboModulePerfLogger::syncMethodCallExecutionEnd(moduleName, methodName);
363
392
  };
364
393
 
365
394
  if (isSync) {
@@ -401,23 +430,23 @@ void ObjCTurboModule::performVoidMethodInvocation(
401
430
  }
402
431
 
403
432
  if (shouldVoidMethodsExecuteSync_) {
404
- TurboModulePerfLogger::syncMethodCallExecutionStart(moduleName, methodNameStr.c_str());
433
+ TurboModulePerfLogger::syncMethodCallExecutionStart(moduleName, methodName);
405
434
  } else {
406
- TurboModulePerfLogger::asyncMethodCallExecutionStart(moduleName, methodNameStr.c_str(), asyncCallCounter);
435
+ TurboModulePerfLogger::asyncMethodCallExecutionStart(moduleName, methodName, asyncCallCounter);
407
436
  }
408
437
 
409
438
  @try {
410
439
  [inv invokeWithTarget:strongModule];
411
440
  } @catch (NSException *exception) {
412
- throw convertNSExceptionToJSError(runtime, exception);
441
+ throw convertNSExceptionToJSError(runtime, exception, std::string{moduleName}, methodNameStr);
413
442
  } @finally {
414
443
  [retainedObjectsForInvocation removeAllObjects];
415
444
  }
416
445
 
417
446
  if (shouldVoidMethodsExecuteSync_) {
418
- TurboModulePerfLogger::syncMethodCallExecutionEnd(moduleName, methodNameStr.c_str());
447
+ TurboModulePerfLogger::syncMethodCallExecutionEnd(moduleName, methodName);
419
448
  } else {
420
- TurboModulePerfLogger::asyncMethodCallExecutionEnd(moduleName, methodNameStr.c_str(), asyncCallCounter);
449
+ TurboModulePerfLogger::asyncMethodCallExecutionEnd(moduleName, methodName, asyncCallCounter);
421
450
  }
422
451
 
423
452
  return;
@@ -46,6 +46,9 @@ void TextAttributes::apply(TextAttributes textAttributes) {
46
46
  allowFontScaling = textAttributes.allowFontScaling.has_value()
47
47
  ? textAttributes.allowFontScaling
48
48
  : allowFontScaling;
49
+ maxFontSizeMultiplier = !std::isnan(textAttributes.maxFontSizeMultiplier)
50
+ ? textAttributes.maxFontSizeMultiplier
51
+ : maxFontSizeMultiplier;
49
52
  dynamicTypeRamp = textAttributes.dynamicTypeRamp.has_value()
50
53
  ? textAttributes.dynamicTypeRamp
51
54
  : dynamicTypeRamp;
@@ -168,6 +171,7 @@ bool TextAttributes::operator==(const TextAttributes& rhs) const {
168
171
  rhs.accessibilityRole,
169
172
  rhs.role,
170
173
  rhs.textTransform) &&
174
+ floatEquality(maxFontSizeMultiplier, rhs.maxFontSizeMultiplier) &&
171
175
  floatEquality(opacity, rhs.opacity) &&
172
176
  floatEquality(fontSize, rhs.fontSize) &&
173
177
  floatEquality(fontSizeMultiplier, rhs.fontSizeMultiplier) &&
@@ -211,6 +215,8 @@ SharedDebugStringConvertibleList TextAttributes::getDebugProps() const {
211
215
  debugStringConvertibleItem("fontStyle", fontStyle),
212
216
  debugStringConvertibleItem("fontVariant", fontVariant),
213
217
  debugStringConvertibleItem("allowFontScaling", allowFontScaling),
218
+ debugStringConvertibleItem(
219
+ "maxFontSizeMultiplier", maxFontSizeMultiplier),
214
220
  debugStringConvertibleItem("dynamicTypeRamp", dynamicTypeRamp),
215
221
  debugStringConvertibleItem("letterSpacing", letterSpacing),
216
222
 
@@ -51,6 +51,7 @@ class TextAttributes : public DebugStringConvertible {
51
51
  std::optional<FontStyle> fontStyle{};
52
52
  std::optional<FontVariant> fontVariant{};
53
53
  std::optional<bool> allowFontScaling{};
54
+ Float maxFontSizeMultiplier{std::numeric_limits<Float>::quiet_NaN()};
54
55
  std::optional<DynamicTypeRamp> dynamicTypeRamp{};
55
56
  Float letterSpacing{std::numeric_limits<Float>::quiet_NaN()};
56
57
  std::optional<TextTransform> textTransform{};
@@ -117,6 +118,7 @@ struct hash<facebook::react::TextAttributes> {
117
118
  textAttributes.opacity,
118
119
  textAttributes.fontFamily,
119
120
  textAttributes.fontSize,
121
+ textAttributes.maxFontSizeMultiplier,
120
122
  textAttributes.fontSizeMultiplier,
121
123
  textAttributes.fontWeight,
122
124
  textAttributes.fontStyle,
@@ -910,6 +910,7 @@ constexpr static MapBuffer::Key TA_KEY_LINE_BREAK_STRATEGY = 25;
910
910
  constexpr static MapBuffer::Key TA_KEY_ROLE = 26;
911
911
  constexpr static MapBuffer::Key TA_KEY_TEXT_TRANSFORM = 27;
912
912
  constexpr static MapBuffer::Key TA_KEY_ALIGNMENT_VERTICAL = 28;
913
+ constexpr static MapBuffer::Key TA_KEY_MAX_FONT_SIZE_MULTIPLIER = 29;
913
914
 
914
915
  // constants for ParagraphAttributes serialization
915
916
  constexpr static MapBuffer::Key PA_KEY_MAX_NUMBER_OF_LINES = 0;
@@ -1004,6 +1005,10 @@ inline MapBuffer toMapBuffer(const TextAttributes& textAttributes) {
1004
1005
  builder.putBool(
1005
1006
  TA_KEY_ALLOW_FONT_SCALING, *textAttributes.allowFontScaling);
1006
1007
  }
1008
+ if (!std::isnan(textAttributes.maxFontSizeMultiplier)) {
1009
+ builder.putDouble(
1010
+ TA_KEY_MAX_FONT_SIZE_MULTIPLIER, textAttributes.maxFontSizeMultiplier);
1011
+ }
1007
1012
  if (!std::isnan(textAttributes.letterSpacing)) {
1008
1013
  builder.putDouble(TA_KEY_LETTER_SPACING, textAttributes.letterSpacing);
1009
1014
  }
@@ -73,6 +73,12 @@ static TextAttributes convertRawProp(
73
73
  "allowFontScaling",
74
74
  sourceTextAttributes.allowFontScaling,
75
75
  defaultTextAttributes.allowFontScaling);
76
+ textAttributes.maxFontSizeMultiplier = convertRawProp(
77
+ context,
78
+ rawProps,
79
+ "maxFontSizeMultiplier",
80
+ sourceTextAttributes.maxFontSizeMultiplier,
81
+ defaultTextAttributes.maxFontSizeMultiplier);
76
82
  textAttributes.dynamicTypeRamp = convertRawProp(
77
83
  context,
78
84
  rawProps,
@@ -266,6 +272,12 @@ void BaseTextProps::setProp(
266
272
  defaults, value, textAttributes, fontVariant, "fontVariant");
267
273
  REBUILD_FIELD_SWITCH_CASE(
268
274
  defaults, value, textAttributes, allowFontScaling, "allowFontScaling");
275
+ REBUILD_FIELD_SWITCH_CASE(
276
+ defaults,
277
+ value,
278
+ textAttributes,
279
+ maxFontSizeMultiplier,
280
+ "maxFontSizeMultiplier");
269
281
  REBUILD_FIELD_SWITCH_CASE(
270
282
  defaults, value, textAttributes, letterSpacing, "letterSpacing");
271
283
  REBUILD_FIELD_SWITCH_CASE(
@@ -52,8 +52,29 @@ BOOL RCTIsAttributedStringEffectivelySame(
52
52
  NSDictionary<NSAttributedStringKey, id> *insensitiveAttributes,
53
53
  const facebook::react::TextAttributes &baseTextAttributes);
54
54
 
55
- @interface RCTWeakEventEmitterWrapper : NSObject
56
- @property (nonatomic, assign) facebook::react::SharedEventEmitter eventEmitter;
57
- @end
55
+ static inline NSData *RCTWrapEventEmitter(const facebook::react::SharedEventEmitter &eventEmitter)
56
+ {
57
+ auto eventEmitterPtr = new std::weak_ptr<const facebook::react::EventEmitter>(eventEmitter);
58
+ return [[NSData alloc] initWithBytesNoCopy:eventEmitterPtr
59
+ length:sizeof(eventEmitterPtr)
60
+ deallocator:^(void *ptrToDelete, NSUInteger) {
61
+ delete (std::weak_ptr<facebook::react::EventEmitter> *)ptrToDelete;
62
+ }];
63
+ }
64
+
65
+ static inline facebook::react::SharedEventEmitter RCTUnwrapEventEmitter(NSData *data)
66
+ {
67
+ if (data.length == 0) {
68
+ return nullptr;
69
+ }
70
+
71
+ auto weakPtr = dynamic_cast<std::weak_ptr<const facebook::react::EventEmitter> *>(
72
+ (std::weak_ptr<const facebook::react::EventEmitter> *)data.bytes);
73
+ if (weakPtr) {
74
+ return weakPtr->lock();
75
+ }
76
+
77
+ return nullptr;
78
+ }
58
79
 
59
80
  NS_ASSUME_NONNULL_END
@@ -16,45 +16,6 @@
16
16
 
17
17
  using namespace facebook::react;
18
18
 
19
- @implementation RCTWeakEventEmitterWrapper {
20
- std::weak_ptr<const EventEmitter> _weakEventEmitter;
21
- }
22
-
23
- - (void)setEventEmitter:(SharedEventEmitter)eventEmitter
24
- {
25
- _weakEventEmitter = eventEmitter;
26
- }
27
-
28
- - (SharedEventEmitter)eventEmitter
29
- {
30
- return _weakEventEmitter.lock();
31
- }
32
-
33
- - (void)dealloc
34
- {
35
- _weakEventEmitter.reset();
36
- }
37
-
38
- - (BOOL)isEqual:(id)object
39
- {
40
- // We consider the underlying EventEmitter as the identity
41
- if (![object isKindOfClass:[self class]]) {
42
- return NO;
43
- }
44
-
45
- auto thisEventEmitter = [self eventEmitter];
46
- auto otherEventEmitter = [((RCTWeakEventEmitterWrapper *)object) eventEmitter];
47
- return thisEventEmitter == otherEventEmitter;
48
- }
49
-
50
- - (NSUInteger)hash
51
- {
52
- // We consider the underlying EventEmitter as the identity
53
- return (NSUInteger)_weakEventEmitter.lock().get();
54
- }
55
-
56
- @end
57
-
58
19
  inline static UIFontWeight RCTUIFontWeightFromInteger(NSInteger fontWeight)
59
20
  {
60
21
  assert(fontWeight > 50);
@@ -135,6 +96,7 @@ inline static CGFloat RCTBaseSizeForDynamicTypeRamp(const DynamicTypeRamp &dynam
135
96
  inline static CGFloat RCTEffectiveFontSizeMultiplierFromTextAttributes(const TextAttributes &textAttributes)
136
97
  {
137
98
  if (textAttributes.allowFontScaling.value_or(true)) {
99
+ CGFloat fontSizeMultiplier = !isnan(textAttributes.fontSizeMultiplier) ? textAttributes.fontSizeMultiplier : 1.0;
138
100
  if (textAttributes.dynamicTypeRamp.has_value()) {
139
101
  DynamicTypeRamp dynamicTypeRamp = textAttributes.dynamicTypeRamp.value();
140
102
  UIFontMetrics *fontMetrics =
@@ -142,10 +104,11 @@ inline static CGFloat RCTEffectiveFontSizeMultiplierFromTextAttributes(const Tex
142
104
  // Using a specific font size reduces rounding errors from -scaledValueForValue:
143
105
  CGFloat requestedSize =
144
106
  isnan(textAttributes.fontSize) ? RCTBaseSizeForDynamicTypeRamp(dynamicTypeRamp) : textAttributes.fontSize;
145
- return [fontMetrics scaledValueForValue:requestedSize] / requestedSize;
146
- } else {
147
- return textAttributes.fontSizeMultiplier;
107
+ fontSizeMultiplier = [fontMetrics scaledValueForValue:requestedSize] / requestedSize;
148
108
  }
109
+ CGFloat maxFontSizeMultiplier =
110
+ !isnan(textAttributes.maxFontSizeMultiplier) ? textAttributes.maxFontSizeMultiplier : 0.0;
111
+ return maxFontSizeMultiplier >= 1.0 ? fminf(maxFontSizeMultiplier, fontSizeMultiplier) : fontSizeMultiplier;
149
112
  } else {
150
113
  return 1.0;
151
114
  }
@@ -403,10 +366,8 @@ static NSMutableAttributedString *RCTNSAttributedStringFragmentWithAttributesFro
403
366
  {
404
367
  auto nsAttributedStringFragment = RCTNSAttributedStringFragmentFromFragment(fragment, placeholderImage);
405
368
 
406
- #if !TARGET_OS_MACCATALYST
407
369
  if (fragment.parentShadowView.componentHandle) {
408
- RCTWeakEventEmitterWrapper *eventEmitterWrapper = [RCTWeakEventEmitterWrapper new];
409
- eventEmitterWrapper.eventEmitter = fragment.parentShadowView.eventEmitter;
370
+ auto eventEmitterWrapper = RCTWrapEventEmitter(fragment.parentShadowView.eventEmitter);
410
371
 
411
372
  NSDictionary<NSAttributedStringKey, id> *additionalTextAttributes =
412
373
  @{RCTAttributedStringEventEmitterKey : eventEmitterWrapper};
@@ -414,7 +375,6 @@ static NSMutableAttributedString *RCTNSAttributedStringFragmentWithAttributesFro
414
375
  [nsAttributedStringFragment addAttributes:additionalTextAttributes
415
376
  range:NSMakeRange(0, nsAttributedStringFragment.length)];
416
377
  }
417
- #endif
418
378
 
419
379
  return nsAttributedStringFragment;
420
380
  }
@@ -280,11 +280,10 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
280
280
  // after (fraction == 1.0) the last character, then the attribute is valid.
281
281
  if (textStorage.length > 0 && (fraction > 0 || characterIndex > 0) &&
282
282
  (fraction < 1 || characterIndex < textStorage.length - 1)) {
283
- RCTWeakEventEmitterWrapper *eventEmitterWrapper =
284
- (RCTWeakEventEmitterWrapper *)[textStorage attribute:RCTAttributedStringEventEmitterKey
285
- atIndex:characterIndex
286
- effectiveRange:NULL];
287
- return eventEmitterWrapper.eventEmitter;
283
+ NSData *eventEmitterWrapper = (NSData *)[textStorage attribute:RCTAttributedStringEventEmitterKey
284
+ atIndex:characterIndex
285
+ effectiveRange:NULL];
286
+ return RCTUnwrapEventEmitter(eventEmitterWrapper);
288
287
  }
289
288
 
290
289
  return nil;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native",
3
- "version": "0.77.0",
3
+ "version": "0.77.2",
4
4
  "description": "A framework for building native apps using React",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -108,13 +108,13 @@
108
108
  },
109
109
  "dependencies": {
110
110
  "@jest/create-cache-key-function": "^29.6.3",
111
- "@react-native/assets-registry": "0.77.0",
112
- "@react-native/codegen": "0.77.0",
113
- "@react-native/community-cli-plugin": "0.77.0",
114
- "@react-native/gradle-plugin": "0.77.0",
115
- "@react-native/js-polyfills": "0.77.0",
116
- "@react-native/normalize-colors": "0.77.0",
117
- "@react-native/virtualized-lists": "0.77.0",
111
+ "@react-native/assets-registry": "0.77.2",
112
+ "@react-native/codegen": "0.77.2",
113
+ "@react-native/community-cli-plugin": "0.77.2",
114
+ "@react-native/gradle-plugin": "0.77.2",
115
+ "@react-native/js-polyfills": "0.77.2",
116
+ "@react-native/normalize-colors": "0.77.2",
117
+ "@react-native/virtualized-lists": "0.77.2",
118
118
  "abort-controller": "^3.0.0",
119
119
  "anser": "^1.4.9",
120
120
  "ansi-regex": "^5.0.0",
@@ -130,8 +130,8 @@
130
130
  "jest-environment-node": "^29.6.3",
131
131
  "jsc-android": "^250231.0.0",
132
132
  "memoize-one": "^5.0.0",
133
- "metro-runtime": "^0.81.0",
134
- "metro-source-map": "^0.81.0",
133
+ "metro-runtime": "^0.81.3",
134
+ "metro-source-map": "^0.81.3",
135
135
  "nullthrows": "^1.1.1",
136
136
  "pretty-format": "^29.7.0",
137
137
  "promise": "^8.3.0",
@@ -44,27 +44,11 @@ try {
44
44
 
45
45
  const commands = [];
46
46
 
47
- try {
48
- const {
49
- bundleCommand,
50
- startCommand,
51
- } = require('@react-native/community-cli-plugin');
52
- commands.push(bundleCommand, startCommand);
53
- } catch (e) {
54
- const known =
55
- e.code === 'MODULE_NOT_FOUND' &&
56
- e.message.includes('@react-native-community/cli-server-api');
57
-
58
- if (!known) {
59
- throw e;
60
- }
61
-
62
- if (verbose) {
63
- console.warn(
64
- '@react-native-community/cli-server-api not found, the react-native.config.js may be unusable.',
65
- );
66
- }
67
- }
47
+ const {
48
+ bundleCommand,
49
+ startCommand,
50
+ } = require('@react-native/community-cli-plugin');
51
+ commands.push(bundleCommand, startCommand);
68
52
 
69
53
  const codegenCommand = {
70
54
  name: 'codegen',
@@ -84,12 +68,18 @@ const codegenCommand = {
84
68
  name: '--outputPath <path>',
85
69
  description: 'Path where generated artifacts will be output to.',
86
70
  },
71
+ {
72
+ name: '--source <string>',
73
+ description: 'Whether the script is invoked from an `app` or a `library`',
74
+ default: 'app',
75
+ },
87
76
  ],
88
77
  func: (argv, config, args) =>
89
78
  require('./scripts/codegen/generate-artifacts-executor').execute(
90
79
  args.path,
91
80
  args.platform,
92
81
  args.outputPath,
82
+ args.source,
93
83
  ),
94
84
  };
95
85
 
@@ -899,11 +899,12 @@ function generateFBReactNativeSpecIOS(projectRoot /*: string */) /*: void*/ {
899
899
  * @parameter projectRoot: the directory with the app source code, where the package.json lives.
900
900
  * @parameter baseOutputPath: the base output path for the CodeGen.
901
901
  * @parameter targetPlatform: the target platform. Supported values: 'android', 'ios', 'all'.
902
+ * @parameter source: the source that is invoking codegen. Supported values: 'app', 'library'.
902
903
  * @throws If it can't find a config file for react-native.
903
904
  * @throws If it can't find a CodeGen configuration in the file.
904
905
  * @throws If it can't find a cli for the CodeGen.
905
906
  */
906
- function execute(projectRoot, targetPlatform, baseOutputPath) {
907
+ function execute(projectRoot, targetPlatform, baseOutputPath, source) {
907
908
  try {
908
909
  codegenLog(`Analyzing ${path.join(projectRoot, 'package.json')}`);
909
910
 
@@ -951,9 +952,12 @@ function execute(projectRoot, targetPlatform, baseOutputPath) {
951
952
  platform,
952
953
  );
953
954
 
954
- generateRCTThirdPartyComponents(libraries, outputPath);
955
- generateCustomURLHandlers(libraries, outputPath);
956
- generateAppDependencyProvider(outputPath);
955
+ if (source === 'app') {
956
+ // These components are only required by apps, not by libraries
957
+ generateRCTThirdPartyComponents(libraries, outputPath);
958
+ generateCustomURLHandlers(libraries, outputPath);
959
+ generateAppDependencyProvider(outputPath);
960
+ }
957
961
 
958
962
  cleanupEmptyFilesAndFolders(outputPath);
959
963
  }
@@ -25,7 +25,12 @@ const argv = yargs
25
25
  alias: 'outputPath',
26
26
  description: 'Path where generated artifacts will be output to.',
27
27
  })
28
+ .option('s', {
29
+ alias: 'source',
30
+ description: 'Whether the script is invoked from an `app` or a `library`',
31
+ default: 'app',
32
+ })
28
33
  .usage('Usage: $0 -p [path to app] -t [target platform] -o [output path]')
29
34
  .demandOption(['p', 't']).argv;
30
35
 
31
- executor.execute(argv.path, argv.targetPlatform, argv.outputPath);
36
+ executor.execute(argv.path, argv.targetPlatform, argv.outputPath, argv.source);
Binary file
Binary file
Binary file
Binary file
Binary file