react-native-tvos 0.82.0-0rc5 → 0.82.1-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.
- package/Libraries/Components/TV/TVFocusGuideView.js +5 -3
- package/Libraries/Core/ReactNativeVersion.js +2 -2
- package/React/Base/RCTVersion.m +2 -2
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/ReactAndroidHWInputDeviceHelper.kt +0 -20
- package/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +0 -33
- package/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactAndroidHWInputDeviceHelper.java +0 -20
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +2 -2
- package/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt +0 -9
- package/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt +14 -28
- package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.kt +2 -3
- package/ReactAndroid/src/main/jni/react/jni/TransformHelper.cpp +3 -1
- package/ReactCommon/cxxreact/ReactNativeVersion.h +3 -3
- package/ReactCommon/react/renderer/components/view/BaseViewProps.cpp +0 -3
- package/ReactCommon/react/renderer/components/view/tests/ResolveTransformTest.cpp +377 -0
- package/package.json +8 -8
- package/sdks/hermesc/osx-bin/hermes +0 -0
- package/sdks/hermesc/osx-bin/hermesc +0 -0
- package/sdks/hermesc/win64-bin/hermesc.exe +0 -0
- package/third-party-podspecs/ReactNativeDependencies.podspec +1 -1
|
@@ -104,10 +104,12 @@ function TVFocusGuideView({
|
|
|
104
104
|
const mergedRef = useMergeRefs(setLocalRef, ref);
|
|
105
105
|
|
|
106
106
|
React.useEffect(() => {
|
|
107
|
-
if (
|
|
107
|
+
if (focusable === false) {
|
|
108
|
+
setDestinations([]);
|
|
109
|
+
} else if (destinationsProp !== null && destinationsProp !== undefined) {
|
|
108
110
|
setDestinations(destinationsProp); // $FlowFixMe[incompatible-call]
|
|
109
111
|
}
|
|
110
|
-
}, [setDestinations, destinationsProp]);
|
|
112
|
+
}, [setDestinations, destinationsProp, focusable]);
|
|
111
113
|
|
|
112
114
|
const enabledStyle = {display: enabled ? 'flex' : 'none'};
|
|
113
115
|
const style = [styles.container, props.style, enabledStyle];
|
|
@@ -124,7 +126,7 @@ function TVFocusGuideView({
|
|
|
124
126
|
style={style}
|
|
125
127
|
ref={mergedRef}
|
|
126
128
|
collapsable={false}
|
|
127
|
-
autoFocus={autoFocus}
|
|
129
|
+
autoFocus={focusable === false ? true : autoFocus}
|
|
128
130
|
// tvOS only prop
|
|
129
131
|
isTVSelectable={tvOSSelectable}
|
|
130
132
|
// Android TV only prop
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
export default class ReactNativeVersion {
|
|
29
29
|
static major: number = 0;
|
|
30
30
|
static minor: number = 82;
|
|
31
|
-
static patch: number =
|
|
32
|
-
static prerelease: string | null = '
|
|
31
|
+
static patch: number = 1;
|
|
32
|
+
static prerelease: string | null = '0';
|
|
33
33
|
|
|
34
34
|
static getVersionString(): string {
|
|
35
35
|
return `${this.major}.${this.minor}.${this.patch}${this.prerelease != null ? `-${this.prerelease}` : ''}`;
|
package/React/Base/RCTVersion.m
CHANGED
|
@@ -23,8 +23,8 @@ NSDictionary* RCTGetReactNativeVersion(void)
|
|
|
23
23
|
__rnVersion = @{
|
|
24
24
|
RCTVersionMajor: @(0),
|
|
25
25
|
RCTVersionMinor: @(82),
|
|
26
|
-
RCTVersionPatch: @(
|
|
27
|
-
RCTVersionPrerelease: @"
|
|
26
|
+
RCTVersionPatch: @(1),
|
|
27
|
+
RCTVersionPrerelease: @"0",
|
|
28
28
|
};
|
|
29
29
|
});
|
|
30
30
|
return __rnVersion;
|
|
@@ -33,26 +33,6 @@ internal class ReactAndroidHWInputDeviceHelper {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
/** Called from [ReactRootView] when focused view changes. */
|
|
37
|
-
fun onFocusChanged(newFocusedView: View, context: ReactContext) {
|
|
38
|
-
if (lastFocusedViewId == newFocusedView.id) {
|
|
39
|
-
return
|
|
40
|
-
}
|
|
41
|
-
if (lastFocusedViewId != View.NO_ID) {
|
|
42
|
-
dispatchEvent(context, "blur", lastFocusedViewId)
|
|
43
|
-
}
|
|
44
|
-
lastFocusedViewId = newFocusedView.id
|
|
45
|
-
dispatchEvent(context, "focus", newFocusedView.id)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** Called from [ReactRootView] when the whole view hierarchy looses focus. */
|
|
49
|
-
fun clearFocus(context: ReactContext) {
|
|
50
|
-
if (lastFocusedViewId != View.NO_ID) {
|
|
51
|
-
dispatchEvent(context, "blur", lastFocusedViewId)
|
|
52
|
-
}
|
|
53
|
-
lastFocusedViewId = View.NO_ID
|
|
54
|
-
}
|
|
55
|
-
|
|
56
36
|
private fun dispatchEvent(
|
|
57
37
|
context: ReactContext,
|
|
58
38
|
eventType: String?,
|
|
@@ -341,39 +341,6 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot {
|
|
|
341
341
|
return super.dispatchKeyEvent(ev);
|
|
342
342
|
}
|
|
343
343
|
|
|
344
|
-
@Override
|
|
345
|
-
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
|
|
346
|
-
if (!hasActiveReactContext() || !isViewAttachedToReactInstance()) {
|
|
347
|
-
FLog.w(
|
|
348
|
-
TAG,
|
|
349
|
-
"Unable to handle focus changed event as the catalyst instance has not been attached");
|
|
350
|
-
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
ReactContext context = getCurrentReactContext();
|
|
354
|
-
if (context != null) {
|
|
355
|
-
mAndroidHWInputDeviceHelper.clearFocus(context);
|
|
356
|
-
}
|
|
357
|
-
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
@Override
|
|
361
|
-
public void requestChildFocus(View child, View focused) {
|
|
362
|
-
if (!hasActiveReactContext() || !isViewAttachedToReactInstance()) {
|
|
363
|
-
FLog.w(
|
|
364
|
-
TAG,
|
|
365
|
-
"Unable to handle child focus changed event as the catalyst instance has not been"
|
|
366
|
-
+ " attached");
|
|
367
|
-
super.requestChildFocus(child, focused);
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
ReactContext context = getCurrentReactContext();
|
|
371
|
-
if (context != null) {
|
|
372
|
-
mAndroidHWInputDeviceHelper.onFocusChanged(focused, context);
|
|
373
|
-
}
|
|
374
|
-
super.requestChildFocus(child, focused);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
344
|
protected void dispatchJSPointerEvent(MotionEvent event, boolean isCapture) {
|
|
378
345
|
if (!hasActiveReactContext() || !isViewAttachedToReactInstance()) {
|
|
379
346
|
FLog.w(TAG, "Unable to dispatch touch to JS as the catalyst instance has not been attached");
|
|
@@ -192,26 +192,6 @@ public class ReactAndroidHWInputDeviceHelper {
|
|
|
192
192
|
);
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
/** Called from {@link com.facebook.react.ReactRootView} when focused view changes. */
|
|
196
|
-
public void onFocusChanged(View newFocusedView, ReactContext context) {
|
|
197
|
-
if (mLastFocusedViewId == newFocusedView.getId()) {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
if (mLastFocusedViewId != View.NO_ID) {
|
|
201
|
-
dispatchEvent("blur", mLastFocusedViewId, context);
|
|
202
|
-
}
|
|
203
|
-
mLastFocusedViewId = newFocusedView.getId();
|
|
204
|
-
dispatchEvent("focus", newFocusedView.getId(), context);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/** Called from {@link com.facebook.react.ReactRootView} when the whole view hierarchy looses focus. */
|
|
208
|
-
public void clearFocus(ReactContext context) {
|
|
209
|
-
if (mLastFocusedViewId != View.NO_ID) {
|
|
210
|
-
dispatchEvent("blur", mLastFocusedViewId, context);
|
|
211
|
-
}
|
|
212
|
-
mLastFocusedViewId = View.NO_ID;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
195
|
private void dispatchEvent(String eventType, int targetViewId, ReactContext context) {
|
|
216
196
|
dispatchEvent(eventType, targetViewId, -1, context);
|
|
217
197
|
}
|
|
@@ -560,15 +560,6 @@ public class ReactModalHostView(context: ThemedReactContext) :
|
|
|
560
560
|
updateState(viewWidth, viewHeight)
|
|
561
561
|
}
|
|
562
562
|
|
|
563
|
-
protected override fun onFocusChanged(
|
|
564
|
-
gainFocus: Boolean,
|
|
565
|
-
direction: Int,
|
|
566
|
-
previouslyFocusedRect: Rect?
|
|
567
|
-
) {
|
|
568
|
-
androidHWInputDeviceHelper.clearFocus(reactContext)
|
|
569
|
-
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect)
|
|
570
|
-
}
|
|
571
|
-
|
|
572
563
|
/*
|
|
573
564
|
public override fun requestChildFocus(child: View?, focused: View?) {
|
|
574
565
|
androidHWInputDeviceHelper.onFocusChanged(focused, reactContext)
|
|
@@ -425,7 +425,7 @@ public open class ReactEditText public constructor(context: Context) : AppCompat
|
|
|
425
425
|
// that. This method will eventually replace requestFocusInternal()
|
|
426
426
|
private fun requestFocusProgrammatically(): Boolean {
|
|
427
427
|
val focused = super.requestFocus(FOCUS_DOWN, null)
|
|
428
|
-
if (
|
|
428
|
+
if (showSoftInputOnFocus) {
|
|
429
429
|
showSoftKeyboard()
|
|
430
430
|
} else {
|
|
431
431
|
if (isKeyboardOpened) {
|
|
@@ -70,9 +70,7 @@ import com.facebook.react.uimanager.UIManagerHelper
|
|
|
70
70
|
import com.facebook.react.uimanager.ViewGroupDrawingOrderHelper
|
|
71
71
|
import com.facebook.react.uimanager.common.UIManagerType
|
|
72
72
|
import com.facebook.react.uimanager.common.ViewUtil.getUIManagerType
|
|
73
|
-
import com.facebook.react.uimanager.events.BlurEvent
|
|
74
73
|
import com.facebook.react.uimanager.events.EventDispatcher
|
|
75
|
-
import com.facebook.react.uimanager.events.FocusEvent
|
|
76
74
|
import com.facebook.react.uimanager.events.PressInEvent
|
|
77
75
|
import com.facebook.react.uimanager.events.PressOutEvent
|
|
78
76
|
import com.facebook.react.uimanager.style.BorderRadiusProp
|
|
@@ -747,6 +745,18 @@ public open class ReactViewGroup public constructor(context: Context?) :
|
|
|
747
745
|
}
|
|
748
746
|
super.onViewAdded(child)
|
|
749
747
|
}
|
|
748
|
+
|
|
749
|
+
override fun removeView(view: View?) {
|
|
750
|
+
if (view != null) {
|
|
751
|
+
recoverFocus(view);
|
|
752
|
+
}
|
|
753
|
+
super.removeView(view);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
override fun removeViewAt(index: Int) {
|
|
757
|
+
recoverFocus(getChildAt(index));
|
|
758
|
+
super.removeViewAt(index);
|
|
759
|
+
}
|
|
750
760
|
|
|
751
761
|
override fun onViewRemoved(child: View) {
|
|
752
762
|
assertOnUiThread()
|
|
@@ -869,7 +879,7 @@ public open class ReactViewGroup public constructor(context: Context?) :
|
|
|
869
879
|
|
|
870
880
|
internal fun removeViewWithSubviewClippingEnabled(view: View) {
|
|
871
881
|
assertOnUiThread()
|
|
872
|
-
|
|
882
|
+
recoverFocus(view)
|
|
873
883
|
check(_removeClippedSubviews)
|
|
874
884
|
val allChildren = checkNotNull(allChildren)
|
|
875
885
|
view.removeOnLayoutChangeListener(childrenLayoutChangeListener)
|
|
@@ -1360,31 +1370,7 @@ public open class ReactViewGroup public constructor(context: Context?) :
|
|
|
1360
1370
|
}
|
|
1361
1371
|
|
|
1362
1372
|
override fun onFocusChanged(gainFocus: Boolean, direction: Int, previouslyFocusedRect: Rect?) {
|
|
1363
|
-
|
|
1364
|
-
// super.onFocusChanged(gainFocus, direction, previouslyFocusedRect)
|
|
1365
|
-
|
|
1366
|
-
val mEventDispatcher: EventDispatcher? =
|
|
1367
|
-
UIManagerHelper.getEventDispatcherForReactTag(
|
|
1368
|
-
this.context as ReactContext, this.id
|
|
1369
|
-
)
|
|
1370
|
-
|
|
1371
|
-
if (mEventDispatcher == null) {
|
|
1372
|
-
return
|
|
1373
|
-
}
|
|
1374
|
-
|
|
1375
|
-
if (gainFocus) {
|
|
1376
|
-
mEventDispatcher.dispatchEvent(
|
|
1377
|
-
FocusEvent(
|
|
1378
|
-
UIManagerHelper.getSurfaceId(this.context), this.id
|
|
1379
|
-
)
|
|
1380
|
-
)
|
|
1381
|
-
} else {
|
|
1382
|
-
mEventDispatcher.dispatchEvent(
|
|
1383
|
-
BlurEvent(
|
|
1384
|
-
UIManagerHelper.getSurfaceId(this.context), this.id
|
|
1385
|
-
)
|
|
1386
|
-
)
|
|
1387
|
-
}
|
|
1373
|
+
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect)
|
|
1388
1374
|
}
|
|
1389
1375
|
|
|
1390
1376
|
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
|
|
@@ -108,7 +108,7 @@ public open class ReactViewManager : ReactClippingViewManager<ReactViewGroup>()
|
|
|
108
108
|
view.isFocusable = false
|
|
109
109
|
view.descendantFocusability = ViewGroup.FOCUS_BLOCK_DESCENDANTS
|
|
110
110
|
} else {
|
|
111
|
-
view.descendantFocusability = ViewGroup.
|
|
111
|
+
view.descendantFocusability = ViewGroup.FOCUS_AFTER_DESCENDANTS
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -407,8 +407,7 @@ public open class ReactViewManager : ReactClippingViewManager<ReactViewGroup>()
|
|
|
407
407
|
} else {
|
|
408
408
|
view.setOnClickListener(null)
|
|
409
409
|
view.isClickable = false
|
|
410
|
-
|
|
411
|
-
// accessibility reasons
|
|
410
|
+
view.isFocusable = false
|
|
412
411
|
}
|
|
413
412
|
// This is required to handle Android TV/ Fire TV Devices that are Touch Enabled as well as LeanBack
|
|
414
413
|
// https://developer.android.com/reference/android/view/View#requestFocus(int,%20android.graphics.Rect)
|
|
@@ -39,7 +39,9 @@ void processTransform(
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
auto result = BaseViewProps::resolveTransform(
|
|
42
|
-
Size
|
|
42
|
+
Size{.width = viewWidth, .height = viewHeight},
|
|
43
|
+
transform,
|
|
44
|
+
transformOrigin);
|
|
43
45
|
|
|
44
46
|
// Convert from matrix of floats to double matrix
|
|
45
47
|
constexpr size_t MatrixSize = std::tuple_size_v<decltype(result.matrix)>;
|
|
@@ -14,15 +14,15 @@
|
|
|
14
14
|
|
|
15
15
|
#define REACT_NATIVE_VERSION_MAJOR 0
|
|
16
16
|
#define REACT_NATIVE_VERSION_MINOR 82
|
|
17
|
-
#define REACT_NATIVE_VERSION_PATCH
|
|
17
|
+
#define REACT_NATIVE_VERSION_PATCH 1
|
|
18
18
|
|
|
19
19
|
namespace facebook::react {
|
|
20
20
|
|
|
21
21
|
constexpr struct {
|
|
22
22
|
int32_t Major = 0;
|
|
23
23
|
int32_t Minor = 82;
|
|
24
|
-
int32_t Patch =
|
|
25
|
-
std::string_view Prerelease = "
|
|
24
|
+
int32_t Patch = 1;
|
|
25
|
+
std::string_view Prerelease = "0";
|
|
26
26
|
} ReactNativeVersion;
|
|
27
27
|
|
|
28
28
|
} // namespace facebook::react
|
|
@@ -646,9 +646,6 @@ Transform BaseViewProps::resolveTransform(
|
|
|
646
646
|
const Transform& transform,
|
|
647
647
|
const TransformOrigin& transformOrigin) {
|
|
648
648
|
auto transformMatrix = Transform{};
|
|
649
|
-
if (frameSize.width == 0 && frameSize.height == 0) {
|
|
650
|
-
return transformMatrix;
|
|
651
|
-
}
|
|
652
649
|
|
|
653
650
|
// transform is matrix
|
|
654
651
|
if (transform.operations.size() == 1 &&
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include <gtest/gtest.h>
|
|
9
|
+
|
|
10
|
+
#include <react/renderer/components/view/BaseViewProps.h>
|
|
11
|
+
|
|
12
|
+
namespace facebook::react {
|
|
13
|
+
|
|
14
|
+
namespace {
|
|
15
|
+
|
|
16
|
+
// For transforms involving rotations, use this helper to fix floating point
|
|
17
|
+
// accuracies
|
|
18
|
+
void expectTransformsEqual(const Transform& t1, const Transform& t2) {
|
|
19
|
+
for (int i = 0; i < 16; i++) {
|
|
20
|
+
EXPECT_NEAR(t1.matrix[i], t2.matrix[i], 0.0001);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
} // namespace
|
|
25
|
+
|
|
26
|
+
class ResolveTransformTest : public ::testing::Test {
|
|
27
|
+
protected:
|
|
28
|
+
TransformOrigin createTransformOriginPoints(float x, float y, float z = 0) {
|
|
29
|
+
TransformOrigin origin;
|
|
30
|
+
origin.xy[0] = ValueUnit(x, UnitType::Point);
|
|
31
|
+
origin.xy[1] = ValueUnit(y, UnitType::Point);
|
|
32
|
+
origin.z = z;
|
|
33
|
+
return origin;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
TransformOrigin createTransformOriginPercent(float x, float y, float z = 0) {
|
|
37
|
+
TransformOrigin origin;
|
|
38
|
+
origin.xy[0] = ValueUnit(x, UnitType::Percent);
|
|
39
|
+
origin.xy[1] = ValueUnit(y, UnitType::Percent);
|
|
40
|
+
origin.z = z;
|
|
41
|
+
return origin;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
TEST_F(ResolveTransformTest, EmptyFrameNoTransformOrigin) {
|
|
46
|
+
Size frameSize{.width = 0, .height = 0};
|
|
47
|
+
Transform transform = Transform::Translate(10.0, 20.0, 0.0);
|
|
48
|
+
TransformOrigin transformOrigin; // Default (not set)
|
|
49
|
+
|
|
50
|
+
auto result =
|
|
51
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
52
|
+
|
|
53
|
+
// With empty frame size and no transform origin, should just apply the
|
|
54
|
+
// transform directly
|
|
55
|
+
EXPECT_EQ(result.matrix, transform.matrix);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
TEST_F(ResolveTransformTest, EmptyFrameTransformOriginPoints) {
|
|
59
|
+
Size frameSize{.width = 0, .height = 0};
|
|
60
|
+
Transform transform = Transform::Translate(10.0, 20.0, 0.0);
|
|
61
|
+
TransformOrigin transformOrigin = createTransformOriginPoints(5, 8);
|
|
62
|
+
|
|
63
|
+
auto result =
|
|
64
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
65
|
+
|
|
66
|
+
// Should handle transform origin even with empty frame size
|
|
67
|
+
EXPECT_EQ(result.matrix, Transform::Translate(10.0, 20.0, 0.0).matrix);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
TEST_F(ResolveTransformTest, EmptyFrameTransformOriginPercent) {
|
|
71
|
+
Size frameSize{.width = 0, .height = 0};
|
|
72
|
+
Transform transform = Transform::Translate(10.0, 20.0, 0.0);
|
|
73
|
+
TransformOrigin transformOrigin = createTransformOriginPercent(50, 50);
|
|
74
|
+
|
|
75
|
+
auto result =
|
|
76
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
77
|
+
|
|
78
|
+
// Transform origin does not affect translate transform
|
|
79
|
+
EXPECT_EQ(result.matrix, Transform::Translate(10.0, 20.0, 0.0).matrix);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
TEST_F(ResolveTransformTest, NonEmptyFrameNoTransformOrigin) {
|
|
83
|
+
Size frameSize{.width = 100, .height = 200};
|
|
84
|
+
Transform transform = Transform::Translate(10.0, 20.0, 0.0);
|
|
85
|
+
TransformOrigin transformOrigin; // Default (not set)
|
|
86
|
+
|
|
87
|
+
auto result =
|
|
88
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
89
|
+
|
|
90
|
+
// Transform origin does not affect translate transform
|
|
91
|
+
EXPECT_EQ(result.matrix, Transform::Translate(10.0, 20.0, 0.0).matrix);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
TEST_F(ResolveTransformTest, NonEmptyFrameTransformOriginPoints) {
|
|
95
|
+
Size frameSize{.width = 100, .height = 200};
|
|
96
|
+
Transform transform = Transform::Scale(2.0, 1.5, 0.);
|
|
97
|
+
TransformOrigin transformOrigin = createTransformOriginPoints(25, 50);
|
|
98
|
+
|
|
99
|
+
auto result =
|
|
100
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
101
|
+
|
|
102
|
+
auto expected = Transform::Translate(25.0, 25.0, 0.0) * transform;
|
|
103
|
+
EXPECT_EQ(result.matrix, expected.matrix);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
TEST_F(ResolveTransformTest, NonEmptyFrameTransformOriginPercent) {
|
|
107
|
+
Size frameSize{.width = 100, .height = 200};
|
|
108
|
+
Transform transform = Transform::Scale(2.0, 1.5, 0.);
|
|
109
|
+
TransformOrigin transformOrigin =
|
|
110
|
+
createTransformOriginPercent(25, 75); // 25% width, 75% height
|
|
111
|
+
|
|
112
|
+
auto result =
|
|
113
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
114
|
+
|
|
115
|
+
// Should resolve percentages: 25% of 100 = 25, 75% of 200 = 150
|
|
116
|
+
auto expected = Transform::Translate(25.0, -25.0, 0.0) * transform;
|
|
117
|
+
EXPECT_EQ(result.matrix, expected.matrix);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
TEST_F(ResolveTransformTest, IdentityTransformWithOrigin) {
|
|
121
|
+
Size frameSize{.width = 100, .height = 200};
|
|
122
|
+
Transform transform = Transform::Identity();
|
|
123
|
+
TransformOrigin transformOrigin = createTransformOriginPoints(25, 50);
|
|
124
|
+
|
|
125
|
+
auto result =
|
|
126
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
127
|
+
|
|
128
|
+
// Even with identity transform, transform origin should still apply
|
|
129
|
+
// translations but they should cancel out, resulting in identity
|
|
130
|
+
EXPECT_EQ(result.matrix, transform.matrix);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
TEST_F(ResolveTransformTest, MultipleTransformOperations) {
|
|
134
|
+
Size frameSize{.width = 100, .height = 200};
|
|
135
|
+
|
|
136
|
+
Transform transform = Transform::Identity();
|
|
137
|
+
transform = transform * Transform::Translate(10.0, 20.0, 0.0);
|
|
138
|
+
transform = transform * Transform::Scale(2.0, 1.5, 0.0);
|
|
139
|
+
|
|
140
|
+
TransformOrigin transformOrigin = createTransformOriginPercent(50, 50);
|
|
141
|
+
|
|
142
|
+
auto result =
|
|
143
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
144
|
+
|
|
145
|
+
EXPECT_EQ(result.matrix, transform.matrix);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
TEST_F(ResolveTransformTest, VariousTransformOriginPositions) {
|
|
149
|
+
Size frameSize{.width = 100, .height = 200};
|
|
150
|
+
Transform transform = Transform::Scale(2.0, 2.0, 0.);
|
|
151
|
+
|
|
152
|
+
// Test origin at top-left (0, 0)
|
|
153
|
+
TransformOrigin topLeft = createTransformOriginPoints(0, 0);
|
|
154
|
+
auto resultTopLeft =
|
|
155
|
+
BaseViewProps::resolveTransform(frameSize, transform, topLeft);
|
|
156
|
+
auto expected = Transform::Translate(50.0, 100.0, 0.0) * transform;
|
|
157
|
+
EXPECT_EQ(resultTopLeft.matrix, expected.matrix);
|
|
158
|
+
|
|
159
|
+
// Test origin at center (50%, 50%)
|
|
160
|
+
TransformOrigin center = createTransformOriginPercent(50, 50);
|
|
161
|
+
auto resultCenter =
|
|
162
|
+
BaseViewProps::resolveTransform(frameSize, transform, center);
|
|
163
|
+
EXPECT_EQ(resultCenter.matrix, transform.matrix);
|
|
164
|
+
|
|
165
|
+
// Test origin at bottom-right (100%, 100%)
|
|
166
|
+
TransformOrigin bottomRight = createTransformOriginPercent(100, 100);
|
|
167
|
+
auto resultBottomRight =
|
|
168
|
+
BaseViewProps::resolveTransform(frameSize, transform, bottomRight);
|
|
169
|
+
expected = Transform::Translate(-50.0, -100.0, 0.0) * transform;
|
|
170
|
+
EXPECT_EQ(resultBottomRight.matrix, expected.matrix);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Test with z-component in transform origin
|
|
174
|
+
TEST_F(ResolveTransformTest, TransformOriginWithZComponent) {
|
|
175
|
+
Size frameSize{.width = 100, .height = 200};
|
|
176
|
+
Transform transform = Transform::Scale(1.5, 1.5, 0.);
|
|
177
|
+
|
|
178
|
+
TransformOrigin transformOrigin;
|
|
179
|
+
transformOrigin.xy[0] = ValueUnit(50, UnitType::Point);
|
|
180
|
+
transformOrigin.xy[1] = ValueUnit(100, UnitType::Point);
|
|
181
|
+
transformOrigin.z = 10.0f;
|
|
182
|
+
|
|
183
|
+
auto result =
|
|
184
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
185
|
+
auto expected = Transform::Translate(0.0, 0.0, 10.0) * transform;
|
|
186
|
+
EXPECT_EQ(result.matrix, expected.matrix);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
TEST_F(ResolveTransformTest, ArbitraryTransformMatrix) {
|
|
190
|
+
Size frameSize{.width = 100, .height = 200};
|
|
191
|
+
|
|
192
|
+
Transform transform;
|
|
193
|
+
transform.operations.push_back({
|
|
194
|
+
.type = TransformOperationType::Arbitrary,
|
|
195
|
+
.x = ValueUnit(0, UnitType::Point),
|
|
196
|
+
.y = ValueUnit(0, UnitType::Point),
|
|
197
|
+
.z = ValueUnit(0, UnitType::Point),
|
|
198
|
+
});
|
|
199
|
+
// Set custom matrix
|
|
200
|
+
transform.matrix = {{2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 10, 20, 0, 1}};
|
|
201
|
+
|
|
202
|
+
TransformOrigin transformOrigin = createTransformOriginPoints(25, 50);
|
|
203
|
+
|
|
204
|
+
auto result =
|
|
205
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
206
|
+
|
|
207
|
+
auto expected = Transform::Translate(25.0, 50.0, 0.0) * transform;
|
|
208
|
+
EXPECT_EQ(result.matrix, expected.matrix);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Test rotation with empty frame size and no transform origin
|
|
212
|
+
TEST_F(ResolveTransformTest, RotationEmptyFrameNoTransformOrigin) {
|
|
213
|
+
Size frameSize{.width = 0, .height = 0};
|
|
214
|
+
Transform transform = Transform::RotateZ(M_PI / 4.0); // 45 degrees
|
|
215
|
+
TransformOrigin transformOrigin; // Default (not set)
|
|
216
|
+
|
|
217
|
+
auto result =
|
|
218
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
219
|
+
|
|
220
|
+
// With empty frame size and no transform origin, should just apply the
|
|
221
|
+
// rotation directly
|
|
222
|
+
expectTransformsEqual(result, transform);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Test rotation with empty frame size and transform origin in points
|
|
226
|
+
TEST_F(ResolveTransformTest, RotationEmptyFrameTransformOriginPoints) {
|
|
227
|
+
Size frameSize{.width = 0, .height = 0};
|
|
228
|
+
Transform transform = Transform::RotateZ(M_PI / 4.0); // 45 degrees
|
|
229
|
+
TransformOrigin transformOrigin = createTransformOriginPoints(10, 20);
|
|
230
|
+
|
|
231
|
+
auto result =
|
|
232
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
233
|
+
|
|
234
|
+
// With empty frame size, center is (0, 0), so origin offset is (10, 20)
|
|
235
|
+
auto expected = Transform::Translate(10.0, 20.0, 0.0) * transform *
|
|
236
|
+
Transform::Translate(-10.0, -20.0, 0.0);
|
|
237
|
+
expectTransformsEqual(result, expected);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Test rotation with empty frame size and transform origin in percentages
|
|
241
|
+
TEST_F(ResolveTransformTest, RotationEmptyFrameTransformOriginPercent) {
|
|
242
|
+
Size frameSize{.width = 0, .height = 0};
|
|
243
|
+
Transform transform = Transform::RotateZ(M_PI / 6.0); // 30 degrees
|
|
244
|
+
TransformOrigin transformOrigin = createTransformOriginPercent(50, 50);
|
|
245
|
+
|
|
246
|
+
auto result =
|
|
247
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
248
|
+
|
|
249
|
+
// With 0 frame size, percentages resolve to 0, so no origin offset
|
|
250
|
+
expectTransformsEqual(result, transform);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Test rotation with non-empty frame size and no transform origin
|
|
254
|
+
TEST_F(ResolveTransformTest, RotationNonEmptyFrameNoTransformOrigin) {
|
|
255
|
+
Size frameSize{.width = 100, .height = 200};
|
|
256
|
+
Transform transform = Transform::RotateZ(M_PI / 3.0); // 60 degrees
|
|
257
|
+
TransformOrigin transformOrigin; // Default (not set)
|
|
258
|
+
|
|
259
|
+
auto result =
|
|
260
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
261
|
+
|
|
262
|
+
// Without transform origin, rotation should happen around default center
|
|
263
|
+
expectTransformsEqual(result, transform);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Test rotation with non-empty frame size and transform origin in points
|
|
267
|
+
TEST_F(ResolveTransformTest, RotationNonEmptyFrameTransformOriginPoints) {
|
|
268
|
+
Size frameSize{.width = 100, .height = 200};
|
|
269
|
+
Transform transform = Transform::RotateZ(M_PI / 4.0); // 45 degrees
|
|
270
|
+
TransformOrigin transformOrigin = createTransformOriginPoints(25, 50);
|
|
271
|
+
|
|
272
|
+
auto result =
|
|
273
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
274
|
+
|
|
275
|
+
// Center of 100x200 frame is (50, 100), origin at (25, 50) means offset of
|
|
276
|
+
// (-25, -50)
|
|
277
|
+
auto expected = Transform::Translate(-25.0, -50.0, 0.0) * transform *
|
|
278
|
+
Transform::Translate(25.0, 50.0, 0.0);
|
|
279
|
+
expectTransformsEqual(result, expected);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Test rotation with non-empty frame size and transform origin in percentages
|
|
283
|
+
TEST_F(ResolveTransformTest, RotationNonEmptyFrameTransformOriginPercent) {
|
|
284
|
+
Size frameSize{.width = 100, .height = 200};
|
|
285
|
+
Transform transform = Transform::RotateZ(M_PI / 2.0); // 90 degrees
|
|
286
|
+
TransformOrigin transformOrigin =
|
|
287
|
+
createTransformOriginPercent(25, 75); // 25% width, 75% height
|
|
288
|
+
|
|
289
|
+
auto result =
|
|
290
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
291
|
+
|
|
292
|
+
// Should resolve percentages: 25% of 100 = 25, 75% of 200 = 150
|
|
293
|
+
// Center is (50, 100), so origin offset is (25-50, 150-100) = (-25, 50)
|
|
294
|
+
auto expected = Transform::Translate(-25.0, 50.0, 0.0) * transform *
|
|
295
|
+
Transform::Translate(25.0, -50.0, 0.0);
|
|
296
|
+
expectTransformsEqual(result, expected);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Test rotation with mixed transform origin units
|
|
300
|
+
TEST_F(ResolveTransformTest, RotationMixedTransformOriginUnits) {
|
|
301
|
+
Size frameSize{.width = 100, .height = 200};
|
|
302
|
+
Transform transform = Transform::RotateZ(M_PI); // 180 degrees
|
|
303
|
+
|
|
304
|
+
TransformOrigin transformOrigin;
|
|
305
|
+
transformOrigin.xy[0] = ValueUnit(30, UnitType::Point); // 30 points
|
|
306
|
+
transformOrigin.xy[1] = ValueUnit(25, UnitType::Percent); // 25% of 200 = 50
|
|
307
|
+
transformOrigin.z = 0;
|
|
308
|
+
|
|
309
|
+
auto result =
|
|
310
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
311
|
+
|
|
312
|
+
// Center is (50, 100), origin is (30, 50), so offset is (-20, -50)
|
|
313
|
+
auto expected = Transform::Translate(-20.0, -50.0, 0.0) * transform *
|
|
314
|
+
Transform::Translate(20.0, 50.0, 0.0);
|
|
315
|
+
expectTransformsEqual(result, expected);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Test multiple rotations (RotateX, RotateY, RotateZ)
|
|
319
|
+
TEST_F(ResolveTransformTest, MultipleRotationsWithTransformOrigin) {
|
|
320
|
+
Size frameSize{.width = 100, .height = 100};
|
|
321
|
+
|
|
322
|
+
Transform transform = Transform::Rotate(M_PI / 6.0, M_PI / 4.0, M_PI / 3.0);
|
|
323
|
+
TransformOrigin transformOrigin = createTransformOriginPercent(50, 50);
|
|
324
|
+
|
|
325
|
+
auto result =
|
|
326
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
327
|
+
expectTransformsEqual(result, transform);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Test rotation with z-component in transform origin
|
|
331
|
+
TEST_F(ResolveTransformTest, RotationWithZTransformOrigin) {
|
|
332
|
+
Size frameSize{.width = 100, .height = 200};
|
|
333
|
+
Transform transform = Transform::RotateZ(M_PI / 4.0); // 45 degrees
|
|
334
|
+
|
|
335
|
+
TransformOrigin transformOrigin;
|
|
336
|
+
transformOrigin.xy[0] = ValueUnit(50, UnitType::Point);
|
|
337
|
+
transformOrigin.xy[1] = ValueUnit(100, UnitType::Point);
|
|
338
|
+
transformOrigin.z = 15.0f;
|
|
339
|
+
|
|
340
|
+
auto result =
|
|
341
|
+
BaseViewProps::resolveTransform(frameSize, transform, transformOrigin);
|
|
342
|
+
|
|
343
|
+
// Center is (50, 100), origin is (50, 100, 15), so offset is (0, 0, 15)
|
|
344
|
+
auto expected = Transform::Translate(0.0, 0.0, 15.0) * transform *
|
|
345
|
+
Transform::Translate(0.0, 0.0, -15.0);
|
|
346
|
+
expectTransformsEqual(result, expected);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Test rotation at different origin positions (corners vs center)
|
|
350
|
+
TEST_F(ResolveTransformTest, RotationDifferentOriginPositions) {
|
|
351
|
+
Size frameSize{.width = 100, .height = 100};
|
|
352
|
+
Transform transform = Transform::RotateZ(M_PI / 2.0); // 90 degrees
|
|
353
|
+
|
|
354
|
+
// Test rotation around top-left corner (0, 0)
|
|
355
|
+
TransformOrigin topLeft = createTransformOriginPoints(0, 0);
|
|
356
|
+
auto resultTopLeft =
|
|
357
|
+
BaseViewProps::resolveTransform(frameSize, transform, topLeft);
|
|
358
|
+
auto expectedTopLeft = Transform::Translate(-50.0, -50.0, 0.0) * transform *
|
|
359
|
+
Transform::Translate(50.0, 50.0, 0.0);
|
|
360
|
+
expectTransformsEqual(resultTopLeft, expectedTopLeft);
|
|
361
|
+
|
|
362
|
+
// Test rotation around center (50%, 50%)
|
|
363
|
+
TransformOrigin center = createTransformOriginPercent(50, 50);
|
|
364
|
+
auto resultCenter =
|
|
365
|
+
BaseViewProps::resolveTransform(frameSize, transform, center);
|
|
366
|
+
expectTransformsEqual(resultCenter, transform);
|
|
367
|
+
|
|
368
|
+
// Test rotation around bottom-right corner (100%, 100%)
|
|
369
|
+
TransformOrigin bottomRight = createTransformOriginPercent(100, 100);
|
|
370
|
+
auto resultBottomRight =
|
|
371
|
+
BaseViewProps::resolveTransform(frameSize, transform, bottomRight);
|
|
372
|
+
auto expectedBottomRight = Transform::Translate(50.0, 50.0, 0.0) * transform *
|
|
373
|
+
Transform::Translate(-50.0, -50.0, 0.0);
|
|
374
|
+
expectTransformsEqual(resultBottomRight, expectedBottomRight);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
} // namespace facebook::react
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-tvos",
|
|
3
|
-
"version": "0.82.0
|
|
3
|
+
"version": "0.82.1-0",
|
|
4
4
|
"description": "A framework for building native apps using React",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -166,12 +166,12 @@
|
|
|
166
166
|
},
|
|
167
167
|
"dependencies": {
|
|
168
168
|
"@jest/create-cache-key-function": "^29.7.0",
|
|
169
|
-
"@react-native/assets-registry": "0.82.
|
|
170
|
-
"@react-native/codegen": "0.82.
|
|
171
|
-
"@react-native/community-cli-plugin": "0.82.
|
|
172
|
-
"@react-native/gradle-plugin": "0.82.
|
|
173
|
-
"@react-native/js-polyfills": "0.82.
|
|
174
|
-
"@react-native/normalize-colors": "0.82.
|
|
169
|
+
"@react-native/assets-registry": "0.82.1",
|
|
170
|
+
"@react-native/codegen": "0.82.1",
|
|
171
|
+
"@react-native/community-cli-plugin": "0.82.1",
|
|
172
|
+
"@react-native/gradle-plugin": "0.82.1",
|
|
173
|
+
"@react-native/js-polyfills": "0.82.1",
|
|
174
|
+
"@react-native/normalize-colors": "0.82.1",
|
|
175
175
|
"abort-controller": "^3.0.0",
|
|
176
176
|
"anser": "^1.4.9",
|
|
177
177
|
"ansi-regex": "^5.0.0",
|
|
@@ -199,7 +199,7 @@
|
|
|
199
199
|
"whatwg-fetch": "^3.0.0",
|
|
200
200
|
"ws": "^6.2.3",
|
|
201
201
|
"yargs": "^17.6.2",
|
|
202
|
-
"@react-native-tvos/virtualized-lists": "0.82.0
|
|
202
|
+
"@react-native-tvos/virtualized-lists": "0.82.1-0"
|
|
203
203
|
},
|
|
204
204
|
"codegenConfig": {
|
|
205
205
|
"libraries": [
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -64,7 +64,7 @@ Pod::Spec.new do |spec|
|
|
|
64
64
|
exit 0
|
|
65
65
|
fi
|
|
66
66
|
|
|
67
|
-
cp -R "$HEADERS_PATH
|
|
67
|
+
cp -R "$HEADERS_PATH/." Headers
|
|
68
68
|
mkdir -p framework/packages/react-native
|
|
69
69
|
cp -R "$XCFRAMEWORK_PATH/../." framework/packages/react-native/
|
|
70
70
|
find "$XCFRAMEWORK_PATH/.." -type f -exec rm {} +
|