@react-native-oh/react-native-harmony 0.72.28 → 0.72.29

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.
@@ -1,5 +1,5 @@
1
1
  import type { TurboModule } from "react-native/Libraries/TurboModule/RCTExport";
2
- import { TurboModuleRegistry, View, ViewProps } from "react-native";
2
+ import { Dimensions, TurboModuleRegistry, View, ViewProps } from "react-native";
3
3
  import { useEffect, useState } from "react";
4
4
  import React from "react";
5
5
 
@@ -22,23 +22,68 @@ const safeAreaTurboModule = TurboModuleRegistry.get<Spec>(
22
22
  "SafeAreaTurboModule"
23
23
  )!;
24
24
 
25
+ const getPaddingTop = (inset: number, pageY: number) => {
26
+ return Math.max(0, inset - (pageY < 0 ? pageY * -1 : pageY));
27
+ }
28
+
29
+ const getPaddingBottom = (insetBottom: number, insetTop: number, paddingTop: number, height: number, windowHeight: number, pageY: number, positionY: number): number => {
30
+ // if SafeArea is not visible or outside the viewport or topped and not full height
31
+ if (height === 0 || (pageY === 0 && height < windowHeight)) {
32
+ return Math.max(0, insetBottom - (Math.round(windowHeight) - Math.round(height)));
33
+ }
34
+
35
+ // if SafeAreaView is not topped and not full height and not visible
36
+ if (pageY < windowHeight && pageY > height && positionY === 0) {
37
+ return 0;
38
+ };
39
+
40
+
41
+ // if SafeAreaView is topped, check for full height
42
+ if (Math.round(height) >= Math.round(windowHeight) && pageY === 0) {
43
+ // if SafeAreaView is full height and at the top without any offset
44
+ return positionY === 0 ? insetBottom : 0;
45
+ }
46
+
47
+ // if SafeAreaView is topped with margin and not full height
48
+ if (height < windowHeight && positionY === 0 && pageY <= insetTop) {
49
+ return Math.max(0, insetBottom - (windowHeight - (height + pageY)));
50
+ }
51
+
52
+ if (height < windowHeight && pageY < windowHeight && pageY > 0 && positionY > 0) {
53
+ return Math.max(0, insetBottom - (windowHeight - pageY));
54
+ }
55
+
56
+ // if SafeAreaView is not topped and not full height and is nested
57
+ if (height < windowHeight && pageY > 0 && pageY > windowHeight) {
58
+ return Math.max(0, insetBottom);
59
+ }
60
+
61
+ // Default case handling scenarios not captured above
62
+ return Math.max(0, insetBottom - (windowHeight - height + paddingTop));
63
+ }
64
+
25
65
  export default React.forwardRef<View, ViewProps>(
26
66
  ({ children, style, ...otherProps }, ref) => {
27
- const [topInset, setTopInset] = useState(
28
- safeAreaTurboModule.getInitialInsets().top
29
- );
30
- const [leftInset, setLeftInset] = useState(
31
- safeAreaTurboModule.getInitialInsets().left
32
- );
33
- const [rightInset, setRightInset] = useState(
34
- safeAreaTurboModule.getInitialInsets().right
35
- );
36
- const [bottomInset, setBottomInset] = useState(
37
- safeAreaTurboModule.getInitialInsets().bottom
38
- );
39
67
 
68
+ const safeAreaViewRef = React.useRef<View>(null);
69
+
70
+ const [topInset, setTopInset] = useState(safeAreaTurboModule.getInitialInsets().top);
71
+ const [leftInset, setLeftInset] = useState(safeAreaTurboModule.getInitialInsets().left);
72
+ const [rightInset, setRightInset] = useState(safeAreaTurboModule.getInitialInsets().right);
73
+ const [bottomInset, setBottomInset] = useState(safeAreaTurboModule.getInitialInsets().bottom);
74
+
75
+ const [measurement, setMeasurement] = useState({ x: 0, y: 0, width: 0, height: 0, pageX: 0, pageY: -1 });
76
+ const [layout, setLayout] = useState({ x: 0, y: 0, width: 0, height: 0 });
77
+
78
+ const measureView = () => {
79
+ safeAreaViewRef?.current?.measure((x, y, width, height, pageX, pageY) => {
80
+ setMeasurement({ x, y, width, height, pageX, pageY });
81
+ });
82
+ }
83
+
40
84
  useEffect(
41
85
  function subscribeToSafeAreaChanges() {
86
+
42
87
  const subscription = (RCTDeviceEventEmitter as any).addListener(
43
88
  "SAFE_AREA_INSETS_CHANGE",
44
89
  (insets: SafeAreaInsets) => {
@@ -52,21 +97,39 @@ export default React.forwardRef<View, ViewProps>(
52
97
  subscription.remove();
53
98
  };
54
99
  },
55
- [setTopInset, setLeftInset, setRightInset, setBottomInset]
100
+ [setTopInset, setLeftInset, setRightInset, setBottomInset, measurement.pageY]
56
101
  );
57
102
 
103
+ useEffect(() => {
104
+ measureView();
105
+ }, []);
106
+
107
+ const isPaddingBottomExplicit = style?.paddingBottom !== undefined;
108
+ const isPaddingTopExplicit = style?.paddingTop !== undefined;
109
+ const isPaddingLeftExplicit = style?.paddingLeft !== undefined;
110
+ const isPaddingRightExplicit = style?.paddingRight !== undefined;
111
+
112
+ const windowHeight = Dimensions.get('window').height;
113
+ const paddingTop = getPaddingTop(topInset, measurement.pageY);
114
+ const paddingBottom = getPaddingBottom(bottomInset, topInset, paddingTop, measurement.height, windowHeight, measurement.pageY, layout.y);
115
+
58
116
  return (
59
117
  <View
60
- ref={ref}
118
+ ref={safeAreaViewRef}
61
119
  style={[
62
120
  style,
63
121
  {
64
- paddingTop: topInset,
65
- paddingLeft: leftInset,
66
- paddingRight: rightInset,
67
- paddingBottom: bottomInset,
122
+ paddingTop: isPaddingTopExplicit ? style.paddingBottom : paddingTop,
123
+ paddingLeft: isPaddingLeftExplicit ? style.paddingLeft : leftInset,
124
+ paddingRight: isPaddingRightExplicit ? style.paddingRight : rightInset,
125
+ paddingBottom: isPaddingBottomExplicit ? style.paddingBottom : paddingBottom,
68
126
  },
69
127
  ]}
128
+ onLayout={(event) => {
129
+ setLayout(event.nativeEvent.layout);
130
+ measureView();
131
+ otherProps?.onLayout && otherProps.onLayout(event);
132
+ }}
70
133
  {...otherProps}
71
134
  >
72
135
  {children}
@@ -684,8 +684,6 @@ type State = {|
684
684
  // RNOH patch - resolving flashScrollIndicators command on the JS side
685
685
  // as it is currently not feasible on the native side
686
686
  showScrollIndicator: boolean,
687
- contentOffset: ?number,
688
- contentHeight: ?number,
689
687
  |};
690
688
 
691
689
  const IS_ANIMATING_TOUCH_START_THRESHOLD_MS = 16;
@@ -774,8 +772,6 @@ class ScrollView extends React.Component<Props, State> {
774
772
  // RNOH patch - resolving flashScrollIndicators command on the JS side
775
773
  // as it is currently not feasible on the native side
776
774
  showScrollIndicator: false,
777
- contentOffset: null,
778
- contentHeight: null,
779
775
  };
780
776
 
781
777
  componentDidMount() {
@@ -1192,15 +1188,14 @@ class ScrollView extends React.Component<Props, State> {
1192
1188
  );
1193
1189
  }
1194
1190
  }
1195
- this.setState({
1196
- contentOffset: e.nativeEvent.contentOffset.y
1197
- });
1198
1191
  this._observedScrollSinceBecomingResponder = true;
1199
1192
  this.props.onScroll && this.props.onScroll(e);
1200
1193
  };
1201
1194
 
1202
1195
  _handleLayout = (e: LayoutEvent) => {
1203
- this.setState({ layoutHeight: e.nativeEvent.layout.height });
1196
+ if (this.props.invertStickyHeaders === true) {
1197
+ this.setState({ layoutHeight: e.nativeEvent.layout.height });
1198
+ }
1204
1199
  if (this.props.onLayout) {
1205
1200
  this.props.onLayout(e);
1206
1201
  }
@@ -1208,26 +1203,6 @@ class ScrollView extends React.Component<Props, State> {
1208
1203
 
1209
1204
  _handleContentOnLayout = (e: LayoutEvent) => {
1210
1205
  const { width, height } = e.nativeEvent.layout;
1211
- /**
1212
- * RNOH patch - Fixed the issue where sticky headers are in disordered position after foldable phone is expanded/folded.
1213
- * When a foldable phone is expanded/folded, the height of the list items often changes,
1214
- * causing the content height of the ScrollView to change.
1215
- * But since the scroll event is not triggered, the position of the sticky headers is
1216
- * still offset according to the original content height.
1217
- * So we should recalculate the contentOffset based on the new contentHeight and trigger
1218
- * the scroll event to fix the position of sticky headers
1219
- */
1220
- let { contentOffset, contentHeight, layoutHeight } = this.state;
1221
- if (contentOffset && contentHeight) {
1222
- contentOffset *= (height - layoutHeight) / (contentHeight - layoutHeight);
1223
- (contentOffset < 0) && (contentOffset = 0);
1224
- this.scrollTo({ y: contentOffset, animated: false });
1225
- this._scrollAnimatedValue.setValue(contentOffset);
1226
- }
1227
- this.setState({
1228
- contentOffset,
1229
- contentHeight: height
1230
- });
1231
1206
  this.props.onContentSizeChange &&
1232
1207
  this.props.onContentSizeChange(width, height);
1233
1208
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native-oh/react-native-harmony",
3
- "version": "0.72.28",
3
+ "version": "0.72.29",
4
4
  "description": "",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/",
@@ -49,7 +49,7 @@
49
49
  "./*.har"
50
50
  ],
51
51
  "dependencies": {
52
- "@react-native-oh/react-native-harmony-cli": "^0.0.26-11",
52
+ "@react-native-oh/react-native-harmony-cli": "^0.0.26-20",
53
53
  "colors": "^1.4.0",
54
54
  "fs-extra": "^11.1.1",
55
55
  "metro": "^0.76.3",
index 5e2274c..6f4d7b1 100644
Binary file