react-native-tvos 0.71.10-0rc0 → 0.71.12-0

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 (35) hide show
  1. package/Libraries/Components/TextInput/TextInput.js +44 -19
  2. package/Libraries/Components/View/View.js +35 -17
  3. package/Libraries/Core/ReactNativeVersion.js +2 -2
  4. package/Libraries/Image/Image.android.js +1 -1
  5. package/Libraries/LogBox/Data/parseLogBoxLog.js +50 -20
  6. package/Libraries/LogBox/UI/LogBoxInspector.js +2 -1
  7. package/Libraries/Text/Text.js +44 -34
  8. package/README.md +2 -7
  9. package/React/Base/RCTJavaScriptLoader.mm +11 -1
  10. package/React/Base/RCTVersion.m +2 -2
  11. package/React/CxxBridge/RCTCxxBridge.mm +9 -4
  12. package/React/Views/RCTTVView.m +16 -0
  13. package/ReactAndroid/gradle.properties +1 -1
  14. package/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +10 -1
  15. package/ReactAndroid/src/main/java/com/facebook/react/animated/FrameBasedAnimationDriver.java +14 -1
  16. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java +2 -2
  17. package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java +4 -4
  18. package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
  19. package/flow-typed/npm/ansi-regex_v5.x.x.js +14 -0
  20. package/package.json +10 -9
  21. package/scripts/cocoapods/__tests__/codegen_utils-test.rb +2 -2
  22. package/scripts/cocoapods/__tests__/utils-test.rb +54 -0
  23. package/scripts/cocoapods/codegen_utils.rb +1 -1
  24. package/scripts/cocoapods/flipper.rb +2 -2
  25. package/scripts/cocoapods/utils.rb +12 -0
  26. package/scripts/react_native_pods.rb +1 -0
  27. package/sdks/hermesc/osx-bin/hermesc +0 -0
  28. package/sdks/hermesc/win64-bin/hermesc.exe +0 -0
  29. package/template/App.tsx +1 -2
  30. package/template/ios/HelloWorld/Info.plist +1 -1
  31. package/template/ios/HelloWorld-tvOS/Info.plist +3 -3
  32. package/template/ios/HelloWorld.xcodeproj/project.pbxproj +7 -0
  33. package/template/ios/Podfile +17 -5
  34. package/template/package.json +2 -2
  35. package/types/public/ReactNativeTVTypes.d.ts +1 -1
@@ -1062,6 +1062,18 @@ const emptyFunctionThatReturnsTrue = () => true;
1062
1062
  *
1063
1063
  */
1064
1064
  function InternalTextInput(props: Props): React.Node {
1065
+ const {
1066
+ 'aria-busy': ariaBusy,
1067
+ 'aria-checked': ariaChecked,
1068
+ 'aria-disabled': ariaDisabled,
1069
+ 'aria-expanded': ariaExpanded,
1070
+ 'aria-selected': ariaSelected,
1071
+ accessibilityState,
1072
+ id,
1073
+ tabIndex,
1074
+ ...otherProps
1075
+ } = props;
1076
+
1065
1077
  const inputRef = useRef<null | React.ElementRef<HostComponent<mixed>>>(null);
1066
1078
 
1067
1079
  // Android sends a "onTextChanged" event followed by a "onSelectionChanged" event, for
@@ -1382,13 +1394,25 @@ function InternalTextInput(props: Props): React.Node {
1382
1394
  // so omitting onBlur and onFocus pressability handlers here.
1383
1395
  const {onBlur, onFocus, ...eventHandlers} = usePressability(config) || {};
1384
1396
 
1385
- const _accessibilityState = {
1386
- busy: props['aria-busy'] ?? props.accessibilityState?.busy,
1387
- checked: props['aria-checked'] ?? props.accessibilityState?.checked,
1388
- disabled: props['aria-disabled'] ?? props.accessibilityState?.disabled,
1389
- expanded: props['aria-expanded'] ?? props.accessibilityState?.expanded,
1390
- selected: props['aria-selected'] ?? props.accessibilityState?.selected,
1391
- };
1397
+ let _accessibilityState;
1398
+ if (
1399
+ accessibilityState != null ||
1400
+ ariaBusy != null ||
1401
+ ariaChecked != null ||
1402
+ ariaDisabled != null ||
1403
+ ariaExpanded != null ||
1404
+ ariaSelected != null
1405
+ ) {
1406
+ _accessibilityState = {
1407
+ busy: ariaBusy ?? accessibilityState?.busy,
1408
+ checked: ariaChecked ?? accessibilityState?.checked,
1409
+ disabled: ariaDisabled ?? accessibilityState?.disabled,
1410
+ expanded: ariaExpanded ?? accessibilityState?.expanded,
1411
+ selected: ariaSelected ?? accessibilityState?.selected,
1412
+ };
1413
+ }
1414
+
1415
+ let style = flattenStyle(props.style);
1392
1416
 
1393
1417
  if (Platform.OS === 'ios') {
1394
1418
  const RCTTextInputView =
@@ -1396,10 +1420,7 @@ function InternalTextInput(props: Props): React.Node {
1396
1420
  ? RCTMultilineTextInputView
1397
1421
  : RCTSinglelineTextInputView;
1398
1422
 
1399
- const style =
1400
- props.multiline === true
1401
- ? StyleSheet.flatten([styles.multilineInput, props.style])
1402
- : props.style;
1423
+ style = props.multiline === true ? [styles.multilineInput, style] : style;
1403
1424
 
1404
1425
  const useOnChangeSync =
1405
1426
  (props.unstable_onChangeSync || props.unstable_onChangeTextSync) &&
@@ -1415,15 +1436,16 @@ function InternalTextInput(props: Props): React.Node {
1415
1436
  textInput = (
1416
1437
  <RCTTextInputView
1417
1438
  ref={_setNativeRef}
1418
- {...props}
1439
+ {...otherProps}
1419
1440
  {...eventHandlers}
1420
- accessible={accessible}
1421
1441
  accessibilityState={_accessibilityState}
1442
+ accessible={accessible}
1422
1443
  submitBehavior={submitBehavior}
1423
1444
  caretHidden={caretHidden}
1424
1445
  dataDetectorTypes={props.dataDetectorTypes}
1425
- focusable={focusable}
1446
+ focusable={tabIndex !== undefined ? !tabIndex : focusable}
1426
1447
  mostRecentEventCount={mostRecentEventCount}
1448
+ nativeID={id ?? props.nativeID}
1427
1449
  onBlur={_onBlur}
1428
1450
  onKeyPressSync={props.unstable_onKeyPressSync}
1429
1451
  onChange={_onChange}
@@ -1439,7 +1461,6 @@ function InternalTextInput(props: Props): React.Node {
1439
1461
  />
1440
1462
  );
1441
1463
  } else if (Platform.OS === 'android') {
1442
- const style = [props.style];
1443
1464
  const autoCapitalize = props.autoCapitalize || 'sentences';
1444
1465
  const _accessibilityLabelledBy =
1445
1466
  props?.['aria-labelledby'] ?? props?.accessibilityLabelledBy;
@@ -1465,18 +1486,19 @@ function InternalTextInput(props: Props): React.Node {
1465
1486
  * fixed */
1466
1487
  <AndroidTextInput
1467
1488
  ref={_setNativeRef}
1468
- {...props}
1489
+ {...otherProps}
1469
1490
  {...eventHandlers}
1470
- accessible={accessible}
1471
1491
  accessibilityState={_accessibilityState}
1472
1492
  accessibilityLabelledBy={_accessibilityLabelledBy}
1493
+ accessible={accessible}
1473
1494
  autoCapitalize={autoCapitalize}
1474
1495
  submitBehavior={submitBehavior}
1475
1496
  caretHidden={caretHidden}
1476
1497
  children={children}
1477
1498
  disableFullscreenUI={props.disableFullscreenUI}
1478
- focusable={focusable}
1499
+ focusable={tabIndex !== undefined ? !tabIndex : focusable}
1479
1500
  mostRecentEventCount={mostRecentEventCount}
1501
+ nativeID={id ?? props.nativeID}
1480
1502
  numberOfLines={props.rows ?? props.numberOfLines}
1481
1503
  onBlur={_onBlur}
1482
1504
  onChange={_onChange}
@@ -1606,11 +1628,12 @@ const ExportedForwardRef: React.AbstractComponent<
1606
1628
  React.ElementRef<HostComponent<mixed>> & ImperativeMethods,
1607
1629
  >,
1608
1630
  ) {
1609
- const style = flattenStyle(restProps.style);
1631
+ let style = flattenStyle(restProps.style);
1610
1632
 
1611
1633
  if (style?.verticalAlign != null) {
1612
1634
  style.textAlignVertical =
1613
1635
  verticalAlignToTextAlignVerticalMap[style.verticalAlign];
1636
+ delete style.verticalAlign;
1614
1637
  }
1615
1638
 
1616
1639
  return (
@@ -1651,6 +1674,8 @@ const ExportedForwardRef: React.AbstractComponent<
1651
1674
  );
1652
1675
  });
1653
1676
 
1677
+ ExportedForwardRef.displayName = 'TextInput';
1678
+
1654
1679
  /**
1655
1680
  * Switch to `deprecated-react-native-prop-types` for compatibility with future
1656
1681
  * releases. This is deprecated and will be removed in the future.
@@ -64,7 +64,6 @@ const View: React.AbstractComponent<
64
64
  nativeID,
65
65
  pointerEvents,
66
66
  role,
67
- style,
68
67
  tabIndex,
69
68
  ...otherProps
70
69
  }: ViewProps,
@@ -73,23 +72,42 @@ const View: React.AbstractComponent<
73
72
  const _accessibilityLabelledBy =
74
73
  ariaLabelledBy?.split(/\s*,\s*/g) ?? accessibilityLabelledBy;
75
74
 
76
- const _accessibilityState = {
77
- busy: ariaBusy ?? accessibilityState?.busy,
78
- checked: ariaChecked ?? accessibilityState?.checked,
79
- disabled: ariaDisabled ?? accessibilityState?.disabled,
80
- expanded: ariaExpanded ?? accessibilityState?.expanded,
81
- selected: ariaSelected ?? accessibilityState?.selected,
82
- };
75
+ let _accessibilityState;
76
+ if (
77
+ accessibilityState != null ||
78
+ ariaBusy != null ||
79
+ ariaChecked != null ||
80
+ ariaDisabled != null ||
81
+ ariaExpanded != null ||
82
+ ariaSelected != null
83
+ ) {
84
+ _accessibilityState = {
85
+ busy: ariaBusy ?? accessibilityState?.busy,
86
+ checked: ariaChecked ?? accessibilityState?.checked,
87
+ disabled: ariaDisabled ?? accessibilityState?.disabled,
88
+ expanded: ariaExpanded ?? accessibilityState?.expanded,
89
+ selected: ariaSelected ?? accessibilityState?.selected,
90
+ };
91
+ }
92
+ let _accessibilityValue;
93
+ if (
94
+ accessibilityValue != null ||
95
+ ariaValueMax != null ||
96
+ ariaValueMin != null ||
97
+ ariaValueNow != null ||
98
+ ariaValueText != null
99
+ ) {
100
+ _accessibilityValue = {
101
+ max: ariaValueMax ?? accessibilityValue?.max,
102
+ min: ariaValueMin ?? accessibilityValue?.min,
103
+ now: ariaValueNow ?? accessibilityValue?.now,
104
+ text: ariaValueText ?? accessibilityValue?.text,
105
+ };
106
+ }
83
107
 
84
- const _accessibilityValue = {
85
- max: ariaValueMax ?? accessibilityValue?.max,
86
- min: ariaValueMin ?? accessibilityValue?.min,
87
- now: ariaValueNow ?? accessibilityValue?.now,
88
- text: ariaValueText ?? accessibilityValue?.text,
89
- };
108
+ let style = flattenStyle(otherProps.style);
90
109
 
91
- const flattenedStyle = flattenStyle(style);
92
- const newPointerEvents = flattenedStyle?.pointerEvents || pointerEvents;
110
+ const newPointerEvents = style?.pointerEvents || pointerEvents;
93
111
 
94
112
  const viewRef = React.useRef<?React.ElementRef<typeof View>>(null);
95
113
 
@@ -143,7 +161,7 @@ const View: React.AbstractComponent<
143
161
  nativeID={id ?? nativeID}
144
162
  style={style}
145
163
  pointerEvents={newPointerEvents}
146
- ref={forwardedRef}
164
+ ref={_setNativeRef}
147
165
  />
148
166
  </TextAncestor.Provider>
149
167
  );
@@ -12,6 +12,6 @@
12
12
  exports.version = {
13
13
  major: 0,
14
14
  minor: 71,
15
- patch: 10,
16
- prerelease: '0rc0',
15
+ patch: 12,
16
+ prerelease: '0',
17
17
  };
@@ -158,13 +158,13 @@ const BaseImage = (props: ImagePropsType, forwardedRef) => {
158
158
  const {width = props.width, height = props.height, uri} = source;
159
159
  style = flattenStyle([{width, height}, styles.base, props.style]);
160
160
  sources = [source];
161
-
162
161
  if (uri === '') {
163
162
  console.warn('source.uri should not be an empty string');
164
163
  }
165
164
  }
166
165
 
167
166
  const {height, width, ...restProps} = props;
167
+
168
168
  const {onLoadStart, onLoad, onLoadEnd, onError} = props;
169
169
  const nativeProps = {
170
170
  ...restProps,
@@ -14,12 +14,38 @@ import type {LogBoxLogData} from './LogBoxLog';
14
14
  import parseErrorStack from '../../Core/Devtools/parseErrorStack';
15
15
  import UTFSequence from '../../UTFSequence';
16
16
  import stringifySafe from '../../Utilities/stringifySafe';
17
+ import ansiRegex from 'ansi-regex';
18
+
19
+ const ANSI_REGEX = ansiRegex().source;
17
20
 
18
21
  const BABEL_TRANSFORM_ERROR_FORMAT =
19
22
  /^(?:TransformError )?(?:SyntaxError: |ReferenceError: )(.*): (.*) \((\d+):(\d+)\)\n\n([\s\S]+)/;
23
+
24
+ // https://github.com/babel/babel/blob/33dbb85e9e9fe36915273080ecc42aee62ed0ade/packages/babel-code-frame/src/index.ts#L183-L184
25
+ const BABEL_CODE_FRAME_MARKER_PATTERN = new RegExp(
26
+ [
27
+ // Beginning of a line (per 'm' flag)
28
+ '^',
29
+ // Optional ANSI escapes for colors
30
+ `(?:${ANSI_REGEX})*`,
31
+ // Marker
32
+ '>',
33
+ // Optional ANSI escapes for colors
34
+ `(?:${ANSI_REGEX})*`,
35
+ // Left padding for line number
36
+ ' +',
37
+ // Line number
38
+ '[0-9]+',
39
+ // Gutter
40
+ ' \\|',
41
+ ].join(''),
42
+ 'm',
43
+ );
44
+
20
45
  const BABEL_CODE_FRAME_ERROR_FORMAT =
21
46
  // eslint-disable-next-line no-control-regex
22
47
  /^(?:TransformError )?(?:.*):? (?:.*?)(\/.*): ([\s\S]+?)\n([ >]{2}[\d\s]+ \|[\s\S]+|\u{001b}[\s\S]+)/u;
48
+
23
49
  const METRO_ERROR_FORMAT =
24
50
  /^(?:InternalError Metro has encountered an error:) (.*): (.*) \((\d+):(\d+)\)\n\n([\s\S]+)/u;
25
51
 
@@ -241,27 +267,31 @@ export function parseLogBoxException(
241
267
  };
242
268
  }
243
269
 
244
- const babelCodeFrameError = message.match(BABEL_CODE_FRAME_ERROR_FORMAT);
270
+ // Perform a cheap match first before trying to parse the full message, which
271
+ // can get expensive for arbitrary input.
272
+ if (BABEL_CODE_FRAME_MARKER_PATTERN.test(message)) {
273
+ const babelCodeFrameError = message.match(BABEL_CODE_FRAME_ERROR_FORMAT);
245
274
 
246
- if (babelCodeFrameError) {
247
- // Codeframe errors are thrown from any use of buildCodeFrameError.
248
- const [fileName, content, codeFrame] = babelCodeFrameError.slice(1);
249
- return {
250
- level: 'syntax',
251
- stack: [],
252
- isComponentError: false,
253
- componentStack: [],
254
- codeFrame: {
255
- fileName,
256
- location: null, // We are not given the location.
257
- content: codeFrame,
258
- },
259
- message: {
260
- content,
261
- substitutions: [],
262
- },
263
- category: `${fileName}-${1}-${1}`,
264
- };
275
+ if (babelCodeFrameError) {
276
+ // Codeframe errors are thrown from any use of buildCodeFrameError.
277
+ const [fileName, content, codeFrame] = babelCodeFrameError.slice(1);
278
+ return {
279
+ level: 'syntax',
280
+ stack: [],
281
+ isComponentError: false,
282
+ componentStack: [],
283
+ codeFrame: {
284
+ fileName,
285
+ location: null, // We are not given the location.
286
+ content: codeFrame,
287
+ },
288
+ message: {
289
+ content,
290
+ substitutions: [],
291
+ },
292
+ category: `${fileName}-${1}-${1}`,
293
+ };
294
+ }
265
295
  }
266
296
 
267
297
  if (message.match(/^TransformError /)) {
@@ -74,12 +74,13 @@ function LogBoxInspector(props: Props): React.Node {
74
74
  total={logs.length}
75
75
  level={log.level}
76
76
  />
77
- <LogBoxInspectorBody log={log} onRetry={_handleRetry} />
77
+ {/* In the TV repo, place the footer above the body for easier navigation */}
78
78
  <LogBoxInspectorFooter
79
79
  onDismiss={props.onDismiss}
80
80
  onMinimize={props.onMinimize}
81
81
  level={log.level}
82
82
  />
83
+ <LogBoxInspectorBody log={log} onRetry={_handleRetry} />
83
84
  </View>
84
85
  );
85
86
  }
@@ -9,17 +9,16 @@
9
9
  */
10
10
 
11
11
  import type {PressEvent} from '../Types/CoreEventTypes';
12
+ import type {TextProps} from './TextProps';
12
13
 
13
14
  import * as PressabilityDebug from '../Pressability/PressabilityDebug';
14
15
  import usePressability from '../Pressability/usePressability';
15
16
  import flattenStyle from '../StyleSheet/flattenStyle';
16
17
  import processColor from '../StyleSheet/processColor';
17
- import StyleSheet from '../StyleSheet/StyleSheet';
18
18
  import {getAccessibilityRoleFromRole} from '../Utilities/AcessibilityMapping';
19
19
  import Platform from '../Utilities/Platform';
20
20
  import TextAncestor from './TextAncestor';
21
21
  import {NativeText, NativeVirtualText} from './TextNativeComponent';
22
- import {type TextProps} from './TextProps';
23
22
  import * as React from 'react';
24
23
  import {useContext, useMemo, useState} from 'react';
25
24
 
@@ -36,6 +35,7 @@ const Text: React.AbstractComponent<
36
35
  accessible,
37
36
  accessibilityLabel,
38
37
  accessibilityRole,
38
+ accessibilityState,
39
39
  allowFontScaling,
40
40
  'aria-busy': ariaBusy,
41
41
  'aria-checked': ariaChecked,
@@ -64,13 +64,23 @@ const Text: React.AbstractComponent<
64
64
 
65
65
  const [isHighlighted, setHighlighted] = useState(false);
66
66
 
67
- const _accessibilityState = {
68
- busy: ariaBusy ?? props.accessibilityState?.busy,
69
- checked: ariaChecked ?? props.accessibilityState?.checked,
70
- disabled: ariaDisabled ?? props.accessibilityState?.disabled,
71
- expanded: ariaExpanded ?? props.accessibilityState?.expanded,
72
- selected: ariaSelected ?? props.accessibilityState?.selected,
73
- };
67
+ let _accessibilityState;
68
+ if (
69
+ accessibilityState != null ||
70
+ ariaBusy != null ||
71
+ ariaChecked != null ||
72
+ ariaDisabled != null ||
73
+ ariaExpanded != null ||
74
+ ariaSelected != null
75
+ ) {
76
+ _accessibilityState = {
77
+ busy: ariaBusy ?? accessibilityState?.busy,
78
+ checked: ariaChecked ?? accessibilityState?.checked,
79
+ disabled: ariaDisabled ?? accessibilityState?.disabled,
80
+ expanded: ariaExpanded ?? accessibilityState?.expanded,
81
+ selected: ariaSelected ?? accessibilityState?.selected,
82
+ };
83
+ }
74
84
 
75
85
  const _disabled =
76
86
  restProps.disabled != null
@@ -174,25 +184,11 @@ const Text: React.AbstractComponent<
174
184
  ? null
175
185
  : processColor(restProps.selectionColor);
176
186
 
177
- let style = flattenStyle(restProps.style);
178
-
179
- let _selectable = restProps.selectable;
180
- if (style?.userSelect != null) {
181
- _selectable = userSelectToSelectableMap[style.userSelect];
182
- }
183
-
184
- if (style?.verticalAlign != null) {
185
- style = StyleSheet.compose(style, {
186
- textAlignVertical:
187
- verticalAlignToTextAlignVerticalMap[style.verticalAlign],
188
- });
189
- }
187
+ let style = restProps.style;
190
188
 
191
189
  if (__DEV__) {
192
190
  if (PressabilityDebug.isEnabled() && onPress != null) {
193
- style = StyleSheet.compose(restProps.style, {
194
- color: 'magenta',
195
- });
191
+ style = [restProps.style, {color: 'magenta'}];
196
192
  }
197
193
  }
198
194
 
@@ -211,10 +207,22 @@ const Text: React.AbstractComponent<
211
207
  default: accessible,
212
208
  });
213
209
 
214
- let flattenedStyle = flattenStyle(style);
210
+ style = flattenStyle(style);
211
+
212
+ if (typeof style?.fontWeight === 'number') {
213
+ style.fontWeight = style?.fontWeight.toString();
214
+ }
215
215
 
216
- if (typeof flattenedStyle?.fontWeight === 'number') {
217
- flattenedStyle.fontWeight = flattenedStyle?.fontWeight.toString();
216
+ let _selectable = restProps.selectable;
217
+ if (style?.userSelect != null) {
218
+ _selectable = userSelectToSelectableMap[style.userSelect];
219
+ delete style.userSelect;
220
+ }
221
+
222
+ if (style?.verticalAlign != null) {
223
+ style.textAlignVertical =
224
+ verticalAlignToTextAlignVerticalMap[style.verticalAlign];
225
+ delete style.verticalAlign;
218
226
  }
219
227
 
220
228
  const _hasOnPressOrOnLongPress =
@@ -223,20 +231,20 @@ const Text: React.AbstractComponent<
223
231
  return hasTextAncestor ? (
224
232
  <NativeVirtualText
225
233
  {...restProps}
226
- accessibilityState={_accessibilityState}
227
234
  {...eventHandlersForText}
228
235
  accessibilityLabel={ariaLabel ?? accessibilityLabel}
229
236
  accessibilityRole={
230
237
  role ? getAccessibilityRoleFromRole(role) : accessibilityRole
231
238
  }
239
+ accessibilityState={_accessibilityState}
232
240
  isHighlighted={isHighlighted}
233
241
  isPressable={isPressable}
234
- selectable={_selectable}
235
242
  nativeID={id ?? nativeID}
236
243
  numberOfLines={numberOfLines}
237
- selectionColor={selectionColor}
238
- style={flattenedStyle}
239
244
  ref={forwardedRef}
245
+ selectable={_selectable}
246
+ selectionColor={selectionColor}
247
+ style={style}
240
248
  />
241
249
  ) : (
242
250
  <TextAncestor.Provider value={true}>
@@ -257,13 +265,15 @@ const Text: React.AbstractComponent<
257
265
  role ? getAccessibilityRoleFromRole(role) : accessibilityRole
258
266
  }
259
267
  allowFontScaling={allowFontScaling !== false}
268
+ disabled={_disabled}
260
269
  ellipsizeMode={ellipsizeMode ?? 'tail'}
261
270
  isHighlighted={isHighlighted}
262
271
  nativeID={id ?? nativeID}
263
272
  numberOfLines={numberOfLines}
264
- selectionColor={selectionColor}
265
- style={flattenedStyle}
266
273
  ref={forwardedRef}
274
+ selectable={_selectable}
275
+ selectionColor={selectionColor}
276
+ style={style}
267
277
  />
268
278
  </TextAncestor.Provider>
269
279
  );
package/README.md CHANGED
@@ -77,7 +77,8 @@ react-native init TestApp --template=react-native-tvos@latest
77
77
  cd TestApp && react-native run-ios --simulator "Apple TV" --scheme "TestApp-tvOS"
78
78
  ```
79
79
 
80
- (_Note_: As of now, `npx react-native run-ios` will no longer run Apple TV targets. A fix for this has been merged (https://github.com/react-native-community/cli/pull/1929) and will be released shortly. To run Apple TV (and Android TV) targets from the command line, it is now possible to use the Expo CLI, using the following steps:
80
+ To run Apple TV (and Android TV) targets from the command line, it is now possible to use the Expo CLI, using the following steps:
81
+
81
82
  - In your app, install the required Expo modules: `yarn add expo`
82
83
  - Add a file `react-native.config.js` at the top level of your app directory, with [these contents](https://github.com/byCedric/custom-prebuild-example/blob/main/app/react-native.config.js).
83
84
  - Then an Apple TV target can be run: `npx expo run:ios --scheme MyApp-tvOS --device "Apple TV"`
@@ -209,9 +210,3 @@ More information on the focus handling improvements above can be found in [this
209
210
 
210
211
  - _TVTextScrollView_: On Apple TV, a ScrollView will not scroll unless there are focusable items inside it or above/below it. This component wraps ScrollView and uses tvOS-specific native code to allow scrolling using swipe gestures from the remote control.
211
212
 
212
- - _Known issues_:
213
-
214
- - The Hermes engine has not yet been ported to Apple TV, so it should be disabled in application Podfiles targeting TV.
215
- - There are known issues with the TabBarIOS component, due to changes that Apple made in UITabBar for tvOS 13.
216
-
217
-
@@ -312,7 +312,17 @@ static void attemptAsynchronousLoadOfBundleAtURL(
312
312
  return;
313
313
  }
314
314
 
315
- RCTSource *source = RCTSourceCreate(scriptURL, data, data.length);
315
+ // Prefer `Content-Location` as the canonical source URL, if given, or fall back to scriptURL.
316
+ NSURL *sourceURL = scriptURL;
317
+ NSString *contentLocationHeader = headers[@"Content-Location"];
318
+ if (contentLocationHeader) {
319
+ NSURL *contentLocationURL = [NSURL URLWithString:contentLocationHeader relativeToURL:scriptURL];
320
+ if (contentLocationURL) {
321
+ sourceURL = contentLocationURL;
322
+ }
323
+ }
324
+
325
+ RCTSource *source = RCTSourceCreate(sourceURL, data, data.length);
316
326
  parseHeaders(headers, source);
317
327
  onComplete(nil, source);
318
328
  }
@@ -23,8 +23,8 @@ NSDictionary* RCTGetReactNativeVersion(void)
23
23
  __rnVersion = @{
24
24
  RCTVersionMajor: @(0),
25
25
  RCTVersionMinor: @(71),
26
- RCTVersionPatch: @(10),
27
- RCTVersionPrerelease: @"0rc0",
26
+ RCTVersionPatch: @(12),
27
+ RCTVersionPrerelease: @"0",
28
28
  };
29
29
  });
30
30
  return __rnVersion;
@@ -474,6 +474,7 @@ struct RCTInstanceCallback : public InstanceCallback {
474
474
  // Load the source asynchronously, then store it for later execution.
475
475
  dispatch_group_enter(prepareBridge);
476
476
  __block NSData *sourceCode;
477
+ __block NSURL *sourceURL = self.bundleURL;
477
478
 
478
479
  #if (RCT_DEV | RCT_ENABLE_LOADING_VIEW) && __has_include(<React/RCTDevLoadingViewProtocol.h>)
479
480
  {
@@ -489,6 +490,9 @@ struct RCTInstanceCallback : public InstanceCallback {
489
490
  }
490
491
 
491
492
  sourceCode = source.data;
493
+ if (source.url) {
494
+ sourceURL = source.url;
495
+ }
492
496
  dispatch_group_leave(prepareBridge);
493
497
  }
494
498
  onProgress:^(RCTLoadingProgress *progressData) {
@@ -503,7 +507,7 @@ struct RCTInstanceCallback : public InstanceCallback {
503
507
  dispatch_group_notify(prepareBridge, dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
504
508
  RCTCxxBridge *strongSelf = weakSelf;
505
509
  if (sourceCode && strongSelf.loading) {
506
- [strongSelf executeSourceCode:sourceCode sync:NO];
510
+ [strongSelf executeSourceCode:sourceCode withSourceURL:sourceURL sync:NO];
507
511
  }
508
512
  });
509
513
  RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
@@ -1049,7 +1053,7 @@ struct RCTInstanceCallback : public InstanceCallback {
1049
1053
  [_displayLink registerModuleForFrameUpdates:module withModuleData:moduleData];
1050
1054
  }
1051
1055
 
1052
- - (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
1056
+ - (void)executeSourceCode:(NSData *)sourceCode withSourceURL:(NSURL *)url sync:(BOOL)sync
1053
1057
  {
1054
1058
  // This will get called from whatever thread was actually executing JS.
1055
1059
  dispatch_block_t completion = ^{
@@ -1074,12 +1078,13 @@ struct RCTInstanceCallback : public InstanceCallback {
1074
1078
  };
1075
1079
 
1076
1080
  if (sync) {
1077
- [self executeApplicationScriptSync:sourceCode url:self.bundleURL];
1081
+ [self executeApplicationScriptSync:sourceCode url:url];
1078
1082
  completion();
1079
1083
  } else {
1080
- [self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:completion];
1084
+ [self enqueueApplicationScript:sourceCode url:url onComplete:completion];
1081
1085
  }
1082
1086
 
1087
+ // Use the original request URL here - HMRClient uses this to derive the /hot URL and entry point.
1083
1088
  [self.devSettings setupHMRClientWithBundleURL:self.bundleURL];
1084
1089
  }
1085
1090
 
@@ -244,6 +244,22 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : unused)
244
244
  motionEffectsAdded = NO;
245
245
  }
246
246
 
247
+ - (void)didMoveToSuperview {
248
+ [super didMoveToSuperview];
249
+
250
+ // There's no way for us to understand if the view is actually getting removed or getting detached.
251
+ // We play safe here and set the focusGuide's preferredFocusEnvs to an empty array
252
+ // to break a potential retain cycle (see `handleFocusGuide`).
253
+ if (self.superview == nil && self.focusGuide != nil) {
254
+ self.focusGuide.preferredFocusEnvironments = @[];
255
+ }
256
+
257
+ // We should restore focusGuide's state if the item was only detached and now getting attached again.
258
+ if (self.superview != nil && self.focusGuide != nil) {
259
+ [self handleFocusGuide];
260
+ }
261
+ }
262
+
247
263
  - (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context
248
264
  {
249
265
  // This is the `trapFocus*` logic that prevents the focus updates if
@@ -1,4 +1,4 @@
1
- VERSION_NAME=0.71.10-0rc0
1
+ VERSION_NAME=0.71.12-0
2
2
 
3
3
  # GROUP=com.facebook.react
4
4
  # Group for the TV repo
@@ -14,6 +14,7 @@ import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE;
14
14
 
15
15
  import android.app.Activity;
16
16
  import android.content.Context;
17
+ import android.content.ContextWrapper;
17
18
  import android.graphics.Canvas;
18
19
  import android.graphics.Insets;
19
20
  import android.graphics.Point;
@@ -917,6 +918,14 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot {
917
918
  checkForDeviceDimensionsChanges();
918
919
  }
919
920
 
921
+ private Activity getActivity() {
922
+ Context context = getContext();
923
+ while (!(context instanceof Activity) && context instanceof ContextWrapper) {
924
+ context = ((ContextWrapper) context).getBaseContext();
925
+ }
926
+ return (Activity) context;
927
+ }
928
+
920
929
  @RequiresApi(api = Build.VERSION_CODES.R)
921
930
  private void checkForKeyboardEvents() {
922
931
  getRootView().getWindowVisibleDisplayFrame(mVisibleViewArea);
@@ -934,7 +943,7 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot {
934
943
  Insets barInsets = rootInsets.getInsets(WindowInsets.Type.systemBars());
935
944
  int height = imeInsets.bottom - barInsets.bottom;
936
945
 
937
- int softInputMode = ((Activity) getContext()).getWindow().getAttributes().softInputMode;
946
+ int softInputMode = getActivity().getWindow().getAttributes().softInputMode;
938
947
  int screenY =
939
948
  softInputMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
940
949
  ? mVisibleViewArea.bottom - height
@@ -7,9 +7,12 @@
7
7
 
8
8
  package com.facebook.react.animated;
9
9
 
10
+ import com.facebook.common.logging.FLog;
10
11
  import com.facebook.react.bridge.ReadableArray;
11
12
  import com.facebook.react.bridge.ReadableMap;
12
13
  import com.facebook.react.bridge.ReadableType;
14
+ import com.facebook.react.common.ReactConstants;
15
+ import com.facebook.react.common.build.ReactBuildConfig;
13
16
 
14
17
  /**
15
18
  * Implementation of {@link AnimationDriver} which provides a support for simple time-based
@@ -70,7 +73,17 @@ class FrameBasedAnimationDriver extends AnimationDriver {
70
73
  long timeFromStartMillis = (frameTimeNanos - mStartFrameTimeNanos) / 1000000;
71
74
  int frameIndex = (int) Math.round(timeFromStartMillis / FRAME_TIME_MILLIS);
72
75
  if (frameIndex < 0) {
73
- throw new IllegalStateException("Calculated frame index should never be lower than 0");
76
+ String message =
77
+ "Calculated frame index should never be lower than 0. Called with frameTimeNanos "
78
+ + frameTimeNanos
79
+ + " and mStartFrameTimeNanos "
80
+ + mStartFrameTimeNanos;
81
+ if (ReactBuildConfig.DEBUG) {
82
+ throw new IllegalStateException(message);
83
+ } else {
84
+ FLog.w(ReactConstants.TAG, message);
85
+ return;
86
+ }
74
87
  } else if (mHasFinished) {
75
88
  // nothing to do here
76
89
  return;
@@ -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", 71,
20
- "patch", 10,
21
- "prerelease", "0rc0");
20
+ "patch", 12,
21
+ "prerelease", "0");
22
22
  }
@@ -791,7 +791,7 @@ public class ReactViewBackgroundDrawable extends Drawable {
791
791
 
792
792
  /** Compute mInnerTopLeftCorner */
793
793
  mInnerTopLeftCorner.x = mInnerClipTempRectForBorderRadius.left;
794
- mInnerTopLeftCorner.y = mInnerClipTempRectForBorderRadius.top * 2;
794
+ mInnerTopLeftCorner.y = mInnerClipTempRectForBorderRadius.top;
795
795
 
796
796
  getEllipseIntersectionWithLine(
797
797
  // Ellipse Bounds
@@ -817,7 +817,7 @@ public class ReactViewBackgroundDrawable extends Drawable {
817
817
  }
818
818
 
819
819
  mInnerBottomLeftCorner.x = mInnerClipTempRectForBorderRadius.left;
820
- mInnerBottomLeftCorner.y = mInnerClipTempRectForBorderRadius.bottom * -2;
820
+ mInnerBottomLeftCorner.y = mInnerClipTempRectForBorderRadius.bottom;
821
821
 
822
822
  getEllipseIntersectionWithLine(
823
823
  // Ellipse Bounds
@@ -843,7 +843,7 @@ public class ReactViewBackgroundDrawable extends Drawable {
843
843
  }
844
844
 
845
845
  mInnerTopRightCorner.x = mInnerClipTempRectForBorderRadius.right;
846
- mInnerTopRightCorner.y = mInnerClipTempRectForBorderRadius.top * 2;
846
+ mInnerTopRightCorner.y = mInnerClipTempRectForBorderRadius.top;
847
847
 
848
848
  getEllipseIntersectionWithLine(
849
849
  // Ellipse Bounds
@@ -869,7 +869,7 @@ public class ReactViewBackgroundDrawable extends Drawable {
869
869
  }
870
870
 
871
871
  mInnerBottomRightCorner.x = mInnerClipTempRectForBorderRadius.right;
872
- mInnerBottomRightCorner.y = mInnerClipTempRectForBorderRadius.bottom * -2;
872
+ mInnerBottomRightCorner.y = mInnerClipTempRectForBorderRadius.bottom;
873
873
 
874
874
  getEllipseIntersectionWithLine(
875
875
  // Ellipse Bounds
@@ -17,8 +17,8 @@ namespace facebook::react {
17
17
  constexpr struct {
18
18
  int32_t Major = 0;
19
19
  int32_t Minor = 71;
20
- int32_t Patch = 10;
21
- std::string_view Prerelease = "0rc0";
20
+ int32_t Patch = 12;
21
+ std::string_view Prerelease = "0";
22
22
  } ReactNativeVersion;
23
23
 
24
24
  } // namespace facebook::react
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @flow strict
3
+ * @format
4
+ */
5
+
6
+ declare module 'ansi-regex' {
7
+ declare export type Options = {
8
+ /**
9
+ * Match only the first ANSI escape.
10
+ */
11
+ +onlyFirst?: boolean,
12
+ };
13
+ declare export default function ansiRegex(options?: Options): RegExp;
14
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-tvos",
3
- "version": "0.71.10-0rc0",
3
+ "version": "0.71.12-0",
4
4
  "bin": "./cli.js",
5
5
  "description": "A framework for building native apps using React",
6
6
  "license": "MIT",
@@ -118,14 +118,15 @@
118
118
  },
119
119
  "dependencies": {
120
120
  "@jest/create-cache-key-function": "^29.2.1",
121
- "@react-native-community/cli": "10.2.2",
121
+ "@react-native-community/cli": "10.2.5",
122
122
  "@react-native-community/cli-platform-android": "10.2.0",
123
- "@react-native-community/cli-platform-ios": "10.2.1",
123
+ "@react-native-community/cli-platform-ios": "10.2.5",
124
124
  "@react-native/assets": "1.0.0",
125
125
  "@react-native/normalize-color": "2.1.0",
126
126
  "@react-native/polyfills": "2.0.0",
127
127
  "abort-controller": "^3.0.0",
128
128
  "anser": "^1.4.9",
129
+ "ansi-regex": "^5.0.0",
129
130
  "base64-js": "^1.1.2",
130
131
  "deprecated-react-native-prop-types": "^3.0.1",
131
132
  "event-target-shim": "^5.0.1",
@@ -133,9 +134,9 @@
133
134
  "jest-environment-node": "^29.2.1",
134
135
  "jsc-android": "^250231.0.0",
135
136
  "memoize-one": "^5.0.0",
136
- "metro-react-native-babel-transformer": "0.73.9",
137
- "metro-runtime": "0.73.9",
138
- "metro-source-map": "0.73.9",
137
+ "metro-react-native-babel-transformer": "0.73.10",
138
+ "metro-runtime": "0.73.10",
139
+ "metro-source-map": "0.73.10",
139
140
  "mkdirp": "^0.5.1",
140
141
  "nullthrows": "^1.1.1",
141
142
  "pretty-format": "^26.5.2",
@@ -191,12 +192,12 @@
191
192
  "jest": "^29.2.1",
192
193
  "jest-junit": "^10.0.0",
193
194
  "jscodeshift": "^0.13.1",
194
- "metro-babel-register": "0.73.9",
195
- "metro-memory-fs": "0.73.9",
195
+ "metro-babel-register": "0.73.10",
196
+ "metro-memory-fs": "0.73.10",
196
197
  "mkdirp": "^0.5.1",
197
198
  "mock-fs": "^5.1.4",
198
199
  "prettier": "^2.4.1",
199
- "react-native-core": "npm:react-native@0.71.10",
200
+ "react-native-core": "npm:react-native@0.71.12",
200
201
  "shelljs": "^0.8.5",
201
202
  "signedsource": "^1.0.0",
202
203
  "typescript": "4.1.3",
@@ -352,7 +352,7 @@ class CodegenUtilsTests < Test::Unit::TestCase
352
352
  '[Codegen] warn: using experimental new codegen integration'
353
353
  ])
354
354
  assert_equal(codegen_utils_mock.get_react_codegen_script_phases_params, [{
355
- :app_path => "~/app",
355
+ :app_path => app_path,
356
356
  :config_file_dir => "",
357
357
  :config_key => "codegenConfig",
358
358
  :fabric_enabled => false,
@@ -361,7 +361,7 @@ class CodegenUtilsTests < Test::Unit::TestCase
361
361
  assert_equal(codegen_utils_mock.get_react_codegen_spec_params, [{
362
362
  :fabric_enabled => false,
363
363
  :folly_version=>"2021.07.22.00",
364
- :package_json_file => "../node_modules/react-native/package.json",
364
+ :package_json_file => "#{app_path}/ios/../node_modules/react-native/package.json",
365
365
  :script_phases => "echo TestScript"
366
366
  }])
367
367
  assert_equal(codegen_utils_mock.generate_react_codegen_spec_params, [{
@@ -435,6 +435,60 @@ class UtilsTests < Test::Unit::TestCase
435
435
  assert_equal(user_project_mock.save_invocation_count, 1)
436
436
  end
437
437
 
438
+ # ================================= #
439
+ # Test - Apply Xcode 15 Patch #
440
+ # ================================= #
441
+
442
+ def test_applyXcode15Patch_correctlyAppliesNecessaryPatch
443
+ # Arrange
444
+ first_target = prepare_target("FirstTarget")
445
+ second_target = prepare_target("SecondTarget")
446
+ third_target = TargetMock.new("ThirdTarget", [
447
+ BuildConfigurationMock.new("Debug", {
448
+ "GCC_PREPROCESSOR_DEFINITIONS" => '$(inherited) "SomeFlag=1" '
449
+ }),
450
+ BuildConfigurationMock.new("Release", {
451
+ "GCC_PREPROCESSOR_DEFINITIONS" => '$(inherited) "SomeFlag=1" '
452
+ }),
453
+ ], nil)
454
+
455
+ user_project_mock = UserProjectMock.new("a/path", [
456
+ prepare_config("Debug"),
457
+ prepare_config("Release"),
458
+ ],
459
+ :native_targets => [
460
+ first_target,
461
+ second_target
462
+ ]
463
+ )
464
+ pods_projects_mock = PodsProjectMock.new([], {"hermes-engine" => {}}, :native_targets => [
465
+ third_target
466
+ ])
467
+ installer = InstallerMock.new(pods_projects_mock, [
468
+ AggregatedProjectMock.new(user_project_mock)
469
+ ])
470
+
471
+ # Act
472
+ ReactNativePodsUtils.apply_xcode_15_patch(installer)
473
+
474
+ # Assert
475
+ first_target.build_configurations.each do |config|
476
+ assert_equal(config.build_settings["GCC_PREPROCESSOR_DEFINITIONS"].strip,
477
+ '$(inherited) "_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION"'
478
+ )
479
+ end
480
+ second_target.build_configurations.each do |config|
481
+ assert_equal(config.build_settings["GCC_PREPROCESSOR_DEFINITIONS"].strip,
482
+ '$(inherited) "_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION"'
483
+ )
484
+ end
485
+ third_target.build_configurations.each do |config|
486
+ assert_equal(config.build_settings["GCC_PREPROCESSOR_DEFINITIONS"].strip,
487
+ '$(inherited) "SomeFlag=1" "_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION"'
488
+ )
489
+ end
490
+ end
491
+
438
492
  # ==================================== #
439
493
  # Test - Set Node_Modules User Setting #
440
494
  # ==================================== #
@@ -275,7 +275,7 @@ class CodegenUtils
275
275
  :config_key => config_key
276
276
  )
277
277
  react_codegen_spec = codegen_utils.get_react_codegen_spec(
278
- File.join(react_native_path, "package.json"),
278
+ File.join(relative_installation_root, react_native_path, "package.json"),
279
279
  :folly_version => folly_version,
280
280
  :fabric_enabled => fabric_enabled,
281
281
  :hermes_enabled => hermes_enabled,
@@ -80,8 +80,8 @@ def flipper_post_install(installer)
80
80
  end
81
81
  end
82
82
 
83
- # Enable flipper for React-Core Debug configuration
84
- if target.name == 'React-Core'
83
+ # Enable flipper for React-Core Debug configuration for iOS
84
+ if target.name == 'React-Core-iOS'
85
85
  target.build_configurations.each do |config|
86
86
  if config.debug?
87
87
  config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = ['$(inherited)', 'FB_SONARKIT_ENABLED=1']
@@ -132,6 +132,18 @@ class ReactNativePodsUtils
132
132
  end
133
133
  end
134
134
 
135
+ def self.apply_xcode_15_patch(installer)
136
+ installer.target_installation_results.pod_target_installation_results
137
+ .each do |pod_name, target_installation_result|
138
+ target_installation_result.native_target.build_configurations.each do |config|
139
+ # unary_function and binary_function are no longer provided in C++17 and newer standard modes as part of Xcode 15. They can be re-enabled with setting _LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION
140
+ # Ref: https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#Deprecations
141
+ config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= '$(inherited) '
142
+ config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << '"_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION" '
143
+ end
144
+ end
145
+ end
146
+
135
147
  private
136
148
 
137
149
  def self.fix_library_search_path(config)
@@ -228,6 +228,7 @@ def react_native_post_install(installer, react_native_path = "../node_modules/re
228
228
  ReactNativePodsUtils.exclude_i386_architecture_while_using_hermes(installer)
229
229
  ReactNativePodsUtils.fix_library_search_paths(installer)
230
230
  ReactNativePodsUtils.set_node_modules_user_settings(installer, react_native_path)
231
+ ReactNativePodsUtils.apply_xcode_15_patch(installer)
231
232
 
232
233
  NewArchitectureHelper.set_clang_cxx_language_standard_if_needed(installer)
233
234
  is_new_arch_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == "1"
Binary file
Binary file
package/template/App.tsx CHANGED
@@ -7,8 +7,7 @@
7
7
 
8
8
  import React from 'react';
9
9
  import type {PropsWithChildren} from 'react';
10
- import ReactNative, {
11
- Platform,
10
+ import {
12
11
  SafeAreaView,
13
12
  ScrollView,
14
13
  StatusBar,
@@ -41,7 +41,7 @@
41
41
  <string>LaunchScreen</string>
42
42
  <key>UIRequiredDeviceCapabilities</key>
43
43
  <array>
44
- <string>armv7</string>
44
+ <string>arm64</string>
45
45
  </array>
46
46
  <key>UISupportedInterfaceOrientations</key>
47
47
  <array>
@@ -15,7 +15,7 @@
15
15
  <key>CFBundlePackageType</key>
16
16
  <string>APPL</string>
17
17
  <key>CFBundleShortVersionString</key>
18
- <string>1.0</string>
18
+ <string>$(MARKETING_VERSION)</string>
19
19
  <key>CFBundleSignature</key>
20
20
  <string>????</string>
21
21
  <key>CFBundleVersion</key>
@@ -39,7 +39,7 @@
39
39
  <string>LaunchScreen</string>
40
40
  <key>UIRequiredDeviceCapabilities</key>
41
41
  <array>
42
- <string>armv7</string>
42
+ <string>arm64</string>
43
43
  </array>
44
44
  <key>UISupportedInterfaceOrientations</key>
45
45
  <array>
@@ -50,4 +50,4 @@
50
50
  <key>UIViewControllerBasedStatusBarAppearance</key>
51
51
  <false/>
52
52
  </dict>
53
- </plist>
53
+ </plist>
@@ -734,6 +734,7 @@
734
734
  );
735
735
  INFOPLIST_FILE = HelloWorld/Info.plist;
736
736
  LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
737
+ MARKETING_VERSION = 1.0;
737
738
  OTHER_LDFLAGS = (
738
739
  "$(inherited)",
739
740
  "-ObjC",
@@ -756,6 +757,7 @@
756
757
  CURRENT_PROJECT_VERSION = 1;
757
758
  INFOPLIST_FILE = HelloWorld/Info.plist;
758
759
  LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
760
+ MARKETING_VERSION = 1.0;
759
761
  OTHER_LDFLAGS = (
760
762
  "$(inherited)",
761
763
  "-ObjC",
@@ -784,6 +786,7 @@
784
786
  GCC_NO_COMMON_BLOCKS = YES;
785
787
  INFOPLIST_FILE = "HelloWorld-tvOS/Info.plist";
786
788
  LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
789
+ MARKETING_VERSION = 1.0;
787
790
  OTHER_LDFLAGS = (
788
791
  "$(inherited)",
789
792
  "-ObjC",
@@ -792,6 +795,8 @@
792
795
  PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.HelloWorld-tvOS";
793
796
  PRODUCT_NAME = "$(TARGET_NAME)";
794
797
  SDKROOT = appletvos;
798
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
799
+ SWIFT_VERSION = 5.0;
795
800
  TARGETED_DEVICE_FAMILY = 3;
796
801
  TVOS_DEPLOYMENT_TARGET = 12.4;
797
802
  };
@@ -813,6 +818,7 @@
813
818
  GCC_NO_COMMON_BLOCKS = YES;
814
819
  INFOPLIST_FILE = "HelloWorld-tvOS/Info.plist";
815
820
  LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
821
+ MARKETING_VERSION = 1.0;
816
822
  OTHER_LDFLAGS = (
817
823
  "$(inherited)",
818
824
  "-ObjC",
@@ -821,6 +827,7 @@
821
827
  PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.HelloWorld-tvOS";
822
828
  PRODUCT_NAME = "$(TARGET_NAME)";
823
829
  SDKROOT = appletvos;
830
+ SWIFT_VERSION = 5.0;
824
831
  TARGETED_DEVICE_FAMILY = 3;
825
832
  TVOS_DEPLOYMENT_TARGET = 12.4;
826
833
  };
@@ -3,7 +3,6 @@ require_relative '../node_modules/@react-native-community/cli-platform-ios/nativ
3
3
 
4
4
  source 'https://github.com/react-native-tvos/react-native-tvos-podspecs.git'
5
5
  source 'https://cdn.cocoapods.org/'
6
- install! 'cocoapods', :deterministic_uuids => false
7
6
  prepare_react_native_project!
8
7
 
9
8
  production = ENV["PRODUCTION"] == "1"
@@ -17,18 +16,29 @@ target 'HelloWorld' do
17
16
  # Flags change depending on the env values.
18
17
  flags = get_default_flags()
19
18
 
19
+ # If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set.
20
+ # because `react-native-flipper` depends on (FlipperKit,...) that will be excluded
21
+ #
22
+ # To fix this you can also exclude `react-native-flipper` using a `react-native.config.js`
23
+ # ```js
24
+ # module.exports = {
25
+ # dependencies: {
26
+ # ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}),
27
+ # ```
28
+ flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled
29
+
20
30
  use_react_native!(
21
31
  :path => config[:reactNativePath],
22
32
  # Hermes is now enabled by default. Disable by setting this flag to false.
23
33
  # Upcoming versions of React Native may rely on get_default_flags(), but
24
34
  # we make it explicit here to aid in the React Native upgrade process.
25
- :hermes_enabled => false,
35
+ :hermes_enabled => true,
26
36
  :fabric_enabled => flags[:fabric_enabled],
27
37
  # Enables Flipper.
28
38
  #
29
39
  # Note that if you have use_frameworks! enabled, Flipper will not work and
30
40
  # you should disable the next line.
31
- # :flipper_configuration => flipper_config,
41
+ :flipper_configuration => flipper_config,
32
42
  # An absolute path to your application root.
33
43
  :app_path => "#{Pod::Config.instance.installation_root}/.."
34
44
  )
@@ -50,8 +60,10 @@ target 'HelloWorld-tvOS' do
50
60
 
51
61
  use_react_native!(
52
62
  :path => config[:reactNativePath],
53
- # Hermes not yet available on tvOS
54
- :hermes_enabled => false,
63
+ # Hermes is now enabled by default. Disable by setting this flag to false.
64
+ # Upcoming versions of React Native may rely on get_default_flags(), but
65
+ # we make it explicit here to aid in the React Native upgrade process.
66
+ :hermes_enabled => true,
55
67
  :fabric_enabled => flags[:fabric_enabled],
56
68
  # An absolute path to your application root.
57
69
  :app_path => "#{Pod::Config.instance.installation_root}/.."
@@ -11,7 +11,7 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "react": "18.2.0",
14
- "react-native": "npm:react-native-tvos@0.71.10-0rc0"
14
+ "react-native": "npm:react-native-tvos@0.71.12-0"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@babel/core": "^7.20.0",
@@ -25,7 +25,7 @@
25
25
  "babel-jest": "^29.2.1",
26
26
  "eslint": "^8.19.0",
27
27
  "jest": "^29.2.1",
28
- "metro-react-native-babel-preset": "0.73.9",
28
+ "metro-react-native-babel-preset": "0.73.10",
29
29
  "prettier": "^2.4.1",
30
30
  "react-test-renderer": "18.2.0",
31
31
  "typescript": "4.8.4"
@@ -31,7 +31,7 @@ declare module 'react-native' {
31
31
  nextFocusUp?: number,
32
32
  }
33
33
 
34
- interface View {
34
+ export interface NativeMethods {
35
35
  requestTVFocus(): void;
36
36
  }
37
37